Skip to main content

fret_runtime/menu/
model.rs

1use std::sync::Arc;
2
3use crate::{CommandId, WhenExpr};
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
8#[serde(rename_all = "snake_case")]
9pub enum MenuRole {
10    App,
11    File,
12    Edit,
13    View,
14    Window,
15    Help,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
19#[serde(rename_all = "snake_case")]
20pub enum SystemMenuType {
21    Services,
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25pub enum MenuItemToggleKind {
26    Checkbox,
27    Radio,
28}
29
30/// Optional checked/radio semantics for command-backed menu items.
31///
32/// This is intentionally data-only so OS menubars and in-window surfaces can share one
33/// source-of-truth for toggle state.
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
35pub struct MenuItemToggle {
36    pub kind: MenuItemToggleKind,
37    pub checked: bool,
38}
39
40/// A minimal, data-only menu model intended to power:
41/// - future menubar rendering,
42/// - context menus,
43/// - command palette “breadcrumbs”.
44///
45/// This keeps menu structures derived from commands (ADR 0023) and avoids duplicating enablement
46/// logic in widget code.
47#[derive(Debug, Clone, PartialEq, Eq)]
48pub struct MenuBar {
49    pub menus: Vec<Menu>,
50}
51
52#[derive(Debug, Clone, PartialEq, Eq)]
53pub struct Menu {
54    pub title: Arc<str>,
55    pub role: Option<MenuRole>,
56    /// Optional mnemonic/access key for Alt+Key activation on platforms that support it.
57    ///
58    /// This is intentionally separate from `title` so titles can remain localization-friendly
59    /// and so OS vs in-window surfaces can share one source of truth.
60    pub mnemonic: Option<char>,
61    pub items: Vec<MenuItem>,
62}
63
64#[derive(Debug, Clone, PartialEq, Eq)]
65pub enum MenuItem {
66    Command {
67        command: CommandId,
68        when: Option<WhenExpr>,
69        toggle: Option<MenuItemToggle>,
70    },
71    /// A non-interactive, disabled menu entry with a custom label.
72    ///
73    /// This is intended for placeholder and dynamic menu content where a `CommandId` is not
74    /// available (yet). Menu surfaces should render this as disabled text.
75    Label {
76        title: Arc<str>,
77    },
78    Separator,
79    Submenu {
80        title: Arc<str>,
81        when: Option<WhenExpr>,
82        items: Vec<MenuItem>,
83    },
84    /// A menu managed by the OS (e.g. the macOS Services menu).
85    ///
86    /// In-window menu surfaces should ignore or render a disabled placeholder for these entries.
87    SystemMenu {
88        title: Arc<str>,
89        menu_type: SystemMenuType,
90    },
91}
92
93impl MenuBar {
94    pub fn empty() -> Self {
95        Self { menus: Vec::new() }
96    }
97}