// SPDX-License-Identifier: LGPL-2.1-only // Copyright (C) 2026 Liberux Labs, S. L. 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 { /// // 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( crate ) value: f32, /// Fill colour. Defaults to the theme's `accent` palette slot. pub( crate ) 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, canvas: &Canvas ) -> (f32, f32) { ( max_width, canvas.geom_px( theme::HEIGHT ) ) } pub fn draw( &self, canvas: &mut Canvas, rect: Rect ) { let track_h = canvas.geom_px( theme::TRACK_H ); let track_y = rect.y + ( rect.height - track_h ) / 2.0; let track_r = track_h / 2.0; let track_rect = Rect { x: rect.x, y: track_y, width: rect.width, height: 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: 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 From for Element { fn from( p: ProgressBar ) -> Self { Element::ProgressBar( p ) } }