diff options
author | 2020-05-05 00:05:47 +0200 | |
---|---|---|
committer | 2020-05-05 00:05:47 +0200 | |
commit | 7dc02a5e16a3143b7c3ba9270207e3ebda71d567 (patch) | |
tree | dd727f138641fbda008af8e7827369cc99420749 /wgpu/src/widget/canvas/cache.rs | |
parent | 27aad74a32fd8ac2b12f9d32df8a3b61a3175457 (diff) | |
parent | 93c6be5eef577f0778b5787dac37351c035ed471 (diff) | |
download | iced-7dc02a5e16a3143b7c3ba9270207e3ebda71d567.tar.gz iced-7dc02a5e16a3143b7c3ba9270207e3ebda71d567.tar.bz2 iced-7dc02a5e16a3143b7c3ba9270207e3ebda71d567.zip |
Merge pull request #325 from hecrj/feature/canvas-interaction
Canvas interactivity and Game of Life example
Diffstat (limited to 'wgpu/src/widget/canvas/cache.rs')
-rw-r--r-- | wgpu/src/widget/canvas/cache.rs | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/wgpu/src/widget/canvas/cache.rs b/wgpu/src/widget/canvas/cache.rs new file mode 100644 index 00000000..4b28d164 --- /dev/null +++ b/wgpu/src/widget/canvas/cache.rs @@ -0,0 +1,108 @@ +use crate::{ + canvas::{Frame, Geometry}, + Primitive, +}; + +use iced_native::Size; +use std::{cell::RefCell, sync::Arc}; + +enum State { + Empty, + Filled { + bounds: Size, + primitive: Arc<Primitive>, + }, +} + +impl Default for State { + fn default() -> Self { + State::Empty + } +} +/// A simple cache that stores generated [`Geometry`] to avoid recomputation. +/// +/// A [`Cache`] will not redraw its geometry unless the dimensions of its layer +/// change or it is explicitly cleared. +/// +/// [`Layer`]: ../trait.Layer.html +/// [`Cache`]: struct.Cache.html +/// [`Geometry`]: struct.Geometry.html +#[derive(Debug, Default)] +pub struct Cache { + state: RefCell<State>, +} + +impl Cache { + /// Creates a new empty [`Cache`]. + /// + /// [`Cache`]: struct.Cache.html + pub fn new() -> Self { + Cache { + state: Default::default(), + } + } + + /// Clears the [`Cache`], forcing a redraw the next time it is used. + /// + /// [`Cache`]: struct.Cache.html + pub fn clear(&mut self) { + *self.state.borrow_mut() = State::Empty; + } + + /// Draws [`Geometry`] using the provided closure and stores it in the + /// [`Cache`]. + /// + /// The closure will only be called when + /// - the bounds have changed since the previous draw call. + /// - the [`Cache`] is empty or has been explicitly cleared. + /// + /// Otherwise, the previously stored [`Geometry`] will be returned. The + /// [`Cache`] is not cleared in this case. In other words, it will keep + /// returning the stored [`Geometry`] if needed. + /// + /// [`Cache`]: struct.Cache.html + pub fn draw(&self, bounds: Size, draw_fn: impl Fn(&mut Frame)) -> Geometry { + use std::ops::Deref; + + if let State::Filled { + bounds: cached_bounds, + primitive, + } = self.state.borrow().deref() + { + if *cached_bounds == bounds { + return Geometry::from_primitive(Primitive::Cached { + cache: primitive.clone(), + }); + } + } + + let mut frame = Frame::new(bounds); + draw_fn(&mut frame); + + let primitive = { + let geometry = frame.into_geometry(); + + Arc::new(geometry.into_primitive()) + }; + + *self.state.borrow_mut() = State::Filled { + bounds, + primitive: primitive.clone(), + }; + + Geometry::from_primitive(Primitive::Cached { cache: primitive }) + } +} + +impl std::fmt::Debug for State { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + State::Empty => write!(f, "Empty"), + State::Filled { primitive, bounds } => f + .debug_struct("Filled") + .field("primitive", primitive) + .field("bounds", bounds) + .finish(), + } + } +} |