Event Loops
Extending the animated render loop and hiding the boilerplate:
extern crate buoyant;
extern crate embedded_graphics;
extern crate embedded_graphics_simulator;
use std::time::{Duration, Instant};
use buoyant::{
environment::DefaultEnvironment,
event::{EventContext, simulator::MouseTracker},
primitives::{Point, Size},
render::{AnimatedJoin, AnimationDomain, Render},
render_target::EmbeddedGraphicsRenderTarget,
view::prelude::*,
};
use embedded_graphics::{prelude::*, pixelcolor::Rgb888};
use embedded_graphics_simulator::{OutputSettings, SimulatorDisplay, Window};
fn main() {
let size = Size::new(200, 100);
let mut display: SimulatorDisplay<Rgb888> = SimulatorDisplay::new(size.into());
let mut target = EmbeddedGraphicsRenderTarget::new(&mut display);
let mut window = Window::new("Example", &OutputSettings::default());
let app_start = Instant::now();
let env = DefaultEnvironment::new(app_start.elapsed());
let mut count = 0;
// This derives higher-level mouse events from the raw simulator events
let mut mouse_tracker = MouseTracker::new();
let mut view = counter_view(count);
let mut state = view.build_state(&mut count);
let layout = view.layout(&size.into(), &env, &mut count, &mut state);
let mut source_tree = view.render_tree(
&layout,
Point::zero(),
&env,
&mut count,
&mut state,
);
let mut target_tree = view.render_tree(
&layout,
Point::zero(),
&env,
&mut count,
&mut state,
);
'running: loop {
target.display_mut().clear(Rgb888::BLACK).unwrap();
// Render...
Render::render_animated(
&mut target,
&source_tree,
&target_tree,
&Rgb888::WHITE,
&AnimationDomain::top_level(app_start.elapsed()),
);
// Flush to display...
window.update(target.display());
// Handle events
let context = EventContext::new(app_start.elapsed());
let mut should_recompute_view = false;
// This is missing a check for simulator exit events!
for event in window.events().filter_map(|event| mouse_tracker.process_event(event)) {
let result = view.handle_event( // <---- Event handling here!
&event,
&context,
&mut target_tree,
&mut count,
&mut state
);
should_recompute_view |= result.recompute_view;
}
if should_recompute_view {
// Construct view again with the updated state
// Create a new target tree
let time = app_start.elapsed();
target_tree.join_from(
&source_tree,
&AnimationDomain::top_level(time),
);
source_tree = target_tree;
view = counter_view(count);
let env = DefaultEnvironment::new(time);
let layout = view.layout(&size.into(), &env, &mut count, &mut state);
target_tree = view.render_tree(
&layout,
Point::zero(),
&env,
&mut count,
&mut state,
);
}
}
}
fn counter_view(count: i32) -> impl View<Rgb888, i32> {
Button::new(
|count: &mut i32| *count += 1,
move |_| {
Text::new_fmt::<48>(
format_args!("I've been tapped {count} times!"),
&embedded_graphics::mono_font::ascii::FONT_10X20,
)
.foreground_color(Rgb888::WHITE)
.padding(Edges::All, 10)
}
)
}