tui_lipan/widgets/slider/
mod.rs1mod layout;
4mod node;
5mod reconcile;
6
7pub use layout::measure_slider;
8pub use node::SliderNode;
9pub use reconcile::reconcile_slider;
10
11use unicode_width::UnicodeWidthStr;
12
13use crate::callback::{Callback, KeyHandler};
14use crate::core::element::Element;
15use crate::style::{Length, Padding, Style, StyleSlot};
16use crate::utils::gradient::ColorGradient;
17
18#[derive(Clone)]
20pub struct Slider {
21 pub value: f64,
23 pub min: f64,
25 pub max: f64,
27 pub step: f64,
29 pub on_change: Option<Callback<f64>>,
31 pub on_click: Option<Callback<f64>>,
33 pub on_key: Option<KeyHandler>,
35 pub style: Style,
37 pub filled_track_style: Style,
39 pub filled_track_gradient: Option<ColorGradient>,
41 pub thumb_style: Style,
43 pub thumb_gradient: Option<ColorGradient>,
45 pub label: Option<String>,
47 pub label_style: Style,
49 pub show_value: bool,
51 pub width: Length,
54 pub height: Length,
57 pub padding: Padding,
60 pub disabled: bool,
62 pub disabled_style: Style,
64 pub focusable: bool,
66 pub tab_stop: bool,
68 pub on_focus: Option<Callback<()>>,
70 pub on_blur: Option<Callback<()>>,
72 pub hover_style: StyleSlot,
74 pub focus_style: StyleSlot,
76 pub focus_thumb_style: StyleSlot,
78 pub hover_thumb_style: StyleSlot,
80 pub thumb_symbol: String,
82 pub track_symbol: String,
84 pub filled_track_symbol: String,
86 pub hover_thumb_symbol: Option<String>,
88}
89
90impl Slider {
91 pub fn new(value: f64) -> Self {
93 Self {
94 value,
95 min: 0.0,
96 max: 100.0,
97 step: 1.0,
98 on_change: None,
99 on_click: None,
100 on_key: None,
101 style: Style::default(),
102 filled_track_style: Style::default(),
103 filled_track_gradient: None,
104 thumb_style: Style::default(),
105 thumb_gradient: None,
106 label: None,
107 label_style: Style::default(),
108 show_value: true,
109 width: Length::Flex(1),
110 height: Length::Px(1),
111 padding: Padding::default(),
112 disabled: false,
113 disabled_style: Style::default(),
114 focusable: true,
115 tab_stop: true,
116 on_focus: None,
117 on_blur: None,
118 hover_style: StyleSlot::Inherit,
119 focus_style: StyleSlot::Inherit,
120 focus_thumb_style: StyleSlot::Inherit,
121 hover_thumb_style: StyleSlot::Inherit,
122 thumb_symbol: "●".to_string(),
123 track_symbol: "─".to_string(),
124 filled_track_symbol: "━".to_string(),
125 hover_thumb_symbol: None,
126 }
127 }
128
129 pub fn min(mut self, min: f64) -> Self {
131 self.min = min;
132 self
133 }
134
135 pub fn max(mut self, max: f64) -> Self {
137 self.max = max;
138 self
139 }
140
141 pub fn step(mut self, step: f64) -> Self {
143 self.step = step;
144 self
145 }
146
147 pub fn label(mut self, label: impl Into<String>) -> Self {
149 self.label = Some(label.into());
150 self
151 }
152
153 pub fn on_change(mut self, cb: Callback<f64>) -> Self {
155 self.on_change = Some(cb);
156 self
157 }
158
159 pub fn on_click(mut self, cb: Callback<f64>) -> Self {
161 self.on_click = Some(cb);
162 self
163 }
164
165 pub fn on_key(mut self, handler: KeyHandler) -> Self {
167 self.on_key = Some(handler);
168 self
169 }
170
171 pub fn label_style(mut self, style: Style) -> Self {
173 self.label_style = style;
174 self
175 }
176
177 pub fn show_value(mut self, show: bool) -> Self {
179 self.show_value = show;
180 self
181 }
182
183 pub fn style(mut self, style: Style) -> Self {
185 self.style = style;
186 self
187 }
188
189 pub fn filled_track_style(mut self, style: Style) -> Self {
191 self.filled_track_style = style;
192 self
193 }
194
195 pub fn filled_track_gradient(mut self, gradient: ColorGradient) -> Self {
197 self.filled_track_gradient = Some(gradient);
198 self
199 }
200
201 pub fn thumb_style(mut self, style: Style) -> Self {
203 self.thumb_style = style;
204 self
205 }
206
207 pub fn thumb_gradient(mut self, gradient: ColorGradient) -> Self {
209 self.thumb_gradient = Some(gradient);
210 self
211 }
212
213 pub fn width(mut self, width: Length) -> Self {
215 self.width = width;
216 self
217 }
218
219 pub fn height(mut self, height: Length) -> Self {
221 self.height = height;
222 self
223 }
224
225 pub fn disabled(mut self, disabled: bool) -> Self {
227 self.disabled = disabled;
228 self
229 }
230
231 pub fn disabled_style(mut self, style: Style) -> Self {
233 self.disabled_style = style;
234 self
235 }
236
237 pub fn focusable(mut self, focusable: bool) -> Self {
239 self.focusable = focusable;
240 self
241 }
242
243 pub fn tab_stop(mut self, tab_stop: bool) -> Self {
245 self.tab_stop = tab_stop;
246 self
247 }
248
249 pub fn on_focus(mut self, cb: Callback<()>) -> Self {
251 self.on_focus = Some(cb);
252 self
253 }
254
255 pub fn on_blur(mut self, cb: Callback<()>) -> Self {
257 self.on_blur = Some(cb);
258 self
259 }
260
261 pub fn hover_style(mut self, style: Style) -> Self {
263 self.hover_style = StyleSlot::Replace(style);
264 self
265 }
266
267 pub fn extend_hover_style(mut self, style: Style) -> Self {
269 self.hover_style = StyleSlot::Extend(style);
270 self
271 }
272
273 pub fn inherit_hover_style(mut self) -> Self {
275 self.hover_style = StyleSlot::Inherit;
276 self
277 }
278
279 pub fn hover_style_slot(mut self, slot: StyleSlot) -> Self {
281 self.hover_style = slot;
282 self
283 }
284
285 pub fn focus_style(mut self, style: Style) -> Self {
287 self.focus_style = StyleSlot::Replace(style);
288 self
289 }
290
291 pub fn extend_focus_style(mut self, style: Style) -> Self {
293 self.focus_style = StyleSlot::Extend(style);
294 self
295 }
296
297 pub fn inherit_focus_style(mut self) -> Self {
299 self.focus_style = StyleSlot::Inherit;
300 self
301 }
302
303 pub fn focus_style_slot(mut self, slot: StyleSlot) -> Self {
305 self.focus_style = slot;
306 self
307 }
308
309 pub fn focus_thumb_style(mut self, style: Style) -> Self {
311 self.focus_thumb_style = StyleSlot::Replace(style);
312 self
313 }
314
315 pub fn extend_focus_thumb_style(mut self, style: Style) -> Self {
317 self.focus_thumb_style = StyleSlot::Extend(style);
318 self
319 }
320
321 pub fn inherit_focus_thumb_style(mut self) -> Self {
323 self.focus_thumb_style = StyleSlot::Inherit;
324 self
325 }
326
327 pub fn focus_thumb_style_slot(mut self, slot: StyleSlot) -> Self {
329 self.focus_thumb_style = slot;
330 self
331 }
332
333 pub fn hover_thumb_style(mut self, style: Style) -> Self {
335 self.hover_thumb_style = StyleSlot::Replace(style);
336 self
337 }
338
339 pub fn extend_hover_thumb_style(mut self, style: Style) -> Self {
341 self.hover_thumb_style = StyleSlot::Extend(style);
342 self
343 }
344
345 pub fn inherit_hover_thumb_style(mut self) -> Self {
347 self.hover_thumb_style = StyleSlot::Inherit;
348 self
349 }
350
351 pub fn hover_thumb_style_slot(mut self, slot: StyleSlot) -> Self {
353 self.hover_thumb_style = slot;
354 self
355 }
356
357 pub fn thumb_symbol(mut self, symbol: impl Into<String>) -> Self {
359 self.thumb_symbol = symbol.into();
360 self
361 }
362
363 pub fn track_symbol(mut self, symbol: impl Into<String>) -> Self {
365 self.track_symbol = symbol.into();
366 self
367 }
368
369 pub fn filled_track_symbol(mut self, symbol: impl Into<String>) -> Self {
371 self.filled_track_symbol = symbol.into();
372 self
373 }
374
375 pub fn hover_thumb_symbol(mut self, symbol: impl Into<String>) -> Self {
377 self.hover_thumb_symbol = Some(symbol.into());
378 self
379 }
380}
381
382impl From<Slider> for Element {
383 fn from(mut slider: Slider) -> Self {
384 if slider.min > slider.max {
386 std::mem::swap(&mut slider.min, &mut slider.max);
387 }
388 if (slider.max - slider.min).abs() < f64::EPSILON {
390 slider.max = slider.min + 1.0;
391 }
392 slider.value = slider.value.clamp(slider.min, slider.max);
394 Element::new(crate::core::element::ElementKind::Slider(slider))
395 }
396}
397
398pub(crate) fn value_slot_width(min: f64, max: f64) -> u16 {
399 let min_text = format!("{:.1}", min);
400 let max_text = format!("{:.1}", max);
401 let width = UnicodeWidthStr::width(min_text.as_str())
402 .max(UnicodeWidthStr::width(max_text.as_str()))
403 .min(u16::MAX as usize) as u16;
404 width.max(1)
405}
406
407impl crate::layout::hash::LayoutHash for Slider {
408 fn layout_hash(
409 &self,
410 hasher: &mut impl std::hash::Hasher,
411 _recurse: &dyn Fn(&crate::core::element::Element) -> Option<u64>,
412 ) -> Option<()> {
413 use std::hash::Hash;
414 self.width.hash(hasher);
415 self.height.hash(hasher);
416 self.label.hash(hasher);
417 self.padding.hash(hasher);
418 Some(())
419 }
420}