summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón <hector0193@gmail.com>2022-10-04 18:20:14 +0200
committerLibravatar GitHub <noreply@github.com>2022-10-04 18:20:14 +0200
commit2278bade55b2bcd530c8c9a30a22d5f800921e55 (patch)
tree40093c0f59136426a04effa417f74bc64359c09b
parent5f758d847f7e0de0ab7134247133c169a6132de1 (diff)
parent8c74464b0d608fb04a1c921b2cbb36b8bc6fc9b8 (diff)
downloadiced-2278bade55b2bcd530c8c9a30a22d5f800921e55.tar.gz
iced-2278bade55b2bcd530c8c9a30a22d5f800921e55.tar.bz2
iced-2278bade55b2bcd530c8c9a30a22d5f800921e55.zip
Merge pull request #1305 from artursapek/canvas-touch
Expose touch events in canvas widget
-rw-r--r--Cargo.toml1
-rw-r--r--examples/game_of_life/src/main.rs14
-rw-r--r--examples/multitouch/Cargo.toml12
-rw-r--r--examples/multitouch/src/main.rs199
-rw-r--r--graphics/src/widget/canvas.rs3
-rw-r--r--graphics/src/widget/canvas/event.rs4
-rw-r--r--src/lib.rs1
-rw-r--r--src/touch.rs2
8 files changed, 236 insertions, 0 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 725baecc..9c6a435a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -72,6 +72,7 @@ members = [
"examples/geometry",
"examples/integration_opengl",
"examples/integration_wgpu",
+ "examples/multitouch",
"examples/pane_grid",
"examples/pick_list",
"examples/pokedex",
diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs
index a2030275..2a8b3721 100644
--- a/examples/game_of_life/src/main.rs
+++ b/examples/game_of_life/src/main.rs
@@ -204,6 +204,7 @@ fn view_controls<'a>(
mod grid {
use crate::Preset;
+ use iced::touch;
use iced::widget::canvas;
use iced::widget::canvas::event::{self, Event};
use iced::widget::canvas::{
@@ -423,6 +424,19 @@ mod grid {
};
match event {
+ Event::Touch(touch::Event::FingerMoved { .. }) => {
+ let message = {
+ *interaction = if is_populated {
+ Interaction::Erasing
+ } else {
+ Interaction::Drawing
+ };
+
+ populate.or(unpopulate)
+ };
+
+ (event::Status::Captured, message)
+ }
Event::Mouse(mouse_event) => match mouse_event {
mouse::Event::ButtonPressed(button) => {
let message = match button {
diff --git a/examples/multitouch/Cargo.toml b/examples/multitouch/Cargo.toml
new file mode 100644
index 00000000..f7c8c145
--- /dev/null
+++ b/examples/multitouch/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "multitouch"
+version = "0.1.0"
+authors = ["Artur Sapek <artur@kraken.com>"]
+edition = "2021"
+publish = false
+
+[dependencies]
+iced = { path = "../..", features = ["canvas", "tokio", "debug"] }
+tokio = { version = "1.0", features = ["sync"] }
+env_logger = "0.9"
+voronator = "0.2"
diff --git a/examples/multitouch/src/main.rs b/examples/multitouch/src/main.rs
new file mode 100644
index 00000000..0345ceb7
--- /dev/null
+++ b/examples/multitouch/src/main.rs
@@ -0,0 +1,199 @@
+//! This example shows how to use touch events in `Canvas` to draw
+//! a circle around each fingertip. This only works on touch-enabled
+//! computers like Microsoft Surface.
+use iced::widget::canvas::event;
+use iced::widget::canvas::{self, Canvas, Cursor, Geometry, Stroke};
+use iced::{
+ executor, touch, window, Application, Color, Command, Element, Length,
+ Point, Rectangle, Settings, Subscription, Theme,
+};
+
+use std::collections::HashMap;
+
+pub fn main() -> iced::Result {
+ env_logger::builder().format_timestamp(None).init();
+
+ Multitouch::run(Settings {
+ antialiasing: true,
+ window: window::Settings {
+ position: window::Position::Centered,
+ ..window::Settings::default()
+ },
+ ..Settings::default()
+ })
+}
+
+struct Multitouch {
+ state: State,
+}
+
+#[derive(Debug)]
+struct State {
+ cache: canvas::Cache,
+ fingers: HashMap<touch::Finger, Point>,
+}
+
+impl State {
+ fn new() -> Self {
+ Self {
+ cache: canvas::Cache::new(),
+ fingers: HashMap::new(),
+ }
+ }
+}
+
+#[derive(Debug)]
+enum Message {
+ FingerPressed { id: touch::Finger, position: Point },
+ FingerLifted { id: touch::Finger },
+}
+
+impl Application for Multitouch {
+ type Executor = executor::Default;
+ type Message = Message;
+ type Theme = Theme;
+ type Flags = ();
+
+ fn new(_flags: ()) -> (Self, Command<Message>) {
+ (
+ Multitouch {
+ state: State::new(),
+ },
+ Command::none(),
+ )
+ }
+
+ fn title(&self) -> String {
+ String::from("Multitouch - Iced")
+ }
+
+ fn update(&mut self, message: Message) -> Command<Message> {
+ match message {
+ Message::FingerPressed { id, position } => {
+ self.state.fingers.insert(id, position);
+ self.state.cache.clear();
+ }
+ Message::FingerLifted { id } => {
+ self.state.fingers.remove(&id);
+ self.state.cache.clear();
+ }
+ }
+
+ Command::none()
+ }
+
+ fn subscription(&self) -> Subscription<Message> {
+ Subscription::none()
+ }
+
+ fn view(&self) -> Element<Message> {
+ Canvas::new(&self.state)
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .into()
+ }
+}
+
+impl canvas::Program<Message> for State {
+ type State = ();
+
+ fn update(
+ &self,
+ _state: &mut Self::State,
+ event: event::Event,
+ _bounds: Rectangle,
+ _cursor: Cursor,
+ ) -> (event::Status, Option<Message>) {
+ match event {
+ event::Event::Touch(touch_event) => match touch_event {
+ touch::Event::FingerPressed { id, position }
+ | touch::Event::FingerMoved { id, position } => (
+ event::Status::Captured,
+ Some(Message::FingerPressed { id, position }),
+ ),
+ touch::Event::FingerLifted { id, .. }
+ | touch::Event::FingerLost { id, .. } => (
+ event::Status::Captured,
+ Some(Message::FingerLifted { id }),
+ ),
+ },
+ _ => (event::Status::Ignored, None),
+ }
+ }
+
+ fn draw(
+ &self,
+ _state: &Self::State,
+ _theme: &Theme,
+ bounds: Rectangle,
+ _cursor: Cursor,
+ ) -> Vec<Geometry> {
+ let fingerweb = self.cache.draw(bounds.size(), |frame| {
+ if self.fingers.len() < 2 {
+ return;
+ }
+
+ // Collect tuples of (id, point);
+ let mut zones: Vec<(u64, Point)> =
+ self.fingers.iter().map(|(id, pt)| (id.0, *pt)).collect();
+
+ // Sort by ID
+ zones.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
+
+ // Generate sorted list of points
+ let vpoints: Vec<(f64, f64)> = zones
+ .iter()
+ .map(|(_, p)| (f64::from(p.x), f64::from(p.y)))
+ .collect();
+
+ let diagram: voronator::VoronoiDiagram<
+ voronator::delaunator::Point,
+ > = voronator::VoronoiDiagram::from_tuple(
+ &(0.0, 0.0),
+ &(700.0, 700.0),
+ &vpoints,
+ )
+ .expect("Generate Voronoi diagram");
+
+ for (cell, zone) in diagram.cells().iter().zip(zones) {
+ let mut builder = canvas::path::Builder::new();
+
+ for (index, p) in cell.points().iter().enumerate() {
+ let p = Point::new(p.x as f32, p.y as f32);
+
+ match index {
+ 0 => builder.move_to(p),
+ _ => builder.line_to(p),
+ }
+ }
+
+ let path = builder.build();
+
+ let color_r = (10 % zone.0) as f32 / 20.0;
+ let color_g = (10 % (zone.0 + 8)) as f32 / 20.0;
+ let color_b = (10 % (zone.0 + 3)) as f32 / 20.0;
+
+ frame.fill(
+ &path,
+ Color {
+ r: color_r,
+ g: color_g,
+ b: color_b,
+ a: 1.0,
+ },
+ );
+
+ frame.stroke(
+ &path,
+ Stroke {
+ color: Color::BLACK,
+ width: 3.0,
+ ..Stroke::default()
+ },
+ );
+ }
+ });
+
+ vec![fingerweb]
+ }
+}
diff --git a/graphics/src/widget/canvas.rs b/graphics/src/widget/canvas.rs
index 88403fd7..b4afd998 100644
--- a/graphics/src/widget/canvas.rs
+++ b/graphics/src/widget/canvas.rs
@@ -173,6 +173,9 @@ where
iced_native::Event::Mouse(mouse_event) => {
Some(Event::Mouse(mouse_event))
}
+ iced_native::Event::Touch(touch_event) => {
+ Some(Event::Touch(touch_event))
+ }
iced_native::Event::Keyboard(keyboard_event) => {
Some(Event::Keyboard(keyboard_event))
}
diff --git a/graphics/src/widget/canvas/event.rs b/graphics/src/widget/canvas/event.rs
index 5bf6f7a6..7c733a4d 100644
--- a/graphics/src/widget/canvas/event.rs
+++ b/graphics/src/widget/canvas/event.rs
@@ -1,6 +1,7 @@
//! Handle events of a canvas.
use iced_native::keyboard;
use iced_native::mouse;
+use iced_native::touch;
pub use iced_native::event::Status;
@@ -12,6 +13,9 @@ pub enum Event {
/// A mouse event.
Mouse(mouse::Event),
+ /// A touch event.
+ Touch(touch::Event),
+
/// A keyboard event.
Keyboard(keyboard::Event),
}
diff --git a/src/lib.rs b/src/lib.rs
index 8209952f..b86780f1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -177,6 +177,7 @@ pub mod mouse;
pub mod overlay;
pub mod settings;
pub mod time;
+pub mod touch;
pub mod widget;
pub mod window;
diff --git a/src/touch.rs b/src/touch.rs
new file mode 100644
index 00000000..0b77c386
--- /dev/null
+++ b/src/touch.rs
@@ -0,0 +1,2 @@
+//! Listen and react to touch events.
+pub use crate::runtime::touch::{Event, Finger};