buoyant 0.6.1

SwiftUI-like UIs in Rust for embedded devices
Documentation
# Event Loops

Extending the animated render loop and hiding the boilerplate:

```rust,no_run
# 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)
        }
    )
}
```