zng_view_api/
menu.rs

1//! Application system menu.
2
3use bitflags::bitflags;
4use zng_txt::Txt;
5
6use crate::image::ImageId;
7
8/// Represents a menu command or submenu header.
9#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
10#[non_exhaustive]
11pub enum MenuItem {
12    /// Clickable action.
13    #[non_exhaustive]
14    Command {
15        /// Unique ID for this command within all menu items in the app.
16        ///
17        /// If this id is empty the menu item is disabled.
18        id: Txt,
19        /// Display text.
20        label: Txt,
21    },
22    /// Submenu.
23    #[non_exhaustive]
24    SubMenu {
25        /// Display text.
26        label: Txt,
27        /// Children items.
28        children: Vec<MenuItem>,
29    },
30    /// Separation line.
31    Separator,
32}
33impl MenuItem {
34    /// New command.
35    pub fn command(id: impl Into<Txt>, label: impl Into<Txt>) -> Self {
36        Self::Command {
37            id: id.into(),
38            label: label.into(),
39        }
40    }
41
42    /// New submenu.
43    pub fn sub_menu(label: impl Into<Txt>, children: Vec<MenuItem>) -> Self {
44        Self::SubMenu {
45            label: label.into(),
46            children,
47        }
48    }
49}
50
51/// Represents a system application menu.
52#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
53#[non_exhaustive]
54pub struct AppMenu {
55    /// The menu items.
56    ///
57    /// If empty no application menu is set.
58    pub children: Vec<MenuItem>,
59}
60impl AppMenu {
61    /// New.
62    pub fn new(children: Vec<MenuItem>) -> Self {
63        Self { children }
64    }
65
66    /// Value that represents no app menu.
67    pub fn none() -> Self {
68        Self::new(vec![])
69    }
70}
71
72/// Represents a *tray icon* status indicator.
73#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
74#[non_exhaustive]
75pub struct TrayIcon {
76    /// Icon image.
77    ///
78    /// The tray icon will only be inserted when this image is valid and loaded.
79    pub icon: ImageId,
80    /// Optional context menu.
81    ///
82    /// If not empty a context menu shows on context clock.
83    pub context_menu: Vec<MenuItem>,
84    /// A command ID for a primary click on the icon.
85    ///
86    /// If set an [`Event::MenuCommand`] notifies on click, otherwise the context menu also opens on primary click.
87    ///
88    /// [`Event::MenuCommand`]: crate::types::Event::MenuCommand
89    pub primary_command_id: Txt,
90}
91impl TrayIcon {
92    /// New.
93    pub fn new(icon: ImageId, context_menu: Vec<MenuItem>) -> Self {
94        Self {
95            icon,
96            context_menu,
97            primary_command_id: Txt::from_static(""),
98        }
99    }
100
101    /// Value that indicates no tray icon.
102    pub fn none() -> Self {
103        Self::new(ImageId::INVALID, vec![])
104    }
105}
106
107bitflags! {
108    /// System menu capability.
109    #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
110    pub struct MenuCapability: u32 {
111        /// View-process can set application menu items.
112        ///
113        /// The application menu is shown outside the app windows, usually at the top of the main screen in macOS and Gnome desktops.
114        const APP_MENU = 1;
115        /// View-process can set tray icon with context menu.
116        ///
117        /// This is a small status indicator icon displayed near the notifications area.
118        const TRAY_ICON = 1 << 1;
119    }
120}