use notan::draw::DrawConfig; use notan::egui::{self, *}; use notan::prelude::*; use tray_icon::menu::MenuEventReceiver; use tray_icon::TrayIcon; use tray_icon::{ menu::{Menu, MenuEvent, MenuItem, PredefinedMenuItem}, TrayIconBuilder, }; #[derive(AppState)] struct State { tray_icon: Option, quit_i: MenuItem, menu_channel: MenuEventReceiver, } #[notan_main] fn main() -> Result<(), String> { let win = WindowConfig::new() .set_vsync(true) .set_lazy_loop(true) .set_high_dpi(true); notan::init_with(init) .add_config(win) .add_config(EguiConfig) .add_config(DrawConfig) .update(update) .draw(draw) .build() } fn update(app: &mut App, state: &mut State) { if let Ok(event) = state.menu_channel.try_recv() { if event.id == state.quit_i.id() { state.tray_icon.take(); app.exit(); } println!("{event:?}"); } } fn draw(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins) { let mut output = plugins.egui(|ctx| { egui::SidePanel::left("side_panel").show(ctx, |ui| { ui.heading("Egui Plugin Example"); ui.separator(); if ui.button("Quit").clicked() { app.exit(); } ui.separator(); ui.label("Welcome to a basic example of how to use Egui with notan."); ui.separator(); ui.label("Check the source code to learn more about how it works"); }); }); output.clear_color(Color::BLACK); gfx.render(&output); } fn init(_gfx: &mut Graphics) -> State { let path = concat!(env!("CARGO_MANIFEST_DIR"), "/icon.png"); let tray_menu = Menu::new(); let test = MenuItem::new("Test", true, None); let quit_i = MenuItem::new("Quit", true, None); tray_menu .append_items(&[&test, &PredefinedMenuItem::separator(), &quit_i]) .unwrap(); let icon = load_icon(std::path::Path::new(path)); let tray_icon = Some( TrayIconBuilder::new() .with_menu(Box::new(tray_menu.clone())) .with_tooltip("Workspace") .with_icon(icon) .build() .unwrap(), ); let menu_channel = MenuEvent::receiver().clone(); State { menu_channel, tray_icon, quit_i, } } fn load_icon(path: &std::path::Path) -> tray_icon::Icon { let (icon_rgba, icon_width, icon_height) = { let image = image::open(path) .expect("Failed to open icon path") .into_rgba8(); let (width, height) = image.dimensions(); let rgba = image.into_raw(); (rgba, width, height) }; tray_icon::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon") }