Skip to content

Commit

Permalink
feat: add handler method on menu item builders
Browse files Browse the repository at this point in the history
closes #9060
  • Loading branch information
amrbashir committed Apr 4, 2024
1 parent b231f4c commit c806574
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 30 deletions.
5 changes: 5 additions & 0 deletions .changes/menu-item-builder-generics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tauri": "patch:breaking"
---

Added `<R: Runtime>` generic on `MenuItemBuilder`, `CheckMenuItemBuilder` and `IconMenuItemBuilder` and removed ite from `build` method.
6 changes: 6 additions & 0 deletions .changes/menu-item-builders-handler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"tauri": "patch:feat"
---

Add `handler` method on `MenuItemBuilder`, `CheckMenuItemBuilder` and `IconMenuItemBuilder`.

8 changes: 7 additions & 1 deletion core/tauri/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down
18 changes: 17 additions & 1 deletion core/tauri/src/manager/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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));
}
}
3 changes: 2 additions & 1 deletion core/tauri/src/manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
45 changes: 37 additions & 8 deletions core/tauri/src/menu/builders/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -25,6 +29,7 @@ impl CheckMenuItemBuilder {
enabled: true,
checked: true,
accelerator: None,
handler: None,
}
}

Expand All @@ -39,6 +44,7 @@ impl CheckMenuItemBuilder {
enabled: true,
checked: true,
accelerator: None,
handler: None,
}
}

Expand Down Expand Up @@ -66,25 +72,48 @@ 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,
self.text,
self.enabled,
self.checked,
self.accelerator,
)
)?
} else {
CheckMenuItem::new(
manager,
self.text,
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)
}
}
46 changes: 36 additions & 10 deletions core/tauri/src/menu/builders/icon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -31,6 +32,7 @@ impl<'a> IconMenuItemBuilder<'a> {
icon: None,
native_icon: None,
accelerator: None,
handler: None,
}
}

Expand All @@ -46,6 +48,7 @@ impl<'a> IconMenuItemBuilder<'a> {
icon: None,
native_icon: None,
accelerator: None,
handler: None,
}
}

Expand Down Expand Up @@ -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,
Expand All @@ -98,15 +110,15 @@ impl<'a> IconMenuItemBuilder<'a> {
self.enabled,
self.icon,
self.accelerator,
)
)?
} else {
IconMenuItem::new(
manager,
self.text,
self.enabled,
self.icon,
self.accelerator,
)
)?
}
} else if let Some(id) = self.id {
IconMenuItem::with_id_and_native_icon(
Expand All @@ -116,15 +128,29 @@ impl<'a> IconMenuItemBuilder<'a> {
self.enabled,
self.native_icon,
self.accelerator,
)
)?
} else {
IconMenuItem::with_native_icon(
manager,
self.text,
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)
}
}
45 changes: 37 additions & 8 deletions core/tauri/src/menu/builders/normal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -23,6 +27,7 @@ impl MenuItemBuilder {
text: text.as_ref().to_string(),
enabled: true,
accelerator: None,
handler: None,
}
}

Expand All @@ -36,6 +41,7 @@ impl MenuItemBuilder {
text: text.as_ref().to_string(),
enabled: true,
accelerator: None,
handler: None,
}
}

Expand All @@ -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)
}
}
2 changes: 1 addition & 1 deletion core/tauri/src/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down

0 comments on commit c806574

Please sign in to comment.