feat: add handler method on menu item builders

closes #9060
This commit is contained in:
amrbashir 2024-04-04 05:19:56 +02:00
parent b231f4c2e5
commit c8065744d0
No known key found for this signature in database
GPG Key ID: BBD7A47A2003FF33
9 changed files with 148 additions and 30 deletions

View File

@ -0,0 +1,5 @@
---
"tauri": "patch:breaking"
---
Added `<R: Runtime>` generic on `MenuItemBuilder`, `CheckMenuItemBuilder` and `IconMenuItemBuilder` and removed ite from `build` method.

View File

@ -0,0 +1,6 @@
---
"tauri": "patch:feat"
---
Add `handler` method on `MenuItemBuilder`, `CheckMenuItemBuilder` and `IconMenuItemBuilder`.

View File

@ -1860,7 +1860,13 @@ fn on_event_loop_event<R: Runtime>(
{
listener(app_handle, e.clone());
}
for (label, listener) in &*app_handle.manager.menu.event_listeners.lock().unwrap() {
for (label, listener) in &*app_handle
.manager
.menu
.window_event_listeners
.lock()
.unwrap()
{
if let Some(w) = app_handle.manager().get_window(label) {
listener(&w, e.clone());
}

View File

@ -24,7 +24,11 @@ pub struct MenuManager<R: Runtime> {
/// Menu event listeners to all windows.
pub global_event_listeners: Mutex<Vec<crate::app::GlobalMenuEventListener<AppHandle<R>>>>,
/// Menu event listeners to specific windows.
pub event_listeners: Mutex<HashMap<String, crate::app::GlobalMenuEventListener<Window<R>>>>,
pub window_event_listeners:
Mutex<HashMap<String, crate::app::GlobalMenuEventListener<Window<R>>>>,
/// Menu event listeners to specific windows.
pub item_event_listeners:
Mutex<HashMap<MenuId, crate::app::GlobalMenuEventListener<AppHandle<R>>>>,
}
impl<R: Runtime> MenuManager<R> {
@ -95,4 +99,16 @@ impl<R: Runtime> MenuManager<R> {
.unwrap()
.push(Box::new(handler));
}
pub fn on_menu_item_event<F: Fn(&AppHandle<R>, MenuEvent) + Send + Sync + 'static>(
&self,
id: MenuId,
handler: F,
) {
self
.item_event_listeners
.lock()
.unwrap()
.insert(id, Box::new(handler));
}
}

View File

@ -267,7 +267,8 @@ impl<R: Runtime> AppManager<R> {
menus: Default::default(),
menu: Default::default(),
global_event_listeners: Default::default(),
event_listeners: Mutex::new(window_menu_event_listeners),
window_event_listeners: Mutex::new(window_menu_event_listeners),
item_event_listeners: Default::default(),
},
plugins: Mutex::new(plugins),
listeners: Listeners::default(),

View File

@ -2,18 +2,22 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use crate::{menu::CheckMenuItem, menu::MenuId, Manager, Runtime};
use crate::{
menu::{CheckMenuItem, MenuEvent, MenuId},
Manager, Runtime,
};
/// A builder type for [`CheckMenuItem`]
pub struct CheckMenuItemBuilder {
pub struct CheckMenuItemBuilder<R: Runtime> {
id: Option<MenuId>,
text: String,
enabled: bool,
checked: bool,
accelerator: Option<String>,
handler: Option<Box<dyn Fn(&CheckMenuItem<R>, MenuEvent) + Send + Sync + 'static>>,
}
impl CheckMenuItemBuilder {
impl<R: Runtime> CheckMenuItemBuilder<R> {
/// Create a new menu item builder.
///
/// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic
@ -25,6 +29,7 @@ impl CheckMenuItemBuilder {
enabled: true,
checked: true,
accelerator: None,
handler: None,
}
}
@ -39,6 +44,7 @@ impl CheckMenuItemBuilder {
enabled: true,
checked: true,
accelerator: None,
handler: None,
}
}
@ -66,9 +72,18 @@ impl CheckMenuItemBuilder {
self
}
/// Set a handler to be called when this item is activated.
pub fn handler<F: Fn(&CheckMenuItem<R>, MenuEvent) + Send + Sync + 'static>(
mut self,
handler: F,
) -> Self {
self.handler.replace(Box::new(handler));
self
}
/// Build the menu item
pub fn build<R: Runtime, M: Manager<R>>(self, manager: &M) -> crate::Result<CheckMenuItem<R>> {
if let Some(id) = self.id {
pub fn build<M: Manager<R>>(self, manager: &M) -> crate::Result<CheckMenuItem<R>> {
let i = if let Some(id) = self.id {
CheckMenuItem::with_id(
manager,
id,
@ -76,7 +91,7 @@ impl CheckMenuItemBuilder {
self.enabled,
self.checked,
self.accelerator,
)
)?
} else {
CheckMenuItem::new(
manager,
@ -84,7 +99,21 @@ impl CheckMenuItemBuilder {
self.enabled,
self.checked,
self.accelerator,
)
}
)?
};
if let Some(handler) = self.handler {
let i = i.clone();
manager
.manager()
.menu
.on_menu_item_event(i.id().clone(), move |_app, e| {
if e.id == i.id() {
handler(&i, e)
}
});
};
Ok(i)
}
}

View File

@ -4,21 +4,22 @@
use crate::{
image::Image,
menu::{IconMenuItem, MenuId, NativeIcon},
menu::{IconMenuItem, MenuEvent, MenuId, NativeIcon},
Manager, Runtime,
};
/// A builder type for [`IconMenuItem`]
pub struct IconMenuItemBuilder<'a> {
pub struct IconMenuItemBuilder<'a, R: Runtime> {
id: Option<MenuId>,
text: String,
enabled: bool,
icon: Option<Image<'a>>,
native_icon: Option<NativeIcon>,
accelerator: Option<String>,
handler: Option<Box<dyn Fn(&IconMenuItem<R>, MenuEvent) + Send + Sync + 'static>>,
}
impl<'a> IconMenuItemBuilder<'a> {
impl<'a, R: Runtime> IconMenuItemBuilder<'a, R> {
/// Create a new menu item builder.
///
/// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic
@ -31,6 +32,7 @@ impl<'a> IconMenuItemBuilder<'a> {
icon: None,
native_icon: None,
accelerator: None,
handler: None,
}
}
@ -46,6 +48,7 @@ impl<'a> IconMenuItemBuilder<'a> {
icon: None,
native_icon: None,
accelerator: None,
handler: None,
}
}
@ -87,9 +90,18 @@ impl<'a> IconMenuItemBuilder<'a> {
self
}
/// Set a handler to be called when this item is activated.
pub fn handler<F: Fn(&IconMenuItem<R>, MenuEvent) + Send + Sync + 'static>(
mut self,
handler: F,
) -> Self {
self.handler.replace(Box::new(handler));
self
}
/// Build the menu item
pub fn build<R: Runtime, M: Manager<R>>(self, manager: &M) -> crate::Result<IconMenuItem<R>> {
if self.icon.is_some() {
pub fn build<M: Manager<R>>(self, manager: &M) -> crate::Result<IconMenuItem<R>> {
let i = if self.icon.is_some() {
if let Some(id) = self.id {
IconMenuItem::with_id(
manager,
@ -98,7 +110,7 @@ impl<'a> IconMenuItemBuilder<'a> {
self.enabled,
self.icon,
self.accelerator,
)
)?
} else {
IconMenuItem::new(
manager,
@ -106,7 +118,7 @@ impl<'a> IconMenuItemBuilder<'a> {
self.enabled,
self.icon,
self.accelerator,
)
)?
}
} else if let Some(id) = self.id {
IconMenuItem::with_id_and_native_icon(
@ -116,7 +128,7 @@ impl<'a> IconMenuItemBuilder<'a> {
self.enabled,
self.native_icon,
self.accelerator,
)
)?
} else {
IconMenuItem::with_native_icon(
manager,
@ -124,7 +136,21 @@ impl<'a> IconMenuItemBuilder<'a> {
self.enabled,
self.native_icon,
self.accelerator,
)
}
)?
};
if let Some(handler) = self.handler {
let i = i.clone();
manager
.manager()
.menu
.on_menu_item_event(i.id().clone(), move |_app, e| {
if e.id == i.id() {
handler(&i, e)
}
});
};
Ok(i)
}
}

