summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/clock/src/main.rs4
-rw-r--r--examples/solar_system/src/main.rs138
-rw-r--r--wgpu/src/widget/canvas.rs46
-rw-r--r--wgpu/src/widget/canvas/cache.rs (renamed from wgpu/src/widget/canvas/layer/cache.rs)76
-rw-r--r--wgpu/src/widget/canvas/drawable.rs9
-rw-r--r--wgpu/src/widget/canvas/geometry.rs15
-rw-r--r--wgpu/src/widget/canvas/layer.rs25
-rw-r--r--wgpu/src/widget/canvas/program.rs16
-rw-r--r--wgpu/src/widget/canvas/state.rs20
9 files changed, 178 insertions, 171 deletions
diff --git a/examples/clock/src/main.rs b/examples/clock/src/main.rs
index 2407db65..8b3a92c7 100644
--- a/examples/clock/src/main.rs
+++ b/examples/clock/src/main.rs
@@ -12,7 +12,7 @@ pub fn main() {
struct Clock {
now: LocalTime,
- clock: canvas::layer::Cache<LocalTime>,
+ clock: canvas::Cache,
}
#[derive(Debug, Clone, Copy)]
@@ -59,7 +59,7 @@ impl Application for Clock {
}
fn view(&mut self) -> Element<Message> {
- let canvas = Canvas::new(&mut self.clock, &self.now)
+ let canvas = Canvas::new(self.clock.with(&self.now))
.width(Length::Units(400))
.height(Length::Units(400));
diff --git a/examples/solar_system/src/main.rs b/examples/solar_system/src/main.rs
index 8870fe52..618f4206 100644
--- a/examples/solar_system/src/main.rs
+++ b/examples/solar_system/src/main.rs
@@ -23,7 +23,6 @@ pub fn main() {
struct SolarSystem {
state: State,
- now: Instant,
}
#[derive(Debug, Clone, Copy)]
@@ -40,7 +39,6 @@ impl Application for SolarSystem {
(
SolarSystem {
state: State::new(),
- now: Instant::now(),
},
Command::none(),
)
@@ -53,8 +51,7 @@ impl Application for SolarSystem {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Tick(instant) => {
- self.now = instant;
- self.state.clear();
+ self.state.update(instant);
}
}
@@ -67,7 +64,7 @@ impl Application for SolarSystem {
}
fn view(&mut self) -> Element<Message> {
- let canvas = Canvas::new(&mut self.state, &self.now)
+ let canvas = Canvas::new(&mut self.state)
.width(Length::Fill)
.height(Length::Fill);
@@ -82,9 +79,11 @@ impl Application for SolarSystem {
#[derive(Debug)]
struct State {
- cache: canvas::layer::Cache,
+ space_cache: canvas::Cache,
+ system_cache: canvas::Cache,
cursor_position: Point,
start: Instant,
+ now: Instant,
stars: Vec<(Point, f32)>,
}
@@ -94,43 +93,52 @@ impl State {
let (width, height) = window::Settings::default().size;
State {
- cache: Default::default(),
+ space_cache: Default::default(),
+ system_cache: Default::default(),
cursor_position: Point::ORIGIN,
start: now,
- stars: {
- use rand::Rng;
-
- let mut rng = rand::thread_rng();
-
- (0..100)
- .map(|_| {
- (
- Point::new(
- rng.gen_range(0.0, width as f32),
- rng.gen_range(0.0, height as f32),
- ),
- rng.gen_range(0.5, 1.0),
- )
- })
- .collect()
- },
+ now,
+ stars: Self::generate_stars(width, height),
}
}
- pub fn clear(&mut self) {
- self.cache.clear();
+ pub fn space(&self) -> Space<'_> {
+ Space { stars: &self.stars }
}
-}
-impl canvas::Program for State {
- type Input = Instant;
+ pub fn system(&self) -> System {
+ System {
+ start: self.start,
+ now: self.now,
+ }
+ }
+
+ pub fn update(&mut self, now: Instant) {
+ self.now = now;
+ self.system_cache.clear();
+ }
+
+ fn generate_stars(width: u32, height: u32) -> Vec<(Point, f32)> {
+ use rand::Rng;
+
+ let mut rng = rand::thread_rng();
+
+ (0..100)
+ .map(|_| {
+ (
+ Point::new(
+ rng.gen_range(0.0, width as f32),
+ rng.gen_range(0.0, height as f32),
+ ),
+ rng.gen_range(0.5, 1.0),
+ )
+ })
+ .collect()
+ }
+}
- fn update(
- &mut self,
- event: canvas::Event,
- _bounds: Size,
- _input: &Instant,
- ) {
+impl canvas::State for State {
+ fn update(&mut self, event: canvas::Event, _bounds: Size) {
match event {
canvas::Event::Mouse(mouse_event) => match mouse_event {
mouse::Event::CursorMoved { x, y } => {
@@ -141,34 +149,50 @@ impl canvas::Program for State {
state: input::ButtonState::Released,
} => {
self.stars.push((self.cursor_position, 2.0));
+ self.space_cache.clear();
}
_ => {}
},
}
}
- fn layers<'a>(
- &'a self,
- now: &'a Instant,
- ) -> Vec<Box<dyn canvas::Layer + 'a>> {
- let system = System {
- stars: &self.stars,
- start: &self.start,
- now,
- };
-
- vec![Box::new(self.cache.with(system))]
+ fn draw(&self, bounds: Size) -> Vec<canvas::Geometry> {
+ vec![
+ self.space_cache.draw(bounds, self.space()),
+ self.system_cache.draw(bounds, self.system()),
+ ]
}
}
#[derive(Debug)]
-struct System<'a> {
+struct Space<'a> {
stars: &'a [(Point, f32)],
- start: &'a Instant,
- now: &'a Instant,
}
-impl System<'_> {
+impl canvas::Drawable for Space<'_> {
+ fn draw(&self, frame: &mut canvas::Frame) {
+ use canvas::Path;
+
+ let space = Path::rectangle(Point::new(0.0, 0.0), frame.size());
+
+ let stars = Path::new(|path| {
+ for (p, size) in self.stars {
+ path.rectangle(*p, Size::new(*size, *size));
+ }
+ });
+
+ frame.fill(&space, Color::BLACK);
+ frame.fill(&stars, Color::WHITE);
+ }
+}
+
+#[derive(Debug)]
+struct System {
+ start: Instant,
+ now: Instant,
+}
+
+impl System {
const SUN_RADIUS: f32 = 70.0;
const ORBIT_RADIUS: f32 = 150.0;
const EARTH_RADIUS: f32 = 12.0;
@@ -176,26 +200,16 @@ impl System<'_> {
const MOON_DISTANCE: f32 = 28.0;
}
-impl<'a> canvas::Drawable for System<'a> {
+impl canvas::Drawable for System {
fn draw(&self, frame: &mut canvas::Frame) {
use canvas::{Path, Stroke};
use std::f32::consts::PI;
let center = frame.center();
- let space = Path::rectangle(Point::new(0.0, 0.0), frame.size());
-
- let stars = Path::new(|path| {
- for (p, size) in self.stars {
- path.rectangle(*p, Size::new(*size, *size));
- }
- });
-
let sun = Path::circle(center, Self::SUN_RADIUS);
let orbit = Path::circle(center, Self::ORBIT_RADIUS);
- frame.fill(&space, Color::BLACK);
- frame.fill(&stars, Color::WHITE);
frame.fill(&sun, Color::from_rgb8(0xF9, 0xD7, 0x1C));
frame.stroke(
&orbit,
@@ -206,7 +220,7 @@ impl<'a> canvas::Drawable for System<'a> {
},
);
- let elapsed = *self.now - *self.start;
+ let elapsed = self.now - self.start;
let elapsed_seconds = elapsed.as_secs() as f32;
let elapsed_millis = elapsed.subsec_millis() as f32;
diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs
index 326bc7d5..2b485e18 100644
--- a/wgpu/src/widget/canvas.rs
+++ b/wgpu/src/widget/canvas.rs
@@ -14,24 +14,26 @@ use iced_native::{
};
use std::hash::Hash;
-pub mod layer;
pub mod path;
+mod cache;
mod drawable;
mod event;
mod fill;
mod frame;
-mod program;
+mod geometry;
+mod state;
mod stroke;
mod text;
+pub use cache::Cache;
pub use drawable::Drawable;
pub use event::Event;
pub use fill::Fill;
pub use frame::Frame;
-pub use layer::Layer;
+pub use geometry::Geometry;
pub use path::Path;
-pub use program::Program;
+pub use state::State;
pub use stroke::{LineCap, LineJoin, Stroke};
pub use text::Text;
@@ -65,7 +67,7 @@ pub use text::Text;
/// # pub use iced_wgpu::canvas;
/// # pub use iced_native::Color;
/// # }
-/// use iced::canvas::{self, layer, Canvas, Drawable, Fill, Frame, Path};
+/// use iced::canvas::{self, Cache, Canvas, Drawable, Fill, Frame, Path};
/// use iced::Color;
///
/// // First, we define the data we need for drawing
@@ -86,31 +88,29 @@ pub use text::Text;
/// }
///
/// // We can use a `Cache` to avoid unnecessary re-tessellation
-/// let mut cache: layer::Cache<Circle> = layer::Cache::new();
+/// let cache = Cache::new();
///
/// // Finally, we simply use our `Cache` to create the `Canvas`!
-/// let canvas = Canvas::new(&mut cache, &Circle { radius: 50.0 });
+/// let canvas = Canvas::new(cache.with(Circle { radius: 50.0 }));
/// ```
#[derive(Debug)]
-pub struct Canvas<'a, P: Program> {
+pub struct Canvas<S: State> {
width: Length,
height: Length,
- program: &'a mut P,
- input: &'a P::Input,
+ state: S,
}
-impl<'a, P: Program> Canvas<'a, P> {
+impl<S: State> Canvas<S> {
const DEFAULT_SIZE: u16 = 100;
/// Creates a new [`Canvas`] with no layers.
///
/// [`Canvas`]: struct.Canvas.html
- pub fn new(program: &'a mut P, input: &'a P::Input) -> Self {
+ pub fn new(state: S) -> Self {
Canvas {
width: Length::Units(Self::DEFAULT_SIZE),
height: Length::Units(Self::DEFAULT_SIZE),
- program,
- input,
+ state,
}
}
@@ -131,7 +131,7 @@ impl<'a, P: Program> Canvas<'a, P> {
}
}
-impl<'a, Message, P: Program> Widget<Message, Renderer> for Canvas<'a, P> {
+impl<Message, S: State> Widget<Message, Renderer> for Canvas<S> {
fn width(&self) -> Length {
self.width
}
@@ -178,7 +178,7 @@ impl<'a, Message, P: Program> Widget<Message, Renderer> for Canvas<'a, P> {
};
if let Some(canvas_event) = canvas_event {
- self.program.update(canvas_event, bounds.size(), self.input)
+ self.state.update(canvas_event, bounds.size())
}
}
@@ -196,12 +196,12 @@ impl<'a, Message, P: Program> Widget<Message, Renderer> for Canvas<'a, P> {
(
Primitive::Group {
primitives: self
- .program
- .layers(self.input)
- .iter()
- .map(|layer| Primitive::Cached {
+ .state
+ .draw(size)
+ .into_iter()
+ .map(|geometry| Primitive::Cached {
origin,
- cache: layer.draw(size),
+ cache: geometry.into_primitive(),
})
.collect(),
},
@@ -218,12 +218,12 @@ impl<'a, Message, P: Program> Widget<Message, Renderer> for Canvas<'a, P> {
}
}
-impl<'a, Message, P: Program> From<Canvas<'a, P>>
+impl<'a, Message, S: State + 'a> From<Canvas<S>>
for Element<'a, Message, Renderer>
where
Message: 'static,
{
- fn from(canvas: Canvas<'a, P>) -> Element<'a, Message, Renderer> {
+ fn from(canvas: Canvas<S>) -> Element<'a, Message, Renderer> {
Element::new(canvas)
}
}
diff --git a/wgpu/src/widget/canvas/layer/cache.rs b/wgpu/src/widget/canvas/cache.rs
index 4ecebb48..c88239af 100644
--- a/wgpu/src/widget/canvas/layer/cache.rs
+++ b/wgpu/src/widget/canvas/cache.rs
@@ -1,10 +1,10 @@
use crate::{
- canvas::{Drawable, Frame, Layer},
+ canvas::{Drawable, Frame, Geometry},
Primitive,
};
use iced_native::Size;
-use std::{borrow::Borrow, cell::RefCell, marker::PhantomData, sync::Arc};
+use std::{cell::RefCell, sync::Arc};
enum State {
Empty,
@@ -48,61 +48,51 @@ impl Cache {
*self.state.borrow_mut() = State::Empty;
}
- /// Binds the [`Cache`] with some data, producing a [`Layer`] that can be
- /// added to a [`Canvas`].
- ///
- /// [`Cache`]: struct.Cache.html
- /// [`Layer`]: ../trait.Layer.html
- /// [`Canvas`]: ../../struct.Canvas.html
- pub fn with<'a, T>(
- &'a self,
- input: impl Borrow<T> + std::fmt::Debug + 'a,
- ) -> impl Layer + 'a
+ pub fn draw<T>(&self, new_bounds: Size, input: T) -> Geometry
where
- T: Drawable + std::fmt::Debug + 'a,
+ T: Drawable + std::fmt::Debug,
{
- Bind {
- cache: self,
- input: input,
- drawable: PhantomData,
- }
- }
-}
-
-#[derive(Debug)]
-struct Bind<'a, T: Drawable, I: Borrow<T> + 'a> {
- cache: &'a Cache,
- input: I,
- drawable: PhantomData<T>,
-}
-
-impl<'a, T, I> Layer for Bind<'a, T, I>
-where
- T: Drawable + std::fmt::Debug,
- I: Borrow<T> + std::fmt::Debug + 'a,
-{
- fn draw(&self, current_bounds: Size) -> Arc<Primitive> {
use std::ops::Deref;
- if let State::Filled { bounds, primitive } =
- self.cache.state.borrow().deref()
+ if let State::Filled { bounds, primitive } = self.state.borrow().deref()
{
- if *bounds == current_bounds {
- return primitive.clone();
+ if *bounds == new_bounds {
+ return Geometry::from_primitive(primitive.clone());
}
}
- let mut frame = Frame::new(current_bounds.width, current_bounds.height);
- self.input.borrow().draw(&mut frame);
+ let mut frame = Frame::new(new_bounds.width, new_bounds.height);
+ input.draw(&mut frame);
let primitive = Arc::new(frame.into_primitive());
- *self.cache.state.borrow_mut() = State::Filled {
- bounds: current_bounds,
+ *self.state.borrow_mut() = State::Filled {
+ bounds: new_bounds,
primitive: primitive.clone(),
};
- primitive
+ Geometry::from_primitive(primitive)
+ }
+
+ pub fn with<'a, T>(&'a self, input: T) -> impl crate::canvas::State + 'a
+ where
+ T: Drawable + std::fmt::Debug + 'a,
+ {
+ Bind { cache: self, input }
+ }
+}
+
+struct Bind<'a, T> {
+ cache: &'a Cache,
+ input: T,
+}
+
+impl<'a, T> crate::canvas::State for Bind<'a, T>
+where
+ T: Drawable + std::fmt::Debug + 'a,
+{
+ fn draw(&self, bounds: Size) -> Vec<Geometry> {
+ vec![self.cache.draw(bounds, &self.input)]
}
}
diff --git a/wgpu/src/widget/canvas/drawable.rs b/wgpu/src/widget/canvas/drawable.rs
index 48ba6b4c..32258b71 100644
--- a/wgpu/src/widget/canvas/drawable.rs
+++ b/wgpu/src/widget/canvas/drawable.rs
@@ -16,3 +16,12 @@ impl<'a> Drawable for dyn Fn(&mut Frame) + 'a {
self(frame)
}
}
+
+impl<T> Drawable for &T
+where
+ T: Drawable,
+{
+ fn draw(&self, frame: &mut Frame) {
+ T::draw(self, frame)
+ }
+}
diff --git a/wgpu/src/widget/canvas/geometry.rs b/wgpu/src/widget/canvas/geometry.rs
new file mode 100644
index 00000000..db7b4054
--- /dev/null
+++ b/wgpu/src/widget/canvas/geometry.rs
@@ -0,0 +1,15 @@
+use crate::Primitive;
+use std::sync::Arc;
+
+#[derive(Debug)]
+pub struct Geometry(Arc<Primitive>);
+
+impl Geometry {
+ pub(crate) fn from_primitive(primitive: Arc<Primitive>) -> Self {
+ Self(primitive)
+ }
+
+ pub(crate) fn into_primitive(self) -> Arc<Primitive> {
+ self.0
+ }
+}
diff --git a/wgpu/src/widget/canvas/layer.rs b/wgpu/src/widget/canvas/layer.rs
deleted file mode 100644
index a46b7fb1..00000000
--- a/wgpu/src/widget/canvas/layer.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-//! Produce, store, and reuse geometry.
-mod cache;
-
-pub use cache::Cache;
-
-use crate::Primitive;
-use iced_native::Size;
-
-use std::sync::Arc;
-
-/// A layer that can be presented at a [`Canvas`].
-///
-/// [`Canvas`]: ../struct.Canvas.html
-pub trait Layer: std::fmt::Debug {
- /// Draws the [`Layer`] in the given bounds and produces a [`Primitive`] as
- /// a result.
- ///
- /// The [`Layer`] may choose to store the produced [`Primitive`] locally and
- /// only recompute it when the bounds change, its contents change, or is
- /// otherwise explicitly cleared by other means.
- ///
- /// [`Layer`]: trait.Layer.html
- /// [`Primitive`]: ../../../enum.Primitive.html
- fn draw(&self, bounds: Size) -> Arc<Primitive>;
-}
diff --git a/wgpu/src/widget/canvas/program.rs b/wgpu/src/widget/canvas/program.rs
deleted file mode 100644
index c65a078b..00000000
--- a/wgpu/src/widget/canvas/program.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-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,
- ) {
- }
-}
diff --git a/wgpu/src/widget/canvas/state.rs b/wgpu/src/widget/canvas/state.rs
new file mode 100644
index 00000000..8388f94d
--- /dev/null
+++ b/wgpu/src/widget/canvas/state.rs
@@ -0,0 +1,20 @@
+use crate::canvas::{Event, Geometry, Size};
+
+pub trait State {
+ fn update(&mut self, _event: Event, _bounds: Size) {}
+
+ fn draw(&self, bounds: Size) -> Vec<Geometry>;
+}
+
+impl<T> State for &mut T
+where
+ T: State,
+{
+ fn update(&mut self, event: Event, bounds: Size) {
+ T::update(self, event, bounds);
+ }
+
+ fn draw(&self, bounds: Size) -> Vec<Geometry> {
+ T::draw(self, bounds)
+ }
+}