Model

Struct Model 

Source
pub struct Model {
    pub width: i32,
    pub full: char,
    pub full_color: String,
    pub empty: char,
    pub empty_color: String,
    pub show_percentage: bool,
    pub percent_format: String,
    pub percentage_style: Style,
    /* private fields */
}
Expand description

The main progress bar model containing all state and configuration.

This structure holds all the data needed to render and animate a progress bar, including visual styling, animation state, and behavioral configuration. The model follows the Elm Architecture pattern used by bubbletea-rs, with separate methods for initialization, updates, and rendering.

§Key Features

  • Smooth animation using spring-based physics for natural transitions
  • Flexible styling with support for gradients, solid colors, and custom characters
  • Responsive design with configurable width and percentage display options
  • Thread safety with unique identifiers for multi-instance usage

§Animation System

The progress bar uses a spring physics model to create smooth, natural-looking transitions between progress values. This provides better visual feedback than instant jumps and makes progress changes feel more responsive and polished.

§Examples

§Basic Usage

use bubbletea_widgets::progress::{new, with_width};

let mut progress = new(&[with_width(50)]);

// Set progress and get animation command
let cmd = progress.set_percent(0.6);

// Render the current state
let view = progress.view();
println!("{}", view); // Shows animated progress bar

§Advanced Configuration

use bubbletea_widgets::progress::*;

let mut progress = new(&[
    with_width(60),
    with_gradient("#ff6b6b".to_string(), "#4ecdc4".to_string()),
    with_spring_options(20.0, 1.0),
]);

// Smooth animated increment
let cmd = progress.incr_percent(0.1);

§Integration with bubbletea-rs

use bubbletea_widgets::progress;
use bubbletea_rs::{Model as TeaModel, Cmd, Msg};

struct App {
    progress: progress::Model,
}

impl TeaModel for App {
    fn init() -> (Self, Option<Cmd>) {
        let progress = progress::new(&[
            progress::with_width(40),
            progress::with_solid_fill("#2ecc71".to_string()),
        ]);
        (Self { progress }, None)
    }

    fn update(&mut self, msg: Msg) -> Option<Cmd> {
        // Forward animation messages to progress bar
        self.progress.update(msg)
    }

    fn view(&self) -> String {
        format!("Loading: {}\n", self.progress.view())
    }
}

Fields§

§width: i32

Total width of the progress bar, including percentage, if set.

§full: char

“Filled” sections of the progress bar.

§full_color: String

Color used for the filled portion (hex or named color string).

§empty: char

“Empty” sections of the progress bar.

§empty_color: String

Color used for the empty portion (hex or named color string).

§show_percentage: bool

Settings for rendering the numeric percentage.

§percent_format: String

Format string for the percentage (e.g., “ %3.0f%%“).

§percentage_style: Style

Lipgloss style applied to the percentage text.

Implementations§

Source§

impl Model

Source

pub fn set_spring_options(&mut self, frequency: f64, damping: f64)

Configures the spring animation parameters for smooth transitions.

Updates the internal spring physics engine that controls how the progress bar animates between different progress values. Higher frequency values make animations faster, while higher damping values reduce bounciness.

§Arguments
  • frequency - Animation speed (typical range: 10.0-30.0)
  • damping - Bounciness control (typical range: 0.5-2.0)
§Examples
use bubbletea_widgets::progress::new;

let mut progress = new(&[]);

// Fast, snappy animation
progress.set_spring_options(25.0, 1.5);

// Slow, bouncy animation  
progress.set_spring_options(12.0, 0.7);

// Now progress changes will use the new animation style
let cmd = progress.set_percent(0.8);
Source

pub fn percent(&self) -> f64

Returns the target percentage that the progress bar is animating towards.

This represents the logical progress value, not necessarily what’s currently being displayed. During animation, the visual progress gradually moves from its current position toward this target value using spring physics.

§Returns

The target progress as a float between 0.0 and 1.0 (0% to 100%).

§Examples
use bubbletea_widgets::progress::new;

let mut progress = new(&[]);
assert_eq!(progress.percent(), 0.0);

// Set target to 75%
progress.set_percent(0.75);
assert_eq!(progress.percent(), 0.75);

// The visual bar will animate smoothly to reach this target
Source

pub fn set_percent(&mut self, p: f64) -> Cmd

Sets the progress to a specific percentage and returns an animation command.