View File

@ -2,17 +2,21 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use crate::{menu::MenuId, menu::MenuItem, Manager, Runtime};
use crate::{
menu::{MenuEvent, MenuId, MenuItem},
Manager, Runtime,
};
/// A builder type for [`MenuItem`]
pub struct MenuItemBuilder {
pub struct MenuItemBuilder<R: Runtime> {
id: Option<MenuId>,
text: String,
enabled: bool,
accelerator: Option<String>,
handler: Option<Box<dyn Fn(&MenuItem<R>, MenuEvent) + Send + Sync + 'static>>,
}
impl MenuItemBuilder {
impl<R: Runtime> MenuItemBuilder<R> {
/// Create a new menu item builder.
///
/// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic
@ -23,6 +27,7 @@ impl MenuItemBuilder {
text: text.as_ref().to_string(),
enabled: true,
accelerator: None,
handler: None,
}
}
@ -36,6 +41,7 @@ impl MenuItemBuilder {
text: text.as_ref().to_string(),
enabled: true,
accelerator: None,
handler: None,
}
}
@ -57,12 +63,35 @@ impl MenuItemBuilder {
self
}
/// Set a handler to be called when this item is activated.
pub fn handler<F: Fn(&MenuItem<R>, MenuEvent) + Send + Sync + 'static>(
mut self,
handler: F,
) -> Self {
self.handler.replace(Box::new(handler));
self
}
/// Build the menu item
pub fn build<R: Runtime, M: Manager<R>>(self, manager: &M) -> crate::Result<MenuItem<R>> {
if let Some(id) = self.id {
MenuItem::with_id(manager, id, self.text, self.enabled, self.accelerator)
pub fn build<M: Manager<R>>(self, manager: &M) -> crate::Result<MenuItem<R>> {
let i = if let Some(id) = self.id {
MenuItem::with_id(manager, id, self.text, self.enabled, self.accelerator)?
} else {
MenuItem::new(manager, self.text, self.enabled, self.accelerator)
}
MenuItem::new(manager, self.text, self.enabled, self.accelerator)?
};
if let Some(handler) = self.handler {
let i = i.clone();
manager
.manager()
.menu
.on_menu_item_event(i.id().clone(), move |_app, e| {
if e.id == i.id() {
handler(&i, e)
}
});
};
Ok(i)
}
}

View File

@ -1105,7 +1105,7 @@ tauri::Builder::default()
self
.manager
.menu
.event_listeners
.window_event_listeners
.lock()
.unwrap()
.insert(self.label().to_string(), Box::new(f));