muda/examples/winit.rs
Amr Bashir 812ff0d37a
refactor: rewrite (#18)
* refactor: rewrite

* fix syncing check items and cleanup

* clippy

* Add `append`, `prepend` and `insert`

* accept different menu items in `*_list` methods

* add context menu for gtk

* add `with_items`

* add `items` getter

* chore: unreachable! and typos

* implement remove

* `*_list`  -> `*_items`

* fix winit example

* add `show_context_menu_for_gtk_window` on `Submenu` type

* Add windows implementation

* TextMenuItem -> MenuItem, MenuItem trait -> MenuEntry

* Add `PredfinedMenuItem`

* move internal mod into its own file

* update tao example to latest tao's `muda` branch

* fix build on linux with latest tao changes

* Fix accelerators on Linux

* update examples

* remove recursive removal of submenus

* remvoe gtk menu items recursively

* fix tao example on macos

* On Windows, remove parents hmenu when removing an item

* Add documentation

* update README.md

* use insert_items with postion 0 for prepend_items

* Add menu mnemonics in examples

* Add `ContextMenu` trait

* Add methods to `ContextMenu` trait necessary for tray icon

* fix linux build

* fix context menu on gtk

* Expose gtk::Menu in ContextMenu trait

* Revert context menu to create a gtk::Menu on each call

* clippy lints

* cleanup crate structure

* update docs

* Fix doc tests and links

* more docs fixes

* error handling

* macOS implementation (#19)

* partial macOS implementation

* fix context menu examples

* add accelerator support for macOS

* strip ampersands from titles on macOS

* add CMD_OR_CTRL shorthand for modifiers

* implement actions for predefined menu items on macos

* fix examples

* more predefined items

* implement insert for macos

* refactor macOS implementation

* menu state getters and setters on macOS

* implement remove for macOS

* code tweaks

* add show_context_menu_for_nsview for Submenu on macOS

* docs improvements

* allow adding item to the same menu multiple times on macOS

* implement `items` for macOS

* strip only single ampersands from menu titles

* add support for menu item actions on macOS

* add app name to macOS About, Hide, Quit menu items

* add methods to set app window and help menus on macOS

* fix clickable submenu titles on macOS

* refactor submenu for safe reuse on macOS

* fmt & clippy

* few cleanups

* fix docs

* clippy

* fix docs

* cleanup examples

* fix tests

* fix clippy??

* use cargo action instead

* ???

* Replace popUpContextMenu with popUpMenuPositioningItem

Co-authored-by: Caesar Schinas <caesar@caesarschinas.com>
Co-authored-by: Wu Wayne <yuweiwu@pm.me>
2022-11-23 18:29:52 +02:00

182 lines
5.7 KiB
Rust

#![allow(unused)]
use muda::{
accelerator::{Accelerator, Code, Modifiers},
menu_event_receiver, AboutMetadata, CheckMenuItem, ContextMenu, Menu, MenuItem,
PredefinedMenuItem, Submenu,
};
#[cfg(target_os = "macos")]
use winit::platform::macos::{EventLoopBuilderExtMacOS, WindowExtMacOS};
#[cfg(target_os = "windows")]
use winit::platform::windows::{EventLoopBuilderExtWindows, WindowExtWindows};
use winit::{
event::{ElementState, Event, MouseButton, WindowEvent},
event_loop::{ControlFlow, EventLoopBuilder},
window::WindowBuilder,
};
fn main() {
let mut event_loop_builder = EventLoopBuilder::new();
let menu_bar = Menu::new();
#[cfg(target_os = "windows")]
{
let menu_bar_c = menu_bar.clone();
event_loop_builder.with_msg_hook(move |msg| {
use windows_sys::Win32::UI::WindowsAndMessaging::{TranslateAcceleratorW, MSG};
unsafe {
let msg = msg as *const MSG;
let translated = TranslateAcceleratorW((*msg).hwnd, menu_bar_c.haccel(), msg);
translated == 1
}
});
}
#[cfg(target_os = "macos")]
event_loop_builder.with_default_menu(false);
let event_loop = event_loop_builder.build();
let window = WindowBuilder::new()
.with_title("Window 1")
.build(&event_loop)
.unwrap();
let window2 = WindowBuilder::new()
.with_title("Window 2")
.build(&event_loop)
.unwrap();
#[cfg(target_os = "macos")]
{
let app_m = Submenu::new("App", true);
menu_bar.append(&app_m);
app_m.append_items(&[
&PredefinedMenuItem::about(None, None),
&PredefinedMenuItem::separator(),
&PredefinedMenuItem::services(None),
&PredefinedMenuItem::separator(),
&PredefinedMenuItem::hide(None),
&PredefinedMenuItem::hide_others(None),
&PredefinedMenuItem::show_all(None),
&PredefinedMenuItem::separator(),
&PredefinedMenuItem::quit(None),
]);
}
let file_m = Submenu::new("&File", true);
let edit_m = Submenu::new("&Edit", true);
let window_m = Submenu::new("&Window", true);
menu_bar.append_items(&[&file_m, &edit_m, &window_m]);
let custom_i_1 = MenuItem::new(
"C&ustom 1",
true,
Some(Accelerator::new(Some(Modifiers::ALT), Code::KeyC)),
);
let custom_i_2 = MenuItem::new("Custom 2", false, None);
let check_custom_i_1 = CheckMenuItem::new("Check Custom 1", true, true, None);
let check_custom_i_2 = CheckMenuItem::new("Check Custom 2", false, true, None);
let check_custom_i_3 = CheckMenuItem::new(
"Check Custom 3",
true,
true,
Some(Accelerator::new(Some(Modifiers::SHIFT), Code::KeyD)),
);
let copy_i = PredefinedMenuItem::copy(None);
let cut_i = PredefinedMenuItem::cut(None);
let paste_i = PredefinedMenuItem::paste(None);
file_m.append_items(&[
&custom_i_1,
&custom_i_2,
&window_m,
&PredefinedMenuItem::separator(),
&check_custom_i_1,
]);
window_m.append_items(&[
&PredefinedMenuItem::minimize(None),
&PredefinedMenuItem::maximize(None),
&PredefinedMenuItem::close_window(Some("Close")),
&PredefinedMenuItem::fullscreen(None),
&PredefinedMenuItem::about(
None,
Some(AboutMetadata {
name: Some("winit".to_string()),
copyright: Some("Copyright winit".to_string()),
..Default::default()
}),
),
&check_custom_i_3,
&custom_i_2,
&custom_i_1,
]);
edit_m.append_items(&[&copy_i, &paste_i, &PredefinedMenuItem::separator()]);
#[cfg(target_os = "windows")]
{
menu_bar.init_for_hwnd(window.hwnd() as _);
menu_bar.init_for_hwnd(window2.hwnd() as _);
}
#[cfg(target_os = "macos")]
{
menu_bar.init_for_nsapp();
window_m.set_windows_menu_for_nsapp();
}
let menu_channel = menu_event_receiver();
let mut x = 0_f64;
let mut y = 0_f64;
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => *control_flow = ControlFlow::Exit,
Event::WindowEvent {
event: WindowEvent::CursorMoved { position, .. },
window_id,
..
} => {
if window_id == window.id() {
x = position.x;
y = position.y;
}
}
Event::WindowEvent {
event:
WindowEvent::MouseInput {
state: ElementState::Pressed,
button: MouseButton::Right,
..
},
window_id,
..
} => {
if window_id == window2.id() {
#[cfg(target_os = "windows")]
window_m.show_context_menu_for_hwnd(window2.hwnd(), x, y);
#[cfg(target_os = "macos")]
menu_bar.show_context_menu_for_nsview(window2.ns_view() as _, x, y);
}
}
Event::MainEventsCleared => {
window.request_redraw();
}
_ => (),
}
if let Ok(event) = menu_channel.try_recv() {
if event.id == custom_i_1.id() {
file_m.insert(&MenuItem::new("New Menu Item", false, None), 2);
}
println!("{:?}", event);
}
})
}