iced-yoda/examples/multitouch/src/main.rs

203 lines
5.6 KiB
Rust
Raw Normal View History

2022-04-13 19:08:53 -06:00
//! 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.
2023-06-08 20:11:59 +02:00
use iced::mouse;
2022-04-13 19:08:53 -06:00
use iced::widget::canvas::event;
2022-11-03 04:42:46 +01:00
use iced::widget::canvas::stroke::{self, Stroke};
2023-06-08 20:11:59 +02:00
use iced::widget::canvas::{self, Canvas, Geometry};
2022-04-13 19:08:53 -06:00
use iced::{
executor, touch, window, Application, Color, Command, Element, Length,
Point, Rectangle, Renderer, Settings, Subscription, Theme,
2022-04-13 19:08:53 -06:00
};
use std::collections::HashMap;
pub fn main() -> iced::Result {
tracing_subscriber::fmt::init();
2022-04-13 19:08:53 -06:00
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 } => {
2022-10-04 11:53:03 +02:00
self.state.fingers.insert(id, position);
2022-04-13 19:08:53 -06:00
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 {
2022-04-13 19:08:53 -06:00
type State = ();
fn update(
&self,
_state: &mut Self::State,
event: event::Event,
_bounds: Rectangle,
2023-06-08 20:11:59 +02:00
_cursor: mouse::Cursor,
2022-04-13 19:08:53 -06:00
) -> (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,
renderer: &Renderer,
2022-04-13 19:08:53 -06:00
_theme: &Theme,
bounds: Rectangle,
2023-06-08 20:11:59 +02:00
_cursor: mouse::Cursor,
2022-04-13 19:08:53 -06:00
) -> Vec<Geometry> {
let fingerweb = self.cache.draw(renderer, bounds.size(), |frame| {
2022-10-04 11:35:22 +02:00
if self.fingers.len() < 2 {
return;
2022-04-27 10:30:32 -06:00
}
2022-04-13 19:08:53 -06:00
2022-04-27 10:30:32 -06:00
// Collect tuples of (id, point);
2022-10-04 11:53:03 +02:00
let mut zones: Vec<(u64, Point)> =
self.fingers.iter().map(|(id, pt)| (id.0, *pt)).collect();
2022-04-27 10:30:32 -06:00
// 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();
2022-04-27 10:30:32 -06:00
let diagram: voronator::VoronoiDiagram<
voronator::delaunator::Point,
> = voronator::VoronoiDiagram::from_tuple(
&(0.0, 0.0),
&(700.0, 700.0),
&vpoints,
)
.expect("Generate Voronoi diagram");
2022-04-27 10:30:32 -06:00
for (cell, zone) in diagram.cells().iter().zip(zones) {
2022-04-27 10:30:32 -06:00
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);
2022-04-27 10:30:32 -06:00
match index {
0 => builder.move_to(p),
_ => builder.line_to(p),
2022-04-27 10:30:32 -06:00
}
}
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,
},
);
2022-04-13 19:08:53 -06:00
frame.stroke(
2022-04-27 10:30:32 -06:00
&path,
2022-04-13 19:08:53 -06:00
Stroke {
2022-11-03 04:42:46 +01:00
style: stroke::Style::Solid(Color::BLACK),
2022-04-13 19:08:53 -06:00
width: 3.0,
..Stroke::default()
},
);
}
});
vec![fingerweb]
}
}