| 1 | //! Canvas drawings kept between frames. |
| 2 | //! |
| 3 | //! The CPU renderer takes a canvas drawn afresh as changed on every frame, shape by shape, and |
| 4 | //! repaints each shape's patch of the window on its own: with a few dozen icons and dots on a |
| 5 | //! page, one hovered row repaints the window dozens of times over. A kept drawing stays the same |
| 6 | //! drawing until what it shows changes, so only what really changed is painted again. |
| 7 | |
| 8 | use std::cell::Cell; |
| 9 | |
| 10 | use iced::widget::canvas::{Cache, Frame, Geometry}; |
| 11 | use iced::{Renderer, Size}; |
| 12 | |
| 13 | /// A canvas's drawing of `K` (what it shows: its colors and values), drawn again only when `K` |
| 14 | /// or the canvas's size changes. It lives in the canvas's state, so it outlasts the view. |
| 15 | pub struct Kept<K> { |
| 16 | cache: Cache, |
| 17 | shows: Cell<Option<K>>, |
| 18 | } |
| 19 | |
| 20 | impl<K> Default for Kept<K> { |
| 21 | fn default() -> Self { |
| 22 | Kept { |
| 23 | cache: Cache::new(), |
| 24 | shows: Cell::new(None), |
| 25 | } |
| 26 | } |
| 27 | } |
| 28 | |
| 29 | impl<K: Copy + PartialEq> Kept<K> { |
| 30 | /// The drawing of `shows`, `size` large: the kept one, or a new one made by `draw`. |
| 31 | pub fn draw(&self, renderer: &Renderer, size: Size, shows: K, draw: impl FnOnce(&mut Frame)) -> Geometry { |
| 32 | if self.shows.get() != Some(shows) { |
| 33 | self.cache.clear(); |
| 34 | self.shows.set(Some(shows)); |
| 35 | } |
| 36 | self.cache.draw(renderer, size, draw) |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | #[cfg(test)] |
| 41 | mod tests { |
| 42 | use super::*; |
| 43 | use iced::{Font, Pixels}; |
| 44 | |
| 45 | #[test] |
| 46 | fn draws_again_only_when_what_it_shows_changes() { |
| 47 | let renderer = Renderer::new(Font::DEFAULT, Pixels(16.0)); |
| 48 | let kept = Kept::default(); |
| 49 | let small = Size::new(10.0, 10.0); |
| 50 | let mut drawn = 0; |
| 51 | for (size, shows) in [ |
| 52 | (small, 1), |
| 53 | (small, 1), |
| 54 | (small, 2), |
| 55 | (small, 2), |
| 56 | (Size::new(20.0, 10.0), 2), |
| 57 | ] { |
| 58 | let _ = kept.draw(&renderer, size, shows, |_| drawn += 1); |
| 59 | } |
| 60 | assert_eq!(drawn, 3, "drawn for 1, for 2, and for 2 at the new size"); |
| 61 | } |
| 62 | } |