summaryrefslogtreecommitdiffstats
path: root/graphics/src/widget/canvas/cache.rs
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón <hector0193@gmail.com>2020-05-28 21:52:34 +0200
committerLibravatar GitHub <noreply@github.com>2020-05-28 21:52:34 +0200
commitd3db055583f4cbef1441fd66d07da70424bd1200 (patch)
tree9f695bd26f688a5aaf3b8fa687a0e3ff096ffe11 /graphics/src/widget/canvas/cache.rs
parentead4186870d1b46015986f702dd63382498060fc (diff)
parent709ed1f3f7ad8cf67a176763e394aaae4e808e93 (diff)
downloadiced-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.rs108
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(),
+ }
+ }
+}