1use std::{
2 collections::{HashMap, HashSet, VecDeque},
3 fmt,
4 mem::MaybeUninit,
5 vec,
6};
7
8use glow::HasContext;
9
10use crate::{
11 collections::{
12 fixed_stack::FixedStack,
13 flat_nary_tree::{LinearTree, NodeID, StackSignal},
14 },
15 text_writer::TextWriter,
16 math::{self, translate4, ComponentWriter, Mat4, MatStack, Vec2, Vec4, AABB2},
17 mem::force_borrow_mut,
18 ogl::{self, ArrayBuilder, Bindable, BufferPair, HasBufferBuilder, OglProg},
19 window::event_util::{EventKind, KeyCode},
20 FlufflState, GlowGL,
21};
22
23mod builder;
24mod components;
25mod gui_key;
26mod handler_block;
27mod renderer;
28
29pub use self::{builder::*, components::*, gui_key::*, handler_block::*, renderer::*};
30pub type ListenerCallBack<ProgramState> =
31 Box<dyn FnMut(EventListenerInfo<'_, ProgramState>) -> Option<()>>;
32
33type VisibilityStack = FixedStack<128, bool>;
34type LevelStack = FixedStack<128, i32>;
35type NodeStack = FixedStack<256, NodeID>;
36
37pub type GuiMutation<T> = Box<dyn FnMut(&T)>;
38
39pub struct MutationRequestQueue<ProgramState> {
40 queue: VecDeque<GuiMutation<ProgramState>>,
41}
42
43impl<ProgramState> Default for MutationRequestQueue<ProgramState> {
44 fn default() -> Self {
45 Self::new()
46 }
47}
48
49impl<ProgramState> MutationRequestQueue<ProgramState> {
50 pub fn new() -> Self {
51 Self {
52 queue: VecDeque::new(),
53 }
54 }
55 pub fn enqueue(&mut self, req: GuiMutation<ProgramState>) {
56 self.queue.push_back(req);
57 }
58 pub fn dequeue(&mut self) -> Option<GuiMutation<ProgramState>> {
59 self.queue.pop_front()
60 }
61 pub fn clear(&mut self) {
62 self.queue.clear()
63 }
64}
65
66pub struct GuiManager<ProgramState> {
67 gl: GlowGL,
68
69 renderer: GuiRenderer,
71
72 component_transform_stack: MatStack<f32>,
74
75 _clipboard: String,
77
78 focused_component: Option<GuiComponentKey>,
80
81 clicked_component: Option<GuiComponentKey>,
83
84 hover_component: Option<GuiComponentKey>,
86
87 gui_component_tree: LinearTree<Box<dyn GuiComponent>>,
89
90 key_to_aabb_table: HashMap<GuiComponentKey, AABB2<f32>>,
92
93 key_to_handler_block_table: HashMap<GuiComponentKey, ComponentHandlerBlock<ProgramState>>,
95
96 visibility_table: Vec<bool>,
98
99 visibility_intersection_stack: VisibilityStack,
101
102 component_signal_bus: VecDeque<components::ComponentEventSignal>,
103
104 key_down_table: HashSet<KeyCode>,
105
106 window_events: VecDeque<EventKind>,
107
108 mutation_queue: MutationRequestQueue<ProgramState>,
109}
110
111impl<ProgramState> GuiManager<ProgramState> {
112 pub fn new(gl: GlowGL) -> Self {
113 Self {
114 renderer: GuiRenderer::new(&gl),
115 focused_component: None,
116 clicked_component: None,
117 hover_component: None,
118 gui_component_tree: LinearTree::new(),
119 component_signal_bus: VecDeque::new(),
120 window_events: VecDeque::new(),
121 component_transform_stack: MatStack::new(),
122 key_to_aabb_table: HashMap::new(),
123 key_to_handler_block_table: HashMap::new(),
124 key_down_table: HashSet::new(),
125 visibility_table: Vec::new(),
126 visibility_intersection_stack: FixedStack::new(),
127 _clipboard: String::new(),
128 gl,
129 mutation_queue: MutationRequestQueue::new(),
130 }
131 }
132
133 pub fn clear_listeners(&mut self, key: GuiComponentKey, event: GuiEventKind) {
134 self.key_to_handler_block_table
135 .get_mut(&key)
136 .expect("key missing")
137 .clear_handlers(event);
138 }
139
140 pub fn push_listener(
141 &mut self,
142 key: GuiComponentKey,
143 listener: ComponentEventListener<ProgramState>,
144 ) {
145 let key_to_handler_block_table = &mut self.key_to_handler_block_table;
146 key_to_handler_block_table
147 .get_mut(&key)
148 .expect("key missing")
149 .push_handler(listener);
150 }
151
152 pub fn push_event(&mut self, event: EventKind) {
153 self.window_events.push_back(event);
154 }
155
156 pub fn render(&mut self, text_writer: &mut TextWriter, window_width: f32, window_height: f32) {
157 self.handle_incoming_events();
158
159 let mut level_stack = LevelStack::new();
160 let mut node_stack = NodeStack::new();
161
162 let gl = &mut self.gl;
163 let transform_stack = &mut self.component_transform_stack;
164
165 let renderer = &mut self.renderer;
166 let gui_component_tree = &mut self.gui_component_tree;
167 let visibility_table = &mut self.visibility_table;
168 let key_to_aabb_table = &mut self.key_to_aabb_table;
169
170 let compute_global_position = |rel_pos, stack: &MatStack<f32>| {
171 let s = stack;
172 let pos = Vec4::to_pos(rel_pos);
173 let &transform = s.peek();
174 transform * pos
175 };
176
177 let compute_current_level = |stack: &LevelStack, comp: &dyn GuiComponent| {
178 let parent_level = stack.peek();
179 if comp.flags().is_set(component_flags::OVERFLOWABLE) {
180 (-127, -126)
181 } else {
182 (parent_level, parent_level + 1)
183 }
184 };
185
186 unsafe {
187 gl.enable(glow::BLEND);
188 gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA);
189 }
190
191 let gui_component_tree_borrowed_by_force =
194 unsafe { crate::mem::force_borrow_mut(gui_component_tree) };
195
196 transform_stack.clear();
197 level_stack.clear_with_root_val(0);
198
199 for (sig, key, comp) in gui_component_tree.iter_mut_stack_signals() {
200 let &rel_pos = comp.rel_position();
201 let transform = translate4(Vec4::to_pos(rel_pos));
202
203 let (cur_level, gpos) = match sig {
205 StackSignal::Nop => {
206 transform_stack.pop();
207 node_stack.pop();
208 level_stack.pop();
209
210 let (cur_level, new_level) = compute_current_level(&level_stack, comp.as_ref());
211 let gpos = compute_global_position(rel_pos, transform_stack);
212
213 transform_stack.push(transform);
214 node_stack.push(key);
215 level_stack.push(new_level);
216
217 (cur_level, gpos)
218 }
219 StackSignal::Pop { n_times } => {
220 level_stack.pop_multi(n_times + 1);
225
226 for _ in 0..n_times + 1 {
227 let popped = Some(transform_stack.pop()).zip(node_stack.pop());
228 if let Some((global_frame, node)) = popped {
229 let global_position = global_frame * Vec4::from([0., 0., 0., 1.0]);
230 let visibility = visibility_table[node.as_usize()];
231 let tree =
232 unsafe { force_borrow_mut(gui_component_tree_borrowed_by_force) };
233 if visibility {
234 let state = RenderState::new(
235 key.into(),
236 global_position,
237 renderer,
238 transform_stack.len() as i32 - 1,
239 gui_component_tree_borrowed_by_force,
240 key_to_aabb_table,
241 window_width,
242 window_height,
243 );
244 tree.get_mut(node)
245 .unwrap()
246 .render_exit(gl, state, text_writer);
247 }
248 }
249 }
250
251 let (cur_level, new_level) = compute_current_level(&level_stack, comp.as_ref());
252 let gpos = compute_global_position(rel_pos, transform_stack);
253
254 transform_stack.push(transform);
255 node_stack.push(key);
256 level_stack.push(new_level);
257
258 (cur_level, gpos)
259 }
260 StackSignal::Push => {
261 let (cur_level, new_level) = compute_current_level(&level_stack, comp.as_ref());
262 let gpos = compute_global_position(rel_pos, transform_stack);
263
264 transform_stack.push(transform);
265 node_stack.push(key);
266 level_stack.push(new_level);
267 (cur_level, gpos)
268 }
269 };
270
271 if visibility_table[key.as_usize()] {
272 comp.render_entry(
273 gl,
274 RenderState::new(
275 key.into(),
276 gpos,
277 renderer,
278 cur_level,
279 gui_component_tree_borrowed_by_force,
280 key_to_aabb_table,
281 window_width,
282 window_height,
283 ),
284 text_writer,
285 );
286 }
287 }
288
289 unsafe {
290 gl.disable(glow::BLEND);
291 }
292 }
293}
294
295impl<ProgramState> GuiManager<ProgramState> {
296 unsafe fn add_component_deferred(
301 &mut self,
302 parent: GuiComponentKey,
303 mut comp: Option<Box<dyn GuiComponent>>,
304 ) -> GuiComponentKey {
305 let comp = comp
306 .take()
307 .map(MaybeUninit::new)
308 .unwrap_or(MaybeUninit::zeroed());
309
310 let id = self
311 .gui_component_tree
312 .add_deferred_reconstruction(comp, parent.into());
313 let key = GuiComponentKey::from(id);
314 self.key_to_handler_block_table
315 .insert(key, ComponentHandlerBlock::new());
316
317 if self.gui_component_tree.len() > self.visibility_table.len() {
319 self.visibility_table.push(false)
320 }
321
322 key
323 }
324
325 pub fn add_component(
326 &mut self,
327 parent: GuiComponentKey,
328 comp: Box<dyn GuiComponent>,
329 ) -> GuiComponentKey {
330 let id = self.gui_component_tree.add(comp, parent.into());
331 let key = GuiComponentKey::from(id);
332 self.key_to_handler_block_table
333 .insert(key, ComponentHandlerBlock::new());
334
335 if self.gui_component_tree.len() > self.visibility_table.len() {
337 self.visibility_table.push(false)
338 }
339
340 key
341 }
342
343 fn handle_incoming_events(&mut self) {
344 self.mutation_queue.clear();
345 self.recompute_visibility();
346 self.recompute_aabb_table();
347 self.queue_signals_to_bus();
348 self.process_signal_queue();
349 }
350
351 fn process_signal_queue(&mut self) {
352 let gui_component_tree = &mut self.gui_component_tree;
353 let component_signal_queue = &mut self.component_signal_bus;
354 let key_to_aabb_table = &mut self.key_to_aabb_table;
355 let key_to_handler_block_table = &mut self.key_to_handler_block_table;
356 let mutation_queue = &mut self.mutation_queue;
357
358 while let Some(signal) = component_signal_queue.pop_front() {
359 let key = signal.component_key;
360 let block = key_to_handler_block_table.get_mut(&key).unwrap();
361 let event = signal.window_event_kind;
362 let kind = signal.listener_kind;
363
364 block.fire_handler(
365 kind,
366 EventListenerInfo {
367 event,
368 key,
369 gui_comp_tree: gui_component_tree,
370 key_to_aabb_table,
371 mutation_queue,
372 },
373 );
374 }
375 }
376
377 fn queue_signals_to_bus(&mut self) {
378 let window_events = &mut self.window_events;
379 let key_to_aabb_table = &mut self.key_to_aabb_table;
380 let gui_component_tree = &mut self.gui_component_tree;
381 let focused_component = &mut self.focused_component;
382 let clicked_component = &mut self.clicked_component;
383 let hover_component = &mut self.hover_component;
384 let component_signal_bus = &mut self.component_signal_bus;
385 let key_down_table = &mut self.key_down_table;
386 let visibility_table = &mut self.visibility_table;
387 let visibility_intersection_stack = &mut self.visibility_intersection_stack;
388 let key_to_handler_block_table = &mut self.key_to_handler_block_table;
389
390 while let Some(event) = window_events.pop_front() {
391 let _old_signal_len = component_signal_bus.len();
392 match event {
393 EventKind::KeyDown { code } => {
394
395 if !key_down_table.contains(&code) {
408 if let &mut Some(fkey) = focused_component {
409 component_signal_bus.push_back(ComponentEventSignal::new(
410 GuiEventKind::OnKeyDown,
411 fkey,
412 event,
413 ));
414 }
415 key_down_table.insert(code);
416 }
417 }
418 EventKind::KeyUp { code } => {
419 if key_down_table.contains(&code) && focused_component.is_some() {
420 component_signal_bus.push_back(ComponentEventSignal::new(
421 GuiEventKind::OnKeyRelease,
422 focused_component.expect("focused key should exist"),
423 event,
424 ));
425 }
426 key_down_table.remove(&code);
427 }
428 EventKind::MouseUp { .. } => {
429 if let &mut Some(gui_comp_key) = clicked_component {
430 component_signal_bus.push_back(ComponentEventSignal::new(
431 GuiEventKind::OnMouseRelease,
432 gui_comp_key,
433 event,
434 ));
435 }
436
437 *clicked_component = None;
438 }
439 EventKind::MouseDown { x, y, .. } => {
440 let mouse_pos = Vec2::from([x as f32, y as f32]);
441 let prev_focused_component = *focused_component;
442
443 *clicked_component = None;
444 *focused_component = None;
445
446 Self::point_in_aabb_cumulative_intersections(
447 gui_component_tree,
448 key_to_aabb_table,
449 visibility_table,
450 visibility_intersection_stack,
451 mouse_pos,
452 |key| {
453 *clicked_component = Some(key);
454 *focused_component = Some(key);
455 },
456 );
457
458 match (prev_focused_component, *focused_component) {
460 (None, Some(cur_key)) => {
461 component_signal_bus.push_back(ComponentEventSignal::new(
462 GuiEventKind::OnFocusIn,
463 cur_key,
464 event,
465 ));
466 }
467 (Some(prev_key), None) => {
468 component_signal_bus.push_back(ComponentEventSignal::new(
469 GuiEventKind::OnFocusOut,
470 prev_key,
471 event,
472 ));
473 }
474 (Some(prev_key), Some(cur_key)) => {
475 if prev_key != cur_key {
476 component_signal_bus.push_back(ComponentEventSignal::new(
477 GuiEventKind::OnFocusOut,
478 prev_key,
479 event,
480 ));
481 component_signal_bus.push_back(ComponentEventSignal::new(
482 GuiEventKind::OnFocusIn,
483 cur_key,
484 event,
485 ));
486 }
487 }
488
489 (None, None) => {
490 }
492 }
493
494 if let &mut Some(clicked) = clicked_component {
495 component_signal_bus.push_back(ComponentEventSignal::new(
496 GuiEventKind::OnMouseDown,
497 clicked,
498 event,
499 ));
500 }
501 }
502 EventKind::MouseMove { x, y, dx, dy } => {
503 let mouse_pos = Vec2::from([x as f32, y as f32]);
504 let _disp = Vec2::from([dx as f32, dy as f32]);
505
506 if let &mut Some(hover_key) = hover_component {
507 if visibility_table[hover_key] {
508 component_signal_bus.push_back(ComponentEventSignal::new(
509 GuiEventKind::OnMouseMove,
510 hover_key,
511 event,
512 ));
513 }
514 }
515
516 if let &mut Some(clicked_key) = clicked_component {
517 if !visibility_table[clicked_key] && clicked_component.is_some() {
519 let clicked_key = clicked_component.expect("clicked should be valid");
520 component_signal_bus.push_back(ComponentEventSignal::new(
521 GuiEventKind::OnMouseRelease,
522 clicked_key,
523 event,
524 ));
525 *clicked_component = None;
526 }
527
528 Self::object_is_clicked_so_send_drag_signal_to_focused_component(
529 gui_component_tree,
530 component_signal_bus,
531 key_to_handler_block_table,
532 clicked_key,
533 event,
534 );
535 } else {
536 Self::check_for_hover_signal_and_send_if_found(
537 mouse_pos,
538 hover_component,
539 gui_component_tree,
540 key_to_aabb_table,
541 component_signal_bus,
542 visibility_table,
543 visibility_intersection_stack,
544 event,
545 );
546 }
547 }
548 EventKind::MouseWheel { .. } => {
549 if let &mut Some(focused_key) = focused_component {
550 component_signal_bus.push_back(ComponentEventSignal::new(
551 GuiEventKind::OnWheelWhileFocused,
552 focused_key,
553 event,
554 ));
555 }
556
557 if let &mut Some(hovered_key) = hover_component {
558 Self::push_signal_to_bus_and_bubble(
559 component_signal_bus,
560 gui_component_tree,
561 key_to_handler_block_table,
562 hovered_key,
563 GuiEventKind::OnWheelWhileHovered,
564 event,
565 );
566 }
567 }
568 _ => (),
569 }
570
571 Self::print_signals_queued_to_bus(component_signal_bus, _old_signal_len);
572 }
573 }
574
575 fn print_signals_queued_to_bus(
576 _component_signal_bus: &mut VecDeque<ComponentEventSignal>,
577 _old_signal_len: usize,
578 ) {
579 }
587
588 fn object_is_clicked_so_send_drag_signal_to_focused_component(
589 gui_component_tree: &LinearTree<Box<dyn GuiComponent>>,
590 component_signal_bus: &mut VecDeque<ComponentEventSignal>,
591 key_to_handler_block_table: &HashMap<GuiComponentKey, ComponentHandlerBlock<ProgramState>>,
592 clicked_component: GuiComponentKey,
593 event: EventKind,
594 ) {
595 Self::push_signal_to_bus_and_bubble(
596 component_signal_bus,
597 gui_component_tree,
598 key_to_handler_block_table,
599 clicked_component,
600 GuiEventKind::OnDrag,
601 event,
602 );
603 }
604
605 #[allow(clippy::too_many_arguments)]
606 fn check_for_hover_signal_and_send_if_found<'a>(
607 mouse_pos: Vec2<f32>,
608 hover_component: &mut Option<GuiComponentKey>,
609 gui_component_tree: &'a LinearTree<Box<dyn GuiComponent>>,
610 key_to_aabb_table: &'a HashMap<GuiComponentKey, AABB2<f32>>,
611 component_signal_bus: &mut VecDeque<ComponentEventSignal>,
612 visibility_table: &'a [bool],
613 visibility_intersection_stack: &'a mut FixedStack<128, bool>,
614 event: EventKind,
615 ) {
616 match hover_component {
617 &mut Some(current_hover_key) => {
619 let mut local_hover = None;
620
621 Self::point_in_aabb_cumulative_intersections(
622 gui_component_tree,
623 key_to_aabb_table,
624 visibility_table,
625 visibility_intersection_stack,
626 mouse_pos,
627 |key| {
628 local_hover = Some(key);
629 },
630 );
631
632 match local_hover {
633 Some(local_hover_key) => {
634 if local_hover_key != current_hover_key {
636 component_signal_bus.push_back(ComponentEventSignal::new(
637 GuiEventKind::OnHoverOut,
638 current_hover_key,
639 event,
640 ));
641 component_signal_bus.push_back(ComponentEventSignal::new(
642 GuiEventKind::OnHoverIn,
643 local_hover_key,
644 event,
645 ));
646 *hover_component = Some(local_hover_key);
647 }
648 }
649 None => {
651 component_signal_bus.push_back(ComponentEventSignal::new(
652 GuiEventKind::OnHoverOut,
653 current_hover_key,
654 event,
655 ));
656 *hover_component = None;
658 }
659 }
660 }
661 None => {
663 Self::point_in_aabb_cumulative_intersections(
665 gui_component_tree,
666 key_to_aabb_table,
667 visibility_table,
668 visibility_intersection_stack,
669 mouse_pos,
670 |key| {
671 *hover_component = Some(key);
672 },
673 );
674
675 if let &mut Some(key) = hover_component {
676 component_signal_bus.push_back(ComponentEventSignal::new(
677 GuiEventKind::OnHoverIn,
678 key,
679 event,
680 ));
681 }
682 }
683 }
684 }
685
686 fn recompute_visibility(&mut self) {
687 let gui_component_tree = &mut self.gui_component_tree;
688 let get_visibility = |id| gui_component_tree.get(id).map(|state| state.is_visible());
689 for node in gui_component_tree.iter() {
690 let mut cur_node_id = node.id;
691 self.visibility_table[cur_node_id.as_usize()] = get_visibility(node.id).unwrap();
692 while let Some(parent) = gui_component_tree.get_parent_id(cur_node_id) {
693 if !get_visibility(parent).unwrap() {
694 self.visibility_table[node.id.as_usize()] = false;
695 break;
696 }
697 cur_node_id = parent;
698 }
699 }
700 }
701
702 fn point_in_aabb_cumulative_intersections<'a, CB>(
703 gui_component_tree: &'a LinearTree<Box<dyn GuiComponent>>,
704 key_to_aabb_table: &'a HashMap<GuiComponentKey, AABB2<f32>>,
705 visibility_table: &'a [bool],
706 visibility_stack: &'a mut VisibilityStack,
707 mouse_pos: Vec2<f32>,
708 mut callback: CB,
709 ) where
710 CB: FnMut(GuiComponentKey),
711 {
712 visibility_stack.clear_with_root_val(true);
713
714 let node_iter = gui_component_tree
715 .iter_stack_signals()
716 .map(|(sig, id, c)| (sig, GuiComponentKey::from(id), c));
717
718 for (sig, key, component) in node_iter {
719 let &aabb = key_to_aabb_table.get(&key).unwrap();
720 let is_mouse_inside = aabb.is_point_inside(mouse_pos) || component.is_origin();
721 let is_overflowable = component.is_overflowable();
722
723 let calc_intersected_visibility =
724 |current_visibility| (current_visibility || is_overflowable) && is_mouse_inside;
725
726 let intersected_visibility = match sig {
727 StackSignal::Nop => {
728 visibility_stack.pop();
729 let current_visibility = visibility_stack.peek();
730 let intersected_visibility = calc_intersected_visibility(current_visibility);
731 visibility_stack.push(intersected_visibility);
732 intersected_visibility
733 }
734 StackSignal::Pop { n_times } => {
735 visibility_stack.pop_multi(n_times + 1);
736 let current_visibility = visibility_stack.peek();
737 let intersected_visibility = calc_intersected_visibility(current_visibility);
738 visibility_stack.push(intersected_visibility);
739 intersected_visibility
740 }
741 StackSignal::Push => {
742 let current_visibility = visibility_stack.peek();
743 let intersected_visibility = calc_intersected_visibility(current_visibility);
744 visibility_stack.push(intersected_visibility);
745 intersected_visibility
746 }
747 };
748
749 if intersected_visibility && visibility_table[key.as_usize()] {
750 callback(key);
751 }
752 }
753 }
754
755 fn recompute_aabb_table(&mut self) {
756 self.key_to_aabb_table.clear();
757 let key_to_aabb_table = unsafe { force_borrow_mut(&mut self.key_to_aabb_table) };
759
760 for (_, key, mat) in self.component_global_position_top_down() {
761 let aabb = {
762 let comp = self.gui_component_tree.get(key).unwrap();
763 let global_pos = mat * Vec4::from([0., 0., 0., 1.]);
764 comp.get_aabb(global_pos)
765 };
766 key_to_aabb_table.insert(key, aabb);
767 }
768 }
769
770 fn component_global_position_top_down(
771 &self,
772 ) -> impl Iterator<Item = (StackSignal, GuiComponentKey, Mat4<f32>)> + '_ {
773 let mut s = MatStack::new();
774 self.gui_component_tree
775 .iter_stack_signals()
776 .map(move |(sig, key, comp)| {
777 let &comp_pos = comp.rel_position();
778 let transform = translate4(Vec4::to_pos(comp_pos));
779 match sig {
780 StackSignal::Nop => {
781 s.pop();
782 s.push(transform);
783 }
784 StackSignal::Pop { n_times } => {
785 s.pop_multi(n_times + 1);
786 s.push(transform);
787 }
788 StackSignal::Push => {
789 s.push(transform);
790 }
791 }
792 (sig, GuiComponentKey::from(key), *s.peek())
793 })
794 }
795
796 fn push_signal_to_bus_and_bubble(
799 component_signal_bus: &mut VecDeque<ComponentEventSignal>,
800 gui_component_tree: &LinearTree<Box<dyn GuiComponent>>,
801 key_to_handler_block_table: &HashMap<GuiComponentKey, ComponentHandlerBlock<ProgramState>>,
802 key: GuiComponentKey,
803 sig_kind: GuiEventKind,
804 event: EventKind,
805 ) {
806 let current_node_has_listener = key_to_handler_block_table
807 .get(&key)
808 .and_then(|block| block.get(sig_kind as usize))
809 .map(|wheel_hovered_handlers| !wheel_hovered_handlers.is_empty())
810 .unwrap_or(false);
811
812 if current_node_has_listener {
813 component_signal_bus.push_back(ComponentEventSignal::new(sig_kind, key, event));
814 } else {
815 let parent_query = Self::find_ancestor_with_event_handler_kind(
816 key,
817 sig_kind,
818 gui_component_tree,
819 key_to_handler_block_table,
820 );
821 if let Some(parent) = parent_query {
822 component_signal_bus.push_back(ComponentEventSignal::new(sig_kind, parent, event));
823 }
824 }
825 }
826
827 fn find_ancestor_with_event_handler_kind(
828 root: GuiComponentKey,
829 target_event_kind: GuiEventKind,
830 gui_component_tree: &LinearTree<Box<dyn GuiComponent>>,
831 key_to_handler_block_table: &HashMap<GuiComponentKey, ComponentHandlerBlock<ProgramState>>,
832 ) -> Option<GuiComponentKey> {
833 let mut node = root;
834
835 while let Some(parent) = gui_component_tree.get_parent_id(node) {
836 let number_of_listeners_for_target_event = key_to_handler_block_table
837 .get(&parent.into())
838 .expect("listener block not found")
839 .get(target_event_kind as usize)
840 .expect("block not initalized")
841 .len();
842
843 if number_of_listeners_for_target_event > 0 {
844 return Some(parent.into());
845 }
846 node = parent.into();
847 }
848
849 None
850 }
851
852 pub fn poll_mutation_requsts(&mut self) -> Option<GuiMutation<ProgramState>> {
853 self.mutation_queue.dequeue()
854 }
855}
856
857impl<State> GuiManager<FlufflState<State>> {
858 pub fn execute_mutation_requests<CB>(state: &FlufflState<State>, mut get_request: CB)
866 where
867 CB: FnMut(&FlufflState<State>) -> Option<GuiMutation<FlufflState<State>>>,
868 {
869 while let Some(mut req) = get_request(state) {
870 req(state);
871 }
872 }
873}