freya_components/scrollviews/
scrollbar.rs

1use freya_core::prelude::*;
2use torin::{
3    prelude::{
4        Alignment,
5        Direction,
6        Position,
7    },
8    size::Size,
9};
10
11use crate::{
12    get_theme,
13    scrollviews::{
14        ScrollThumb,
15        shared::Axis,
16    },
17    theming::component_themes::ScrollBarThemePartial,
18};
19
20#[derive(Clone, Copy, PartialEq, Debug)]
21enum ScrollBarState {
22    Idle,
23    Hovering,
24}
25
26#[derive(Clone, PartialEq)]
27pub struct ScrollBar {
28    pub(crate) theme: Option<ScrollBarThemePartial>,
29    pub clicking_scrollbar: State<Option<(Axis, f64)>>,
30    pub axis: Axis,
31    pub offset: f32,
32    pub thumb: ScrollThumb,
33}
34
35impl RenderOwned for ScrollBar {
36    fn render(self) -> impl IntoElement {
37        let scrollbar_theme = get_theme!(&self.theme, scrollbar);
38
39        let mut state = use_state(|| ScrollBarState::Idle);
40
41        let (size, opacity) = match *state.read() {
42            _ if self.clicking_scrollbar.read().is_some() => (16., 160),
43            ScrollBarState::Idle => (5., 0),
44            ScrollBarState::Hovering => (16., 160),
45        };
46
47        let (
48            width,
49            height,
50            offset_x,
51            offset_y,
52            inner_offset_x,
53            inner_offset_y,
54            inner_width,
55            inner_height,
56        ) = match self.axis {
57            Axis::X => (
58                Size::fill(),
59                Size::px(16.),
60                0.,
61                -16.,
62                self.offset,
63                0.,
64                Size::fill(),
65                Size::px(size),
66            ),
67            Axis::Y => (
68                Size::px(16.),
69                Size::fill(),
70                -16.,
71                0.,
72                0.,
73                self.offset,
74                Size::px(size),
75                Size::fill(),
76            ),
77        };
78
79        let on_pointer_enter = move |_| {
80            state.set(ScrollBarState::Hovering);
81        };
82        let on_pointer_leave = move |_| state.set(ScrollBarState::Idle);
83
84        rect()
85            .position(Position::new_absolute())
86            .width(width)
87            .height(height)
88            .offset_x(offset_x)
89            .offset_y(offset_y)
90            .layer(999)
91            .child(
92                rect()
93                    .width(Size::fill())
94                    .height(Size::fill())
95                    .direction(if self.axis == Axis::Y {
96                        Direction::vertical()
97                    } else {
98                        Direction::horizontal()
99                    })
100                    .cross_align(Alignment::end())
101                    .background(scrollbar_theme.background.with_a(opacity))
102                    .on_pointer_enter(on_pointer_enter)
103                    .on_pointer_leave(on_pointer_leave)
104                    .child(
105                        rect()
106                            .width(inner_width)
107                            .height(inner_height)
108                            .offset_x(inner_offset_x)
109                            .offset_y(inner_offset_y)
110                            .child(self.thumb),
111                    ),
112            )
113    }
114}