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