bubbles/components/
progress.rs

1use std::cmp;
2
3use crossterm::{
4    event::{KeyEvent, MouseEvent},
5    style::Stylize,
6};
7
8use crate::{
9    colors::gradient::Gradients,
10    core::{
11        component::Component, dimension::Dimension, events::EventHandler, lifecycle::LifeCycle,
12        render::Render, renderer::Renderer, style::Style, view::View,
13    },
14};
15
16/// Progress bar
17pub struct Progress<'a> {
18    pub value: usize,
19    pub style: Style,
20    pub dimension: Dimension,
21    content: &'static str,
22    content_empty: &'static str,
23    pub renderer: Renderer<'a, Self>,
24}
25
26impl<'a> Progress<'a> {
27    const CONTENT: &'static str = "█";
28    const CONTENT_EMPTY: &'static str = "░";
29
30    pub fn new(
31        value: usize,
32        style: Style,
33        dimension: Dimension,
34        renderer: Renderer<'a, Self>,
35    ) -> Self {
36        Self {
37            value,
38            style,
39            dimension,
40            renderer,
41            content: Progress::CONTENT,
42            content_empty: Progress::CONTENT_EMPTY,
43        }
44    }
45}
46
47impl Default for Progress<'_> {
48    fn default() -> Self {
49        Self {
50            value: 0,
51            dimension: Dimension::default(),
52            style: Style::default(),
53            content: Progress::CONTENT,
54            content_empty: Progress::CONTENT_EMPTY,
55            renderer: Renderer::default(),
56        }
57    }
58}
59
60impl Render for Progress<'_> {
61    fn render(&self) -> View {
62        let colors = Gradients::from_colors(&self.style.gradient, self.dimension.width);
63
64        let max_colors = cmp::min(self.value, self.dimension.width);
65
66        let bar_content = colors[..max_colors]
67            .iter()
68            .map(|c| self.content.to_owned().with(c.to_owned()).to_string())
69            .collect::<Vec<String>>()
70            .join("")
71            + &self.content_empty.repeat(self.dimension.width - max_colors);
72
73        View {
74            color: self.style.color,
75            dimension: self.dimension,
76            background: self.style.background,
77            content: bar_content + format!(" {}%", self.value).as_str(),
78        }
79    }
80}
81
82impl LifeCycle for Progress<'_> {
83    fn handle_mount(&mut self) {}
84
85    fn handle_render(&mut self) {
86        (self.renderer.on_render)(self)
87    }
88
89    fn handle_unmount(&mut self) {}
90}
91
92impl Component for Progress<'_> {}
93impl EventHandler for Progress<'_> {
94    fn handle_key_event(&mut self, _event: KeyEvent) {}
95
96    fn handle_mouse_event(&mut self, _event: MouseEvent) {}
97
98    fn handle_paste_event(&mut self, _event: MouseEvent) {}
99}