Skip to main content

material_ui_rs/design/style/
scrollable.rs

1use iced_widget::core::{Background, Border, Shadow, border};
2use iced_widget::scrollable::{AutoScroll, Catalog, Rail, Scroller, Status, Style, StyleFn};
3
4use crate::Theme;
5use crate::style::container::surface_container;
6use crate::utils::{
7    HOVERED_LAYER_OPACITY, PRESSED_LAYER_OPACITY, disabled_container, disabled_text, mix,
8};
9
10impl Catalog for Theme {
11    type Class<'a> = StyleFn<'a, Self>;
12
13    fn default<'a>() -> Self::Class<'a> {
14        Box::new(default)
15    }
16
17    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {
18        class(self, status)
19    }
20}
21
22pub fn default(theme: &Theme, status: Status) -> Style {
23    let surface = theme.colors().surface;
24
25    let active_rail = Rail {
26        background: None,
27        scroller: Scroller {
28            background: surface.text.into(),
29            border: border::rounded(9999),
30        },
31        border: Border::default(),
32    };
33
34    let disabled_rail = Rail {
35        background: Some(Background::Color(disabled_container(surface.text))),
36        scroller: Scroller {
37            background: disabled_text(surface.text).into(),
38            border: border::rounded(9999),
39        },
40        ..active_rail
41    };
42
43    let active_auto_scroll = AutoScroll {
44        background: surface.color.into(),
45        border: border::rounded(500).width(1).color(surface.text),
46        icon: surface.text,
47        shadow: Shadow::default(),
48    };
49
50    let disabled_auto_scroll = AutoScroll {
51        background: disabled_container(surface.text).into(),
52        border: border::rounded(9999),
53        icon: disabled_text(surface.text),
54        shadow: Shadow::default(),
55    };
56
57    let style = Style {
58        container: surface_container(theme),
59        vertical_rail: active_rail,
60        horizontal_rail: active_rail,
61        gap: None,
62        auto_scroll: active_auto_scroll,
63    };
64
65    match status {
66        Status::Active {
67            is_horizontal_scrollbar_disabled,
68            is_vertical_scrollbar_disabled,
69        } => Style {
70            horizontal_rail: if is_horizontal_scrollbar_disabled {
71                disabled_rail
72            } else {
73                active_rail
74            },
75            vertical_rail: if is_vertical_scrollbar_disabled {
76                disabled_rail
77            } else {
78                active_rail
79            },
80            auto_scroll: if is_vertical_scrollbar_disabled && is_horizontal_scrollbar_disabled {
81                disabled_auto_scroll
82            } else {
83                active_auto_scroll
84            },
85            ..style
86        },
87        Status::Hovered {
88            is_horizontal_scrollbar_hovered,
89            is_vertical_scrollbar_hovered,
90            is_horizontal_scrollbar_disabled,
91            is_vertical_scrollbar_disabled,
92        } => {
93            let hovered_rail = Rail {
94                scroller: Scroller {
95                    background: mix(surface.text, surface.color, HOVERED_LAYER_OPACITY).into(),
96                    border: border::rounded(9999),
97                },
98                ..active_rail
99            };
100
101            Style {
102                horizontal_rail: if is_horizontal_scrollbar_disabled {
103                    disabled_rail
104                } else if is_horizontal_scrollbar_hovered {
105                    hovered_rail
106                } else {
107                    active_rail
108                },
109                vertical_rail: if is_vertical_scrollbar_disabled {
110                    disabled_rail
111                } else if is_vertical_scrollbar_hovered {
112                    hovered_rail
113                } else {
114                    active_rail
115                },
116                auto_scroll: if is_vertical_scrollbar_disabled && is_horizontal_scrollbar_disabled {
117                    disabled_auto_scroll
118                } else {
119                    active_auto_scroll
120                },
121                ..style
122            }
123        }
124        Status::Dragged {
125            is_horizontal_scrollbar_dragged,
126            is_vertical_scrollbar_dragged,
127            is_horizontal_scrollbar_disabled,
128            is_vertical_scrollbar_disabled,
129        } => {
130            let dragged_rail = Rail {
131                scroller: Scroller {
132                    background: mix(surface.text, surface.color, PRESSED_LAYER_OPACITY).into(),
133                    border: border::rounded(9999),
134                },
135                ..active_rail
136            };
137
138            Style {
139                horizontal_rail: if is_horizontal_scrollbar_disabled {
140                    disabled_rail
141                } else if is_horizontal_scrollbar_dragged {
142                    dragged_rail
143                } else {
144                    active_rail
145                },
146                vertical_rail: if is_vertical_scrollbar_disabled {
147                    disabled_rail
148                } else if is_vertical_scrollbar_dragged {
149                    dragged_rail
150                } else {
151                    active_rail
152                },
153                auto_scroll: if is_vertical_scrollbar_disabled && is_horizontal_scrollbar_disabled {
154                    disabled_auto_scroll
155                } else {
156                    active_auto_scroll
157                },
158                ..style
159            }
160        }
161    }
162}