fluffl/
gui.rs

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    /// lets us actually draw stuff
70    renderer: GuiRenderer,
71
72    /// used to compute global coordinates from scene-graph
73    component_transform_stack: MatStack<f32>,
74
75    /// used for cut+copy+paste
76    _clipboard: String,
77
78    ///component that is currently in "focus"
79    focused_component: Option<GuiComponentKey>,
80
81    ///component that is currently in "clicked"
82    clicked_component: Option<GuiComponentKey>,
83
84    ///component that the mouse is currently overlapping,but my not necessarily be in focus
85    hover_component: Option<GuiComponentKey>,
86
87    ///encodes the parent child relationship between nodes
88    gui_component_tree: LinearTree<Box<dyn GuiComponent>>,
89
90    /// maps a componentKey to its global AABB
91    key_to_aabb_table: HashMap<GuiComponentKey, AABB2<f32>>,
92
93    /// maps a componentKey to its event handlers
94    key_to_handler_block_table: HashMap<GuiComponentKey, ComponentHandlerBlock<ProgramState>>,
95
96    /// recomputed every Self::render(..), tells us if a component is visible (globally)
97    visibility_table: Vec<bool>,
98
99    /// used when doing visibility testing, uses this to compute cumulative intersections aabbs  
100    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        // forced a clone the gui_component_tree because it is actually very safe mutate
192        // there are very few ways in which this tree could invalidate keys
193        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            // println!("sig:{:?}",sig);
204            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                    // stack.pop_multi(n_times + 1);
221
222                    // i just said "fuck it" and popped all removable levels in one step
223                    // because don't care if level is accurate for render_exit(..)
224                    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    /// ## Description
297    /// allows you to generate a valid Key without providing a GuiComponent up-front
298    /// ## Comments
299    /// - **MUST CALL `LinearTree::recontruct_preorder(..)` or the tree WONT WORK**
300    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        //make sure that number of nodes allocated equals
318        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        //make sure that number of nodes allocated equals
336        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                    // // for debugging purposes 
396                    // if let KeyCode::BRACKET_R = code {
397                    //     let v = gui_component_tree
398                    //         .get_mut(GuiComponentKey(5))
399                    //         .unwrap()
400                    //         .is_visible();
401                    //     gui_component_tree
402                    //         .get_mut(GuiComponentKey(5))
403                    //         .unwrap()
404                    //         .set_visible(!v);
405                    // }
406
407                    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                    // handle focused events
459                    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                            // do nothing
491                        }
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                        //force release of component if its being clicked on while being invisible
518                        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        // prints the queued events that waiting to be sent to their handlers
580        // if _component_signal_bus.len() > _old_signal_len {
581        //     println!("signal added:");
582        //     for sig in &_component_signal_bus.make_contiguous()[_old_signal_len..] {
583        //         println!("{:?}", sig)
584        //     }
585        // }
586    }
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            // if something is being hovered check if mouse has left the component
618            &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                        //mouse has left the current component and has entered another component
635                        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                    //mouse has left the current component and is hovering over nothing
650                    None => {
651                        component_signal_bus.push_back(ComponentEventSignal::new(
652                            GuiEventKind::OnHoverOut,
653                            current_hover_key,
654                            event,
655                        ));
656                        //nothing is being hovered so set pointer to None
657                        *hover_component = None;
658                    }
659                }
660            }
661            //if nothing is being hovered check if mouse is inside hovering a component
662            None => {
663                //run through aabbs in pre-order traversal
664                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        //force a split borrow, safe because key_to_aabb_table is never mutated in the component_global_position_top_down(..) function
758        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    /// pushes the signal onto the bus headed for `key` but if `key` has no handler for `sig_kind`
797    /// it will redirect signal to an ancestor of `key`
798    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    /// ## Description
859    /// Certain event handlers may make requests to mutate `ProgramState` and this function
860    /// is responsible for executing those requests.
861    /// ## Comments
862    /// - Works be dequeing the `mutation_queue`
863    /// - `FluffleState<State>` is smartpointer with a read/write lock, so we need to access the mutation request
864    /// queue carefully. This pointer is expected to point to a memory location that owns a GuiManager `Self`.
865    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}