diff options
author | 2020-05-28 21:52:34 +0200 | |
---|---|---|
committer | 2020-05-28 21:52:34 +0200 | |
commit | d3db055583f4cbef1441fd66d07da70424bd1200 (patch) | |
tree | 9f695bd26f688a5aaf3b8fa687a0e3ff096ffe11 /graphics/src/widget/canvas/cache.rs | |
parent | ead4186870d1b46015986f702dd63382498060fc (diff) | |
parent | 709ed1f3f7ad8cf67a176763e394aaae4e808e93 (diff) | |
download | iced-d3db055583f4cbef1441fd66d07da70424bd1200.tar.gz iced-d3db055583f4cbef1441fd66d07da70424bd1200.tar.bz2 iced-d3db055583f4cbef1441fd66d07da70424bd1200.zip |
Merge pull request #354 from hecrj/feature/glow-renderer
OpenGL renderer and backend-agnostic graphics subcrate
Diffstat (limited to 'graphics/src/widget/canvas/cache.rs')
-rw-r--r-- | graphics/src/widget/canvas/cache.rs | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/graphics/src/widget/canvas/cache.rs b/graphics/src/widget/canvas/cache.rs new file mode 100644 index 00000000..4b28d164 --- /dev/null +++ b/graphics/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(), + } + } +} |