ansiq_widgets/
scrollbar.rs1use ansiq_core::{
2 Element, ElementKind, Layout, Length, ScrollHandler, ScrollbarOrientation, ScrollbarProps,
3 ScrollbarState, Style, symbols::scrollbar::Set as ScrollbarSymbolSet,
4};
5
6fn default_symbols(orientation: ScrollbarOrientation) -> ScrollbarSymbolSet {
7 if orientation.is_vertical() {
8 ansiq_core::symbols::scrollbar::DOUBLE_VERTICAL
9 } else {
10 ansiq_core::symbols::scrollbar::DOUBLE_HORIZONTAL
11 }
12}
13
14pub struct Scrollbar<Message = ()> {
15 orientation: ScrollbarOrientation,
16 state: ScrollbarState,
17 thumb_symbol: String,
18 thumb_style: Style,
19 track_symbol: Option<String>,
20 track_style: Style,
21 begin_symbol: Option<String>,
22 begin_style: Style,
23 end_symbol: Option<String>,
24 end_style: Style,
25 on_scroll: Option<ScrollHandler<Message>>,
26 layout: Layout,
27 style: Style,
28 focusable: bool,
29}
30
31impl<Message> Default for Scrollbar<Message> {
32 fn default() -> Self {
33 Self::new(ScrollbarOrientation::VerticalRight)
34 }
35}
36
37impl<Message> Scrollbar<Message> {
38 pub fn new(orientation: ScrollbarOrientation) -> Self {
39 let symbols = default_symbols(orientation);
40 Self {
41 orientation,
42 state: ScrollbarState::default(),
43 thumb_symbol: symbols.thumb.to_string(),
44 thumb_style: Style::default(),
45 track_symbol: Some(symbols.track.to_string()),
46 track_style: Style::default(),
47 begin_symbol: Some(symbols.begin.to_string()),
48 begin_style: Style::default(),
49 end_symbol: Some(symbols.end.to_string()),
50 end_style: Style::default(),
51 on_scroll: None,
52 layout: match orientation {
53 ScrollbarOrientation::VerticalRight | ScrollbarOrientation::VerticalLeft => {
54 Layout {
55 width: Length::Fixed(1),
56 height: Length::Fill,
57 }
58 }
59 ScrollbarOrientation::HorizontalBottom | ScrollbarOrientation::HorizontalTop => {
60 Layout {
61 width: Length::Fill,
62 height: Length::Fixed(1),
63 }
64 }
65 },
66 style: Style::default(),
67 focusable: false,
68 }
69 }
70
71 pub fn state(mut self, state: ScrollbarState) -> Self {
72 self.state = state;
73 self
74 }
75
76 pub fn position(mut self, position: usize) -> Self {
77 self.state = self.state.position(position);
78 self
79 }
80
81 pub fn content_length(mut self, content_length: usize) -> Self {
82 self.state = self.state.content_length(content_length);
83 self
84 }
85
86 pub fn viewport_length(self, viewport_length: usize) -> Self {
87 self.viewport_content_length(viewport_length)
88 }
89
90 pub fn viewport_content_length(mut self, viewport_length: usize) -> Self {
91 self.state = self.state.viewport_content_length(viewport_length);
92 self
93 }
94
95 pub fn orientation(mut self, orientation: ScrollbarOrientation) -> Self {
96 self.orientation = orientation;
97 let symbols = default_symbols(orientation);
98 self = self.symbols(symbols);
99 self.layout = match orientation {
100 ScrollbarOrientation::VerticalRight | ScrollbarOrientation::VerticalLeft => Layout {
101 width: Length::Fixed(1),
102 height: Length::Fill,
103 },
104 ScrollbarOrientation::HorizontalBottom | ScrollbarOrientation::HorizontalTop => {
105 Layout {
106 width: Length::Fill,
107 height: Length::Fixed(1),
108 }
109 }
110 };
111 self
112 }
113
114 pub fn orientation_and_symbol(
115 mut self,
116 orientation: ScrollbarOrientation,
117 symbols: ScrollbarSymbolSet,
118 ) -> Self {
119 self.orientation = orientation;
120 self = self.symbols(symbols);
121 self.layout = match orientation {
122 ScrollbarOrientation::VerticalRight | ScrollbarOrientation::VerticalLeft => Layout {
123 width: Length::Fixed(1),
124 height: Length::Fill,
125 },
126 ScrollbarOrientation::HorizontalBottom | ScrollbarOrientation::HorizontalTop => {
127 Layout {
128 width: Length::Fill,
129 height: Length::Fixed(1),
130 }
131 }
132 };
133 self
134 }
135
136 pub fn symbols(mut self, symbols: ScrollbarSymbolSet) -> Self {
137 self.thumb_symbol = symbols.thumb.to_string();
138 if self.track_symbol.is_some() {
139 self.track_symbol = Some(symbols.track.to_string());
140 }
141 if self.begin_symbol.is_some() {
142 self.begin_symbol = Some(symbols.begin.to_string());
143 }
144 if self.end_symbol.is_some() {
145 self.end_symbol = Some(symbols.end.to_string());
146 }
147 self
148 }
149
150 pub fn thumb_symbol(mut self, thumb_symbol: impl Into<String>) -> Self {
151 self.thumb_symbol = thumb_symbol.into();
152 self
153 }
154
155 pub fn thumb_style<S: Into<Style>>(mut self, style: S) -> Self {
156 self.thumb_style = style.into();
157 self
158 }
159
160 pub fn track_symbol<S: Into<String>>(mut self, track_symbol: Option<S>) -> Self {
161 self.track_symbol = track_symbol.map(Into::into);
162 self
163 }
164
165 pub fn track_style<S: Into<Style>>(mut self, style: S) -> Self {
166 self.track_style = style.into();
167 self
168 }
169
170 pub fn begin_symbol<S: Into<String>>(mut self, begin_symbol: Option<S>) -> Self {
171 self.begin_symbol = begin_symbol.map(Into::into);
172 self
173 }
174
175 pub fn begin_style<S: Into<Style>>(mut self, style: S) -> Self {
176 self.begin_style = style.into();
177 self
178 }
179
180 pub fn end_symbol<S: Into<String>>(mut self, end_symbol: Option<S>) -> Self {
181 self.end_symbol = end_symbol.map(Into::into);
182 self
183 }
184
185 pub fn end_style<S: Into<Style>>(mut self, style: S) -> Self {
186 self.end_style = style.into();
187 self
188 }
189
190 pub fn on_scroll<F>(mut self, handler: F) -> Self
191 where
192 F: FnMut(usize) -> Option<Message> + 'static,
193 {
194 self.on_scroll = Some(std::boxed::Box::new(handler));
195 self.focusable = true;
196 self
197 }
198
199 pub fn layout(mut self, layout: Layout) -> Self {
200 self.layout = layout;
201 self
202 }
203
204 pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
205 let style = style.into();
206 self.style = style;
207 self.thumb_style = style;
208 self.track_style = style;
209 self.begin_style = style;
210 self.end_style = style;
211 self
212 }
213
214 pub fn build(self) -> Element<Message> {
215 Element::new(ElementKind::Scrollbar(ScrollbarProps {
216 orientation: self.orientation,
217 state: self.state,
218 thumb_symbol: self.thumb_symbol,
219 thumb_style: self.thumb_style,
220 track_symbol: self.track_symbol,
221 track_style: self.track_style,
222 begin_symbol: self.begin_symbol,
223 begin_style: self.begin_style,
224 end_symbol: self.end_symbol,
225 end_style: self.end_style,
226 on_scroll: self.on_scroll,
227 }))
228 .with_layout(self.layout)
229 .with_style(self.style)
230 .with_focusable(self.focusable)
231 }
232}