Skip to content

Menu Utilities for Desktop Applications in Rust.

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

tauri-apps/muda

Repository files navigation

muda

Menu Utilities library for Desktop Applications.

Documentation

Platforms supported:

  • Windows
  • macOS
  • Linux (gtk Only)

Platform-specific notes:

Cargo Features

  • common-controls-v6: Use TaskDialogIndirect API from ComCtl32.dll v6 on Windows for showing the predefined About menu item dialog.
  • libxdo: Enables linking to libxdo on Linux which is used for the predfined Copy, Cut, Paste and SelectAll menu item.
  • serde: Enables de/serializing the dpi types.

Dependencies (Linux Only)

gtk is used for menus and libxdo is used to make the predfined Copy, Cut, Paste and SelectAll menu items work. Be sure to install following packages before building:

Arch Linux / Manjaro:

pacman -S gtk3 xdotool

Debian / Ubuntu:

sudo apt install libgtk-3-dev libxdo-dev

Example

Create the menu and add your items

let menu = Menu::new();
let menu_item2 = MenuItem::new("Menu item #2", false, None);
let submenu = Submenu::with_items("Submenu Outer", true,&[
  &MenuItem::new("Menu item #1", true, Some(Accelerator::new(Some(Modifiers::ALT), Code::KeyD))),
  &PredefinedMenuItem::separator(),
  &menu_item2,
  &MenuItem::new("Menu item #3", true, None),
  &PredefinedMenuItem::separator(),
  &Submenu::with_items("Submenu Inner", true,&[
    &MenuItem::new("Submenu item #1", true, None),
    &PredefinedMenuItem::separator(),
    &menu_item2,
  ])
]);

Then add your root menu to a Window on Windows and Linux or use it as your global app menu on macOS

// --snip--
#[cfg(target_os = "windows")]
unsafe { menu.init_for_hwnd(window.hwnd() as isize) };
#[cfg(target_os = "linux")]
menu.init_for_gtk_window(&gtk_window, Some(&vertical_gtk_box));
#[cfg(target_os = "macos")]
menu.init_for_nsapp();

Context menus (Popup menus)

You can also use a [Menu] or a [Submenu] show a context menu.

// --snip--
let position = muda::PhysicalPosition { x: 100., y: 120. };
#[cfg(target_os = "windows")]
unsafe { menu.show_context_menu_for_hwnd(window.hwnd() as isize, Some(position.into())) };
#[cfg(target_os = "linux")]
menu.show_context_menu_for_gtk_window(&gtk_window, Some(position.into()));
#[cfg(target_os = "macos")]
unsafe { menu.show_context_menu_for_nsview(nsview, Some(position.into())) };

Processing menu events

You can use MenuEvent::receiver to get a reference to the MenuEventReceiver which you can use to listen to events when a menu item is activated

if let Ok(event) = MenuEvent::receiver().try_recv() {
    match event.id {
        _ if event.id == save_item.id() => {
            println!("Save menu item activated");
        },
        _ => {}
    }
}

Note for winit or tao users:

You should use [MenuEvent::set_event_handler] and forward the menu events to the event loop by using EventLoopProxy so that the event loop is awakened on each menu event.

enum UserEvent {
  MenuEvent(muda::MenuEvent)
}

let event_loop = EventLoop::<UserEvent>::with_user_event().build().unwrap();

let proxy = event_loop.create_proxy();
muda::MenuEvent::set_event_handler(Some(move |event| {
    proxy.send_event(UserEvent::MenuEvent(event));
}));

License

Apache-2.0/MIT