use std::{
collections::hash_map::DefaultHasher,
fmt,
hash::{Hash, Hasher},
};
pub type MenuHash = u16;
pub type MenuId = String;
pub type MenuIdRef<'a> = &'a str;
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
#[derive(Debug, Clone)]
pub enum NativeImage {
Add,
Advanced,
Bluetooth,
Bookmarks,
Caution,
ColorPanel,
ColumnView,
Computer,
EnterFullScreen,
Everyone,
ExitFullScreen,
FlowView,
Folder,
FolderBurnable,
FolderSmart,
FollowLinkFreestanding,
FontPanel,
GoLeft,
GoRight,
Home,
IChatTheater,
IconView,
Info,
InvalidDataFreestanding,
LeftFacingTriangle,
ListView,
LockLocked,
LockUnlocked,
MenuMixedState,
MenuOnState,
MobileMe,
MultipleDocuments,
Network,
Path,
PreferencesGeneral,
QuickLook,
RefreshFreestanding,
Refresh,
Remove,
RevealFreestanding,
RightFacingTriangle,
Share,
Slideshow,
SmartBadge,
StatusAvailable,
StatusNone,
StatusPartiallyAvailable,
StatusUnavailable,
StopProgressFreestanding,
StopProgress,
TrashEmpty,
TrashFull,
User,
UserAccounts,
UserGroup,
UserGuest,
}
#[derive(Debug, Clone)]
pub enum MenuUpdate {
SetEnabled(bool),
SetTitle(String),
SetSelected(bool),
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
SetNativeImage(NativeImage),
}
pub trait TrayHandle: fmt::Debug {
fn set_icon(&self, icon: crate::Icon) -> crate::Result<()>;
fn update_item(&self, id: u16, update: MenuUpdate) -> crate::Result<()>;
#[cfg(target_os = "macos")]
fn set_icon_as_template(&self, is_template: bool) -> crate::Result<()>;
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct Menu {
pub items: Vec<MenuEntry>,
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct Submenu {
pub title: String,
pub enabled: bool,
pub inner: Menu,
}
impl Submenu {
pub fn new<S: Into<String>>(title: S, menu: Menu) -> Self {
Self {
title: title.into(),
enabled: true,
inner: menu,
}
}
}
impl Default for Menu {
fn default() -> Self {
Self { items: Vec::new() }
}
}
impl Menu {
pub fn new() -> Self {
Default::default()
}
pub fn add_item(mut self, item: CustomMenuItem) -> Self {
self.items.push(MenuEntry::CustomItem(item));
self
}
pub fn add_native_item(mut self, item: MenuItem) -> Self {
self.items.push(MenuEntry::NativeItem(item));
self
}
pub fn add_submenu(mut self, submenu: Submenu) -> Self {
self.items.push(MenuEntry::Submenu(submenu));
self
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct CustomMenuItem {
pub id: MenuHash,
pub id_str: MenuId,
pub title: String,
pub keyboard_accelerator: Option<String>,
pub enabled: bool,
pub selected: bool,
#[cfg(target_os = "macos")]
pub native_image: Option<NativeImage>,
}
impl CustomMenuItem {
pub fn new<I: Into<String>, T: Into<String>>(id: I, title: T) -> Self {
let id_str = id.into();
Self {
id: Self::hash(&id_str),
id_str,
title: title.into(),
keyboard_accelerator: None,
enabled: true,
selected: false,
#[cfg(target_os = "macos")]
native_image: None,
}
}
pub fn accelerator<T: Into<String>>(mut self, accelerator: T) -> Self {
self.keyboard_accelerator.replace(accelerator.into());
self
}
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
pub fn native_image(mut self, image: NativeImage) -> Self {
self.native_image.replace(image);
self
}
pub fn disabled(mut self) -> Self {
self.enabled = false;
self
}
pub fn selected(mut self) -> Self {
self.selected = true;
self
}
fn hash(id: &str) -> MenuHash {
let mut hasher = DefaultHasher::new();
id.hash(&mut hasher);
hasher.finish() as MenuHash
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct SystemTrayMenu {
pub items: Vec<SystemTrayMenuEntry>,
}
impl Default for SystemTrayMenu {
fn default() -> Self {
Self { items: Vec::new() }
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct SystemTraySubmenu {
pub title: String,
pub enabled: bool,
pub inner: SystemTrayMenu,
}
impl SystemTraySubmenu {
pub fn new<S: Into<String>>(title: S, menu: SystemTrayMenu) -> Self {
Self {
title: title.into(),
enabled: true,
inner: menu,
}
}
}
impl SystemTrayMenu {
pub fn new() -> Self {
Default::default()
}
pub fn add_item(mut self, item: CustomMenuItem) -> Self {
self.items.push(SystemTrayMenuEntry::CustomItem(item));
self
}
pub fn add_native_item(mut self, item: SystemTrayMenuItem) -> Self {
self.items.push(SystemTrayMenuEntry::NativeItem(item));
self
}
pub fn add_submenu(mut self, submenu: SystemTraySubmenu) -> Self {
self.items.push(SystemTrayMenuEntry::Submenu(submenu));
self
}
}
#[derive(Debug, Clone)]
pub enum SystemTrayMenuEntry {
CustomItem(CustomMenuItem),
NativeItem(SystemTrayMenuItem),
Submenu(SystemTraySubmenu),
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum SystemTrayMenuItem {
Separator,
}
#[derive(Debug, Clone)]
pub enum MenuEntry {
CustomItem(CustomMenuItem),
NativeItem(MenuItem),
Submenu(Submenu),
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum MenuItem {
About(String),
Hide,
Services,
HideOthers,
ShowAll,
CloseWindow,
Quit,
Copy,
Cut,
Undo,
Redo,
SelectAll,
Paste,
EnterFullScreen,
Minimize,
Zoom,
Separator,
}