Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: rewrite #18

Merged
merged 49 commits into from
Nov 23, 2022
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
af47ed4
refactor: rewrite
amrbashir Oct 6, 2022
f5eacc6
fix syncing check items and cleanup
amrbashir Oct 7, 2022
a6a2f7f
clippy
amrbashir Oct 7, 2022
2b0dbda
Add `append`, `prepend` and `insert`
amrbashir Oct 10, 2022
e2ccb74
accept different menu items in `*_list` methods
amrbashir Oct 10, 2022
b79cde2
add context menu for gtk
amrbashir Oct 10, 2022
59d01a3
add `with_items`
amrbashir Oct 10, 2022
d812ec8
add `items` getter
amrbashir Oct 10, 2022
47d825c
chore: unreachable! and typos
amrbashir Oct 11, 2022
0efd231
implement remove
amrbashir Oct 11, 2022
eaabe62
`*_list` -> `*_items`
amrbashir Oct 11, 2022
f9ae6e0
fix winit example
amrbashir Oct 11, 2022
6a726a7
add `show_context_menu_for_gtk_window` on `Submenu` type
amrbashir Oct 11, 2022
d3fe560
Add windows implementation
amrbashir Oct 13, 2022
be8313a
TextMenuItem -> MenuItem, MenuItem trait -> MenuEntry
amrbashir Oct 14, 2022
a14be97
Add `PredfinedMenuItem`
amrbashir Oct 14, 2022
3d4c620
move internal mod into its own file
amrbashir Oct 14, 2022
5c32f6b
update tao example to latest tao's `muda` branch
amrbashir Oct 15, 2022
3f45ae5
fix build on linux with latest tao changes
amrbashir Oct 15, 2022
f27ff47
Fix accelerators on Linux
amrbashir Oct 15, 2022
ca775b4
update examples
amrbashir Oct 15, 2022
aaa88e4
remove recursive removal of submenus
amrbashir Oct 15, 2022
ecffac1
remvoe gtk menu items recursively
amrbashir Oct 15, 2022
39054d1
fix tao example on macos
amrbashir Oct 15, 2022
25b5b17
On Windows, remove parents hmenu when removing an item
amrbashir Oct 16, 2022
695e84e
Add documentation
amrbashir Oct 19, 2022
6df33cf
update README.md
amrbashir Oct 19, 2022
1ed0c96
use insert_items with postion 0 for prepend_items
amrbashir Oct 19, 2022
1c01aa1
Add menu mnemonics in examples
amrbashir Oct 19, 2022
19e2e33
Add `ContextMenu` trait
amrbashir Oct 19, 2022
586b523
Add methods to `ContextMenu` trait necessary for tray icon
amrbashir Oct 19, 2022
fed89a0
fix linux build
amrbashir Oct 20, 2022
c936914
fix context menu on gtk
amrbashir Oct 20, 2022
a24ea1b
Expose gtk::Menu in ContextMenu trait
amrbashir Oct 20, 2022
f9c3798
Revert context menu to create a gtk::Menu on each call
amrbashir Oct 20, 2022
84597fc
Merge branch 'master' into rewrite
amrbashir Nov 6, 2022
650c587
clippy lints
amrbashir Nov 6, 2022
7c485a4
Merge branch 'master' into rewrite
amrbashir Nov 6, 2022
676bbf7
Merge branch 'master' into rewrite
amrbashir Nov 6, 2022
a55a7f4
cleanup crate structure
amrbashir Nov 6, 2022
025ace2
update docs
amrbashir Nov 6, 2022
5f4bd28
Fix doc tests and links
amrbashir Nov 6, 2022
d863338
more docs fixes
amrbashir Nov 6, 2022
c787aa4
error handling
amrbashir Nov 6, 2022
b899b66
macOS implementation (#19)
caesar Nov 11, 2022
b2aa55c
fix clippy??
amrbashir Nov 11, 2022
72dd777
use cargo action instead
amrbashir Nov 11, 2022
9541ed1
???
amrbashir Nov 11, 2022
773dbb9
Replace popUpContextMenu with popUpMenuPositioningItem
wusyong Nov 23, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ categories = ["gui"]

[dependencies]
crossbeam-channel = "0.5"
once_cell = "1.10"
keyboard-types = "0.6"
once_cell = "1"

[target.'cfg(target_os = "windows")'.dependencies.windows-sys]
version = "0.34"
version = "0.42"
features = [
"Win32_UI_WindowsAndMessaging",
"Win32_Foundation",
"Win32_Graphics_Gdi",
"Win32_UI_Shell",
"Win32_Globalization",
"Win32_UI_Input_KeyboardAndMouse"
"Win32_UI_Input_KeyboardAndMouse",
]

[target.'cfg(target_os = "linux")'.dependencies]
Expand All @@ -36,5 +36,5 @@ cocoa = "0.24"
objc = "0.2"

[dev-dependencies]
winit = { git = "https://github.com/rust-windowing/winit" }
winit = "0.27"
tao = { git = "https://github.com/tauri-apps/tao", branch = "muda" }
61 changes: 49 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,59 @@
# muda

Menu Utilities for Desktop Applications.
muda is a Menu Utilities library for Desktop Applications.

## Example

Create the root menu and add submenus and men items.
Create the menu and add your items

```rs
let mut menu = Menu::new();
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,
])
]);

let file_menu = menu.add_submenu("File", true);
let open_item = file_menu.add_text_item("Open", true);
let save_item = file_menu.add_text_item("Save", true);
```

let edit_menu = menu.add_submenu("Edit", true);
let copy_item = file_menu.add_text_item("Copy", true);
let cut_item = file_menu.add_text_item("Cut", true);
Then Add your root menu to a Window on Windows and Linux Only or use it
as your global app menu on macOS

```rs
// --snip--
#[cfg(target_os = "windows")]
menu.init_for_hwnd(window.hwnd() as isize);
#[cfg(target_os = "linux")]
menu.init_for_gtk_window(&gtk_window);
#[cfg(target_os = "macos")]
menu.init_for_nsapp();
```
Then listen for the events

## Context menus (Popup menus)

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

```rs
// --snip--
let x = 100;
let y = 120;
#[cfg(target_os = "windows")]
menu.show_context_menu_for_hwnd(window.hwnd() as isize, x, y);
#[cfg(target_os = "linux")]
menu.show_context_menu_for_gtk_window(&gtk_window, x, y);
#[cfg(target_os = "macos")]
menu.show_context_menu_for_nsview(nsview, x, y);
```
## Processing menu events

You can use [`menu_event_receiver`](https://docs.rs/muda/latest/muda/fn.menu_event_receiver.html) to get a reference to the [`MenuEventReceiver`](https://docs.rs/muda/latest/muda/type.MenuEventReceiver.html)
which you can use to listen to events when a menu item is activated
```rs
if let Ok(event) = menu_event_receiver().try_recv() {
match event.id {
Expand All @@ -34,3 +64,10 @@ if let Ok(event) = menu_event_receiver().try_recv() {
}
}
```

## Accelerators on Windows

Accelerators don't work unless the win32 message loop calls
[`TranslateAcceleratorW`](https://docs.rs/windows-sys/latest/windows_sys/Win32/UI/WindowsAndMessaging/fn.TranslateAcceleratorW.html)

See [`Menu::init_for_hwnd`](https://docs.rs/muda/latest/muda/struct.Menu.html#method.init_for_hwnd) for more details
145 changes: 108 additions & 37 deletions examples/tao.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,98 @@
use keyboard_types::Code;
#![allow(unused)]
use muda::{
accelerator::{Accelerator, Mods},
menu_event_receiver, Menu, NativeMenuItem,
accelerator::{Accelerator, Code, Modifiers},
menu_event_receiver, AboutMetadata, CheckMenuItem, Menu, MenuItem, PredefinedMenuItem, Submenu,
};
#[cfg(target_os = "linux")]
use tao::platform::unix::WindowExtUnix;
#[cfg(target_os = "windows")]
use tao::platform::windows::WindowExtWindows;
use tao::platform::windows::{EventLoopBuilderExtWindows, WindowExtWindows};
use tao::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
event::{ElementState, Event, MouseButton, WindowEvent},
event_loop::{ControlFlow, EventLoopBuilder},
window::WindowBuilder,
};

fn main() {
let event_loop = EventLoop::new();
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
}
});
}

