ltk/widget/progress_bar/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

use crate::types::{ Color, Rect };
use crate::render::Canvas;
use super::Element;

mod theme;

#[cfg(test)]
mod tests;

/// A linear progress indicator for determinate operations.
///
/// Renders a horizontal track with a coloured fill from the left edge to
/// `value × width`. `value` is clamped to `[0.0, 1.0]` at construction.
/// For indeterminate progress (the operation has no ETA) prefer an
/// animated spinner — `ltk` has no built-in spinner widget yet; build one
/// from a [`Container`](super::container::Container) that rotates a glyph
/// while [`crate::App::is_animating`] returns `true`.
///
/// ```rust,no_run
/// # use ltk::{ column, progress_bar, text, Element };
/// # #[ derive( Clone ) ] enum Msg {}
/// # struct App { progress: f32 }
/// # impl App { fn _ex( &self ) -> Element<Msg> {
/// // In view():
/// column()
///     .push( text( format!( "Downloading… {}%", ( self.progress * 100.0 ) as u32 ) ) )
///     .push( progress_bar( self.progress ) )
/// .into()
/// # }}
/// ```
pub struct ProgressBar
{
	/// Current progress in `[0.0, 1.0]`. Always clamped at construction.
	pub value: f32,
	/// Fill colour. Defaults to the theme's `accent` palette slot.
	pub fill:  Color,
}

impl ProgressBar
{
	/// Create a progress bar at the given fraction. `value` outside
	/// `[0.0, 1.0]` is clamped silently.
	pub fn new( value: f32 ) -> Self
	{
		Self { value: value.clamp( 0.0, 1.0 ), fill: theme::fill() }
	}

	/// Override the fill colour. Useful for "danger" / "success" variants
	/// (red for nearly-full disks, green for completed work).
	pub fn color( mut self, color: Color ) -> Self
	{
		self.fill = color;
		self
	}

	/// Return the preferred `(width, height)`. Width fills the available
	/// `max_width`; height is the theme-defined row height.
	pub fn preferred_size( &self, max_width: f32 ) -> (f32, f32)
	{
		( max_width, theme::HEIGHT )
	}

	pub fn draw( &self, canvas: &mut Canvas, rect: Rect )
	{
		let track_y = rect.y + ( rect.height - theme::TRACK_H ) / 2.0;
		let track_r = theme::TRACK_H / 2.0;

		let track_rect = Rect
		{
			x:      rect.x,
			y:      track_y,
			width:  rect.width,
			height: theme::TRACK_H,
		};
		canvas.fill_rect( track_rect, theme::track_bg(), track_r );

		let fill_w = rect.width * self.value;
		if fill_w > 0.0
		{
			let fill_rect = Rect
			{
				x:      rect.x,
				y:      track_y,
				width:  fill_w,
				height: theme::TRACK_H,
			};
			canvas.fill_rect( fill_rect, self.fill, track_r );
		}
	}
}

/// Create a [`ProgressBar`] at the given fraction (clamped to
/// `[0.0, 1.0]`).
///
/// ```rust,no_run
/// # use ltk::{ progress_bar, ProgressBar };
/// # struct App { download_fraction: f32 }
/// # impl App { fn _ex( &self ) -> ProgressBar {
/// progress_bar( self.download_fraction )
/// # }}
/// ```
pub fn progress_bar( value: f32 ) -> ProgressBar
{
	ProgressBar::new( value )
}

impl<Msg: Clone> From<ProgressBar> for Element<Msg>
{
	fn from( p: ProgressBar ) -> Self
	{
		Element::ProgressBar( p )
	}
}