Add option to customize progress bar rounding (#2881)
The minimum filled width is adapted to the radius and the animation is disabled so it renders correctly. --------- Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
parent
3b19303e02
commit
4a6999bbad
|
|
@ -16,6 +16,7 @@ pub struct ProgressBar {
|
|||
text: Option<ProgressBarText>,
|
||||
fill: Option<Color32>,
|
||||
animate: bool,
|
||||
rounding: Option<Rounding>,
|
||||
}
|
||||
|
||||
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<Rounding>) -> 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<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()
|
||||
|
|
|
|||
Loading…
Reference in New Issue