diff options
author | 2020-05-03 01:53:45 +0200 | |
---|---|---|
committer | 2020-05-03 01:53:45 +0200 | |
commit | 5aaaea7c8824fb65bac35307cdf760c57f2bf5df (patch) | |
tree | 07888f300ac0ec1cc310dce319e2ae0b5e6665f1 /examples/game_of_life | |
parent | c3c5161386cb527bf6d0fe34e5f4103392733599 (diff) | |
download | iced-5aaaea7c8824fb65bac35307cdf760c57f2bf5df.tar.gz iced-5aaaea7c8824fb65bac35307cdf760c57f2bf5df.tar.bz2 iced-5aaaea7c8824fb65bac35307cdf760c57f2bf5df.zip |
Render stats as an overlay in `game_of_life`
Also allow toggling the grid lines
Diffstat (limited to 'examples/game_of_life')
-rw-r--r-- | examples/game_of_life/src/main.rs | 185 |
1 files changed, 103 insertions, 82 deletions
diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs index 52b04696..018ebc50 100644 --- a/examples/game_of_life/src/main.rs +++ b/examples/game_of_life/src/main.rs @@ -7,8 +7,8 @@ use iced::{ button::{self, Button}, executor, slider::{self, Slider}, - time, Align, Application, Column, Command, Container, Element, Length, Row, - Settings, Subscription, Text, + time, Align, Application, Checkbox, Column, Command, Container, Element, + Length, Row, Settings, Subscription, Text, }; use std::time::{Duration, Instant}; @@ -23,7 +23,6 @@ pub fn main() { struct GameOfLife { grid: Grid, controls: Controls, - statistics: Statistics, is_playing: bool, queued_ticks: usize, speed: usize, @@ -34,7 +33,8 @@ struct GameOfLife { enum Message { Grid(grid::Message), Tick(Instant), - Toggle, + TogglePlayback, + ToggleGrid(bool), Next, Clear, SpeedChanged(f32), @@ -62,9 +62,7 @@ impl Application for GameOfLife { fn update(&mut self, message: Message) -> Command<Message> { match message { Message::Grid(message) => { - if let Some(tick_duration) = self.grid.update(message) { - self.statistics.tick_duration = tick_duration; - } + self.grid.update(message); } Message::Tick(_) | Message::Next => { self.queued_ticks = (self.queued_ticks + 1).min(self.speed); @@ -74,15 +72,17 @@ impl Application for GameOfLife { self.speed = speed; } - self.statistics.last_queued_ticks = self.queued_ticks; self.queued_ticks = 0; return Command::perform(task, Message::Grid); } } - Message::Toggle => { + Message::TogglePlayback => { self.is_playing = !self.is_playing; } + Message::ToggleGrid(show_grid_lines) => { + self.grid.toggle_lines(show_grid_lines); + } Message::Clear => { self.grid.clear(); } @@ -110,9 +110,8 @@ impl Application for GameOfLife { fn view(&mut self) -> Element<Message> { let selected_speed = self.next_speed.unwrap_or(self.speed); let controls = self.controls.view( - &self.grid, - &self.statistics, self.is_playing, + self.grid.are_lines_visible(), selected_speed, ); @@ -130,8 +129,11 @@ impl Application for GameOfLife { mod grid { use iced::{ - canvas::{self, Cache, Canvas, Cursor, Event, Frame, Geometry, Path}, - mouse, Color, Element, Length, Point, Rectangle, Size, Vector, + canvas::{ + self, Cache, Canvas, Cursor, Event, Frame, Geometry, Path, Text, + }, + mouse, Color, Element, HorizontalAlignment, Length, Point, Rectangle, + Size, Vector, VerticalAlignment, }; use rustc_hash::{FxHashMap, FxHashSet}; use std::future::Future; @@ -145,6 +147,9 @@ mod grid { grid_cache: Cache, translation: Vector, scaling: f32, + show_lines: bool, + last_tick_duration: Duration, + last_queued_ticks: usize, version: usize, } @@ -172,6 +177,9 @@ mod grid { grid_cache: Cache::default(), translation: Vector::default(), scaling: 1.0, + show_lines: true, + last_tick_duration: Duration::default(), + last_queued_ticks: 0, version: 0, } } @@ -181,10 +189,6 @@ mod grid { const MIN_SCALING: f32 = 0.1; const MAX_SCALING: f32 = 2.0; - pub fn cell_count(&self) -> usize { - self.state.cell_count() - } - pub fn tick( &mut self, amount: usize, @@ -192,6 +196,8 @@ mod grid { let version = self.version; let tick = self.state.tick(amount)?; + self.last_queued_ticks = amount; + Some(async move { let start = Instant::now(); let result = tick.await; @@ -205,20 +211,11 @@ mod grid { }) } - pub fn clear(&mut self) { - self.state = State::default(); - self.version += 1; - - self.life_cache.clear(); - } - - pub fn update(&mut self, message: Message) -> Option<Duration> { + pub fn update(&mut self, message: Message) { match message { Message::Populate(cell) => { self.state.populate(cell); self.life_cache.clear(); - - None } Message::Ticked { result: Ok(life), @@ -228,16 +225,14 @@ mod grid { self.state.update(life); self.life_cache.clear(); - Some(tick_duration) + self.last_tick_duration = tick_duration; } Message::Ticked { result: Err(error), .. } => { dbg!(error); - - None } - Message::Ticked { .. } => None, + Message::Ticked { .. } => {} } } @@ -248,7 +243,22 @@ mod grid { .into() } - pub fn visible_region(&self, size: Size) -> Region { + pub fn clear(&mut self) { + self.state = State::default(); + self.version += 1; + + self.life_cache.clear(); + } + + pub fn toggle_lines(&mut self, enabled: bool) { + self.show_lines = enabled; + } + + pub fn are_lines_visible(&self) -> bool { + self.show_lines + } + + fn visible_region(&self, size: Size) -> Region { let width = size.width / self.scaling; let height = size.height / self.scaling; @@ -260,7 +270,7 @@ mod grid { } } - pub fn project(&self, position: Point, size: Size) -> Point { + fn project(&self, position: Point, size: Size) -> Point { let region = self.visible_region(size); Point::new( @@ -388,33 +398,64 @@ mod grid { }); }); - let hovered_cell = { + let overlay = { let mut frame = Frame::new(bounds.size()); - frame.translate(center); - frame.scale(self.scaling); - frame.translate(self.translation); - frame.scale(Cell::SIZE as f32); - - if let Some(cursor_position) = cursor.position_in(&bounds) { - let cell = - Cell::at(self.project(cursor_position, frame.size())); - - frame.fill_rectangle( - Point::new(cell.j as f32, cell.i as f32), - Size::UNIT, - Color { - a: 0.5, - ..Color::BLACK - }, - ); + let hovered_cell = + cursor.position_in(&bounds).map(|position| { + Cell::at(self.project(position, frame.size())) + }); + + if let Some(cell) = hovered_cell { + frame.with_save(|frame| { + frame.translate(center); + frame.scale(self.scaling); + frame.translate(self.translation); + frame.scale(Cell::SIZE as f32); + + frame.fill_rectangle( + Point::new(cell.j as f32, cell.i as f32), + Size::UNIT, + Color { + a: 0.5, + ..Color::BLACK + }, + ); + }); + } + + let text = Text { + color: Color::WHITE, + size: 14.0, + position: Point::new(frame.width(), frame.height()), + horizontal_alignment: HorizontalAlignment::Right, + vertical_alignment: VerticalAlignment::Bottom, + ..Text::default() + }; + + if let Some(cell) = hovered_cell { + frame.fill_text(Text { + content: format!("({}, {})", cell.i, cell.j), + position: text.position - Vector::new(0.0, 16.0), + ..text + }); } + frame.fill_text(Text { + content: format!( + "{} cells @ {:?} ({})", + self.state.cell_count(), + self.last_tick_duration, + self.last_queued_ticks + ), + ..text + }); + frame.into_geometry() }; - if self.scaling < 0.2 { - vec![life, hovered_cell] + if self.scaling < 0.2 || !self.show_lines { + vec![life, overlay] } else { let grid = self.grid_cache.draw(bounds.size(), |frame| { frame.translate(center); @@ -449,7 +490,7 @@ mod grid { } }); - vec![life, grid, hovered_cell] + vec![life, grid, overlay] } } @@ -677,9 +718,8 @@ struct Controls { impl Controls { fn view<'a>( &'a mut self, - grid: &Grid, - statistics: &'a Statistics, is_playing: bool, + is_grid_enabled: bool, speed: usize, ) -> Element<'a, Message> { let playback_controls = Row::new() @@ -689,7 +729,7 @@ impl Controls { &mut self.toggle_button, Text::new(if is_playing { "Pause" } else { "Play" }), ) - .on_press(Message::Toggle) + .on_press(Message::TogglePlayback) .style(style::Button), ) .push( @@ -719,7 +759,12 @@ impl Controls { .align_items(Align::Center) .push(playback_controls) .push(speed_controls) - .push(statistics.view(grid)) + .push( + Checkbox::new(is_grid_enabled, "Grid", Message::ToggleGrid) + .size(16) + .spacing(5) + .text_size(16), + ) .push( Button::new(&mut self.clear_button, Text::new("Clear")) .on_press(Message::Clear) @@ -728,27 +773,3 @@ impl Controls { .into() } } - -#[derive(Default)] -struct Statistics { - tick_duration: Duration, - last_queued_ticks: usize, -} - -impl Statistics { - fn view(&self, grid: &Grid) -> Element<Message> { - Column::new() - .width(Length::Units(150)) - .align_items(Align::Center) - .spacing(2) - .push(Text::new(format!("{} cells", grid.cell_count())).size(14)) - .push( - Text::new(format!( - "{:?} ({})", - self.tick_duration, self.last_queued_ticks - )) - .size(14), - ) - .into() - } -} |