Skip to main content

ferroui_controls/primitives/
popup_overlay_layer.rs

1use super::VisualLayerManager;
2use crate::{Canvas, CanvasImpl, ControlImpl, PanelImpl, TopLevel};
3use ferroui_base::input::InputElementImpl;
4use ferroui_base::interactivity::InteractiveImpl;
5use ferroui_base::layout::{LayoutableImpl, LayoutableImplExt};
6use ferroui_base::{
7    ferro_class, ferro_impl_classes, instantiate, FerroObjectImpl, Ref, Size, StyledElementImpl, Visual, VisualImpl,
8};
9use std::cell::Cell;
10
11/// The surface that hosts the popups shown inside their top-level (internal
12/// upstream).
13#[repr(C)]
14pub struct PopupOverlayLayer {
15    base: Canvas,
16    available_size: Cell<Size>,
17}
18
19ferro_class!(PopupOverlayLayer: Canvas);
20ferroui_base::ferro_class_info!(PopupOverlayLayer { new: PopupOverlayLayer::new });
21ferro_impl_classes!(
22    PopupOverlayLayer: FerroObjectImpl,
23    StyledElementImpl,
24    InteractiveImpl,
25    InputElementImpl,
26    ControlImpl,
27    PanelImpl,
28    CanvasImpl
29);
30
31impl VisualImpl for PopupOverlayLayer {
32    fn bypass_flow_direction_policies(_this: &Self) -> bool {
33        true
34    }
35}
36
37impl LayoutableImpl for PopupOverlayLayer {
38    fn measure_override(this: &Self, available_size: Size) -> Size {
39        for child in this.children().snapshot().iter() {
40            child.measure(available_size);
41        }
42        available_size
43    }
44
45    fn arrange_override(this: &Self, final_size: Size) -> Size {
46        // We are saving it here since child controls might need to know the entire size of the overlay
47        // and Bounds won't be updated in time
48        this.available_size.set(final_size);
49        Self::parent_arrange_override(this, final_size)
50    }
51}
52
53impl PopupOverlayLayer {
54    pub fn new() -> Ref<Self> {
55        instantiate(Self { base: Canvas::construct(), available_size: Cell::new(Size::default()) })
56    }
57
58    /// The size the layer was last arranged with.
59    pub fn available_size(&self) -> Size {
60        self.available_size.get()
61    }
62
63    /// Retrieves the popup overlay layer associated with the specified
64    /// visual, if any.
65    pub fn get_popup_overlay_layer(visual: &Visual) -> Option<Ref<PopupOverlayLayer>> {
66        for v in visual.get_self_and_visual_ancestors() {
67            if let Some(layer) = v.cast::<VisualLayerManager>().and_then(|manager| manager.popup_overlay_layer()) {
68                return Some(layer);
69            }
70        }
71
72        if let Some(tl) = TopLevel::get_top_level(Some(visual)) {
73            let layers = tl.get_visual_descendants().find_map(|v| v.cast::<VisualLayerManager>());
74            return layers.and_then(|layers| layers.popup_overlay_layer());
75        }
76
77        None
78    }
79}