diff options
Diffstat (limited to 'examples/game_of_life')
| -rw-r--r-- | examples/game_of_life/src/main.rs | 270 | 
1 files changed, 137 insertions, 133 deletions
diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs index 62ecc2d1..a2030275 100644 --- a/examples/game_of_life/src/main.rs +++ b/examples/game_of_life/src/main.rs @@ -3,18 +3,18 @@  mod preset;  use grid::Grid; -use iced::button::{self, Button}; +use preset::Preset; +  use iced::executor; -use iced::pick_list::{self, PickList}; -use iced::slider::{self, Slider};  use iced::theme::{self, Theme};  use iced::time; +use iced::widget::{ +    button, checkbox, column, container, pick_list, row, slider, text, +};  use iced::window;  use iced::{ -    Alignment, Application, Checkbox, Column, Command, Element, Length, Row, -    Settings, Subscription, Text, +    Alignment, Application, Command, Element, Length, Settings, Subscription,  }; -use preset::Preset;  use std::time::{Duration, Instant};  pub fn main() -> iced::Result { @@ -33,7 +33,6 @@ pub fn main() -> iced::Result {  #[derive(Default)]  struct GameOfLife {      grid: Grid, -    controls: Controls,      is_playing: bool,      queued_ticks: usize,      speed: usize, @@ -132,23 +131,26 @@ impl Application for GameOfLife {          }      } -    fn view(&mut self) -> Element<Message> { +    fn view(&self) -> Element<Message> {          let version = self.version;          let selected_speed = self.next_speed.unwrap_or(self.speed); -        let controls = self.controls.view( +        let controls = view_controls(              self.is_playing,              self.grid.are_lines_visible(),              selected_speed,              self.grid.preset(),          ); -        Column::new() -            .push( -                self.grid -                    .view() -                    .map(move |message| Message::Grid(message, version)), -            ) -            .push(controls) +        let content = column![ +            self.grid +                .view() +                .map(move |message| Message::Grid(message, version)), +            controls +        ]; + +        container(content) +            .width(Length::Fill) +            .height(Length::Fill)              .into()      } @@ -157,13 +159,59 @@ impl Application for GameOfLife {      }  } +fn view_controls<'a>( +    is_playing: bool, +    is_grid_enabled: bool, +    speed: usize, +    preset: Preset, +) -> Element<'a, Message> { +    let playback_controls = row![ +        button(if is_playing { "Pause" } else { "Play" }) +            .on_press(Message::TogglePlayback), +        button("Next") +            .on_press(Message::Next) +            .style(theme::Button::Secondary), +    ] +    .spacing(10); + +    let speed_controls = row![ +        slider(1.0..=1000.0, speed as f32, Message::SpeedChanged), +        text(format!("x{}", speed)).size(16), +    ] +    .width(Length::Fill) +    .align_items(Alignment::Center) +    .spacing(10); + +    row![ +        playback_controls, +        speed_controls, +        checkbox("Grid", is_grid_enabled, Message::ToggleGrid) +            .size(16) +            .spacing(5) +            .text_size(16), +        pick_list(preset::ALL, Some(preset), Message::PresetPicked) +            .padding(8) +            .text_size(16), +        button("Clear") +            .on_press(Message::Clear) +            .style(theme::Button::Destructive), +    ] +    .padding(10) +    .spacing(20) +    .align_items(Alignment::Center) +    .into() +} +  mod grid {      use crate::Preset; +    use iced::widget::canvas; +    use iced::widget::canvas::event::{self, Event}; +    use iced::widget::canvas::{ +        Cache, Canvas, Cursor, Frame, Geometry, Path, Text, +    };      use iced::{ -        alignment, -        canvas::event::{self, Event}, -        canvas::{self, Cache, Canvas, Cursor, Frame, Geometry, Path, Text}, -        mouse, Color, Element, Length, Point, Rectangle, Size, Theme, Vector, +        alignment, mouse, Color, Element, Length, Point, Rectangle, Size, +        Theme, Vector,      };      use rustc_hash::{FxHashMap, FxHashSet};      use std::future::Future; @@ -173,7 +221,6 @@ mod grid {      pub struct Grid {          state: State,          preset: Preset, -        interaction: Interaction,          life_cache: Cache,          grid_cache: Cache,          translation: Vector, @@ -187,6 +234,8 @@ mod grid {      pub enum Message {          Populate(Cell),          Unpopulate(Cell), +        Translated(Vector), +        Scaled(f32, Option<Vector>),          Ticked {              result: Result<Life, TickError>,              tick_duration: Duration, @@ -218,7 +267,6 @@ mod grid {                          .collect(),                  ),                  preset, -                interaction: Interaction::None,                  life_cache: Cache::default(),                  grid_cache: Cache::default(),                  translation: Vector::default(), @@ -263,6 +311,22 @@ mod grid {                      self.preset = Preset::Custom;                  } +                Message::Translated(translation) => { +                    self.translation = translation; + +                    self.life_cache.clear(); +                    self.grid_cache.clear(); +                } +                Message::Scaled(scaling, translation) => { +                    self.scaling = scaling; + +                    if let Some(translation) = translation { +                        self.translation = translation; +                    } + +                    self.life_cache.clear(); +                    self.grid_cache.clear(); +                }                  Message::Ticked {                      result: Ok(life),                      tick_duration, @@ -280,7 +344,7 @@ mod grid {              }          } -        pub fn view(&mut self) -> Element<Message> { +        pub fn view(&self) -> Element<Message> {              Canvas::new(self)                  .width(Length::Fill)                  .height(Length::Fill) @@ -329,14 +393,17 @@ mod grid {      }      impl canvas::Program<Message> for Grid { +        type State = Interaction; +          fn update( -            &mut self, +            &self, +            interaction: &mut Interaction,              event: Event,              bounds: Rectangle,              cursor: Cursor,          ) -> (event::Status, Option<Message>) {              if let Event::Mouse(mouse::Event::ButtonReleased(_)) = event { -                self.interaction = Interaction::None; +                *interaction = Interaction::None;              }              let cursor_position = @@ -360,7 +427,7 @@ mod grid {                      mouse::Event::ButtonPressed(button) => {                          let message = match button {                              mouse::Button::Left => { -                                self.interaction = if is_populated { +                                *interaction = if is_populated {                                      Interaction::Erasing                                  } else {                                      Interaction::Drawing @@ -369,7 +436,7 @@ mod grid {                                  populate.or(unpopulate)                              }                              mouse::Button::Right => { -                                self.interaction = Interaction::Panning { +                                *interaction = Interaction::Panning {                                      translation: self.translation,                                      start: cursor_position,                                  }; @@ -382,23 +449,20 @@ mod grid {                          (event::Status::Captured, message)                      }                      mouse::Event::CursorMoved { .. } => { -                        let message = match self.interaction { +                        let message = match *interaction {                              Interaction::Drawing => populate,                              Interaction::Erasing => unpopulate,                              Interaction::Panning { translation, start } => { -                                self.translation = translation -                                    + (cursor_position - start) -                                        * (1.0 / self.scaling); - -                                self.life_cache.clear(); -                                self.grid_cache.clear(); - -                                None +                                Some(Message::Translated( +                                    translation +                                        + (cursor_position - start) +                                            * (1.0 / self.scaling), +                                ))                              }                              _ => None,                          }; -                        let event_status = match self.interaction { +                        let event_status = match interaction {                              Interaction::None => event::Status::Ignored,                              _ => event::Status::Captured,                          }; @@ -413,30 +477,38 @@ mod grid {                              {                                  let old_scaling = self.scaling; -                                self.scaling = (self.scaling -                                    * (1.0 + y / 30.0)) +                                let scaling = (self.scaling * (1.0 + y / 30.0))                                      .max(Self::MIN_SCALING)                                      .min(Self::MAX_SCALING); -                                if let Some(cursor_to_center) = -                                    cursor.position_from(bounds.center()) -                                { -                                    let factor = self.scaling - old_scaling; - -                                    self.translation = self.translation -                                        - Vector::new( -                                            cursor_to_center.x * factor -                                                / (old_scaling * old_scaling), -                                            cursor_to_center.y * factor -                                                / (old_scaling * old_scaling), -                                        ); -                                } - -                                self.life_cache.clear(); -                                self.grid_cache.clear(); +                                let translation = +                                    if let Some(cursor_to_center) = +                                        cursor.position_from(bounds.center()) +                                    { +                                        let factor = scaling - old_scaling; + +                                        Some( +                                            self.translation +                                                - Vector::new( +                                                    cursor_to_center.x * factor +                                                        / (old_scaling +                                                            * old_scaling), +                                                    cursor_to_center.y * factor +                                                        / (old_scaling +                                                            * old_scaling), +                                                ), +                                        ) +                                    } else { +                                        None +                                    }; + +                                ( +                                    event::Status::Captured, +                                    Some(Message::Scaled(scaling, translation)), +                                ) +                            } else { +                                (event::Status::Captured, None)                              } - -                            (event::Status::Captured, None)                          }                      },                      _ => (event::Status::Ignored, None), @@ -447,6 +519,7 @@ mod grid {          fn draw(              &self, +            _interaction: &Interaction,              _theme: &Theme,              bounds: Rectangle,              cursor: Cursor, @@ -576,10 +649,11 @@ mod grid {          fn mouse_interaction(              &self, +            interaction: &Interaction,              bounds: Rectangle,              cursor: Cursor,          ) -> mouse::Interaction { -            match self.interaction { +            match interaction {                  Interaction::Drawing => mouse::Interaction::Crosshair,                  Interaction::Erasing => mouse::Interaction::Crosshair,                  Interaction::Panning { .. } => mouse::Interaction::Grabbing, @@ -808,86 +882,16 @@ mod grid {          }      } -    enum Interaction { +    pub enum Interaction {          None,          Drawing,          Erasing,          Panning { translation: Vector, start: Point },      } -} - -#[derive(Default)] -struct Controls { -    toggle_button: button::State, -    next_button: button::State, -    clear_button: button::State, -    speed_slider: slider::State, -    preset_list: pick_list::State<Preset>, -} -impl Controls { -    fn view( -        &mut self, -        is_playing: bool, -        is_grid_enabled: bool, -        speed: usize, -        preset: Preset, -    ) -> Element<Message> { -        let playback_controls = Row::new() -            .spacing(10) -            .push( -                Button::new( -                    &mut self.toggle_button, -                    Text::new(if is_playing { "Pause" } else { "Play" }), -                ) -                .on_press(Message::TogglePlayback) -                .style(theme::Button::Primary), -            ) -            .push( -                Button::new(&mut self.next_button, Text::new("Next")) -                    .on_press(Message::Next) -                    .style(theme::Button::Secondary), -            ); - -        let speed_controls = Row::new() -            .width(Length::Fill) -            .align_items(Alignment::Center) -            .spacing(10) -            .push(Slider::new( -                &mut self.speed_slider, -                1.0..=1000.0, -                speed as f32, -                Message::SpeedChanged, -            )) -            .push(Text::new(format!("x{}", speed)).size(16)); - -        Row::new() -            .padding(10) -            .spacing(20) -            .align_items(Alignment::Center) -            .push(playback_controls) -            .push(speed_controls) -            .push( -                Checkbox::new(is_grid_enabled, "Grid", Message::ToggleGrid) -                    .size(16) -                    .spacing(5) -                    .text_size(16), -            ) -            .push( -                PickList::new( -                    &mut self.preset_list, -                    preset::ALL, -                    Some(preset), -                    Message::PresetPicked, -                ) -                .padding(8) -                .text_size(16), -            ) -            .push( -                Button::new(&mut self.clear_button, Text::new("Clear")) -                    .on_press(Message::Clear) -                    .style(theme::Button::Destructive), -            ) -            .into() +    impl Default for Interaction { +        fn default() -> Self { +            Self::None +        }      }  }  | 
