mod layout;
mod node;
mod reconcile;
pub use layout::measure_progress_bar;
pub use node::ProgressNode;
pub use reconcile::reconcile_progress_bar;
use crate::callback::Callback;
use crate::core::element::{Element, ElementKind};
use crate::core::event::MouseEvent;
use crate::style::{Length, Padding, Style, StyleSlot};
use crate::utils::gradient::ColorGradient;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ProgressEvent {
pub progress: f64,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ProgressZone {
pub upto: f64,
pub style: Style,
pub symbol: Option<char>,
}
impl ProgressZone {
pub fn new(upto: f64) -> Self {
Self {
upto: upto.clamp(0.0, 1.0),
style: Style::default(),
symbol: None,
}
}
pub fn style(mut self, style: Style) -> Self {
self.style = style;
self
}
pub fn symbol(mut self, symbol: char) -> Self {
self.symbol = Some(symbol);
self
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum ProgressStyle {
#[default]
Block,
Line,
LineDotted,
Dots,
Arrow,
Rect,
Custom {
filled: char,
empty: char,
},
Braille,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum ProgressTextPosition {
Left,
#[default]
Right,
Above,
Below,
Middle,
}
impl ProgressStyle {
pub fn filled_char(self) -> char {
match self {
Self::Block => '█',
Self::Line | Self::LineDotted => '━',
Self::Dots => '●',
Self::Arrow => '►',
Self::Rect => '▮',
Self::Custom { filled, .. } => filled,
Self::Braille => '⣿',
}
}
pub fn empty_char(self) -> char {
match self {
Self::Block => '░',
Self::Line => '─',
Self::LineDotted => '┄',
Self::Dots => '○',
Self::Arrow => '─',
Self::Rect => '▯',
Self::Custom { empty, .. } => empty,
Self::Braille => '⣀',
}
}
pub fn partial_chars(self) -> Option<&'static [char]> {
match self {
Self::Braille => Some(&['⣀', '⣄', '⣤', '⣦', '⣶', '⣷', '⣿']),
_ => None,
}
}
}
#[derive(Clone)]
pub struct ProgressBar {
pub progress: f64,
pub progress_style: ProgressStyle,
pub show_percentage: bool,
pub percentage_position: ProgressTextPosition,
pub label: Option<String>,
pub label_position: ProgressTextPosition,
pub filled_style: Style,
pub filled_gradient: Option<ColorGradient>,
pub empty_style: Style,
pub label_style: Style,
pub style: Style,
pub padding: Padding,
pub width: Length,
pub height: Length,
pub draggable: bool,
pub step: Option<f64>,
pub inverted: bool,
pub on_change: Option<Callback<ProgressEvent>>,
pub on_click: Option<Callback<MouseEvent>>,
pub focusable: bool,
pub focus_style: StyleSlot,
pub hover_style: StyleSlot,
pub target: Option<f64>,
pub target_style: Style,
pub target_symbol: char,
pub zones: Vec<ProgressZone>,
pub block_empty_bg_dim: f32,
}
impl Default for ProgressBar {
fn default() -> Self {
Self {
progress: 0.0,
progress_style: ProgressStyle::Block,
show_percentage: false,
percentage_position: ProgressTextPosition::Right,
label: None,
label_position: ProgressTextPosition::Right,
filled_style: Style::default(),
filled_gradient: None,
empty_style: Style::default(),
label_style: Style::default(),
style: Style::default(),
padding: Padding::default(),
width: Length::Flex(1),
height: Length::Auto,
draggable: false,
step: None,
inverted: false,
on_change: None,
on_click: None,
focusable: false,
focus_style: StyleSlot::Inherit,
hover_style: StyleSlot::Inherit,
target: None,
target_style: Style::default(),
target_symbol: '◆',
zones: Vec::new(),
block_empty_bg_dim: 0.85,
}
}
}
impl ProgressBar {
pub fn new(progress: f64) -> Self {
Self {
progress: progress.clamp(0.0, 1.0),
..Self::default()
}
}
pub fn progress(mut self, progress: f64) -> Self {
self.progress = progress.clamp(0.0, 1.0);
self
}
pub fn inverted(mut self, inverted: bool) -> Self {
self.inverted = inverted;
self
}
pub fn progress_style(mut self, style: ProgressStyle) -> Self {
self.progress_style = style;
self
}
pub fn show_percentage(mut self, show: bool) -> Self {
self.show_percentage = show;
self
}
pub fn percentage_position(mut self, position: ProgressTextPosition) -> Self {
self.percentage_position = position;
self
}
pub fn label(mut self, label: impl Into<String>) -> Self {
self.label = Some(label.into());
self
}
pub fn label_position(mut self, position: ProgressTextPosition) -> Self {
self.label_position = position;
self
}
pub fn filled_style(mut self, style: Style) -> Self {
self.filled_style = style;
self
}
pub fn filled_gradient(mut self, gradient: ColorGradient) -> Self {
self.filled_gradient = Some(gradient);
self
}
pub fn empty_style(mut self, style: Style) -> Self {
self.empty_style = style;
self
}
pub fn label_style(mut self, style: Style) -> Self {
self.label_style = style;
self
}
pub fn style(mut self, style: Style) -> Self {
self.style = style;
self
}
pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
self.padding = padding.into();
self
}
pub fn width(mut self, width: Length) -> Self {
self.width = width;
self
}
pub fn height(mut self, height: Length) -> Self {
self.height = height;
self
}
pub fn draggable(mut self, draggable: bool) -> Self {
self.draggable = draggable;
self
}
pub fn step(mut self, step: f64) -> Self {
self.step = Some(step);
self
}
pub fn on_change(mut self, cb: Callback<ProgressEvent>) -> Self {
self.on_change = Some(cb);
self
}
pub fn on_click(mut self, cb: Callback<MouseEvent>) -> Self {
self.on_click = Some(cb);
self
}
pub fn focusable(mut self, focusable: bool) -> Self {
self.focusable = focusable;
self
}
pub fn focus_style(mut self, style: Style) -> Self {
self.focus_style = StyleSlot::Replace(style);
self
}
pub fn extend_focus_style(mut self, style: Style) -> Self {
self.focus_style = StyleSlot::Extend(style);
self
}
pub fn inherit_focus_style(mut self) -> Self {
self.focus_style = StyleSlot::Inherit;
self
}
pub fn focus_style_slot(mut self, slot: StyleSlot) -> Self {
self.focus_style = slot;
self
}
pub fn hover_style(mut self, style: Style) -> Self {
self.hover_style = StyleSlot::Replace(style);
self
}
pub fn extend_hover_style(mut self, style: Style) -> Self {
self.hover_style = StyleSlot::Extend(style);
self
}
pub fn inherit_hover_style(mut self) -> Self {
self.hover_style = StyleSlot::Inherit;
self
}
pub fn hover_style_slot(mut self, slot: StyleSlot) -> Self {
self.hover_style = slot;
self
}
pub fn target(mut self, target: f64) -> Self {
self.target = Some(target.clamp(0.0, 1.0));
self
}
pub fn clear_target(mut self) -> Self {
self.target = None;
self
}
pub fn target_style(mut self, style: Style) -> Self {
self.target_style = style;
self
}
pub fn target_symbol(mut self, symbol: char) -> Self {
self.target_symbol = symbol;
self
}
pub fn zones(mut self, zones: impl IntoIterator<Item = ProgressZone>) -> Self {
self.zones = zones.into_iter().collect();
self
}
pub fn add_zone(mut self, zone: ProgressZone) -> Self {
self.zones.push(zone);
self
}
pub fn block_empty_bg_dim(mut self, amount: f32) -> Self {
self.block_empty_bg_dim = amount.clamp(0.0, 1.0);
self
}
}
impl From<ProgressBar> for Element {
fn from(value: ProgressBar) -> Self {
Element::new(ElementKind::ProgressBar(value))
}
}
impl crate::layout::hash::LayoutHash for ProgressBar {
fn layout_hash(
&self,
hasher: &mut impl std::hash::Hasher,
_recurse: &dyn Fn(&Element) -> Option<u64>,
) -> Option<()> {
use std::hash::Hash;
self.width.hash(hasher);
self.height.hash(hasher);
self.show_percentage.hash(hasher);
self.percentage_position.hash(hasher);
self.label_position.hash(hasher);
self.padding.hash(hasher);
self.label.hash(hasher);
Some(())
}
}