freya_components/scrollviews/
scrollbar.rs

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