This method updates the target percentage and initiates a smooth animation to the new value using spring physics. The returned command should be handled by your bubbletea-rs application to drive the animation.

§Arguments
  • p - Progress percentage as a float (will be clamped to 0.0-1.0 range)
§Returns

A Cmd that drives the animation. This must be returned from your application’s update() method to enable smooth progress transitions.

§Examples
use bubbletea_widgets::progress::new;
use bubbletea_rs::{Model, Msg, Cmd};

struct App {
    progress: bubbletea_widgets::progress::Model,
}

impl Model for App {
    fn update(&mut self, msg: Msg) -> Option<Cmd> {
        // Handle progress animation
        if let Some(cmd) = self.progress.update(msg) {
            return Some(cmd);
        }

        // Set progress and return animation command
        Some(self.progress.set_percent(0.6))
    }
}
§Direct Usage
use bubbletea_widgets::progress::new;

let mut progress = new(&[]);

// Values are automatically clamped
let cmd1 = progress.set_percent(0.5);   // 50%
let cmd2 = progress.set_percent(1.5);   // Clamped to 100%
let cmd3 = progress.set_percent(-0.2);  // Clamped to 0%
Source

pub fn incr_percent(&mut self, v: f64) -> Cmd

Increases the progress by a specified amount and returns an animation command.

This is a convenience method that adds the given value to the current progress percentage. The result is automatically clamped to the valid range (0.0-1.0) and animated smoothly to the new position.

§Arguments
  • v - Amount to add to current progress (can be negative for decrease)
§Returns

A Cmd that drives the animation to the new progress value.

§Examples
use bubbletea_widgets::progress::new;

let mut progress = new(&[]);

// Start at 0%, increment by 25%
let cmd1 = progress.incr_percent(0.25);
assert_eq!(progress.percent(), 0.25);

// Add another 30%
let cmd2 = progress.incr_percent(0.3);
assert_eq!(progress.percent(), 0.55);

// Try to go over 100% (will be clamped)
let cmd3 = progress.incr_percent(0.7);
assert_eq!(progress.percent(), 1.0);
§Use in Loading Scenarios
use bubbletea_widgets::progress::new;

let mut download_progress = new(&[]);

// Simulate incremental progress updates
for _chunk in 0..10 {
    let cmd = download_progress.incr_percent(0.1); // Add 10% each chunk
    // Return cmd from your update() method
}
Source

pub fn decr_percent(&mut self, v: f64) -> Cmd

Decreases the progress by a specified amount and returns an animation command.

This is a convenience method that subtracts the given value from the current progress percentage. The result is automatically clamped to the valid range (0.0-1.0) and animated smoothly to the new position.

§Arguments
  • v - Amount to subtract from current progress (positive values decrease progress)
§Returns

A Cmd that drives the animation to the new progress value.

§Examples
use bubbletea_widgets::progress::new;

let mut progress = new(&[]);

// Start at 100%
progress.set_percent(1.0);

// Decrease by 20%
let cmd1 = progress.decr_percent(0.2);
assert_eq!(progress.percent(), 0.8);

// Decrease by another 30%
let cmd2 = progress.decr_percent(0.3);
assert_eq!(progress.percent(), 0.5);

// Try to go below 0% (will be clamped)
let cmd3 = progress.decr_percent(0.8);
assert_eq!(progress.percent(), 0.0);
§Use in Error Recovery
use bubbletea_widgets::progress::new;

let mut upload_progress = new(&[]);
upload_progress.set_percent(0.7); // 70% uploaded

// Network error - need to retry from earlier point
let cmd = upload_progress.decr_percent(0.2); // Back to 50%
Source

pub fn update(&mut self, msg: Msg) -> Option<Cmd>

Processes animation messages and updates the visual progress state.

This method handles FrameMsg instances that drive the smooth animation between progress values. It should be called from your application’s update() method to enable animated progress transitions.

The method uses spring physics to gradually move the visual progress from its current position toward the target percentage, creating natural-looking animations.

§Arguments
  • msg - A message that might contain animation frame data
§Returns
  • Some(Cmd) if animation should continue (return this from your update method)
  • None if the message wasn’t relevant or animation has finished
§Examples
§Integration with bubbletea-rs
use bubbletea_widgets::progress;
use bubbletea_rs::{Model, Msg, Cmd};

struct App {
    progress: progress::Model,
}

