feat(progress_bar): draw circular line caps directly & fix gaps between the bar and caps
This commit is contained in:
parent
04a93d304c
commit
c9255fe871
2 changed files with 16 additions and 39 deletions
|
|
@ -9,7 +9,8 @@ use iced::{Element, Event, Length, Radians, Rectangle, Renderer, Size, Vector, m
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
const MIN_ANGLE: Radians = Radians(PI / 8.0);
|
const MIN_GAP_ANGLE: Radians = Radians(PI / 4.0);
|
||||||
|
const MAX_WRAP: f32 = 1.0 - MIN_GAP_ANGLE.0 / (2.0 * PI);
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct Circular<Theme>
|
pub struct Circular<Theme>
|
||||||
|
|
@ -76,12 +77,6 @@ where
|
||||||
self.progress = Some(progress.clamp(0.0, 1.0));
|
self.progress = Some(progress.clamp(0.0, 1.0));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn min_wrap(&self, track_radius: f32) -> (f32, f32) {
|
|
||||||
let cap_angle = self.bar_height / track_radius;
|
|
||||||
let gap = MIN_ANGLE.0.max(cap_angle);
|
|
||||||
((gap - cap_angle) / (2.0 * PI), 1.0 - gap / PI)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Theme> Default for Circular<Theme>
|
impl<Theme> Default for Circular<Theme>
|
||||||
|
|
@ -148,11 +143,12 @@ where
|
||||||
shell.request_redraw();
|
shell.request_redraw();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let (_, wrap) = self.min_wrap(self.size / 2.0 - self.bar_height);
|
state.animation = state.animation.timed_transition(
|
||||||
state.animation =
|
self.cycle_duration,
|
||||||
state
|
self.period,
|
||||||
.animation
|
MAX_WRAP,
|
||||||
.timed_transition(self.cycle_duration, self.period, wrap, *now);
|
*now,
|
||||||
|
);
|
||||||
state.cache.clear();
|
state.cache.clear();
|
||||||
shell.request_redraw();
|
shell.request_redraw();
|
||||||
}
|
}
|
||||||
|
|
@ -191,25 +187,6 @@ where
|
||||||
|
|
||||||
// Converts a track fraction to an angle in radians, with 0 being top of circle
|
// Converts a track fraction to an angle in radians, with 0 being top of circle
|
||||||
let to_angle = |t: f32| t * 2.0 * PI - PI / 2.0;
|
let to_angle = |t: f32| t * 2.0 * PI - PI / 2.0;
|
||||||
|
|
||||||
let draw_cap = |frame: &mut canvas::Frame, t: f32, flip: bool| {
|
|
||||||
let angle = to_angle(t);
|
|
||||||
let center = frame.center() + Vector::new(angle.cos(), angle.sin()) * track_radius;
|
|
||||||
let (start_angle, end_angle) = if flip {
|
|
||||||
(angle - PI, angle)
|
|
||||||
} else {
|
|
||||||
(angle, angle + PI)
|
|
||||||
};
|
|
||||||
let mut builder = canvas::path::Builder::new();
|
|
||||||
builder.arc(canvas::path::Arc {
|
|
||||||
center,
|
|
||||||
radius: self.bar_height / 2.0,
|
|
||||||
start_angle: Radians(start_angle),
|
|
||||||
end_angle: Radians(end_angle),
|
|
||||||
});
|
|
||||||
frame.fill(&builder.build(), custom_style.bar_color);
|
|
||||||
};
|
|
||||||
|
|
||||||
let draw_bar = |frame: &mut canvas::Frame, start: f32, end: f32| {
|
let draw_bar = |frame: &mut canvas::Frame, start: f32, end: f32| {
|
||||||
let mut builder = canvas::path::Builder::new();
|
let mut builder = canvas::path::Builder::new();
|
||||||
builder.arc(canvas::path::Arc {
|
builder.arc(canvas::path::Arc {
|
||||||
|
|
@ -222,10 +199,9 @@ where
|
||||||
&builder.build(),
|
&builder.build(),
|
||||||
canvas::Stroke::default()
|
canvas::Stroke::default()
|
||||||
.with_color(custom_style.bar_color)
|
.with_color(custom_style.bar_color)
|
||||||
.with_width(self.bar_height),
|
.with_width(self.bar_height)
|
||||||
|
.with_line_cap(canvas::LineCap::Round),
|
||||||
);
|
);
|
||||||
draw_cap(frame, end, false);
|
|
||||||
draw_cap(frame, start, true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.progress.is_some() {
|
if self.progress.is_some() {
|
||||||
|
|
@ -243,10 +219,11 @@ where
|
||||||
}
|
}
|
||||||
draw_bar(frame, 0.0, state.progress.current);
|
draw_bar(frame, 0.0, state.progress.current);
|
||||||
} else {
|
} else {
|
||||||
let (min, wrap) = self.min_wrap(track_radius);
|
// f32::EPSILON prevents flicker when wrap angle is 0.0
|
||||||
let (start, end) = state
|
let (start, end) =
|
||||||
.animation
|
state
|
||||||
.bar_positions(self.cycle_duration, min, wrap);
|
.animation
|
||||||
|
.bar_positions(self.cycle_duration, f32::EPSILON, MAX_WRAP);
|
||||||
draw_bar(frame, start, end);
|
draw_bar(frame, start, end);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -259,7 +259,7 @@ where
|
||||||
|
|
||||||
// draw bar segment
|
// draw bar segment
|
||||||
if current_p > seg_lo {
|
if current_p > seg_lo {
|
||||||
let fill = ((current_p - seg_lo) / (seg_hi - seg_lo)).clamp(0.0, 1.0);
|
let fill = ((current_p - seg_lo) / (seg_hi - seg_lo)).min(1.0);
|
||||||
draw_quad(
|
draw_quad(
|
||||||
x_start,
|
x_start,
|
||||||
x_width * fill,
|
x_width * fill,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue