atmos/os_lib/web_engine/
scrollbar.rs1use alloc::string::{String, ToString};
6use alloc::vec::Vec;
7use crate::os_lib::css::parse_color;
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
11pub enum ScrollbarWidth {
12 #[default]
13 Auto,
14 Thin,
15 None,
16}
17
18impl ScrollbarWidth {
19 pub fn parse(s: &str) -> Option<Self> {
20 match s.trim().to_ascii_lowercase().as_str() {
21 "auto" => Some(ScrollbarWidth::Auto),
22 "thin" => Some(ScrollbarWidth::Thin),
23 "none" => Some(ScrollbarWidth::None),
24 _ => None,
25 }
26 }
27
28 pub fn resolve(s: &str) -> Self {
29 Self::parse(s).unwrap_or(ScrollbarWidth::Auto)
30 }
31
32 pub fn thumb_width_px(&self) -> i32 {
34 match self {
35 ScrollbarWidth::Auto => 6,
36 ScrollbarWidth::Thin => 3,
37 ScrollbarWidth::None => 0,
38 }
39 }
40
41 pub fn track_width_px(&self) -> i32 {
43 match self {
44 ScrollbarWidth::Auto => 10,
45 ScrollbarWidth::Thin => 5,
46 ScrollbarWidth::None => 0,
47 }
48 }
49
50 pub fn is_none(&self) -> bool {
51 matches!(self, ScrollbarWidth::None)
52 }
53}
54
55#[derive(Clone, Copy, Debug, PartialEq, Eq)]
57pub struct ScrollbarColor {
58 pub thumb: u32,
59 pub track: u32,
60}
61
62#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
63pub enum ScrollbarColorMode {
64 #[default]
65 Auto,
66 Custom(ScrollbarColor),
67}
68
69pub fn split_scrollbar_color_tokens(val: &str) -> Option<(String, String)> {
72 let s = val.trim();
73 if s.is_empty() {
74 return None;
75 }
76 let mut tokens = Vec::new();
77 let mut current = String::new();
78 let mut depth = 0;
79
80 for ch in s.chars() {
81 if ch == '(' {
82 depth += 1;
83 current.push(ch);
84 } else if ch == ')' {
85 if depth > 0 {
86 depth -= 1;
87 }
88 current.push(ch);
89 } else if ch.is_whitespace() && depth == 0 {
90 if !current.trim().is_empty() {
91 tokens.push(current.trim().to_string());
92 current.clear();
93 }
94 } else {
95 current.push(ch);
96 }
97 }
98 if !current.trim().is_empty() {
99 tokens.push(current.trim().to_string());
100 }
101
102 if tokens.len() == 2 {
103 Some((tokens.remove(0), tokens.remove(0)))
104 } else {
105 None
106 }
107}
108
109pub fn parse_scrollbar_color(val: &str) -> Option<ScrollbarColorMode> {
112 let s = val.trim();
113 if s.is_empty() {
114 return None;
115 }
116 if s.eq_ignore_ascii_case("auto") {
117 return Some(ScrollbarColorMode::Auto);
118 }
119
120 let (thumb_str, track_str) = split_scrollbar_color_tokens(s)?;
121 let thumb = parse_color(&thumb_str)?;
122 let track = parse_color(&track_str)?;
123 Some(ScrollbarColorMode::Custom(ScrollbarColor { thumb, track }))
124}