impl Model for App {
    fn update(&mut self, msg: Msg) -> Option<Cmd> {
        // Always forward messages to progress bar first
        if let Some(cmd) = self.progress.update(msg) {
            return Some(cmd);
        }

        // Handle your own application messages
        None
    }
}
§Manual Animation Handling
use bubbletea_widgets::progress::new;

let mut progress = new(&[]);

// Start an animation
let initial_cmd = progress.set_percent(0.8);

// In a real app, you'd handle this through bubbletea-rs
// but here's what happens internally:
// 1. FrameMsg is sent after a delay
// 2. update() processes it and returns next FrameMsg
// 3. Process continues until animation completes
Source

pub fn view(&self) -> String

Renders the progress bar in its current animated state.

This method displays the progress bar with the current visual progress, which may be different from the target percentage during animations. The output includes both the visual bar and percentage text (if enabled).

For static rendering with a specific percentage, use view_as() instead.

§Returns

A formatted string containing the styled progress bar ready for terminal display.

§Examples
§Basic Rendering
use bubbletea_widgets::progress::new;

let progress = new(&[]);
let output = progress.view();
println!("{}", output); // Displays: [░░░░░░░] 0%
§Animated Progress
use bubbletea_widgets::progress::{new, with_width};

let mut progress = new(&[with_width(20)]);

// Set target percentage
let cmd = progress.set_percent(0.6);

// During animation, view() shows the current animated position
let frame1 = progress.view(); // Might show: [██████░░░] 35%

// After animation completes:
let final_frame = progress.view(); // Shows: [███████████░] 60%
§Integration Example
use bubbletea_widgets::progress::{new, with_solid_fill};

let progress = new(&[
    with_solid_fill("#2ecc71".to_string()),
]);

// Use in your application's view method
fn render_ui(progress: &bubbletea_widgets::progress::Model) -> String {
    format!("Download Progress:\n{}\n", progress.view())
}
Source

pub fn view_as(&self, percent: f64) -> String

Renders the progress bar with a specific percentage value.

This method bypasses the animation system and renders the progress bar at exactly the specified percentage. This is useful for static displays, testing, or when you want to show progress without animation.

§Arguments
  • percent - Progress percentage as a float between 0.0 and 1.0
§Returns

A formatted string containing the styled progress bar at the exact percentage.

§Examples
§Static Progress Display
use bubbletea_widgets::progress::new;

let progress = new(&[]);

// Show various progress levels without animation
let empty = progress.view_as(0.0);    // [░░░░░░░] 0%
let half = progress.view_as(0.5);     // [███░░░░] 50%
let full = progress.view_as(1.0);     // [███████] 100%
§Testing Different Progress Values
use bubbletea_widgets::progress::{new, with_width, without_percentage};

let progress = new(&[
    with_width(10),
    without_percentage(),
]);

// Test various progress levels
assert_eq!(progress.view_as(0.0).contains('█'), false);
assert_eq!(progress.view_as(1.0).contains('░'), false);
§Dynamic Progress Calculation
use bubbletea_widgets::progress::new;

let progress = new(&[]);

// Show progress based on calculation
let completed_items = 7;
let total_items = 10;
let percentage = completed_items as f64 / total_items as f64;

let view = progress.view_as(percentage);
println!("Tasks: {}", view); // Shows 70% progress
Source

pub fn is_animating(&self) -> bool

Returns whether the progress bar is currently animating.

This method checks if the progress bar is in the middle of an animated transition between progress values. It returns false when the visual progress has reached equilibrium with the target percentage.

§Returns
  • true if the progress bar is currently animating
  • false if the animation has completed or no animation is in progress
§Examples
§Checking Animation State
use bubbletea_widgets::progress::new;

let mut progress = new(&[]);

// Initially not animating
assert!(!progress.is_animating());

// Start an animation
let cmd = progress.set_percent(0.8);
assert!(progress.is_animating()); // Now animating

// After animation completes (in a real app, this happens via update())
// assert!(!progress.is_animating());
§Conditional Rendering
use bubbletea_widgets::progress::new;

let progress = new(&[]);

// Show different UI based on animation state
if progress.is_animating() {
    println!("Progress updating...");
} else {
    println!("Progress stable at {}%", (progress.percent() * 100.0) as i32);
}
§Performance Optimization
use bubbletea_widgets::progress::new;

