Skip to content

Commit

Permalink
Progress bar (emilk#519)
Browse files Browse the repository at this point in the history
* add progress bar

* update changelog

* apply suggestions

* disable animation by default and tweak colors

* allow toggling the animation by clicking

* Update egui/src/widgets/progress_bar.rs

Co-authored-by: Emil Ernerfeldt <[email protected]>

* Update egui/src/widgets/progress_bar.rs

Co-authored-by: Emil Ernerfeldt <[email protected]>

* Update egui/src/widgets/progress_bar.rs

Co-authored-by: Emil Ernerfeldt <[email protected]>

* address review comments

Co-authored-by: Emil Ernerfeldt <[email protected]>
  • Loading branch information
EmbersArc and emilk authored Jul 1, 2021
1 parent 52e3663 commit 89cea7a
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ NOTE: [`eframe`](eframe/CHANGELOG.md), [`egui_web`](egui_web/CHANGELOG.md) and [


## Unreleased
* [Progress bar](https://github.com/emilk/egui/pull/519)


## 0.13.1 - 2021-06-28 - Plot fixes
Expand Down
2 changes: 2 additions & 0 deletions egui/src/widgets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ mod hyperlink;
mod image;
mod label;
pub mod plot;
mod progress_bar;
mod selected_label;
mod separator;
mod slider;
pub(crate) mod text_edit;

pub use hyperlink::*;
pub use label::*;
pub use progress_bar::ProgressBar;
pub use selected_label::*;
pub use separator::*;
pub use {button::*, drag_value::DragValue, image::Image, slider::*, text_edit::*};
Expand Down
141 changes: 141 additions & 0 deletions egui/src/widgets/progress_bar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
use crate::*;

enum ProgressBarText {
Custom(String),
Percentage,
}

/// A simple progress bar.
pub struct ProgressBar {
progress: f32,
desired_width: Option<f32>,
text: Option<ProgressBarText>,
animate: bool,
}

impl ProgressBar {
/// Progress in the `[0, 1]` range, where `1` means "completed".
pub fn new(progress: f32) -> Self {
Self {
progress: progress.clamp(0.0, 1.0),
desired_width: None,
text: None,
animate: false,
}
}

/// The desired width of the bar. Will use all horizonal space if not set.
pub fn desired_width(mut self, desired_width: f32) -> Self {
self.desired_width = Some(desired_width);
self
}

/// A custom text to display on the progress bar.
#[allow(clippy::needless_pass_by_value)]
pub fn text(mut self, text: impl ToString) -> Self {
self.text = Some(ProgressBarText::Custom(text.to_string()));
self
}

/// Show the progress in percent on the progress bar.
pub fn show_percentage(mut self) -> Self {
self.text = Some(ProgressBarText::Percentage);
self
}

/// Whether to display a loading animation when progress `< 1`.
/// Note that this require the UI to be redrawn.
/// Defaults to `false`.
pub fn animate(mut self, animate: bool) -> Self {
self.animate = animate;
self
}
}

impl Widget for ProgressBar {
fn ui(self, ui: &mut Ui) -> Response {
let ProgressBar {
progress,
desired_width,
text,
mut animate,
} = self;

animate &= progress < 1.0;

let desired_width = desired_width.unwrap_or(ui.available_size_before_wrap().x);
let height = ui.spacing().interact_size.y;
let (outer_rect, response) =
ui.allocate_exact_size(vec2(desired_width, height), Sense::hover());
let visuals = ui.style().visuals.clone();
let corner_radius = outer_rect.height() / 2.0;
ui.painter().rect(
outer_rect,
corner_radius,
visuals.extreme_bg_color,
Stroke::none(),
);
let inner_rect = Rect::from_min_size(
outer_rect.min,
vec2(
(outer_rect.width() * progress).at_least(outer_rect.height()),
outer_rect.height(),
),
);

let (dark, bright) = (0.7, 1.0);
let color_factor = if animate {
ui.ctx().request_repaint();
lerp(dark..=bright, ui.input().time.cos().abs())
} else {
bright
};

ui.painter().rect(
inner_rect,
corner_radius,
Color32::from(Rgba::from(visuals.selection.bg_fill) * color_factor as f32),
Stroke::none(),
);

if animate {
let n_points = 20;
let start_angle = ui.input().time as f64 * 360f64.to_radians();
let end_angle = start_angle + 240f64.to_radians() * ui.input().time.sin();
let circle_radius = corner_radius - 2.0;
let points: Vec<Pos2> = (0..n_points)
.map(|i| {
let angle = lerp(start_angle..=end_angle, i as f64 / n_points as f64);
let (sin, cos) = angle.sin_cos();
inner_rect.right_center()
+ circle_radius * vec2(cos as f32, sin as f32)
+ vec2(-corner_radius, 0.0)
})
.collect();
ui.painter().add(Shape::Path {
points,
closed: false,
fill: Color32::TRANSPARENT,
stroke: Stroke::new(2.0, visuals.faint_bg_color),
});
}

if let Some(text_kind) = text {
let text = match text_kind {
ProgressBarText::Custom(string) => string,
ProgressBarText::Percentage => format!("{}%", (progress * 100.0) as usize),
};
ui.painter().sub_region(outer_rect).text(
outer_rect.left_center() + vec2(ui.spacing().item_spacing.x, 0.0),
Align2::LEFT_CENTER,
text,
TextStyle::Button,
visuals
.override_text_color
.unwrap_or(visuals.selection.stroke.color),
);
}

response
}
}
14 changes: 14 additions & 0 deletions egui_demo_lib/src/apps/demo/widget_gallery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct WidgetGallery {
scalar: f32,
string: String,
color: egui::Color32,
animate_progress_bar: bool,
}

impl Default for WidgetGallery {
Expand All @@ -28,6 +29,7 @@ impl Default for WidgetGallery {
scalar: 42.0,
string: Default::default(),
color: egui::Color32::LIGHT_BLUE.linear_multiply(0.5),
animate_progress_bar: false,
}
}
}
Expand Down Expand Up @@ -95,6 +97,7 @@ impl WidgetGallery {
scalar,
string,
color,
animate_progress_bar,
} = self;

ui.add(doc_link_label("Label", "label,heading"));
Expand Down Expand Up @@ -157,6 +160,17 @@ impl WidgetGallery {
ui.add(egui::Slider::new(scalar, 0.0..=360.0).suffix("°"));
ui.end_row();

ui.add(doc_link_label("ProgressBar", "ProgressBar"));
let progress = *scalar / 360.0;
let progress_bar = egui::ProgressBar::new(progress)
.show_percentage()
.animate(*animate_progress_bar);
*animate_progress_bar = ui
.add(progress_bar)
.on_hover_text("The progress bar can be animated!")
.hovered();
ui.end_row();

ui.add(doc_link_label("DragValue", "DragValue"));
ui.add(egui::DragValue::new(scalar).speed(1.0));
ui.end_row();
Expand Down

0 comments on commit 89cea7a

Please sign in to comment.