#[allow(unused_mut)]
let mut event_loop = event_loop_builder.build();

let window = WindowBuilder::new().build(&event_loop).unwrap();
let window2 = WindowBuilder::new().build(&event_loop).unwrap();

let mut menu_bar = Menu::new();
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 mut file_menu = menu_bar.add_submenu("&File", true);
let mut open_item = file_menu.add_item("&Open", true, None);
let mut save_item = file_menu.add_item(
"&Save",
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(Mods::Ctrl, Code::KeyS)),
Some(Accelerator::new(Some(Modifiers::SHIFT), Code::KeyD)),
);
file_menu.add_native_item(NativeMenuItem::Minimize);
file_menu.add_native_item(NativeMenuItem::CloseWindow);
file_menu.add_native_item(NativeMenuItem::Quit);

let mut edit_menu = menu_bar.add_submenu("&Edit", true);
edit_menu.add_native_item(NativeMenuItem::Cut);
edit_menu.add_native_item(NativeMenuItem::Copy);
edit_menu.add_native_item(NativeMenuItem::Paste);
edit_menu.add_native_item(NativeMenuItem::SelectAll);
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(&[
&check_custom_i_2,
&PredefinedMenuItem::close_window(None),
&PredefinedMenuItem::separator(),
&PredefinedMenuItem::quit(None),
&PredefinedMenuItem::select_all(None),
&PredefinedMenuItem::about(
None,
Some(AboutMetadata {
name: Some("tao".to_string()),
copyright: Some("Copyright TAO".to_string()),
..Default::default()
}),
),
&PredefinedMenuItem::minimize(None),
&check_custom_i_3,
&custom_i_1,
]);

edit_m.append_items(&[&copy_i, &PredefinedMenuItem::separator(), &cut_i]);

edit_m.prepend(&paste_i);
window_m.insert(&cut_i, 2);

#[cfg(target_os = "windows")]
{
Expand All @@ -50,9 +106,9 @@ fn main() {
}

let menu_channel = menu_event_receiver();
let mut open_item_disabled = false;
let mut counter = 0;

let mut x = 0_f64;
let mut y = 0_f64;
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;

Expand All @@ -65,27 +121,42 @@ fn main() {
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 == window.id() {
#[cfg(target_os = "windows")]
window_m.show_context_menu_for_hwnd(window2.hwnd() as _, x, y);
}
}
Event::MainEventsCleared => {
// window.request_redraw();
window.request_redraw();
}
_ => (),
}

if let Ok(event) = menu_channel.try_recv() {
match event.id {
_ if event.id == save_item.id() => {
println!("Save menu item activated!");
counter += 1;
save_item.set_label(format!("&Save activated {counter} times"));

if !open_item_disabled {
println!("Open item disabled!");
open_item.set_enabled(false);
open_item_disabled = true;
}
}
_ => {}
if event.id == custom_i_1.id() {
file_m.insert(&MenuItem::new("asdasd", false, None), 2);
}
println!("{:?}", event);
}
})
}
Loading