Implement event capturing for `Canvas`

This commit is contained in:
Héctor Ramón Jiménez 2020-11-12 01:24:59 +01:00
parent bf6c65b5ad
commit 3aca177132
5 changed files with 98 additions and 66 deletions

View File

@ -69,7 +69,8 @@ impl Sandbox for Example {
mod bezier { mod bezier {
use iced::{ use iced::{
canvas::{self, Canvas, Cursor, Event, Frame, Geometry, Path, Stroke}, canvas::event::{self, Event},
canvas::{self, Canvas, Cursor, Frame, Geometry, Path, Stroke},
mouse, Element, Length, Point, Rectangle, mouse, Element, Length, Point, Rectangle,
}; };
@ -109,41 +110,51 @@ mod bezier {
event: Event, event: Event,
bounds: Rectangle, bounds: Rectangle,
cursor: Cursor, cursor: Cursor,
) -> Option<Curve> { ) -> (event::Status, Option<Curve>) {
let cursor_position = cursor.position_in(&bounds)?; let cursor_position =
if let Some(position) = cursor.position_in(&bounds) {
position
} else {
return (event::Status::Ignored, None);
};
match event { match event {
Event::Mouse(mouse_event) => match mouse_event { Event::Mouse(mouse_event) => {
mouse::Event::ButtonPressed(mouse::Button::Left) => { let message = match mouse_event {
match self.state.pending { mouse::Event::ButtonPressed(mouse::Button::Left) => {
None => { match self.state.pending {
self.state.pending = Some(Pending::One { None => {
from: cursor_position, self.state.pending = Some(Pending::One {
}); from: cursor_position,
None });
}
Some(Pending::One { from }) => {
self.state.pending = Some(Pending::Two {
from,
to: cursor_position,
});
None None
} }
Some(Pending::Two { from, to }) => { Some(Pending::One { from }) => {
self.state.pending = None; self.state.pending = Some(Pending::Two {
from,
to: cursor_position,
});
Some(Curve { None
from, }
to, Some(Pending::Two { from, to }) => {
control: cursor_position, self.state.pending = None;
})
Some(Curve {
from,
to,
control: cursor_position,
})
}
} }
} }
} _ => None,
_ => None, };
},
_ => None, (event::Status::Captured, message)
}
_ => (event::Status::Ignored, None),
} }
} }

View File

@ -153,9 +153,8 @@ impl Application for GameOfLife {
mod grid { mod grid {
use crate::Preset; use crate::Preset;
use iced::{ use iced::{
canvas::{ canvas::event::{self, Event},
self, Cache, Canvas, Cursor, Event, Frame, Geometry, Path, Text, canvas::{self, Cache, Canvas, Cursor, Frame, Geometry, Path, Text},
},
mouse, Color, Element, HorizontalAlignment, Length, Point, Rectangle, mouse, Color, Element, HorizontalAlignment, Length, Point, Rectangle,
Size, Vector, VerticalAlignment, Size, Vector, VerticalAlignment,
}; };
@ -328,12 +327,18 @@ mod grid {
event: Event, event: Event,
bounds: Rectangle, bounds: Rectangle,
cursor: Cursor, cursor: Cursor,
) -> Option<Message> { ) -> (event::Status, Option<Message>) {
if let Event::Mouse(mouse::Event::ButtonReleased(_)) = event { if let Event::Mouse(mouse::Event::ButtonReleased(_)) = event {
self.interaction = Interaction::None; self.interaction = Interaction::None;
} }
let cursor_position = cursor.position_in(&bounds)?; let cursor_position =
if let Some(position) = cursor.position_in(&bounds) {
position
} else {
return (event::Status::Ignored, None);
};
let cell = Cell::at(self.project(cursor_position, bounds.size())); let cell = Cell::at(self.project(cursor_position, bounds.size()));
let is_populated = self.state.contains(&cell); let is_populated = self.state.contains(&cell);
@ -345,28 +350,32 @@ mod grid {
match event { match event {
Event::Mouse(mouse_event) => match mouse_event { Event::Mouse(mouse_event) => match mouse_event {
mouse::Event::ButtonPressed(button) => match button { mouse::Event::ButtonPressed(button) => {
mouse::Button::Left => { let message = match button {
self.interaction = if is_populated { mouse::Button::Left => {
Interaction::Erasing self.interaction = if is_populated {
} else { Interaction::Erasing
Interaction::Drawing } else {
}; Interaction::Drawing
};
populate.or(unpopulate) populate.or(unpopulate)
} }
mouse::Button::Right => { mouse::Button::Right => {
self.interaction = Interaction::Panning { self.interaction = Interaction::Panning {
translation: self.translation, translation: self.translation,
start: cursor_position, start: cursor_position,
}; };
None None
} }
_ => None, _ => None,
}, };
(event::Status::Captured, message)
}
mouse::Event::CursorMoved { .. } => { mouse::Event::CursorMoved { .. } => {
match self.interaction { let message = match self.interaction {
Interaction::Drawing => populate, Interaction::Drawing => populate,
Interaction::Erasing => unpopulate, Interaction::Erasing => unpopulate,
Interaction::Panning { translation, start } => { Interaction::Panning { translation, start } => {
@ -380,7 +389,14 @@ mod grid {
None None
} }
_ => None, _ => None,
} };
let event_status = match self.interaction {
Interaction::None => event::Status::Ignored,
_ => event::Status::Captured,
};
(event_status, message)
} }
mouse::Event::WheelScrolled { delta } => match delta { mouse::Event::WheelScrolled { delta } => match delta {
mouse::ScrollDelta::Lines { y, .. } mouse::ScrollDelta::Lines { y, .. }
@ -413,12 +429,12 @@ mod grid {
self.grid_cache.clear(); self.grid_cache.clear();
} }
None (event::Status::Captured, None)
} }
}, },
_ => None, _ => (event::Status::Ignored, None),
}, },
_ => None, _ => (event::Status::Ignored, None),
} }
} }

View File

@ -16,11 +16,11 @@ use iced_native::{
use std::hash::Hash; use std::hash::Hash;
use std::marker::PhantomData; use std::marker::PhantomData;
pub mod event;
pub mod path; pub mod path;
mod cache; mod cache;
mod cursor; mod cursor;
mod event;
mod fill; mod fill;
mod frame; mod frame;
mod geometry; mod geometry;
@ -184,11 +184,14 @@ where
let cursor = Cursor::from_window_position(cursor_position); let cursor = Cursor::from_window_position(cursor_position);
if let Some(canvas_event) = canvas_event { if let Some(canvas_event) = canvas_event {
if let Some(message) = let (event_status, message) =
self.program.update(canvas_event, bounds, cursor) self.program.update(canvas_event, bounds, cursor);
{
if let Some(message) = message {
messages.push(message); messages.push(message);
} }
return event_status;
} }
event::Status::Ignored event::Status::Ignored

View File

@ -1,3 +1,4 @@
//! Handle events of a canvas.
use iced_native::keyboard; use iced_native::keyboard;
use iced_native::mouse; use iced_native::mouse;

View File

@ -1,4 +1,5 @@
use crate::canvas::{Cursor, Event, Geometry}; use crate::canvas::event::{self, Event};
use crate::canvas::{Cursor, Geometry};
use iced_native::{mouse, Rectangle}; use iced_native::{mouse, Rectangle};
/// The state and logic of a [`Canvas`]. /// The state and logic of a [`Canvas`].
@ -27,8 +28,8 @@ pub trait Program<Message> {
_event: Event, _event: Event,
_bounds: Rectangle, _bounds: Rectangle,
_cursor: Cursor, _cursor: Cursor,
) -> Option<Message> { ) -> (event::Status, Option<Message>) {
None (event::Status::Ignored, None)
} }
/// Draws the state of the [`Program`], producing a bunch of [`Geometry`]. /// Draws the state of the [`Program`], producing a bunch of [`Geometry`].
@ -67,7 +68,7 @@ where
event: Event, event: Event,
bounds: Rectangle, bounds: Rectangle,
cursor: Cursor, cursor: Cursor,
) -> Option<Message> { ) -> (event::Status, Option<Message>) {
T::update(self, event, bounds, cursor) T::update(self, event, bounds, cursor)
} }