mirror of
https://github.com/italicsjenga/muda.git
synced 2024-12-23 12:01:31 +11:00
use an event channel instead of callbacks
This commit is contained in:
parent
b5598554a0
commit
fbef2d8a40
15
Cargo.toml
15
Cargo.toml
|
@ -3,15 +3,20 @@ name = "menu-rs"
|
|||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
windows-sys = { version = "0.34", features = [
|
||||
[dependencies]
|
||||
crossbeam-channel = "0.5"
|
||||
once_cell = "1.10"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies.windows-sys]
|
||||
version = "0.34"
|
||||
features = [
|
||||
"Win32_UI_WindowsAndMessaging",
|
||||
"Win32_Foundation",
|
||||
"Win32_Graphics_Gdi"
|
||||
] }
|
||||
"Win32_Graphics_Gdi",
|
||||
]
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
parking_lot = "0.12.0"
|
||||
parking_lot = "0.12"
|
||||
gtk = "0.15"
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use menu_rs::Menu;
|
||||
use menu_rs::{menu_event_receiver, Menu};
|
||||
#[cfg(target_os = "linux")]
|
||||
use tao::platform::unix::WindowExtUnix;
|
||||
#[cfg(target_os = "windows")]
|
||||
|
@ -9,12 +9,8 @@ use tao::{
|
|||
window::WindowBuilder,
|
||||
};
|
||||
|
||||
enum UserEvent {
|
||||
MenuEvent(u64),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let event_loop = EventLoop::<UserEvent>::with_user_event();
|
||||
let event_loop = EventLoop::new();
|
||||
|
||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||
let window2 = WindowBuilder::new().build(&event_loop).unwrap();
|
||||
|
@ -23,19 +19,13 @@ fn main() {
|
|||
let mut file_menu = menu_bar.add_submenu("File", true);
|
||||
let mut edit_menu = menu_bar.add_submenu("Edit", true);
|
||||
|
||||
let mut open_item = file_menu.add_text_item("Open", true, |_| {});
|
||||
let mut open_item = file_menu.add_text_item("Open", true);
|
||||
|
||||
let proxy = event_loop.create_proxy();
|
||||
let mut counter = 0;
|
||||
let save_item = file_menu.add_text_item("Save", true, move |i| {
|
||||
counter += 1;
|
||||
i.set_label(format!("Save triggered {} times", counter));
|
||||
let _ = proxy.send_event(UserEvent::MenuEvent(i.id()));
|
||||
});
|
||||
let _quit_item = file_menu.add_text_item("Quit", true, |_| {});
|
||||
let mut save_item = file_menu.add_text_item("Save", true);
|
||||
let _quit_item = file_menu.add_text_item("Quit", true);
|
||||
|
||||
let _copy_item = edit_menu.add_text_item("Copy", true, |_| {});
|
||||
let _cut_item = edit_menu.add_text_item("Cut", true, |_| {});
|
||||
let _copy_item = edit_menu.add_text_item("Copy", true);
|
||||
let _cut_item = edit_menu.add_text_item("Cut", true);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
|
@ -48,10 +38,29 @@ fn main() {
|
|||
menu_bar.init_for_gtk_window(window2.gtk_window());
|
||||
}
|
||||
|
||||
let menu_channel = menu_event_receiver();
|
||||
let mut open_item_disabled = false;
|
||||
let counter = 0;
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
*control_flow = ControlFlow::Wait;
|
||||
|
||||
if let Ok(event) = menu_channel.try_recv() {
|
||||
match event.id {
|
||||
_ if event.id == save_item.id() => {
|
||||
println!("Save menu item triggered");
|
||||
|
||||
save_item.set_label(format!("Save triggered {counter} times"));
|
||||
if !open_item_disabled {
|
||||
println!("Open item disabled!");
|
||||
open_item.set_enabled(false);
|
||||
open_item_disabled = true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
match event {
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
|
@ -60,20 +69,6 @@ fn main() {
|
|||
Event::MainEventsCleared => {
|
||||
window.request_redraw();
|
||||
}
|
||||
|
||||
Event::UserEvent(e) => match e {
|
||||
UserEvent::MenuEvent(id) => {
|
||||
if id == save_item.id() {
|
||||
println!("Save menu item triggered");
|
||||
|
||||
if !open_item_disabled {
|
||||
println!("Open item disabled!");
|
||||
open_item.set_enabled(false);
|
||||
open_item_disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use menu_rs::Menu;
|
||||
use menu_rs::{menu_event_receiver, Menu};
|
||||
#[cfg(target_os = "windows")]
|
||||
use winit::platform::windows::WindowExtWindows;
|
||||
use winit::{
|
||||
|
@ -7,63 +7,61 @@ use winit::{
|
|||
window::WindowBuilder,
|
||||
};
|
||||
|
||||
enum UserEvent {
|
||||
MenuEvent(u64),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let event_loop = EventLoop::<UserEvent>::with_user_event();
|
||||
let event_loop = EventLoop::new();
|
||||
|
||||
let _window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||
let _window2 = WindowBuilder::new().build(&event_loop).unwrap();
|
||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||
let window2 = WindowBuilder::new().build(&event_loop).unwrap();
|
||||
|
||||
let mut menu_bar = Menu::new();
|
||||
let mut file_menu = menu_bar.add_submenu("File", true);
|
||||
let mut edit_menu = menu_bar.add_submenu("Edit", true);
|
||||
|
||||
let mut open_item = file_menu.add_text_item("Open", true, |_| {});
|
||||
let mut open_item = file_menu.add_text_item("Open", true);
|
||||
|
||||
let proxy = event_loop.create_proxy();
|
||||
let mut counter = 0;
|
||||
let save_item = file_menu.add_text_item("Save", true, move |i| {
|
||||
counter += 1;
|
||||
i.set_label(format!("Save triggered {} times", counter));
|
||||
let _ = proxy.send_event(UserEvent::MenuEvent(i.id()));
|
||||
});
|
||||
let _quit_item = file_menu.add_text_item("Quit", true, |_| {});
|
||||
let mut save_item = file_menu.add_text_item("Save", true);
|
||||
let _quit_item = file_menu.add_text_item("Quit", true);
|
||||
|
||||
let _copy_item = edit_menu.add_text_item("Copy", true, |_| {});
|
||||
let _cut_item = edit_menu.add_text_item("Cut", true, |_| {});
|
||||
let _copy_item = edit_menu.add_text_item("Copy", true);
|
||||
let _cut_item = edit_menu.add_text_item("Cut", true);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
menu_bar.init_for_hwnd(_window.hwnd() as _);
|
||||
menu_bar.init_for_hwnd(_window2.hwnd() as _);
|
||||
menu_bar.init_for_hwnd(window.hwnd() as _);
|
||||
menu_bar.init_for_hwnd(window2.hwnd() as _);
|
||||
}
|
||||
|
||||
let menu_channel = menu_event_receiver();
|
||||
let mut open_item_disabled = false;
|
||||
let counter = 0;
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
*control_flow = ControlFlow::Wait;
|
||||
|
||||
if let Ok(event) = menu_channel.try_recv() {
|
||||
match event.id {
|
||||
_ if event.id == save_item.id() => {
|
||||
println!("Save menu item triggered");
|
||||
|
||||
save_item.set_label(format!("Save triggered {counter} times"));
|
||||
if !open_item_disabled {
|
||||
println!("Open item disabled!");
|
||||
open_item.set_enabled(false);
|
||||
open_item_disabled = true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
match event {
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => *control_flow = ControlFlow::Exit,
|
||||
|
||||
Event::UserEvent(e) => match e {
|
||||
UserEvent::MenuEvent(id) => {
|
||||
if id == save_item.id() {
|
||||
println!("Save menu item triggered");
|
||||
|
||||
if !open_item_disabled {
|
||||
println!("Open item disabled!");
|
||||
open_item.set_enabled(false);
|
||||
open_item_disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Event::MainEventsCleared => {
|
||||
window.request_redraw();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
})
|
||||
|
|
24
src/lib.rs
24
src/lib.rs
|
@ -1,6 +1,21 @@
|
|||
use crossbeam_channel::{unbounded, Receiver, Sender};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
mod platform_impl;
|
||||
mod util;
|
||||
|
||||
static MENU_CHANNEL: Lazy<(Sender<MenuEvent>, Receiver<MenuEvent>)> = Lazy::new(|| unbounded());
|
||||
|
||||
/// Event channel for receiving menu events.
|
||||
pub fn menu_event_receiver<'a>() -> &'a Receiver<MenuEvent> {
|
||||
&MENU_CHANNEL.1
|
||||
}
|
||||
|
||||
/// Describes a menu event emitted when a menu item is activated
|
||||
pub struct MenuEvent {
|
||||
pub id: u64,
|
||||
}
|
||||
|
||||
pub struct Menu(platform_impl::Menu);
|
||||
|
||||
impl Menu {
|
||||
|
@ -36,13 +51,8 @@ impl Submenu {
|
|||
Submenu(self.0.add_submenu(label, enabled))
|
||||
}
|
||||
|
||||
pub fn add_text_item<F: FnMut(&mut TextMenuItem) + 'static>(
|
||||
&mut self,
|
||||
label: impl AsRef<str>,
|
||||
enabled: bool,
|
||||
f: F,
|
||||
) -> TextMenuItem {
|
||||
TextMenuItem(self.0.add_text_item(label, enabled, f))
|
||||
pub fn add_text_item(&mut self, label: impl AsRef<str>, enabled: bool) -> TextMenuItem {
|
||||
TextMenuItem(self.0.add_text_item(label, enabled))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use parking_lot::Mutex;
|
||||
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
||||
use std::sync::Arc;
|
||||
|
||||
use gtk::{prelude::*, Orientation};
|
||||
|
||||
|
@ -17,7 +17,6 @@ struct MenuEntry {
|
|||
enabled: bool,
|
||||
entries: Option<Vec<Arc<Mutex<MenuEntry>>>>,
|
||||
etype: MenuEntryType,
|
||||
item_handler: Option<Rc<RefCell<dyn FnMut(&mut crate::TextMenuItem) + 'static>>>,
|
||||
item_id: Option<u64>,
|
||||
menu_gtk_items: Option<Arc<Mutex<Vec<(gtk::MenuItem, gtk::Menu)>>>>,
|
||||
item_gtk_items: Option<Arc<Mutex<Vec<gtk::MenuItem>>>>,
|
||||
|
@ -46,7 +45,6 @@ impl Menu {
|
|||
enabled,
|
||||
entries: Some(Vec::new()),
|
||||
etype: MenuEntryType::Submenu,
|
||||
item_handler: None,
|
||||
item_id: None,
|
||||
menu_gtk_items: Some(gtk_items.clone()),
|
||||
item_gtk_items: None,
|
||||
|
@ -78,7 +76,6 @@ impl Menu {
|
|||
|
||||
fn add_entries_to_menu<M: IsA<gtk::MenuShell>>(gtk_menu: &M, entries: &Vec<Arc<Mutex<MenuEntry>>>) {
|
||||
for entry in entries {
|
||||
let entry_clone = entry.clone();
|
||||
let mut entry = entry.lock();
|
||||
let gtk_item = gtk::MenuItem::with_label(&entry.label);
|
||||
gtk_menu.append(>k_item);
|
||||
|
@ -94,18 +91,9 @@ fn add_entries_to_menu<M: IsA<gtk::MenuShell>>(gtk_menu: &M, entries: &Vec<Arc<M
|
|||
.lock()
|
||||
.push((gtk_item, gtk_menu));
|
||||
} else {
|
||||
let handler = Rc::clone(&entry.item_handler.as_mut().unwrap());
|
||||
let item = TextMenuItem {
|
||||
label: entry.label.clone(),
|
||||
enabled: entry.enabled,
|
||||
id: entry.item_id.unwrap(),
|
||||
entry: entry_clone,
|
||||
gtk_items: entry.item_gtk_items.as_ref().unwrap().clone(),
|
||||
};
|
||||
let id = entry.item_id.unwrap_or_default();
|
||||
gtk_item.connect_activate(move |_| {
|
||||
let mut handler = handler.borrow_mut();
|
||||
let mut item = crate::TextMenuItem(item.clone());
|
||||
handler(&mut item);
|
||||
let _ = crate::MENU_CHANNEL.0.send(crate::MenuEvent { id });
|
||||
});
|
||||
entry.item_gtk_items.as_mut().unwrap().lock().push(gtk_item);
|
||||
}
|
||||
|
@ -148,7 +136,6 @@ impl Submenu {
|
|||
enabled,
|
||||
entries: Some(Vec::new()),
|
||||
etype: MenuEntryType::Submenu,
|
||||
item_handler: None,
|
||||
item_id: None,
|
||||
menu_gtk_items: Some(gtk_items.clone()),
|
||||
item_gtk_items: None,
|
||||
|
@ -167,12 +154,7 @@ impl Submenu {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_text_item<F: FnMut(&mut crate::TextMenuItem) + 'static>(
|
||||
&mut self,
|
||||
label: impl AsRef<str>,
|
||||
enabled: bool,
|
||||
f: F,
|
||||
) -> TextMenuItem {
|
||||
pub fn add_text_item(&mut self, label: impl AsRef<str>, enabled: bool) -> TextMenuItem {
|
||||
let id = COUNTER.next();
|
||||
let label = label.as_ref().to_string();
|
||||
let gtk_items = Arc::new(Mutex::new(Vec::new()));
|
||||
|
@ -181,7 +163,6 @@ impl Submenu {
|
|||
enabled,
|
||||
entries: None,
|
||||
etype: MenuEntryType::Text,
|
||||
item_handler: Some(Rc::new(RefCell::new(f))),
|
||||
item_id: Some(id),
|
||||
menu_gtk_items: None,
|
||||
item_gtk_items: Some(gtk_items.clone()),
|
||||
|
|
Loading…
Reference in a new issue