refactor: remove unnecessary canvas complexity
This commit is contained in:
parent
9d69af10cc
commit
290b47f312
1 changed files with 67 additions and 120 deletions
|
|
@ -5,7 +5,7 @@ use iced::advanced::widget::tree::{self, Tree};
|
||||||
use iced::advanced::{Clipboard, Layout, Renderer, Shell, Widget};
|
use iced::advanced::{Clipboard, Layout, Renderer, Shell, Widget};
|
||||||
use iced::event;
|
use iced::event;
|
||||||
use iced::time::Instant;
|
use iced::time::Instant;
|
||||||
use iced::widget::canvas::{self, Cursor, Program};
|
use iced::widget::canvas;
|
||||||
use iced::window::{self, RedrawRequest};
|
use iced::window::{self, RedrawRequest};
|
||||||
use iced::{Background, Color, Element, Rectangle};
|
use iced::{Background, Color, Element, Rectangle};
|
||||||
use iced::{Event, Length, Point, Size, Vector};
|
use iced::{Event, Length, Point, Size, Vector};
|
||||||
|
|
@ -15,8 +15,6 @@ use super::easing::{self, Easing};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
type R<Theme> = iced::Renderer<Theme>;
|
|
||||||
|
|
||||||
const MIN_RADIANS: f32 = PI / 8.0;
|
const MIN_RADIANS: f32 = PI / 8.0;
|
||||||
const WRAP_RADIANS: f32 = 2.0 * PI - PI / 4.0;
|
const WRAP_RADIANS: f32 = 2.0 * PI - PI / 4.0;
|
||||||
const BASE_ROTATION_SPEED: u32 = u32::MAX / 80;
|
const BASE_ROTATION_SPEED: u32 = u32::MAX / 80;
|
||||||
|
|
@ -98,7 +96,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
enum State {
|
enum Animation {
|
||||||
Expanding {
|
Expanding {
|
||||||
start: Instant,
|
start: Instant,
|
||||||
progress: f32,
|
progress: f32,
|
||||||
|
|
@ -113,7 +111,7 @@ enum State {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for State {
|
impl Default for Animation {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Expanding {
|
Self::Expanding {
|
||||||
start: Instant::now(),
|
start: Instant::now(),
|
||||||
|
|
@ -124,7 +122,7 @@ impl Default for State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl Animation {
|
||||||
fn next(&self, additional_rotation: u32, now: Instant) -> Self {
|
fn next(&self, additional_rotation: u32, now: Instant) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Expanding { rotation, .. } => Self::Contracting {
|
Self::Expanding { rotation, .. } => Self::Contracting {
|
||||||
|
|
@ -224,7 +222,14 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, Theme> Widget<Message, R<Theme>> for Circular<'a, Theme>
|
#[derive(Default)]
|
||||||
|
struct State {
|
||||||
|
animation: Animation,
|
||||||
|
cache: canvas::Cache,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message, Theme> Widget<Message, iced::Renderer<Theme>>
|
||||||
|
for Circular<'a, Theme>
|
||||||
where
|
where
|
||||||
Message: 'a + Clone,
|
Message: 'a + Clone,
|
||||||
Theme: StyleSheet,
|
Theme: StyleSheet,
|
||||||
|
|
@ -271,12 +276,13 @@ where
|
||||||
let state = tree.state.downcast_mut::<State>();
|
let state = tree.state.downcast_mut::<State>();
|
||||||
|
|
||||||
if let Event::Window(window::Event::RedrawRequested(now)) = event {
|
if let Event::Window(window::Event::RedrawRequested(now)) = event {
|
||||||
*state = state.timed_transition(
|
state.animation = state.animation.timed_transition(
|
||||||
self.cycle_duration,
|
self.cycle_duration,
|
||||||
self.rotation_duration,
|
self.rotation_duration,
|
||||||
now,
|
now,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
state.cache.clear();
|
||||||
shell.request_redraw(RedrawRequest::At(
|
shell.request_redraw(RedrawRequest::At(
|
||||||
now + Duration::from_millis(1000 / FRAME_RATE),
|
now + Duration::from_millis(1000 / FRAME_RATE),
|
||||||
));
|
));
|
||||||
|
|
@ -288,42 +294,76 @@ where
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
tree: &Tree,
|
tree: &Tree,
|
||||||
renderer: &mut R<Theme>,
|
renderer: &mut iced::Renderer<Theme>,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
_style: &renderer::Style,
|
_style: &renderer::Style,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
_cursor_position: Point,
|
_cursor_position: Point,
|
||||||
_viewport: &Rectangle,
|
_viewport: &Rectangle,
|
||||||
) {
|
) {
|
||||||
let bounds = layout.bounds();
|
|
||||||
let state = tree.state.downcast_ref::<State>();
|
let state = tree.state.downcast_ref::<State>();
|
||||||
|
let bounds = layout.bounds();
|
||||||
|
let custom_style =
|
||||||
|
<Theme as StyleSheet>::appearance(theme, &self.style);
|
||||||
|
|
||||||
|
let geometry = state.cache.draw(renderer, bounds.size(), |frame| {
|
||||||
|
let track_radius = frame.width() / 2.0 - self.bar_height;
|
||||||
|
let track_path = canvas::Path::circle(frame.center(), track_radius);
|
||||||
|
|
||||||
|
frame.stroke(
|
||||||
|
&track_path,
|
||||||
|
canvas::Stroke::default()
|
||||||
|
.with_color(custom_style.track_color)
|
||||||
|
.with_width(self.bar_height),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut builder = canvas::path::Builder::new();
|
||||||
|
|
||||||
|
let start = state.animation.rotation() * 2.0 * PI;
|
||||||
|
|
||||||
|
match state.animation {
|
||||||
|
Animation::Expanding { progress, .. } => {
|
||||||
|
builder.arc(canvas::path::Arc {
|
||||||
|
center: frame.center(),
|
||||||
|
radius: track_radius,
|
||||||
|
start_angle: start,
|
||||||
|
end_angle: start
|
||||||
|
+ MIN_RADIANS
|
||||||
|
+ WRAP_RADIANS * (self.easing.y_at_x(progress)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Animation::Contracting { progress, .. } => {
|
||||||
|
builder.arc(canvas::path::Arc {
|
||||||
|
center: frame.center(),
|
||||||
|
radius: track_radius,
|
||||||
|
start_angle: start
|
||||||
|
+ WRAP_RADIANS * (self.easing.y_at_x(progress)),
|
||||||
|
end_angle: start + MIN_RADIANS + WRAP_RADIANS,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let bar_path = builder.build();
|
||||||
|
|
||||||
|
frame.stroke(
|
||||||
|
&bar_path,
|
||||||
|
canvas::Stroke::default()
|
||||||
|
.with_color(custom_style.bar_color)
|
||||||
|
.with_width(self.bar_height),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
renderer.with_translation(
|
renderer.with_translation(
|
||||||
Vector::new(bounds.x, bounds.y),
|
Vector::new(bounds.x, bounds.y),
|
||||||
|renderer| {
|
|renderer| {
|
||||||
canvas::Renderer::draw(
|
renderer.draw_primitive(geometry.0);
|
||||||
renderer,
|
|
||||||
<StateWithStyle<Theme> as Program<Message, R<Theme>>>::draw(
|
|
||||||
&StateWithStyle {
|
|
||||||
state,
|
|
||||||
style: &self.style,
|
|
||||||
bar_height: self.bar_height,
|
|
||||||
easing: self.easing,
|
|
||||||
},
|
|
||||||
&(),
|
|
||||||
renderer,
|
|
||||||
theme,
|
|
||||||
bounds,
|
|
||||||
Cursor::Unavailable,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, Theme> From<Circular<'a, Theme>>
|
impl<'a, Message, Theme> From<Circular<'a, Theme>>
|
||||||
for Element<'a, Message, R<Theme>>
|
for Element<'a, Message, iced::Renderer<Theme>>
|
||||||
where
|
where
|
||||||
Message: Clone + 'a,
|
Message: Clone + 'a,
|
||||||
Theme: StyleSheet + 'a,
|
Theme: StyleSheet + 'a,
|
||||||
|
|
@ -375,96 +415,3 @@ impl StyleSheet for iced::Theme {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StateWithStyle<'a, Theme>
|
|
||||||
where
|
|
||||||
Theme: StyleSheet,
|
|
||||||
{
|
|
||||||
state: &'a State,
|
|
||||||
style: &'a <Theme as StyleSheet>::Style,
|
|
||||||
easing: &'a Easing,
|
|
||||||
bar_height: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Message, Theme> Program<Message, iced::Renderer<Theme>>
|
|
||||||
for StateWithStyle<'a, Theme>
|
|
||||||
where
|
|
||||||
Theme: StyleSheet,
|
|
||||||
{
|
|
||||||
type State = ();
|
|
||||||
|
|
||||||
fn update(
|
|
||||||
&self,
|
|
||||||
_state: &mut Self::State,
|
|
||||||
_event: canvas::Event,
|
|
||||||
_bounds: Rectangle,
|
|
||||||
_cursor: canvas::Cursor,
|
|
||||||
) -> (canvas::event::Status, Option<Message>) {
|
|
||||||
(canvas::event::Status::Ignored, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw(
|
|
||||||
&self,
|
|
||||||
_state: &Self::State,
|
|
||||||
renderer: &iced::Renderer<Theme>,
|
|
||||||
theme: &Theme,
|
|
||||||
bounds: Rectangle,
|
|
||||||
_cursor: canvas::Cursor,
|
|
||||||
) -> Vec<canvas::Geometry> {
|
|
||||||
let mut frame = canvas::Frame::new(renderer, bounds.size());
|
|
||||||
let custom_style = <Theme as StyleSheet>::appearance(theme, self.style);
|
|
||||||
let track_radius = frame.width() / 2.0 - self.bar_height;
|
|
||||||
|
|
||||||
if let Some(Background::Color(color)) = custom_style.background {
|
|
||||||
let background_path =
|
|
||||||
canvas::Path::circle(frame.center(), track_radius);
|
|
||||||
frame.fill(&background_path, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
let track_path = canvas::Path::circle(frame.center(), track_radius);
|
|
||||||
|
|
||||||
frame.stroke(
|
|
||||||
&track_path,
|
|
||||||
canvas::Stroke::default()
|
|
||||||
.with_color(custom_style.track_color)
|
|
||||||
.with_width(self.bar_height),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut builder = canvas::path::Builder::new();
|
|
||||||
|
|
||||||
let start = self.state.rotation() * 2.0 * PI;
|
|
||||||
|
|
||||||
match self.state {
|
|
||||||
State::Expanding { progress, .. } => {
|
|
||||||
builder.arc(canvas::path::Arc {
|
|
||||||
center: frame.center(),
|
|
||||||
radius: track_radius,
|
|
||||||
start_angle: start,
|
|
||||||
end_angle: start
|
|
||||||
+ MIN_RADIANS
|
|
||||||
+ WRAP_RADIANS * (self.easing.y_at_x(*progress)),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
State::Contracting { progress, .. } => {
|
|
||||||
builder.arc(canvas::path::Arc {
|
|
||||||
center: frame.center(),
|
|
||||||
radius: track_radius,
|
|
||||||
start_angle: start
|
|
||||||
+ WRAP_RADIANS * (self.easing.y_at_x(*progress)),
|
|
||||||
end_angle: start + MIN_RADIANS + WRAP_RADIANS,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let bar_path = builder.build();
|
|
||||||
|
|
||||||
frame.stroke(
|
|
||||||
&bar_path,
|
|
||||||
canvas::Stroke::default()
|
|
||||||
.with_color(custom_style.bar_color)
|
|
||||||
.with_width(self.bar_height),
|
|
||||||
);
|
|
||||||
|
|
||||||
vec![frame.into_geometry()]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue