use std::collections::HashMap; use tray_icon::{ menu::{IsMenuItem, Menu, MenuId, MenuItemKind, PredefinedMenuItem}, TrayIconBuilder, }; // The app winit thing can listen in on the same events // coming from the state machine to give feedback to the user // changing the icon, the alt texts, and the context menu // based on the last received event type Callback = Box Result<(), anyhow::Error> + 'static>; pub struct TrayIcon { icon: tray_icon::Icon, title: String, menu_items: HashMap, menu: Menu, tray_icon: Option, } #[allow(unused)] impl TrayIcon { pub fn new(icon: tray_icon::Icon, title: &str) -> Self { Self { icon, title: title.to_string(), menu_items: HashMap::new(), menu: Menu::new(), tray_icon: None, } } pub fn add_seperator(&mut self) -> Result<(), anyhow::Error> { self.menu.append(&PredefinedMenuItem::separator())?; Ok(()) } pub fn add_menu_item( &mut self, item: &dyn IsMenuItem, callback: F, ) -> Result where F: Fn(&MenuItemKind) -> Result<(), anyhow::Error> + 'static, { let id = item.id().clone(); self.menu.append(item)?; self.menu_items .insert(id.clone(), Box::new(callback) as Callback); Ok(id) } pub fn set_enabled(&self, id: &MenuId, enabled: bool) -> Result<(), anyhow::Error> { if let Some(item) = self.menu.items().iter().find(|i| i.id() == id) { if let Some(menuitem) = item.as_menuitem() { menuitem.set_enabled(enabled); } if let Some(menuitem) = item.as_check_menuitem() { menuitem.set_enabled(enabled); } if let Some(menuitem) = item.as_icon_menuitem() { menuitem.set_enabled(enabled); } if let Some(menuitem) = item.as_submenu() { menuitem.set_enabled(enabled); } } Ok(()) } pub fn set_text(&self, id: &MenuId, text: &str) -> Result<(), anyhow::Error> { if let Some(item) = self.menu.items().iter().find(|i| i.id() == id) { if let Some(menuitem) = item.as_menuitem() { menuitem.set_text(text); } if let Some(menuitem) = item.as_check_menuitem() { menuitem.set_text(text); } if let Some(menuitem) = item.as_icon_menuitem() { menuitem.set_text(text); } if let Some(menuitem) = item.as_predefined_menuitem() { menuitem.set_text(text); } if let Some(menuitem) = item.as_submenu() { menuitem.set_text(text); } } Ok(()) } pub fn handle(&self, id: &MenuId) { if let Some(item) = self.menu_items.get(id) { if let Some(i) = self.menu.items().iter().find(|i| i.id() == id) { if let Err(e) = item(i) { eprintln!("{:#?}", e); } } } } pub fn build(&mut self) -> Result<(), anyhow::Error> { self.tray_icon = Some( TrayIconBuilder::new() .with_tooltip(self.title.clone()) .with_menu(Box::new(self.menu.clone())) .with_icon(self.icon.clone()) .build()?, ); Ok(()) } }