ashlar_native/menu/mod.rs
1//! A native menu bar described by a plain, serializable [`MenuSpec`].
2//!
3//! The model lives in [`ashlar_command::menu`] (one model for every renderer; `ashlar-ui` draws
4//! the same spec in the window). Its types are re-exported here so `ashlar_native::menu::MenuSpec`
5//! keeps working; new code may use either path.
6//!
7//! The app builds the spec from its state every frame (cheap: plain data), and
8//! [`NativeMenuBar::update`] turns it into the OS menu: it rebuilds only when
9//! [`MenuSpec::structure_hash`] changes (items added or removed, accelerators changed) and
10//! otherwise pushes label / enabled / checked changes in place, only when
11//! [`MenuSpec::state_hash`] changes. Activations arrive as item ids on a channel, with a
12//! [`crate::Waker`] call so an idle app wakes up.
13//!
14//! The spec has no OS or UI types, builds everywhere (the web uses an in-window menu bar drawn
15//! from the same spec) and is tested without creating real menus. The native bar exists on macOS
16//! (the app's menu bar) and Windows (a window's menu bar, see [`NativeMenuBar::attach_window`]);
17//! elsewhere [`NativeMenuBar::install`] returns `Unsupported`.
18
19mod accelerator;
20#[cfg(any(target_os = "macos", target_os = "windows"))]
21mod native;
22
23#[cfg(any(target_os = "macos", target_os = "windows"))]
24pub use accelerator::to_muda;
25#[allow(deprecated)]
26pub use accelerator::{Accelerator, Modifiers, menu_accelerator};
27pub use ashlar_command::menu::{Item, MAX_DEPTH, MAX_NODES, MAX_TEXT, MenuNode, MenuSpec, Path, Role, Submenu, SubmenuRole, menu_chord};
28#[cfg(any(target_os = "macos", target_os = "windows"))]
29pub use native::NativeMenuBar;
30
31#[cfg(not(any(target_os = "macos", target_os = "windows")))]
32use crate::{NativeError, Result};
33
34/// What [`NativeMenuBar::update`] did.
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum Update {
37 Unchanged,
38 /// Labels / enabled / checked state pushed in place.
39 Patched,
40 /// The native menus were rebuilt.
41 Rebuilt,
42}
43
44/// No native menu bar on this platform: every call reports `Unsupported` (draw the spec in the
45/// window instead).
46#[cfg(not(any(target_os = "macos", target_os = "windows")))]
47pub struct NativeMenuBar(());
48
49#[cfg(not(any(target_os = "macos", target_os = "windows")))]
50impl NativeMenuBar {
51 pub fn install(_spec: &MenuSpec, _waker: crate::Waker) -> Result<Self> {
52 Err(NativeError::Unsupported)
53 }
54 pub fn attach_window(&self, _window: &impl raw_window_handle::HasWindowHandle) -> Result<()> {
55 Err(NativeError::Unsupported)
56 }
57 pub fn update(&mut self, _spec: &MenuSpec) -> Result<Update> {
58 Err(NativeError::Unsupported)
59 }
60 pub fn try_recv(&self) -> Option<String> {
61 None
62 }
63 pub fn drain(&self) -> Vec<String> {
64 vec![]
65 }
66}