Skip to content

Latest commit

 

History

History
134 lines (105 loc) · 4.2 KB

drawing_with_caches.md

File metadata and controls

134 lines (105 loc) · 4.2 KB

Drawing With Caches

Previously, we mentioned that Program has the method draw that every time the corresponding Canvas needed to be re-drawn, the method is called. However, if the shapes of the Canvas remain unchanged, it is not performant to re-draw all these shapes. Instead, we store an image of these shapes in a Cache, and we draw this cache when the draw method of Program is called.

To do so, we declare a field of type Cache in our app

struct MyApp {
    cache: Cache,
}

and initialize it.

fn new() -> Self {
    Self {
        cache: Cache::new(),
    }
}

In the draw method, instead of creating a new Frame

let mut frame = Frame::new(renderer, bounds.size());
// ...
vec![frame.into_geometry()]

we use cache.draw to construct the Geometry.

let geometry = self.cache.draw(renderer, bounds.size(), |frame| {
    // ...
});

vec![geometry]

The closure |frame| { /* ... */ } is only called when the dimensions of the frame change or the cache is explicitly cleared.

In addition, previously, we implement Program for the struct MyProgram. But because we need to access the cache field of MyApp, we have to implement Program for MyApp.

The full code is as follows:

use iced::{
    mouse,
    widget::{
        canvas::{Cache, Geometry, Path, Program, Stroke},
        column, Canvas,
    },
    Alignment, Color, Length, Point, Rectangle, Renderer, Sandbox, Settings, Theme, Vector,
};

fn main() -> iced::Result {
    MyApp::run(Settings::default())
}

struct MyApp {
    cache: Cache,
}

impl Sandbox for MyApp {
    type Message = ();

    fn new() -> Self {
        Self {
            cache: Cache::new(),
        }
    }

    fn title(&self) -> String {
        String::from("My App")
    }

    fn update(&mut self, _message: Self::Message) {}

    fn view(&self) -> iced::Element<Self::Message> {
        column![
            "A Canvas",
            Canvas::new(self).width(Length::Fill).height(Length::Fill)
        ]
        .align_items(Alignment::Center)
        .into()
    }
}

impl<Message> Program<Message> for MyApp {
    type State = ();

    fn draw(
        &self,
        _state: &Self::State,
        renderer: &Renderer,
        _theme: &Theme,
        bounds: Rectangle,
        _cursor: mouse::Cursor,
    ) -> Vec<Geometry> {
        let geometry = self.cache.draw(renderer, bounds.size(), |frame| {
            frame.fill_rectangle(Point::ORIGIN, bounds.size(), Color::from_rgb(0.0, 0.2, 0.4));

            frame.fill(
                &Path::circle(frame.center(), frame.width().min(frame.height()) / 4.0),
                Color::from_rgb(0.6, 0.8, 1.0),
            );

            frame.stroke(
                &Path::line(
                    frame.center() + Vector::new(-250.0, 100.0),
                    frame.center() + Vector::new(250.0, -100.0),
                ),
                Stroke {
                    style: Color::WHITE.into(),
                    width: 50.0,
                    ..Default::default()
                },
            );
        });

        vec![geometry]
    }
}

Drawing With Caches

➡️ Next: Drawing Widgets

📘 Back: Table of contents