summaryrefslogtreecommitdiffstats
path: root/examples/progress_indicators/src/circular.rs
diff options
context:
space:
mode:
Diffstat (limited to 'examples/progress_indicators/src/circular.rs')
-rw-r--r--examples/progress_indicators/src/circular.rs425
1 files changed, 0 insertions, 425 deletions
diff --git a/examples/progress_indicators/src/circular.rs b/examples/progress_indicators/src/circular.rs
deleted file mode 100644
index 2a9f7e1e..00000000
--- a/examples/progress_indicators/src/circular.rs
+++ /dev/null
@@ -1,425 +0,0 @@
-//! Show a circular progress indicator.
-use iced::widget::canvas::{self, Cursor, Program, Renderer as CanvasRenderer};
-use iced::window;
-use iced_core::event::{self, Event};
-use iced_core::time::Instant;
-use iced_core::widget::tree::{self, Tree};
-use iced_core::window::RedrawRequest;
-use iced_core::{layout, Size};
-use iced_core::{renderer, Vector};
-use iced_core::{
- Background, Clipboard, Color, Element, Layout, Length, Point, Rectangle,
- Renderer, Shell, Widget,
-};
-
-use super::easing::{self, Easing};
-
-use std::borrow::Cow;
-use std::f32::consts::PI;
-use std::time::Duration;
-
-type R<Theme> = iced_widget::renderer::Renderer<Theme>;
-
-const MIN_RADIANS: f32 = PI / 8.0;
-const WRAP_RADIANS: f32 = 2.0 * PI - PI / 4.0;
-const PROCESSION_VELOCITY: u32 = u32::MAX / 120;
-
-#[allow(missing_debug_implementations)]
-pub struct Circular<'a, Theme>
-where
- Theme: StyleSheet,
-{
- size: f32,
- bar_height: f32,
- style: <Theme as StyleSheet>::Style,
- easing: Cow<'a, Easing>,
- cycle_duration: Duration,
-}
-
-impl<'a, Theme> Circular<'a, Theme>
-where
- Theme: StyleSheet,
-{
- /// Creates a new [`Circular`] with the given content.
- pub fn new() -> Self {
- Circular {
- size: 40.0,
- bar_height: 4.0,
- style: <Theme as StyleSheet>::Style::default(),
- easing: Cow::Borrowed(&easing::STANDARD),
- cycle_duration: Duration::from_millis(600),
- }
- }
-
- /// Sets the size of the [`Circular`].
- pub fn size(mut self, size: f32) -> Self {
- self.size = size;
- self
- }
-
- /// Sets the bar height of the [`Circular`].
- pub fn bar_height(mut self, bar_height: f32) -> Self {
- self.bar_height = bar_height;
- self
- }
-
- /// Sets the style variant of this [`Circular`].
- pub fn style(mut self, style: <Theme as StyleSheet>::Style) -> Self {
- self.style = style;
- self
- }
-
- /// Sets the easing of this [`Circular`].
- pub fn easing(mut self, easing: impl Into<Cow<'a, Easing>>) -> Self {
- self.easing = easing.into();
- self
- }
-
- /// Sets the cycle duration of this [`Circular`].
- pub fn cycle_duration(mut self, duration: Duration) -> Self {
- self.cycle_duration = duration / 2;
- self
- }
-}
-
-impl<'a, Theme> Default for Circular<'a, Theme>
-where
- Theme: StyleSheet,
-{
- fn default() -> Self {
- Self::new()
- }
-}
-
-#[derive(Clone, Copy)]
-enum State {
- Expanding {
- start: Instant,
- progress: f32,
- procession: u32,
- },
- Contracting {
- start: Instant,
- progress: f32,
- procession: u32,
- },
-}
-
-impl Default for State {
- fn default() -> Self {
- Self::Expanding {
- start: Instant::now(),
- progress: 0.0,
- procession: 0,
- }
- }
-}
-
-impl State {
- fn next(&self, now: Instant) -> Self {
- match self {
- Self::Expanding { procession, .. } => Self::Contracting {
- start: now,
- progress: 0.0,
- procession: procession.wrapping_add(PROCESSION_VELOCITY),
- },
- Self::Contracting { procession, .. } => Self::Expanding {
- start: now,
- progress: 0.0,
- procession: procession.wrapping_add(
- PROCESSION_VELOCITY.wrapping_add(
- ((WRAP_RADIANS / (2.0 * PI)) * u32::MAX as f32) as u32,
- ),
- ),
- },
- }
- }
-
- fn start(&self) -> Instant {
- match self {
- Self::Expanding { start, .. } | Self::Contracting { start, .. } => {
- *start
- }
- }
- }
-
- fn timed_transition(&self, cycle_duration: Duration, now: Instant) -> Self {
- let elapsed = now.duration_since(self.start());
-
- match elapsed {
- elapsed if elapsed > cycle_duration => self.next(now),
- _ => self.with_elapsed(cycle_duration, elapsed),
- }
- }
-
- fn with_elapsed(
- &self,
- cycle_duration: Duration,
- elapsed: Duration,
- ) -> Self {
- let progress = elapsed.as_secs_f32() / cycle_duration.as_secs_f32();
- match self {
- Self::Expanding {
- start, procession, ..
- } => Self::Expanding {
- start: *start,
- progress,
- procession: procession.wrapping_add(PROCESSION_VELOCITY),
- },
- Self::Contracting {
- start, procession, ..
- } => Self::Contracting {
- start: *start,
- progress,
- procession: procession.wrapping_add(PROCESSION_VELOCITY),
- },
- }
- }
-
- fn procession(&self) -> f32 {
- match self {
- Self::Expanding { procession, .. }
- | Self::Contracting { procession, .. } => {
- *procession as f32 / u32::MAX as f32
- }
- }
- }
-}
-
-impl<'a, Message, Theme> Widget<Message, R<Theme>> for Circular<'a, Theme>
-where
- Message: 'a + Clone,
- Theme: StyleSheet,
-{
- fn tag(&self) -> tree::Tag {
- tree::Tag::of::<State>()
- }
-
- fn state(&self) -> tree::State {
- tree::State::new(State::default())
- }
-
- fn width(&self) -> Length {
- Length::Fixed(self.size)
- }
-
- fn height(&self) -> Length {
- Length::Fixed(self.size)
- }
-
- fn layout(
- &self,
- _renderer: &iced_widget::renderer::Renderer<Theme>,
- limits: &layout::Limits,
- ) -> layout::Node {
- let limits = limits.width(self.size).height(self.size);
- let size = limits.resolve(Size::ZERO);
-
- layout::Node::new(size)
- }
-
- fn on_event(
- &mut self,
- tree: &mut Tree,
- event: Event,
- _layout: Layout<'_>,
- _cursor_position: Point,
- _renderer: &iced_widget::renderer::Renderer<Theme>,
- _clipboard: &mut dyn Clipboard,
- shell: &mut Shell<'_, Message>,
- ) -> event::Status {
- let state = tree.state.downcast_mut::<State>();
-
- if let Event::Window(window::Event::RedrawRequested(now)) = event {
- *state = state.timed_transition(self.cycle_duration, now);
-
- shell.request_redraw(RedrawRequest::NextFrame);
- }
-
- event::Status::Ignored
- }
-
- fn draw(
- &self,
- tree: &Tree,
- renderer: &mut R<Theme>,
- theme: &Theme,
- _style: &renderer::Style,
- layout: Layout<'_>,
- _cursor_position: Point,
- _viewport: &Rectangle,
- ) {
- let bounds = layout.bounds();
- let state = tree.state.downcast_ref::<State>();
-
- renderer.with_translation(
- Vector::new(bounds.x, bounds.y),
- |renderer| {
- renderer.draw(<StateWithStyle<Theme> as Program<
- Message,
- R<Theme>,
- >>::draw(
- &StateWithStyle {
- state,
- style: &self.style,
- bar_height: self.bar_height,
- easing: self.easing.as_ref(),
- },
- &(),
- renderer,
- theme,
- bounds,
- Cursor::Unavailable,
- ));
- },
- );
- }
-}
-
-impl<'a, Message, Theme> From<Circular<'a, Theme>>
- for Element<'a, Message, R<Theme>>
-where
- Message: Clone + 'a,
- Theme: StyleSheet + 'a,
-{
- fn from(circular: Circular<'a, Theme>) -> Self {
- Self::new(circular)
- }
-}
-
-#[derive(Debug, Clone, Copy)]
-pub struct Appearance {
- /// The [`Background`] of the progress indicator.
- pub background: Option<Background>,
- /// The track [`Color`] of the progress indicator.
- pub track_color: Color,
- /// The bar [`Color`] of the progress indicator.
- pub bar_color: Color,
-}
-
-impl std::default::Default for Appearance {
- fn default() -> Self {
- Self {
- background: None,
- track_color: Color::TRANSPARENT,
- bar_color: Color::BLACK,
- }
- }
-}
-
-/// A set of rules that dictate the style of an indicator.
-pub trait StyleSheet {
- /// The supported style of the [`StyleSheet`].
- type Style: Default;
-
- /// Produces the active [`Appearance`] of a indicator.
- fn appearance(&self, style: &Self::Style) -> Appearance;
-}
-
-impl StyleSheet for iced::Theme {
- type Style = ();
-
- fn appearance(&self, _style: &Self::Style) -> Appearance {
- let palette = self.extended_palette();
-
- Appearance {
- background: None,
- track_color: palette.background.weak.color,
- bar_color: palette.primary.base.color,
- }
- }
-}
-
-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>
- canvas::Program<Message, iced_widget::renderer::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_widget::renderer::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.procession() * 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()]
- }
-}