summaryrefslogtreecommitdiffstats
path: root/examples/game_of_life
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-05-01 04:35:59 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-05-01 04:35:59 +0200
commit404122e0b17300aa46cdb5ec5f0366f24b8ea931 (patch)
tree36606634d5ffa246c1905e523f189bc5b7a637b2 /examples/game_of_life
parent08b376c6d7d2f3c1fab1328202325cb47ce369e5 (diff)
downloadiced-404122e0b17300aa46cdb5ec5f0366f24b8ea931.tar.gz
iced-404122e0b17300aa46cdb5ec5f0366f24b8ea931.tar.bz2
iced-404122e0b17300aa46cdb5ec5f0366f24b8ea931.zip
Implement zooming for `game_of_life` example
Diffstat (limited to 'examples/game_of_life')
-rw-r--r--examples/game_of_life/src/main.rs157
1 files changed, 97 insertions, 60 deletions
diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs
index 3b37dc34..d9ff5a14 100644
--- a/examples/game_of_life/src/main.rs
+++ b/examples/game_of_life/src/main.rs
@@ -156,17 +156,17 @@ impl Application for GameOfLife {
mod grid {
use iced::{
- canvas::{self, Canvas, Cursor, Event, Frame, Geometry, Path},
+ canvas::{self, Cache, Canvas, Cursor, Event, Frame, Geometry, Path},
mouse, Color, Element, Length, Point, Rectangle, Size, Vector,
};
use std::collections::{HashMap, HashSet};
- #[derive(Default)]
pub struct Grid {
life: Life,
interaction: Interaction,
- cache: canvas::Cache,
+ cache: Cache,
translation: Vector,
+ scaling: f32,
}
#[derive(Debug, Clone, Copy)]
@@ -174,6 +174,18 @@ mod grid {
Populate(Cell),
}
+ impl Default for Grid {
+ fn default() -> Self {
+ Self {
+ life: Life::default(),
+ interaction: Interaction::default(),
+ cache: Cache::default(),
+ translation: Vector::default(),
+ scaling: 1.0,
+ }
+ }
+ }
+
impl Grid {
pub fn tick(&mut self) {
self.life.tick();
@@ -195,6 +207,27 @@ mod grid {
.height(Length::Fill)
.into()
}
+
+ pub fn visible_region(&self, size: Size) -> Rectangle {
+ let width = size.width / self.scaling;
+ let height = size.height / self.scaling;
+
+ Rectangle {
+ x: -self.translation.x - width / 2.0,
+ y: -self.translation.y - height / 2.0,
+ width,
+ height,
+ }
+ }
+
+ pub fn project(&self, position: Point, size: Size) -> Point {
+ let region = self.visible_region(size);
+
+ Point::new(
+ position.x / self.scaling + region.x,
+ position.y / self.scaling + region.y,
+ )
+ }
}
impl<'a> canvas::Program<Message> for Grid {
@@ -209,7 +242,7 @@ mod grid {
}
let cursor_position = cursor.position_in(&bounds)?;
- let cell = Cell::at(cursor_position - self.translation);
+ let cell = Cell::at(self.project(cursor_position, bounds.size()));
let populate = if self.life.contains(&cell) {
None
@@ -239,8 +272,9 @@ mod grid {
match self.interaction {
Interaction::Drawing => populate,
Interaction::Panning { translation, start } => {
- self.translation =
- translation + (cursor_position - start);
+ self.translation = translation
+ + (cursor_position - start)
+ * (1.0 / self.scaling);
self.cache.clear();
@@ -249,62 +283,65 @@ mod grid {
_ => None,
}
}
+ mouse::Event::WheelScrolled { delta } => match delta {
+ mouse::ScrollDelta::Lines { y, .. }
+ | mouse::ScrollDelta::Pixels { y, .. } => {
+ if y > 0.0 && self.scaling < 2.0
+ || y < 0.0 && self.scaling > 0.25
+ {
+ self.scaling += y / 30.0;
+
+ self.cache.clear();
+ }
+
+ None
+ }
+ },
_ => None,
},
}
}
fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec<Geometry> {
- let cell_size = Size::new(1.0, 1.0);
+ let center = Vector::new(bounds.width / 2.0, bounds.height / 2.0);
let life = self.cache.draw(bounds.size(), |frame| {
let background = Path::rectangle(Point::ORIGIN, frame.size());
- frame.fill(
- &background,
- Color::from_rgb(
- 0x40 as f32 / 255.0,
- 0x44 as f32 / 255.0,
- 0x4B as f32 / 255.0,
- ),
- );
+ frame.fill(&background, Color::from_rgb8(0x40, 0x44, 0x4B));
frame.with_save(|frame| {
+ frame.translate(center);
+ frame.scale(self.scaling);
frame.translate(self.translation);
frame.scale(Cell::SIZE as f32);
- let cells = Path::new(|p| {
- let region = Rectangle {
- x: -self.translation.x,
- y: -self.translation.y,
- width: frame.width(),
- height: frame.height(),
- };
-
- for cell in Cell::all_visible_in(region) {
- if self.life.contains(&cell) {
- p.rectangle(
- Point::new(cell.j as f32, cell.i as f32),
- cell_size,
- );
- }
- }
- });
- frame.fill(&cells, Color::WHITE);
+ let region = self.visible_region(frame.size());
+
+ for cell in self.life.visible_in(region) {
+ frame.fill_rectangle(
+ Point::new(cell.j as f32, cell.i as f32),
+ Size::UNIT,
+ Color::WHITE,
+ );
+ }
});
});
let hovered_cell = {
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(cursor_position - self.translation);
+ let cell =
+ Cell::at(self.project(cursor_position, frame.size()));
let interaction = Path::rectangle(
Point::new(cell.j as f32, cell.i as f32),
- cell_size,
+ Size::UNIT,
);
frame.fill(
@@ -344,14 +381,6 @@ mod grid {
}
impl Life {
- fn contains(&self, cell: &Cell) -> bool {
- self.cells.contains(cell)
- }
-
- fn populate(&mut self, cell: Cell) {
- self.cells.insert(cell);
- }
-
fn tick(&mut self) {
let mut adjacent_life = HashMap::new();
@@ -377,6 +406,31 @@ mod grid {
}
}
}
+
+ fn contains(&self, cell: &Cell) -> bool {
+ self.cells.contains(cell)
+ }
+
+ fn populate(&mut self, cell: Cell) {
+ self.cells.insert(cell);
+ }
+
+ fn visible_in(&self, region: Rectangle) -> impl Iterator<Item = &Cell> {
+ let first_row = (region.y / Cell::SIZE as f32).floor() as isize;
+ let first_column = (region.x / Cell::SIZE as f32).floor() as isize;
+
+ let visible_rows =
+ (region.height / Cell::SIZE as f32).ceil() as isize;
+ let visible_columns =
+ (region.width / Cell::SIZE as f32).ceil() as isize;
+
+ let rows = first_row..=first_row + visible_rows;
+ let columns = first_column..=first_column + visible_columns;
+
+ self.cells.iter().filter(move |cell| {
+ rows.contains(&cell.i) && columns.contains(&cell.j)
+ })
+ }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -410,23 +464,6 @@ mod grid {
fn neighbors(cell: Cell) -> impl Iterator<Item = Cell> {
Cell::cluster(cell).filter(move |candidate| *candidate != cell)
}
-
- fn all_visible_in(region: Rectangle) -> impl Iterator<Item = Cell> {
- use itertools::Itertools;
-
- let first_row = (region.y / Cell::SIZE as f32).floor() as isize;
- let first_column = (region.x / Cell::SIZE as f32).floor() as isize;
-
- let visible_rows =
- (region.height / Cell::SIZE as f32).ceil() as isize;
- let visible_columns =
- (region.width / Cell::SIZE as f32).ceil() as isize;
-
- let rows = first_row..=first_row + visible_rows;
- let columns = first_column..=first_column + visible_columns;
-
- rows.cartesian_product(columns).map(|(i, j)| Cell { i, j })
- }
}
enum Interaction {