summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Bingus <shankern@protonmail.com>2022-10-07 16:58:45 -0700
committerLibravatar GitHub <noreply@github.com>2022-10-07 16:58:45 -0700
commitaabc4e87b51af8025910681dc427260254877e4c (patch)
tree44dc50e04e58c15871cc56d22221dc43685d1d58
parent7a124476b1f609019bb0fdfa1254236af2d2a49e (diff)
parent77c838011fe6f8f567389d5994584a1a1b8420c5 (diff)
downloadiced-aabc4e87b51af8025910681dc427260254877e4c.tar.gz
iced-aabc4e87b51af8025910681dc427260254877e4c.tar.bz2
iced-aabc4e87b51af8025910681dc427260254877e4c.zip
Merge branch 'master' into fear/linear-gradients
-rw-r--r--Cargo.toml1
-rw-r--r--README.md2
-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--native/src/widget/radio.rs4
-rw-r--r--src/lib.rs1
-rw-r--r--src/touch.rs2
-rw-r--r--style/src/radio.rs4
-rw-r--r--style/src/theme.rs14
-rw-r--r--style/src/toggler.rs2
-rw-r--r--wgpu/README.md7
14 files changed, 257 insertions, 12 deletions
diff --git a/Cargo.toml b/Cargo.toml
index e4754782..e72d9152 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -72,6 +72,7 @@ members = [
"examples/integration_opengl",
"examples/integration_wgpu",
"examples/modern_art",
+ "examples/multitouch",
"examples/pane_grid",
"examples/pick_list",
"examples/pokedex",
diff --git a/README.md b/README.md
index 5e52234e..dc065ada 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
[![Crates.io](https://img.shields.io/crates/v/iced.svg)](https://crates.io/crates/iced)
[![License](https://img.shields.io/crates/l/iced.svg)](https://github.com/iced-rs/iced/blob/master/LICENSE)
[![Downloads](https://img.shields.io/crates/d/iced.svg)](https://crates.io/crates/iced)
-[![Test Status](https://github.com/iced-rs/iced/workflows/Test/badge.svg?event=push)](https://github.com/iced-rs/iced/actions)
+[![Test Status](https://img.shields.io/github/workflow/status/iced-rs/iced/Test?event=push&label=test)](https://github.com/iced-rs/iced/actions)
[![Discord Server](https://img.shields.io/discord/628993209984614400?label=&labelColor=6A7EC2&logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/3xZJ65GAhd)
A cross-platform GUI library for Rust focused on simplicity and type-safety.
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 36c17906..ea2efcc1 100644
--- a/graphics/src/widget/canvas.rs
+++ b/graphics/src/widget/canvas.rs
@@ -170,6 +170,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/native/src/widget/radio.rs b/native/src/widget/radio.rs
index c9152d05..cb83f745 100644
--- a/native/src/widget/radio.rs
+++ b/native/src/widget/radio.rs
@@ -230,9 +230,9 @@ where
let mut children = layout.children();
let custom_style = if is_mouse_over {
- theme.hovered(self.style)
+ theme.hovered(self.style, self.is_selected)
} else {
- theme.active(self.style)
+ theme.active(self.style, self.is_selected)
};
{
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};
diff --git a/style/src/radio.rs b/style/src/radio.rs
index a4d4a83b..d14ea33e 100644
--- a/style/src/radio.rs
+++ b/style/src/radio.rs
@@ -15,7 +15,7 @@ pub struct Appearance {
pub trait StyleSheet {
type Style: Default + Copy;
- fn active(&self, style: Self::Style) -> Appearance;
+ fn active(&self, style: Self::Style, is_selected: bool) -> Appearance;
- fn hovered(&self, style: Self::Style) -> Appearance;
+ fn hovered(&self, style: Self::Style, is_selected: bool) -> Appearance;
}
diff --git a/style/src/theme.rs b/style/src/theme.rs
index 9e9abfa0..ea538c3a 100644
--- a/style/src/theme.rs
+++ b/style/src/theme.rs
@@ -415,7 +415,11 @@ impl pick_list::StyleSheet for Theme {
impl radio::StyleSheet for Theme {
type Style = ();
- fn active(&self, _style: Self::Style) -> radio::Appearance {
+ fn active(
+ &self,
+ _style: Self::Style,
+ _is_selected: bool,
+ ) -> radio::Appearance {
let palette = self.extended_palette();
radio::Appearance {
@@ -427,8 +431,12 @@ impl radio::StyleSheet for Theme {
}
}
- fn hovered(&self, style: Self::Style) -> radio::Appearance {
- let active = self.active(style);
+ fn hovered(
+ &self,
+ style: Self::Style,
+ is_selected: bool,
+ ) -> radio::Appearance {
+ let active = self.active(style, is_selected);
let palette = self.extended_palette();
radio::Appearance {
diff --git a/style/src/toggler.rs b/style/src/toggler.rs
index 4ee7db46..0acf8e97 100644
--- a/style/src/toggler.rs
+++ b/style/src/toggler.rs
@@ -2,7 +2,7 @@
use iced_core::Color;
/// The appearance of a toggler.
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
pub struct Appearance {
pub background: Color,
pub background_border: Option<Color>,
diff --git a/wgpu/README.md b/wgpu/README.md
index 50440baf..016af179 100644
--- a/wgpu/README.md
+++ b/wgpu/README.md
@@ -4,9 +4,9 @@
[![License](https://img.shields.io/crates/l/iced_wgpu.svg)](https://github.com/iced-rs/iced/blob/master/LICENSE)
[![Discord Server](https://img.shields.io/discord/628993209984614400?label=&labelColor=6A7EC2&logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/3xZJ65GAhd)
-`iced_wgpu` is a [`wgpu`] renderer for [`iced_native`]. For now, it is the default renderer of Iced in native platforms.
+`iced_wgpu` is a [`wgpu`] renderer for [`iced_native`]. For now, it is the default renderer of Iced on [native platforms].
-[`wgpu`] supports most modern graphics backends: Vulkan, Metal, DX11, and DX12 (OpenGL and WebGL are still WIP). Additionally, it will support the incoming [WebGPU API].
+[`wgpu`] supports most modern graphics backends: Vulkan, Metal, and DX12 (OpenGL and WebGL are still WIP). Additionally, it will support the incoming [WebGPU API].
Currently, `iced_wgpu` supports the following primitives:
- Text, which is rendered using [`wgpu_glyph`]. No shaping at all.
@@ -22,6 +22,7 @@ Currently, `iced_wgpu` supports the following primitives:
[documentation]: https://docs.rs/iced_wgpu
[`iced_native`]: ../native
[`wgpu`]: https://github.com/gfx-rs/wgpu
+[native platforms]: https://github.com/gfx-rs/wgpu#supported-platforms
[WebGPU API]: https://gpuweb.github.io/gpuweb/
[`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph
@@ -39,7 +40,7 @@ you want to learn about a specific release, check out [the release list].
## Current limitations
-The current implementation is quite naive, it uses:
+The current implementation is quite naive; it uses:
- A different pipeline/shader for each primitive
- A very simplistic layer model: every `Clip` primitive will generate new layers