fn should_update_ui(progress: &bubbletea_widgets::progress::Model) -> bool {
    // Only redraw UI if progress is changing
    progress.is_animating()
}

Trait Implementations§

Source§

impl Clone for Model

Source§

fn clone(&self) -> Model

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Model

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Model

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Model for Model

Source§

fn init() -> (Self, Option<Cmd>)

Initialize the model with its initial state and optional startup command. Read more
Source§

fn update(&mut self, msg: Msg) -> Option<Cmd>

Update the model in response to a received message. Read more
Source§

fn view(&self) -> String

Render the current model state as a string for terminal display. Read more

Auto Trait Implementations§

§

impl Freeze for Model

§

impl !RefUnwindSafe for Model

§

impl Send for Model

§

impl Sync for Model

§

impl Unpin for Model

§

impl !UnwindSafe for Model

Blanket Implementations§

Source§

impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for S
where T: Real + Zero + Arithmetics + Clone, Swp: WhitePoint<T>, Dwp: WhitePoint<T>, D: AdaptFrom<S, Swp, Dwp, T>,

Source§

fn adapt_into_using<M>(self, method: M) -> D
where M: TransformMatrix<T>,

Convert the source color to the destination color using the specified method.
Source§

fn adapt_into(self) -> D

Convert the source color to the destination color using the bradford method by default.
Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T, C> ArraysFrom<C> for T
where C: IntoArrays<T>,

Source§

fn arrays_from(colors: C) -> T

Cast a collection of colors into a collection of arrays.
Source§

impl<T, C> ArraysInto<C> for T
where C: FromArrays<T>,

Source§

fn arrays_into(self) -> C

Cast this collection of arrays into a collection of colors.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for U
where T: FromCam16Unclamped<WpParam, U>,

Source§

type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar

The number type that’s used in parameters when converting.
Source§

fn cam16_into_unclamped( self, parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>, ) -> T

Converts self into C, using the provided parameters.
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T, C> ComponentsFrom<C> for T
where C: IntoComponents<T>,

Source§

fn components_from(colors: C) -> T

Cast a collection of colors into a collection of color components.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromAngle<T> for T

Source§

fn from_angle(angle: T) -> T

Performs a conversion from angle.
Source§

impl<T, U> FromStimulus<U> for T
where U: IntoStimulus<T>,

Source§

fn from_stimulus(other: U) -> T

Converts other into Self, while performing the appropriate scaling, rounding and clamping.
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> IntoAngle<U> for T
where U: FromAngle<T>,

Source§

fn into_angle(self) -> U

Performs a conversion into T.
Source§

impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for U
where T: Cam16FromUnclamped<WpParam, U>,

Source§

type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar

The number type that’s used in parameters when converting.
Source§

fn into_cam16_unclamped( self, parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>, ) -> T

Converts self into C, using the provided parameters.
Source§

impl<T, U> IntoColor<U> for T
where U: FromColor<T>,

Source§

fn into_color(self) -> U

Convert into T with values clamped to the color defined bounds Read more
Source§

impl<T, U> IntoColorUnclamped<U> for T
where U: FromColorUnclamped<T>,

Source§

fn into_color_unclamped(self) -> U

Convert into T. The resulting color might be invalid in its color space Read more
Source§

impl<T> IntoStimulus<T> for T

Source§

fn into_stimulus(self) -> T

Converts self into T, while performing the appropriate scaling, rounding and clamping.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, C> TryComponentsInto<C> for T
where C: TryFromComponents<T>,

Source§

type Error = <C as TryFromComponents<T>>::Error

The error for when try_into_colors fails to cast.
Source§

fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>

Try to cast this collection of color components into a collection of colors. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T, U> TryIntoColor<U> for T
where U: TryFromColor<T>,

Source§

fn try_into_color(self) -> Result<U, OutOfBounds<U>>

Convert into T, returning ok if the color is inside of its defined range, otherwise an OutOfBounds error is returned which contains the unclamped color. Read more
Source§

impl<C, U> UintsFrom<C> for U
where C: IntoUints<U>,

Source§

fn uints_from(colors: C) -> U

Cast a collection of colors into a collection of unsigned integers.
Source§

impl<C, U> UintsInto<C> for U
where C: FromUints<U>,

Source§

fn uints_into(self) -> C

Cast this collection of unsigned integers into a collection of colors.