diff options
author | 2020-04-19 14:39:30 +0200 | |
---|---|---|
committer | 2020-04-19 14:39:30 +0200 | |
commit | 0b5028b1ab47707a469176e9bf20cacdd3a19861 (patch) | |
tree | ba4ea88bbb5e3d3ebf22699a758c30181f535b35 | |
parent | 90c3a183d5e79aee1f323991c8c45161ccf9e187 (diff) | |
download | iced-0b5028b1ab47707a469176e9bf20cacdd3a19861.tar.gz iced-0b5028b1ab47707a469176e9bf20cacdd3a19861.tar.bz2 iced-0b5028b1ab47707a469176e9bf20cacdd3a19861.zip |
Draft `Program` interactivity for `Canvas`
-rw-r--r-- | core/src/rectangle.rs | 10 | ||||
-rw-r--r-- | examples/clock/src/main.rs | 5 | ||||
-rw-r--r-- | examples/solar_system/src/main.rs | 5 | ||||
-rw-r--r-- | wgpu/src/lib.rs | 2 | ||||
-rw-r--r-- | wgpu/src/widget/canvas.rs | 82 | ||||
-rw-r--r-- | wgpu/src/widget/canvas/drawable.rs | 6 | ||||
-rw-r--r-- | wgpu/src/widget/canvas/event.rs | 6 | ||||
-rw-r--r-- | wgpu/src/widget/canvas/layer/cache.rs | 16 | ||||
-rw-r--r-- | wgpu/src/widget/canvas/program.rs | 16 |
9 files changed, 112 insertions, 36 deletions
diff --git a/core/src/rectangle.rs b/core/src/rectangle.rs index aead6e9a..db8ebfc8 100644 --- a/core/src/rectangle.rs +++ b/core/src/rectangle.rs @@ -1,4 +1,4 @@ -use crate::Point; +use crate::{Point, Size}; /// A rectangle. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] @@ -43,6 +43,14 @@ impl Rectangle<f32> { self.y + self.height / 2.0 } + /// Returns the [`Size`] of the [`Rectangle`]. + /// + /// [`Size`]: struct.Size.html + /// [`Rectangle`]: struct.Rectangle.html + pub fn size(&self) -> Size { + Size::new(self.width, self.height) + } + /// Returns true if the given [`Point`] is contained in the [`Rectangle`]. /// /// [`Point`]: struct.Point.html diff --git a/examples/clock/src/main.rs b/examples/clock/src/main.rs index 827379fa..2407db65 100644 --- a/examples/clock/src/main.rs +++ b/examples/clock/src/main.rs @@ -59,10 +59,9 @@ impl Application for Clock { } fn view(&mut self) -> Element<Message> { - let canvas = Canvas::new() + let canvas = Canvas::new(&mut self.clock, &self.now) .width(Length::Units(400)) - .height(Length::Units(400)) - .push(self.clock.with(&self.now)); + .height(Length::Units(400)); Container::new(canvas) .width(Length::Fill) diff --git a/examples/solar_system/src/main.rs b/examples/solar_system/src/main.rs index bcd1dc71..eeb0796a 100644 --- a/examples/solar_system/src/main.rs +++ b/examples/solar_system/src/main.rs @@ -66,10 +66,9 @@ impl Application for SolarSystem { } fn view(&mut self) -> Element<Message> { - let canvas = Canvas::new() + let canvas = Canvas::new(&mut self.solar_system, &self.state) .width(Length::Fill) - .height(Length::Fill) - .push(self.solar_system.with(&self.state)); + .height(Length::Fill); Container::new(canvas) .width(Length::Fill) diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 799c1f34..30b5bb4a 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -20,7 +20,7 @@ //! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs //! [WebGPU API]: https://gpuweb.github.io/gpuweb/ //! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph -#![deny(missing_docs)] +//#![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] #![forbid(unsafe_code)] diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index 325f90ce..de4f0203 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -9,7 +9,8 @@ use crate::{Defaults, Primitive, Renderer}; use iced_native::{ - layout, Element, Hasher, Layout, Length, MouseCursor, Point, Size, Widget, + input::mouse, layout, Clipboard, Element, Hasher, Layout, Length, + MouseCursor, Point, Size, Widget, }; use std::hash::Hash; @@ -17,16 +18,20 @@ pub mod layer; pub mod path; mod drawable; +mod event; mod fill; mod frame; +mod program; mod stroke; mod text; pub use drawable::Drawable; +pub use event::Event; pub use fill::Fill; pub use frame::Frame; pub use layer::Layer; pub use path::Path; +pub use program::Program; pub use stroke::{LineCap, LineJoin, Stroke}; pub use text::Text; @@ -81,31 +86,31 @@ pub use text::Text; /// } /// /// // We can use a `Cache` to avoid unnecessary re-tessellation -/// let cache: layer::Cache<Circle> = layer::Cache::new(); +/// let mut cache: layer::Cache<Circle> = layer::Cache::new(); /// -/// // Finally, we simply provide the data to our `Cache` and push the resulting -/// // layer into a `Canvas` -/// let canvas = Canvas::new() -/// .push(cache.with(&Circle { radius: 50.0 })); +/// // Finally, we simply use our `Cache` to create the `Canvas`! +/// let canvas = Canvas::new(&mut cache, &Circle { radius: 50.0 }); /// ``` #[derive(Debug)] -pub struct Canvas<'a> { +pub struct Canvas<'a, P: Program> { width: Length, height: Length, - layers: Vec<Box<dyn Layer + 'a>>, + program: &'a mut P, + input: &'a P::Input, } -impl<'a> Canvas<'a> { +impl<'a, P: Program> Canvas<'a, P> { const DEFAULT_SIZE: u16 = 100; /// Creates a new [`Canvas`] with no layers. /// /// [`Canvas`]: struct.Canvas.html - pub fn new() -> Self { + pub fn new(program: &'a mut P, input: &'a P::Input) -> Self { Canvas { width: Length::Units(Self::DEFAULT_SIZE), height: Length::Units(Self::DEFAULT_SIZE), - layers: Vec::new(), + program, + input, } } @@ -124,20 +129,9 @@ impl<'a> Canvas<'a> { self.height = height; self } - - /// Adds a [`Layer`] to the [`Canvas`]. - /// - /// It will be drawn on top of previous layers. - /// - /// [`Layer`]: layer/trait.Layer.html - /// [`Canvas`]: struct.Canvas.html - pub fn push(mut self, layer: impl Layer + 'a) -> Self { - self.layers.push(Box::new(layer)); - self - } } -impl<'a, Message> Widget<Message, Renderer> for Canvas<'a> { +impl<'a, Message, P: Program> Widget<Message, Renderer> for Canvas<'a, P> { fn width(&self) -> Length { self.width } @@ -157,6 +151,37 @@ impl<'a, Message> Widget<Message, Renderer> for Canvas<'a> { layout::Node::new(size) } + fn on_event( + &mut self, + event: iced_native::Event, + layout: Layout<'_>, + cursor_position: Point, + _messages: &mut Vec<Message>, + _renderer: &Renderer, + _clipboard: Option<&dyn Clipboard>, + ) { + let bounds = layout.bounds(); + + let canvas_event = match event { + iced_native::Event::Mouse(mouse_event) => { + Some(Event::Mouse(match mouse_event { + mouse::Event::CursorMoved { .. } => { + mouse::Event::CursorMoved { + x: cursor_position.x - bounds.x, + y: cursor_position.y - bounds.y, + } + } + _ => mouse_event, + })) + } + _ => None, + }; + + if let Some(canvas_event) = canvas_event { + self.program.update(canvas_event, bounds.size(), self.input) + } + } + fn draw( &self, _renderer: &mut Renderer, @@ -171,7 +196,8 @@ impl<'a, Message> Widget<Message, Renderer> for Canvas<'a> { ( Primitive::Group { primitives: self - .layers + .program + .layers(self.input) .iter() .map(|layer| Primitive::Cached { origin, @@ -184,18 +210,20 @@ impl<'a, Message> Widget<Message, Renderer> for Canvas<'a> { } fn hash_layout(&self, state: &mut Hasher) { - std::any::TypeId::of::<Canvas<'static>>().hash(state); + struct Marker; + std::any::TypeId::of::<Marker>().hash(state); self.width.hash(state); self.height.hash(state); } } -impl<'a, Message> From<Canvas<'a>> for Element<'a, Message, Renderer> +impl<'a, Message, P: Program> From<Canvas<'a, P>> + for Element<'a, Message, Renderer> where Message: 'static, { - fn from(canvas: Canvas<'a>) -> Element<'a, Message, Renderer> { + fn from(canvas: Canvas<'a, P>) -> Element<'a, Message, Renderer> { Element::new(canvas) } } diff --git a/wgpu/src/widget/canvas/drawable.rs b/wgpu/src/widget/canvas/drawable.rs index 6c74071c..48ba6b4c 100644 --- a/wgpu/src/widget/canvas/drawable.rs +++ b/wgpu/src/widget/canvas/drawable.rs @@ -10,3 +10,9 @@ pub trait Drawable { /// [`Frame`]: struct.Frame.html fn draw(&self, frame: &mut Frame); } + +impl<'a> Drawable for dyn Fn(&mut Frame) + 'a { + fn draw(&self, frame: &mut Frame) { + self(frame) + } +} diff --git a/wgpu/src/widget/canvas/event.rs b/wgpu/src/widget/canvas/event.rs new file mode 100644 index 00000000..7a8b0829 --- /dev/null +++ b/wgpu/src/widget/canvas/event.rs @@ -0,0 +1,6 @@ +use iced_native::input::mouse; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Event { + Mouse(mouse::Event), +} diff --git a/wgpu/src/widget/canvas/layer/cache.rs b/wgpu/src/widget/canvas/layer/cache.rs index 4f8c2bec..2e87297c 100644 --- a/wgpu/src/widget/canvas/layer/cache.rs +++ b/wgpu/src/widget/canvas/layer/cache.rs @@ -1,5 +1,5 @@ use crate::{ - canvas::{Drawable, Frame, Layer}, + canvas::{Drawable, Frame, Layer, Program}, Primitive, }; @@ -79,6 +79,20 @@ where } } +impl<T> Program for Cache<T> +where + T: Drawable + std::fmt::Debug, +{ + type Input = T; + + fn layers<'a>( + &'a self, + input: &'a Self::Input, + ) -> Vec<Box<dyn Layer + 'a>> { + vec![Box::new(self.with(input))] + } +} + #[derive(Debug)] struct Bind<'a, T: Drawable> { cache: &'a Cache<T>, diff --git a/wgpu/src/widget/canvas/program.rs b/wgpu/src/widget/canvas/program.rs new file mode 100644 index 00000000..c65a078b --- /dev/null +++ b/wgpu/src/widget/canvas/program.rs @@ -0,0 +1,16 @@ +use crate::canvas::{Event, Layer, Size}; + +pub trait Program { + type Input; + + fn layers<'a>(&'a self, input: &'a Self::Input) + -> Vec<Box<dyn Layer + 'a>>; + + fn update<'a>( + &'a mut self, + _event: Event, + _bounds: Size, + _input: &'a Self::Input, + ) { + } +} |