freya_components/
context_menu.rs

1use freya_core::{
2    integration::ScopeId,
3    prelude::*,
4};
5use torin::prelude::CursorPoint;
6
7use crate::menu::Menu;
8
9/// Context for managing a global context menu.
10///
11/// # Example
12///
13/// ```rust
14/// # use freya::prelude::*;
15/// fn app() -> impl IntoElement {
16///     let mut show_menu = use_state(|| false);
17///
18///     rect()
19///         .on_secondary_press(move |_| {
20///             ContextMenu::open(Menu::new().child(MenuButton::new().child("Option 1")));
21///             show_menu.set(true);
22///         })
23///         .child("Right click to open menu")
24/// }
25/// ```
26#[derive(Clone, Copy, PartialEq)]
27pub struct ContextMenu {
28    pub(crate) location: State<CursorPoint>,
29    pub(crate) menu: State<Option<(CursorPoint, Menu)>>,
30}
31
32impl ContextMenu {
33    pub fn get() -> Self {
34        match try_consume_root_context() {
35            Some(rt) => rt,
36            None => {
37                let context_menu_state = ContextMenu {
38                    location: State::create_in_scope(CursorPoint::default(), ScopeId::ROOT),
39                    menu: State::create_in_scope(None, ScopeId::ROOT),
40                };
41                provide_context_for_scope_id(context_menu_state, ScopeId::ROOT);
42                context_menu_state
43            }
44        }
45    }
46
47    pub fn is_open() -> bool {
48        Self::get().menu.read().is_some()
49    }
50
51    pub fn open(menu: Menu) {
52        let mut this = Self::get();
53        this.menu.set(Some(((this.location)(), menu)));
54    }
55
56    pub fn close() {
57        Self::get().menu.set(None);
58    }
59}