use egui::style::ScrollStyle;
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ScrollVisibility {
AlwaysVisible,
VisibleWhenNeeded,
AlwaysHidden,
}
impl ScrollVisibility {
pub fn to_egui(self) -> egui::scroll_area::ScrollBarVisibility {
use egui::scroll_area::ScrollBarVisibility as V;
match self {
ScrollVisibility::AlwaysVisible => V::AlwaysVisible,
ScrollVisibility::VisibleWhenNeeded => V::VisibleWhenNeeded,
ScrollVisibility::AlwaysHidden => V::AlwaysHidden,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub struct ScrollSpec {
pub floating: bool,
pub bar_width: f32,
pub handle_min_length: f32,
pub bar_inner_margin: f32,
pub bar_outer_margin: f32,
pub floating_width: f32,
pub floating_allocated_width: f32,
pub foreground_color: bool,
pub dormant_background_opacity: f32,
pub active_background_opacity: f32,
pub interact_background_opacity: f32,
pub dormant_handle_opacity: f32,
pub active_handle_opacity: f32,
pub interact_handle_opacity: f32,
pub visibility: ScrollVisibility,
}
impl Default for ScrollSpec {
fn default() -> Self {
Self::windows()
}
}
impl ScrollSpec {
pub fn windows() -> Self {
Self {
floating: false,
bar_width: 14.0,
handle_min_length: 16.0,
bar_inner_margin: 4.0,
bar_outer_margin: 0.0,
floating_width: 2.0,
floating_allocated_width: 0.0,
foreground_color: false,
dormant_background_opacity: 0.6,
active_background_opacity: 0.7,
interact_background_opacity: 0.9,
dormant_handle_opacity: 0.7,
active_handle_opacity: 0.9,
interact_handle_opacity: 1.0,
visibility: ScrollVisibility::AlwaysVisible,
}
}
pub fn macos() -> Self {
Self {
floating: true,
bar_width: 10.0,
handle_min_length: 16.0,
bar_inner_margin: 2.0,
bar_outer_margin: 0.0,
floating_width: 8.0,
floating_allocated_width: 0.0,
foreground_color: true,
dormant_background_opacity: 0.0,
active_background_opacity: 0.0,
interact_background_opacity: 0.4,
dormant_handle_opacity: 0.0,
active_handle_opacity: 0.6,
interact_handle_opacity: 1.0,
visibility: ScrollVisibility::VisibleWhenNeeded,
}
}
pub fn device() -> Self {
Self {
floating: false,
bar_width: 16.0,
handle_min_length: 24.0,
bar_inner_margin: 4.0,
bar_outer_margin: 0.0,
floating_width: 2.0,
floating_allocated_width: 0.0,
foreground_color: false,
dormant_background_opacity: 1.0,
active_background_opacity: 1.0,
interact_background_opacity: 1.0,
dormant_handle_opacity: 1.0,
active_handle_opacity: 1.0,
interact_handle_opacity: 1.0,
visibility: ScrollVisibility::AlwaysVisible,
}
}
pub fn to_scroll_style(&self) -> ScrollStyle {
let mut s = if self.floating { ScrollStyle::floating() } else { ScrollStyle::solid() };
s.floating = self.floating;
s.bar_width = self.bar_width;
s.handle_min_length = self.handle_min_length;
s.bar_inner_margin = self.bar_inner_margin;
s.bar_outer_margin = self.bar_outer_margin;
s.floating_width = self.floating_width;
s.floating_allocated_width = self.floating_allocated_width;
s.foreground_color = self.foreground_color;
s.dormant_background_opacity = self.dormant_background_opacity;
s.active_background_opacity = self.active_background_opacity;
s.interact_background_opacity = self.interact_background_opacity;
s.dormant_handle_opacity = self.dormant_handle_opacity;
s.active_handle_opacity = self.active_handle_opacity;
s.interact_handle_opacity = self.interact_handle_opacity;
s
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn windows_is_solid_and_always_visible() {
let s = ScrollSpec::windows();
assert!(!s.floating);
assert_eq!(s.visibility, ScrollVisibility::AlwaysVisible);
assert!(s.bar_width >= 14.0);
}
#[test]
fn macos_is_floating_and_dormant_invisible() {
let s = ScrollSpec::macos();
assert!(s.floating);
assert_eq!(s.dormant_handle_opacity, 0.0, "macOS bar fades away when idle");
}
#[test]
fn device_is_always_opaque() {
let s = ScrollSpec::device();
assert_eq!(s.dormant_handle_opacity, 1.0);
assert_eq!(s.visibility, ScrollVisibility::AlwaysVisible);
}
#[test]
fn to_scroll_style_copies_all_fields() {
let s = ScrollSpec::macos();
let e = s.to_scroll_style();
assert_eq!(e.bar_width, s.bar_width);
assert_eq!(e.floating, s.floating);
assert_eq!(e.interact_handle_opacity, s.interact_handle_opacity);
}
}