Skip to main content

ferroui_controls/flyouts/
menu_flyout_presenter.rs

1use crate::platform::{DefaultMenuInteractionHandler, IMenuInteractionHandler};
2use crate::primitives::{Popup, SelectingItemsControlImpl, TemplatedControlImpl};
3use crate::{ControlImpl, ItemsControlImpl, MenuBase, MenuBaseImpl, MenuItem};
4use ferroui_base::input::InputElementImpl;
5use ferroui_base::interactivity::InteractiveImpl;
6use ferroui_base::layout::LayoutableImpl;
7use ferroui_base::{
8    ferro_class, ferro_class_info, ferro_impl_classes, instantiate, FerroObjectImpl, Ref, StyledElement,
9    StyledElementImpl, VisualImpl, VisualImplExt, VisualTreeAttachmentEventArgs,
10};
11use std::rc::Rc;
12
13/// The control that hosts the items of a menu flyout.
14#[repr(C)]
15pub struct MenuFlyoutPresenter {
16    base: MenuBase,
17}
18
19ferro_class!(MenuFlyoutPresenter: MenuBase);
20ferro_class_info!(MenuFlyoutPresenter { new: MenuFlyoutPresenter::new });
21
22ferro_impl_classes!(
23    MenuFlyoutPresenter: FerroObjectImpl,
24    StyledElementImpl,
25    LayoutableImpl,
26    InteractiveImpl,
27    InputElementImpl,
28    ControlImpl,
29    TemplatedControlImpl,
30    ItemsControlImpl,
31    SelectingItemsControlImpl
32);
33
34impl VisualImpl for MenuFlyoutPresenter {
35    fn on_detached_from_visual_tree(this: &Self, e: &VisualTreeAttachmentEventArgs) {
36        Self::parent_on_detached_from_visual_tree(this, e);
37
38        let children = StyledElement::logical_children(this).to_vec();
39        for i in children {
40            if let Some(menu_item) = i.cast::<MenuItem>() {
41                menu_item.set_is_sub_menu_open(false);
42            }
43        }
44    }
45}
46
47impl MenuBaseImpl for MenuFlyoutPresenter {
48    fn close(this: &Self) {
49        // The default menu interaction handler calls this
50        let host = this.find_logical_ancestor_of_type::<Popup>(false);
51        if let Some(host) = host {
52            this.set_selected_index(-1);
53            host.set_is_open(false);
54        }
55    }
56
57    fn open(_this: &Self) {
58        panic!("Use MenuFlyout.ShowAt(Control) instead");
59    }
60}
61
62impl MenuFlyoutPresenter {
63    /// Creates the class data of a presenter that uses the default menu
64    /// interaction handler of context menus; see
65    /// [`ferroui_base::FerroObject::construct`].
66    pub fn construct() -> Self {
67        Self::construct_with(DefaultMenuInteractionHandler::new(true))
68    }
69
70    /// Creates the class data of a presenter that uses
71    /// `menu_interaction_handler`.
72    pub fn construct_with(menu_interaction_handler: Rc<dyn IMenuInteractionHandler>) -> Self {
73        Self { base: MenuBase::construct_with(menu_interaction_handler) }
74    }
75
76    /// Creates a menu flyout presenter.
77    pub fn new() -> Ref<Self> {
78        instantiate(Self::construct())
79    }
80
81    /// Creates a menu flyout presenter that uses `menu_interaction_handler`.
82    pub fn with_interaction_handler(menu_interaction_handler: Rc<dyn IMenuInteractionHandler>) -> Ref<Self> {
83        instantiate(Self::construct_with(menu_interaction_handler))
84    }
85}