Skip to content

Commit d128d1b

Browse files
committed
Only draw once per frame
1 parent e51f2a8 commit d128d1b

File tree

2 files changed

+67
-30
lines changed

2 files changed

+67
-30
lines changed

backend-embedded-graphics/src/widgets/canvas.rs

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -135,60 +135,69 @@ where
135135
}
136136
}
137137

138-
pub struct Canvas<P, H: FnMut(InputContext, InputEvent) -> bool> {
138+
pub struct Canvas<P, H, D> {
139139
pub bounds: BoundingBox,
140140
pub parent_index: usize,
141141
pub canvas_properties: P,
142142
pub state: WidgetState,
143143
handler: Option<H>,
144+
on_draw: D,
145+
draw: bool,
144146
}
145147

146-
impl Canvas<(), fn(InputContext, InputEvent) -> bool> {
148+
impl Canvas<(), (), ()> {
147149
pub const STATE_SELECTED: Selected = Selected;
148150
pub const STATE_UNSELECTED: Unselected = Unselected;
149151
}
150152

151-
impl<P> Canvas<P, fn(InputContext, InputEvent) -> bool> {
152-
pub fn new() -> Canvas<P, fn(InputContext, InputEvent) -> bool>
153+
impl<P> Canvas<P, (), ()>
154+
where
155+
P: CanvasProperties,
156+
{
157+
pub fn new() -> Canvas<P, fn(InputContext, InputEvent) -> bool, fn(&mut Cropped<'_, P::Canvas>)>
153158
where
154159
P: Default,
155160
{
156-
Self {
161+
Canvas {
157162
parent_index: 0,
158163
bounds: BoundingBox::default(),
159164
canvas_properties: P::default(),
160165
state: WidgetState::default(),
161166
handler: None,
167+
on_draw: |_| {},
168+
draw: true,
162169
}
163170
}
164171

165-
pub fn with_properties(properties: P) -> Canvas<P, fn(InputContext, InputEvent) -> bool>
172+
pub fn with_properties(
173+
properties: P,
174+
) -> Canvas<P, fn(InputContext, InputEvent) -> bool, fn(&mut Cropped<'_, P::Canvas>)>
166175
where
167176
P: Default,
168177
{
169-
Self {
178+
Canvas {
170179
parent_index: 0,
171180
bounds: BoundingBox::default(),
172181
canvas_properties: properties,
173182
state: WidgetState::default(),
174183
handler: None,
184+
on_draw: |_| {},
185+
draw: true,
175186
}
176187
}
177188
}
178189

179-
impl<P, H> Canvas<P, H>
190+
impl<P, H, D> Canvas<P, H, D>
180191
where
192+
P: CanvasProperties,
181193
H: FnMut(InputContext, InputEvent) -> bool,
194+
D: FnMut(&mut Cropped<'_, P::Canvas>),
182195
{
183-
pub fn canvas(&mut self) -> Cropped<'_, P::Canvas>
184-
where
185-
P: CanvasProperties,
186-
{
187-
let bounds = self.bounding_box().to_rectangle();
188-
self.canvas_properties.canvas().cropped(&bounds)
196+
pub fn invalidate(&mut self) {
197+
self.draw = true;
189198
}
190199

191-
pub fn with_input_handler<H2>(self, handler: H2) -> Canvas<P, H2>
200+
pub fn with_input_handler<H2>(self, handler: H2) -> Canvas<P, H2, D>
192201
where
193202
H2: FnMut(InputContext, InputEvent) -> bool,
194203
{
@@ -198,21 +207,41 @@ where
198207
canvas_properties: self.canvas_properties,
199208
state: self.state,
200209
handler: Some(handler),
210+
on_draw: self.on_draw,
211+
draw: self.draw,
212+
}
213+
}
214+
215+
pub fn with_on_draw<D2>(self, on_draw: D2) -> Canvas<P, H, D2>
216+
where
217+
P: CanvasProperties,
218+
D2: FnMut(&mut Cropped<'_, P::Canvas>),
219+
{
220+
Canvas {
221+
parent_index: self.parent_index,
222+
bounds: self.bounds,
223+
canvas_properties: self.canvas_properties,
224+
state: self.state,
225+
handler: self.handler,
226+
on_draw,
227+
draw: self.draw,
201228
}
202229
}
203230
}
204231

205-
impl<P, H> WrapperBindable for Canvas<P, H>
232+
impl<P, H, D> WrapperBindable for Canvas<P, H, D>
206233
where
207234
P: CanvasProperties,
208235
H: FnMut(InputContext, InputEvent) -> bool,
236+
D: FnMut(&mut Cropped<'_, P::Canvas>),
209237
{
210238
}
211239

212-
impl<P, H> Widget for Canvas<P, H>
240+
impl<P, H, D> Widget for Canvas<P, H, D>
213241
where
214242
P: CanvasProperties,
215243
H: FnMut(InputContext, InputEvent) -> bool,
244+
D: FnMut(&mut Cropped<'_, P::Canvas>),
216245
{
217246
fn bounding_box(&self) -> BoundingBox {
218247
self.bounds
@@ -309,14 +338,26 @@ where
309338
}
310339
}
311340

312-
impl<C, DT, P, H> WidgetRenderer<EgCanvas<DT>> for Canvas<P, H>
341+
impl<C, DT, P, H, D> WidgetRenderer<EgCanvas<DT>> for Canvas<P, H, D>
313342
where
314343
C: PixelColor,
315344
DT: DrawTarget<Color = C>,
316345
P: CanvasProperties<Color = C>,
317346
H: FnMut(InputContext, InputEvent) -> bool,
347+
D: FnMut(&mut Cropped<'_, P::Canvas>),
318348
{
319349
fn draw(&mut self, canvas: &mut EgCanvas<DT>) -> Result<(), DT::Error> {
350+
if self.draw {
351+
self.draw = false;
352+
let bounds = self.bounding_box().to_rectangle();
353+
let clear_color = self.canvas_properties.clear_color();
354+
let mut canvas = self.canvas_properties.canvas().cropped(&bounds);
355+
356+
_ = canvas.clear(clear_color);
357+
358+
(self.on_draw)(&mut canvas);
359+
}
360+
320361
let bounds = self.bounding_box().to_rectangle();
321362
self.canvas_properties
322363
.canvas()

examples/canvas.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::{thread, time::Duration};
22

33
use backend_embedded_graphics::{
44
themes::{default::DefaultTheme, Theme},
5-
widgets::canvas::{Canvas, CanvasProperties, CanvasStyle},
5+
widgets::canvas::{Canvas, CanvasStyle},
66
EgCanvas,
77
};
88
use embedded_graphics::{
@@ -201,14 +201,8 @@ fn main() {
201201
});
202202
true
203203
})
204-
.bind(&state)
205-
.on_data_changed(|widget, state| {
206-
let clear_color = widget.canvas_properties.clear_color();
207-
let mut canvas = widget.canvas();
208-
209-
canvas.clear(clear_color).unwrap();
210-
211-
let t = state.time % 100;
204+
.with_on_draw(|canvas| {
205+
let t = state.with_data(|state| state.time % 100);
212206

213207
let increment = if t < 50 { t } else { 50 - (t - 50) };
214208

@@ -220,13 +214,15 @@ fn main() {
220214
},
221215
)
222216
.into_styled(PrimitiveStyle::with_stroke(Rgb888::BLUE, 1));
223-
rectangle.draw(&mut canvas).unwrap();
217+
rectangle.draw(canvas).unwrap();
224218

225219
let circle =
226220
Circle::with_center(canvas.bounding_box().center(), 40 + increment)
227221
.into_styled(PrimitiveStyle::with_stroke(Rgb888::RED, 1));
228-
circle.draw(&mut canvas).unwrap();
229-
}),
222+
circle.draw(canvas).unwrap();
223+
})
224+
.bind(&state)
225+
.on_data_changed(|widget, _| widget.invalidate()),
230226
)))
231227
.add_layer(
232228
DefaultTheme::primary_button("Animate")

0 commit comments

Comments
 (0)