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>,
|
text: Option<ProgressBarText>,
|
||||||
fill: Option<Color32>,
|
fill: Option<Color32>,
|
||||||
animate: bool,
|
animate: bool,
|
||||||
|
rounding: Option<Rounding>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProgressBar {
|
impl ProgressBar {
|
||||||
|
|
@ -28,6 +29,7 @@ impl ProgressBar {
|
||||||
text: None,
|
text: None,
|
||||||
fill: None,
|
fill: None,
|
||||||
animate: false,
|
animate: false,
|
||||||
|
rounding: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,11 +71,26 @@ impl ProgressBar {
|
||||||
/// Whether to display a loading animation when progress `< 1`.
|
/// Whether to display a loading animation when progress `< 1`.
|
||||||
/// Note that this will cause the UI to be redrawn.
|
/// Note that this will cause the UI to be redrawn.
|
||||||
/// Defaults to `false`.
|
/// 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]
|
#[inline]
|
||||||
pub fn animate(mut self, animate: bool) -> Self {
|
pub fn animate(mut self, animate: bool) -> Self {
|
||||||
self.animate = animate;
|
self.animate = animate;
|
||||||
self
|
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 {
|
impl Widget for ProgressBar {
|
||||||
|
|
@ -85,6 +102,7 @@ impl Widget for ProgressBar {
|
||||||
text,
|
text,
|
||||||
fill,
|
fill,
|
||||||
animate,
|
animate,
|
||||||
|
rounding,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let animate = animate && progress < 1.0;
|
let animate = animate && progress < 1.0;
|
||||||
|
|
@ -101,16 +119,15 @@ impl Widget for ProgressBar {
|
||||||
}
|
}
|
||||||
|
|
||||||
let visuals = ui.style().visuals.clone();
|
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()
|
ui.painter()
|
||||||
.rect(outer_rect, rounding, visuals.extreme_bg_color, Stroke::NONE);
|
.rect(outer_rect, rounding, visuals.extreme_bg_color, Stroke::NONE);
|
||||||
let inner_rect = Rect::from_min_size(
|
let min_width = 2.0 * rounding.sw.at_least(rounding.nw).at_most(corner_radius);
|
||||||
outer_rect.min,
|
let filled_width = (outer_rect.width() * progress).at_least(min_width);
|
||||||
vec2(
|
let inner_rect =
|
||||||
(outer_rect.width() * progress).at_least(outer_rect.height()),
|
Rect::from_min_size(outer_rect.min, vec2(filled_width, outer_rect.height()));
|
||||||
outer_rect.height(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
let (dark, bright) = (0.7, 1.0);
|
let (dark, bright) = (0.7, 1.0);
|
||||||
let color_factor = if animate {
|
let color_factor = if animate {
|
||||||
|
|
@ -129,19 +146,19 @@ impl Widget for ProgressBar {
|
||||||
Stroke::NONE,
|
Stroke::NONE,
|
||||||
);
|
);
|
||||||
|
|
||||||
if animate {
|
if animate && !is_custom_rounding {
|
||||||
let n_points = 20;
|
let n_points = 20;
|
||||||
let time = ui.input(|i| i.time);
|
let time = ui.input(|i| i.time);
|
||||||
let start_angle = time * std::f64::consts::TAU;
|
let start_angle = time * std::f64::consts::TAU;
|
||||||
let end_angle = start_angle + 240f64.to_radians() * time.sin();
|
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)
|
let points: Vec<Pos2> = (0..n_points)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let angle = lerp(start_angle..=end_angle, i as f64 / n_points as f64);
|
let angle = lerp(start_angle..=end_angle, i as f64 / n_points as f64);
|
||||||
let (sin, cos) = angle.sin_cos();
|
let (sin, cos) = angle.sin_cos();
|
||||||
inner_rect.right_center()
|
inner_rect.right_center()
|
||||||
+ circle_radius * vec2(cos as f32, sin as f32)
|
+ circle_radius * vec2(cos as f32, sin as f32)
|
||||||
+ vec2(-rounding, 0.0)
|
+ vec2(-corner_radius, 0.0)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
ui.painter()
|
ui.painter()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue