2024-10-07 19:00:53 +00:00
|
|
|
use notan::draw::DrawConfig;
|
|
|
|
|
use notan::egui::{self, *};
|
|
|
|
|
use notan::prelude::*;
|
|
|
|
|
use tray_icon::menu::MenuEventReceiver;
|
|
|
|
|
use tray_icon::TrayIcon;
|
2024-10-07 17:48:28 +00:00
|
|
|
use tray_icon::{
|
2024-10-07 19:00:53 +00:00
|
|
|
menu::{Menu, MenuEvent, MenuItem, PredefinedMenuItem},
|
|
|
|
|
TrayIconBuilder,
|
2024-10-07 17:48:28 +00:00
|
|
|
};
|
|
|
|
|
|
2024-10-07 19:00:53 +00:00
|
|
|
#[derive(AppState)]
|
|
|
|
|
struct State {
|
|
|
|
|
tray_icon: Option<TrayIcon>,
|
|
|
|
|
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");
|
|
|
|
|
});
|
|
|
|
|
});
|
2024-10-07 17:48:28 +00:00
|
|
|
|
2024-10-07 19:00:53 +00:00
|
|
|
output.clear_color(Color::BLACK);
|
|
|
|
|
gfx.render(&output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn init(_gfx: &mut Graphics) -> State {
|
|
|
|
|
let path = concat!(env!("CARGO_MANIFEST_DIR"), "/icon.png");
|
2024-10-07 17:48:28 +00:00
|
|
|
|
|
|
|
|
let tray_menu = Menu::new();
|
|
|
|
|
|
|
|
|
|
let test = MenuItem::new("Test", true, None);
|
|
|
|
|
let quit_i = MenuItem::new("Quit", true, None);
|
2024-10-07 19:00:53 +00:00
|
|
|
tray_menu
|
|
|
|
|
.append_items(&[&test, &PredefinedMenuItem::separator(), &quit_i])
|
|
|
|
|
.unwrap();
|
|
|
|
|
let icon = load_icon(std::path::Path::new(path));
|
2024-10-07 17:48:28 +00:00
|
|
|
|
2024-10-07 19:00:53 +00:00
|
|
|
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,
|
|
|
|
|
}
|
2024-10-07 17:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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")
|
|
|
|
|
}
|