Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
crates/strato-ui-core/src/elements/container_test.rs
StratoSDK / crates / strato-ui-core / src / elements / container_test.rs
1use super::*;
2use crate::{
3 elements::{ConstrainedBox, DispatchEventResult, EventHandler, Rect, ZIndex},
4 platform::WindowStyle,
5 App, AppContext, Entity, Event, Presenter, TypedActionView, ViewContext, WindowInvalidation,
6};
7use pathfinder_geometry::vector::vec2f;
8use std::{
9 cell::RefCell,
10 collections::{HashMap, HashSet},
11 rc::Rc,
12};
13 
14#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
15enum ElementIdentifier {
16 BottomContainer,
17}
18 
19#[derive(Default)]
20struct View {
21 // Maps identifier to number of mouse down events
22 mouse_downs: HashMap<ElementIdentifier, usize>,
23}
24 
25fn init(app: &mut AppContext) {
26 app.add_action("container_test:mouse_down", View::mouse_down);
27}
28 
29impl View {
30 fn mouse_down(&mut self, identifier: &ElementIdentifier, _: &mut ViewContext<Self>) -> bool {
31 log::info!("Recording mouse_down on element {identifier:?}");
32 let entry = self.mouse_downs.entry(*identifier).or_insert(0);
33 *entry += 1;
34 true
35 }
36}
37 
38impl Entity for View {
39 type Event = ();
40}
41 
42impl crate::core::View for View {
43 fn ui_name() -> &'static str {
44 "container_test_view"
45 }
46 
47 fn render(&self, _: &AppContext) -> Box<dyn Element> {
48 Container::new(
49 EventHandler::new(
50 ConstrainedBox::new(Rect::new().finish())
51 .with_height(100.)
52 .with_width(100.)
53 .finish(),
54 )
55 .on_left_mouse_down(|evt, _, _| {
56 evt.dispatch_action(
57 "container_test:mouse_down",
58 ElementIdentifier::BottomContainer,
59 );
60 DispatchEventResult::StopPropagation
61 })
62 .finish(),
63 )
64 .with_foreground_overlay(Fill::Solid(ColorU::white()))
65 .finish()
66 }
67}
68 
69impl TypedActionView for View {
70 type Action = ();
71}
72 
73#[test]
74fn test_container_element_overlay_click_handling() {
75 App::test((), |mut app| async move {
76 let app = &mut app;
77 app.update(init);
78 let (window_id, view) = app.add_window(WindowStyle::NotStealFocus, |_| View::default());
79 
80 let mut presenter = Presenter::new(window_id);
81 
82 let mut updated = HashSet::new();
83 updated.insert(app.root_view_id(window_id).unwrap());
84 let invalidation = WindowInvalidation {
85 updated,
86 ..Default::default()
87 };
88 
89 app.update(move |ctx| {
90 presenter.invalidate(invalidation, ctx);
91 let scene = presenter.build_scene(vec2f(100., 100.), 1., None, ctx);
92 assert_eq!(scene.z_index(), ZIndex::new(0));
93 assert_eq!(scene.layer_count(), 2);
94 let presenter = Rc::new(RefCell::new(presenter));
95 
96 ctx.simulate_window_event(
97 Event::LeftMouseDown {
98 position: vec2f(50., 50.),
99 modifiers: Default::default(),
100 click_count: 1,
101 is_first_mouse: false,
102 },
103 window_id,
104 presenter,
105 );
106 });
107 
108 view.read(app, |view, _| {
109 assert_eq!(
110 1,
111 *view
112 .mouse_downs
113 .get(&ElementIdentifier::BottomContainer)
114 .unwrap()
115 );
116 });
117 });
118}
119