Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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)
        }
    )
}