diff --git a/crates/egui/src/widgets/progress_bar.rs b/crates/egui/src/widgets/progress_bar.rs index ad3c298399a..e8ae467c1ec 100644 --- a/crates/egui/src/widgets/progress_bar.rs +++ b/crates/egui/src/widgets/progress_bar.rs @@ -16,6 +16,7 @@ pub struct ProgressBar { text: Option, fill: Option, animate: bool, + rounding: Option, } impl ProgressBar { @@ -28,6 +29,7 @@ impl ProgressBar { text: None, fill: None, animate: false, + rounding: None, } } @@ -69,11 +71,26 @@ impl ProgressBar { /// Whether to display a loading animation when progress `< 1`. /// Note that this will cause the UI to be redrawn. /// Defaults to `false`. + /// + /// If [`Self::rounding`] and [`Self::animate`] are used simultaneously, the animation is not + /// rendered, since it requires a perfect circle to render correctly. However, the UI is still + /// redrawn. #[inline] pub fn animate(mut self, animate: bool) -> Self { self.animate = animate; self } + + /// Set the rounding of the progress bar. + /// + /// If [`Self::rounding`] and [`Self::animate`] are used simultaneously, the animation is not + /// rendered, since it requires a perfect circle to render correctly. However, the UI is still + /// redrawn. + #[inline] + pub fn rounding(mut self, rounding: impl Into) -> Self { + self.rounding = Some(rounding.into()); + self + } } impl Widget for ProgressBar { @@ -85,6 +102,7 @@ impl Widget for ProgressBar { text, fill, animate, + rounding, } = self; let animate = animate && progress < 1.0; @@ -101,16 +119,15 @@ 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 = 2.0 * rounding.sw.at_least(rounding.nw).at_most(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 { @@ -129,19 +146,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 = (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()