tui_lipan/widgets/progress/
mod.rs1mod layout;
4mod node;
5mod reconcile;
6
7pub use layout::measure_progress_bar;
8pub use node::ProgressNode;
9pub use reconcile::reconcile_progress_bar;
10
11use crate::callback::Callback;
12use crate::core::element::{Element, ElementKind};
13use crate::core::event::MouseEvent;
14use crate::style::{Length, Padding, Style, StyleSlot};
15use crate::utils::gradient::ColorGradient;
16
17#[derive(Clone, Copy, Debug, PartialEq)]
19pub struct ProgressEvent {
20 pub progress: f64,
22}
23
24#[derive(Clone, Copy, Debug, PartialEq)]
26pub struct ProgressZone {
27 pub upto: f64,
29 pub style: Style,
31 pub symbol: Option<char>,
33}
34
35impl ProgressZone {
36 pub fn new(upto: f64) -> Self {
38 Self {
39 upto: upto.clamp(0.0, 1.0),
40 style: Style::default(),
41 symbol: None,
42 }
43 }
44
45 pub fn style(mut self, style: Style) -> Self {
47 self.style = style;
48 self
49 }
50
51 pub fn symbol(mut self, symbol: char) -> Self {
53 self.symbol = Some(symbol);
54 self
55 }
56}
57
58#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
60pub enum ProgressStyle {
61 #[default]
63 Block,
64 Line,
66 LineDotted,
68 Dots,
70 Arrow,
72 Rect,
74 Custom {
76 filled: char,
78 empty: char,
80 },
81 Braille,
83}
84
85#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
87pub enum ProgressTextPosition {
88 Left,
90 #[default]
92 Right,
93 Above,
95 Below,
97 Middle,
99}
100
101impl ProgressStyle {
102 pub fn filled_char(self) -> char {
104 match self {
105 Self::Block => '█',
106 Self::Line | Self::LineDotted => '━',
107 Self::Dots => '●',
108 Self::Arrow => '►',
109 Self::Rect => '▮',
110 Self::Custom { filled, .. } => filled,
111 Self::Braille => '⣿',
112 }
113 }
114
115 pub fn empty_char(self) -> char {
117 match self {
118 Self::Block => '░',
119 Self::Line => '─',
120 Self::LineDotted => '┄',
121 Self::Dots => '○',
122 Self::Arrow => '─',
123 Self::Rect => '▯',
124 Self::Custom { empty, .. } => empty,
125 Self::Braille => '⣀',
126 }
127 }
128
129 pub fn partial_chars(self) -> Option<&'static [char]> {
131 match self {
132 Self::Braille => Some(&['⣀', '⣄', '⣤', '⣦', '⣶', '⣷', '⣿']),
135 _ => None,
136 }
137 }
138}
139
140#[derive(Clone)]
142pub struct ProgressBar {
143 pub progress: f64,
145 pub progress_style: ProgressStyle,
147 pub show_percentage: bool,
149 pub percentage_position: ProgressTextPosition,
151 pub label: Option<String>,
153 pub label_position: ProgressTextPosition,
155 pub filled_style: Style,
157 pub filled_gradient: Option<ColorGradient>,
159 pub empty_style: Style,
161 pub label_style: Style,
163 pub style: Style,
165 pub padding: Padding,
168 pub width: Length,
171 pub height: Length,
174 pub draggable: bool,
176 pub step: Option<f64>,
178 pub inverted: bool,
180 pub on_change: Option<Callback<ProgressEvent>>,
182 pub on_click: Option<Callback<MouseEvent>>,
184 pub focusable: bool,
186 pub focus_style: StyleSlot,
188 pub hover_style: StyleSlot,
190 pub target: Option<f64>,
192 pub target_style: Style,
194 pub target_symbol: char,
196 pub zones: Vec<ProgressZone>,
198 pub block_empty_bg_dim: f32,
200}
201
202impl Default for ProgressBar {
203 fn default() -> Self {
204 Self {
205 progress: 0.0,
206 progress_style: ProgressStyle::Block,
207 show_percentage: false,
208 percentage_position: ProgressTextPosition::Right,
209 label: None,
210 label_position: ProgressTextPosition::Right,
211 filled_style: Style::default(),
212 filled_gradient: None,
213 empty_style: Style::default(),
214 label_style: Style::default(),
215 style: Style::default(),
216 padding: Padding::default(),
217 width: Length::Flex(1),
218 height: Length::Auto,
219 draggable: false,
220 step: None,
221 inverted: false,
222 on_change: None,
223 on_click: None,
224 focusable: false,
225 focus_style: StyleSlot::Inherit,
226 hover_style: StyleSlot::Inherit,
227 target: None,
228 target_style: Style::default(),
229 target_symbol: '◆',
230 zones: Vec::new(),
231 block_empty_bg_dim: 0.85,
232 }
233 }
234}
235
236impl ProgressBar {
237 pub fn new(progress: f64) -> Self {
239 Self {
240 progress: progress.clamp(0.0, 1.0),
241 ..Self::default()
242 }
243 }
244
245 pub fn progress(mut self, progress: f64) -> Self {
247 self.progress = progress.clamp(0.0, 1.0);
248 self
249 }
250
251 pub fn inverted(mut self, inverted: bool) -> Self {
253 self.inverted = inverted;
254 self
255 }
256
257 pub fn progress_style(mut self, style: ProgressStyle) -> Self {
259 self.progress_style = style;
260 self
261 }
262
263 pub fn show_percentage(mut self, show: bool) -> Self {
265 self.show_percentage = show;
266 self
267 }
268
269 pub fn percentage_position(mut self, position: ProgressTextPosition) -> Self {
271 self.percentage_position = position;
272 self
273 }
274
275 pub fn label(mut self, label: impl Into<String>) -> Self {
277 self.label = Some(label.into());
278 self
279 }
280
281 pub fn label_position(mut self, position: ProgressTextPosition) -> Self {
283 self.label_position = position;
284 self
285 }
286
287 pub fn filled_style(mut self, style: Style) -> Self {
289 self.filled_style = style;
290 self
291 }
292
293 pub fn filled_gradient(mut self, gradient: ColorGradient) -> Self {
295 self.filled_gradient = Some(gradient);
296 self
297 }
298
299 pub fn empty_style(mut self, style: Style) -> Self {
301 self.empty_style = style;
302 self
303 }
304
305 pub fn label_style(mut self, style: Style) -> Self {
307 self.label_style = style;
308 self
309 }
310
311 pub fn style(mut self, style: Style) -> Self {
313 self.style = style;
314 self
315 }
316
317 pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
319 self.padding = padding.into();
320 self
321 }
322
323 pub fn width(mut self, width: Length) -> Self {
325 self.width = width;
326 self
327 }
328
329 pub fn height(mut self, height: Length) -> Self {
331 self.height = height;
332 self
333 }
334
335 pub fn draggable(mut self, draggable: bool) -> Self {
337 self.draggable = draggable;
338 self
339 }
340
341 pub fn step(mut self, step: f64) -> Self {
343 self.step = Some(step);
344 self
345 }
346
347 pub fn on_change(mut self, cb: Callback<ProgressEvent>) -> Self {
349 self.on_change = Some(cb);
350 self
351 }
352
353 pub fn on_click(mut self, cb: Callback<MouseEvent>) -> Self {
355 self.on_click = Some(cb);
356 self
357 }
358
359 pub fn focusable(mut self, focusable: bool) -> Self {
361 self.focusable = focusable;
362 self
363 }
364
365 pub fn focus_style(mut self, style: Style) -> Self {
367 self.focus_style = StyleSlot::Replace(style);
368 self
369 }
370
371 pub fn extend_focus_style(mut self, style: Style) -> Self {
373 self.focus_style = StyleSlot::Extend(style);
374 self
375 }
376
377 pub fn inherit_focus_style(mut self) -> Self {
379 self.focus_style = StyleSlot::Inherit;
380 self
381 }
382
383 pub fn focus_style_slot(mut self, slot: StyleSlot) -> Self {
385 self.focus_style = slot;
386 self
387 }
388
389 pub fn hover_style(mut self, style: Style) -> Self {
391 self.hover_style = StyleSlot::Replace(style);
392 self
393 }
394
395 pub fn extend_hover_style(mut self, style: Style) -> Self {
397 self.hover_style = StyleSlot::Extend(style);
398 self
399 }
400
401 pub fn inherit_hover_style(mut self) -> Self {
403 self.hover_style = StyleSlot::Inherit;
404 self
405 }
406
407 pub fn hover_style_slot(mut self, slot: StyleSlot) -> Self {
409 self.hover_style = slot;
410 self
411 }
412
413 pub fn target(mut self, target: f64) -> Self {
415 self.target = Some(target.clamp(0.0, 1.0));
416 self
417 }
418
419 pub fn clear_target(mut self) -> Self {
421 self.target = None;
422 self
423 }
424
425 pub fn target_style(mut self, style: Style) -> Self {
427 self.target_style = style;
428 self
429 }
430
431 pub fn target_symbol(mut self, symbol: char) -> Self {
433 self.target_symbol = symbol;
434 self
435 }
436
437 pub fn zones(mut self, zones: impl IntoIterator<Item = ProgressZone>) -> Self {
439 self.zones = zones.into_iter().collect();
440 self
441 }
442
443 pub fn add_zone(mut self, zone: ProgressZone) -> Self {
445 self.zones.push(zone);
446 self
447 }
448
449 pub fn block_empty_bg_dim(mut self, amount: f32) -> Self {
451 self.block_empty_bg_dim = amount.clamp(0.0, 1.0);
452 self
453 }
454}
455
456impl From<ProgressBar> for Element {
457 fn from(value: ProgressBar) -> Self {
458 Element::new(ElementKind::ProgressBar(value))
459 }
460}
461
462impl crate::layout::hash::LayoutHash for ProgressBar {
463 fn layout_hash(
464 &self,
465 hasher: &mut impl std::hash::Hasher,
466 _recurse: &dyn Fn(&Element) -> Option<u64>,
467 ) -> Option<()> {
468 use std::hash::Hash;
469 self.width.hash(hasher);
470 self.height.hash(hasher);
471 self.show_percentage.hash(hasher);
472 self.percentage_position.hash(hasher);
473 self.label_position.hash(hasher);
474 self.padding.hash(hasher);
475 self.label.hash(hasher);
476 Some(())
477 }
478}