Skip to content

Commit

Permalink
Add option to customize progress bar rounding
Browse files Browse the repository at this point in the history
The minimum filled width is adapted to the radius and the animation is
disabled so it renders correctly.
  • Loading branch information
YgorSouza committed Apr 19, 2023
1 parent d486c76 commit a6e5f9a
Showing 1 changed file with 24 additions and 11 deletions.
35 changes: 24 additions & 11 deletions crates/egui/src/widgets/progress_bar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub struct ProgressBar {
text: Option<ProgressBarText>,
fill: Option<Color32>,
animate: bool,
rounding: Option<Rounding>,
}

impl ProgressBar {
Expand All @@ -26,6 +27,7 @@ impl ProgressBar {
text: None,
fill: None,
animate: false,
rounding: None,
}
}

Expand Down Expand Up @@ -60,6 +62,14 @@ impl ProgressBar {
self.animate = animate;
self
}

/// Set the rounding of the progress bar.
/// If this option is set, the [`Self::animate`] option is ignored, since the loading animation
/// requires a perfect circle to render correctly.
pub fn rounding(mut self, rounding: impl Into<Rounding>) -> Self {
self.rounding = Some(rounding.into());
self
}
}

impl Widget for ProgressBar {
Expand All @@ -70,6 +80,7 @@ impl Widget for ProgressBar {
text,
fill,
animate,
rounding,
} = self;

let animate = animate && progress < 1.0;
Expand All @@ -86,16 +97,18 @@ impl Widget for ProgressBar {
}

let visuals = ui.style().visuals.clone();
let rounding = outer_rect.height() / 2.0;
let is_custom_rounding = rounding.is_some();
let corner_radius = outer_rect.height() / 2.0;
let rounding = rounding.unwrap_or_else(|| corner_radius.into());
ui.painter()
.rect(outer_rect, rounding, 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 min_width = rounding
.sw
.at_least(rounding.nw)
.at_most(2.0 * corner_radius);
let filled_width = (outer_rect.width() * progress).at_least(min_width);
let inner_rect =
Rect::from_min_size(outer_rect.min, vec2(filled_width, outer_rect.height()));

let (dark, bright) = (0.7, 1.0);
let color_factor = if animate {
Expand All @@ -114,19 +127,19 @@ impl Widget for ProgressBar {
Stroke::NONE,
);

if animate {
if animate && !is_custom_rounding {
let n_points = 20;
let time = ui.input(|i| i.time);
let start_angle = time * std::f64::consts::TAU;
let end_angle = start_angle + 240f64.to_radians() * time.sin();
let circle_radius = rounding - 2.0;
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(-rounding, 0.0)
+ vec2(-corner_radius, 0.0)
})
.collect();
ui.painter()
Expand Down

0 comments on commit a6e5f9a

Please sign in to comment.