diff --git a/core/tauri/src/menu/builders/check.rs b/core/tauri/src/menu/builders/check.rs new file mode 100644 index 000000000000..cbef93a0976f --- /dev/null +++ b/core/tauri/src/menu/builders/check.rs @@ -0,0 +1,66 @@ +// Copyright 2019-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{menu::CheckMenuItem, Manager, Runtime}; + +/// A builder type for [`CheckMenuItem`] +pub struct CheckMenuItemBuilder { + text: String, + enabled: bool, + checked: bool, + accelerator: Option, +} + +impl Default for CheckMenuItemBuilder { + fn default() -> Self { + Self::new("") + } +} + +impl CheckMenuItemBuilder { + /// Create a new menu item builder. + pub fn new>(text: S) -> Self { + Self { + text: text.as_ref().to_string(), + enabled: true, + checked: true, + accelerator: None, + } + } + + /// Set the text for this menu item. + pub fn text>(mut self, text: S) -> Self { + self.text = text.as_ref().to_string(); + self + } + + /// Set the enabled state for this menu item. + pub fn enabled(mut self, enabled: bool) -> Self { + self.enabled = enabled; + self + } + + /// Set the checked state for this menu item. + pub fn checked(mut self, checked: bool) -> Self { + self.checked = checked; + self + } + + /// Set the accelerator for this menu item. + pub fn accelerator>(mut self, accelerator: S) -> Self { + self.accelerator.replace(accelerator.as_ref().to_string()); + self + } + + /// Build the menu item + pub fn build>(self, manager: &M) -> CheckMenuItem { + CheckMenuItem::new( + manager, + self.text, + self.enabled, + self.checked, + self.accelerator, + ) + } +} diff --git a/core/tauri/src/menu/builders/icon.rs b/core/tauri/src/menu/builders/icon.rs new file mode 100644 index 000000000000..74ed18e36511 --- /dev/null +++ b/core/tauri/src/menu/builders/icon.rs @@ -0,0 +1,94 @@ +// Copyright 2019-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use tauri_runtime::menu::icon::NativeIcon; + +use crate::{menu::IconMenuItem, Icon, Manager, Runtime}; + +/// A builder type for [`IconMenuItem`] +pub struct IconMenuItemBuilder { + text: String, + enabled: bool, + icon: Option, + native_icon: Option, + accelerator: Option, +} + +impl Default for IconMenuItemBuilder { + fn default() -> Self { + Self::new("") + } +} + +impl IconMenuItemBuilder { + /// Create a new menu item builder. + pub fn new>(text: S) -> Self { + Self { + text: text.as_ref().to_string(), + enabled: true, + icon: None, + native_icon: None, + accelerator: None, + } + } + + /// Set the text for this menu item. + pub fn text>(mut self, text: S) -> Self { + self.text = text.as_ref().to_string(); + self + } + + /// Set the enabled state for this menu item. + pub fn enabled(mut self, enabled: bool) -> Self { + self.enabled = enabled; + self + } + + /// Set the accelerator for this menu item. + pub fn accelerator>(mut self, accelerator: S) -> Self { + self.accelerator.replace(accelerator.as_ref().to_string()); + self + } + + /// Set the icon for this menu item. + /// + /// **Note:** This method conflicts with [`Self::native_icon`] + /// so calling one of them, will reset the other. + pub fn icon(mut self, icon: Icon) -> Self { + self.icon.replace(icon); + self.native_icon = None; + self + } + + /// Set the icon for this menu item. + /// + /// **Note:** This method conflicts with [`Self::icon`] + /// so calling one of them, will reset the other. + pub fn native_icon(mut self, icon: NativeIcon) -> Self { + self.native_icon.replace(icon); + self.icon = None; + self + } + + /// Build the menu item + pub fn build>(self, manager: &M) -> IconMenuItem { + if self.icon.is_some() { + IconMenuItem::new( + manager, + self.text, + self.enabled, + self.icon, + self.accelerator, + ) + } else { + IconMenuItem::with_native_icon( + manager, + self.text, + self.enabled, + self.native_icon, + self.accelerator, + ) + } + } +} diff --git a/core/tauri/src/menu/builders/menu.rs b/core/tauri/src/menu/builders/menu.rs new file mode 100644 index 000000000000..5eb70834965f --- /dev/null +++ b/core/tauri/src/menu/builders/menu.rs @@ -0,0 +1,291 @@ +// Copyright 2019-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{menu::*, AppHandle, Icon, Manager, Runtime}; + +/// A builder type for [`Menu`] +/// +/// # Example +/// +/// ```no_run +/// # let icon1 = Icon::Rgba { +/// # rgba: Vec::new(), +/// # width: 0, +/// # height: 0, +/// # }; +/// # let icon2 = icon1.clone(); +/// MenuBuilder::new(handle) +/// .item(&MenuItem::new(handle, "MenuItem 1", true, None))? +/// .items(&[ +/// &CheckMenuItem::new(handle, "CheckMenuItem 1", true, true, None), +/// &IconMenuItem::new(handle, "IconMenuItem 1", true, Some(icon1), None), +/// ])? +/// .separator()? +/// .cut()? +/// .copy()? +/// .paste()? +/// .separator()? +/// .text("MenuItem 2")? +/// .check("CheckMenuItem 2")? +/// .icon("IconMenuItem 2", icon2)? +/// .build(); +/// ``` +pub struct MenuBuilder { + menu: Menu, + app_handle: AppHandle, +} + +impl MenuBuilder { + /// Create a new menu builder. + pub fn new>(manager: &M) -> Self { + Self { + menu: Menu::new(manager), + app_handle: manager.app_handle(), + } + } + + /// Add this item to the menu. + pub fn item(self, item: &dyn IsMenuItem) -> crate::Result { + self.menu.append(item)?; + Ok(self) + } + + /// Add these items to the menu. + pub fn items(self, items: &[&dyn IsMenuItem]) -> crate::Result { + self.menu.append_items(items)?; + Ok(self) + } + + /// Add a [MenuItem] to the menu. + pub fn text>(self, text: S) -> crate::Result { + self + .menu + .append(&MenuItem::new(&self.app_handle, text, true, None))?; + Ok(self) + } + + /// Add a [CheckMenuItem] to the menu. + pub fn check>(self, text: S) -> crate::Result { + self.menu.append(&CheckMenuItem::new( + &self.app_handle, + text, + true, + true, + None, + ))?; + Ok(self) + } + + /// Add an [IconMenuItem] to the menu. + pub fn icon>(self, text: S, icon: Icon) -> crate::Result { + self.menu.append(&IconMenuItem::new( + &self.app_handle, + text, + true, + Some(icon), + None, + ))?; + Ok(self) + } + + /// Add an [IconMenuItem] with a native icon to the menu. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux**: Unsupported. + pub fn native_icon>(self, text: S, icon: NativeIcon) -> crate::Result { + self.menu.append(&IconMenuItem::with_native_icon( + &self.app_handle, + text, + true, + Some(icon), + None, + ))?; + Ok(self) + } + + /// Add Separator menu item to the menu. + pub fn separator(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::separator(&self.app_handle))?; + Ok(self) + } + + /// Add Copy menu item to the menu. + pub fn copy(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::copy(&self.app_handle, None))?; + Ok(self) + } + + /// Add Cut menu item to the menu. + pub fn cut(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::cut(&self.app_handle, None))?; + Ok(self) + } + + /// Add Paste menu item to the menu. + pub fn paste(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::paste(&self.app_handle, None))?; + Ok(self) + } + + /// Add SelectAll menu item to the menu. + pub fn select_all(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::select_all(&self.app_handle, None))?; + Ok(self) + } + + /// Add Undo menu item to the menu. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux:** Unsupported. + pub fn undo(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::undo(&self.app_handle, None))?; + Ok(self) + } + /// Add Redo menu item to the menu. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux:** Unsupported. + pub fn redo(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::redo(&self.app_handle, None))?; + Ok(self) + } + + /// Add Minimize window menu item to the menu. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn minimize(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::minimize(&self.app_handle, None))?; + Ok(self) + } + + /// Add Maximize window menu item to the menu. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn maximize(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::maximize(&self.app_handle, None))?; + Ok(self) + } + + /// Add Fullscreen menu item to the menu. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux:** Unsupported. + pub fn fullscreen(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::fullscreen(&self.app_handle, None))?; + Ok(self) + } + + /// Add Hide window menu item to the menu. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn hide(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::hide(&self.app_handle, None))?; + Ok(self) + } + + /// Add Hide other windows menu item to the menu. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn hide_others(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::hide_others(&self.app_handle, None))?; + Ok(self) + } + + /// Add Show all app windows menu item to the menu. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux:** Unsupported. + pub fn show_all(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::show_all(&self.app_handle, None))?; + Ok(self) + } + + /// Add Close window menu item to the menu. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn close_window(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::close_window(&self.app_handle, None))?; + Ok(self) + } + + /// Add Quit app menu item to the menu. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn quit(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::quit(&self.app_handle, None))?; + Ok(self) + } + + /// Add About app menu item to the menu. + pub fn about(self, metadata: Option) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::about(&self.app_handle, None, metadata))?; + Ok(self) + } + + /// Add Services menu item to the menu. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux:** Unsupported. + pub fn services(self) -> crate::Result { + self + .menu + .append(&PredefinedMenuItem::services(&self.app_handle, None))?; + Ok(self) + } + + /// Builds this menu + pub fn build(self) -> Menu { + self.menu + } +} diff --git a/core/tauri/src/menu/builders/mod.rs b/core/tauri/src/menu/builders/mod.rs index 6eb7ec8e9009..80f57d005588 100644 --- a/core/tauri/src/menu/builders/mod.rs +++ b/core/tauri/src/menu/builders/mod.rs @@ -6,4 +6,13 @@ pub use crate::runtime::menu::builders::AboutMetadataBuilder; -// TODO(muda-migration): add builder types +mod menu; +pub use menu::MenuBuilder; +mod normal; +pub use normal::MenuItemBuilder; +mod submenu; +pub use submenu::SubmenuBuilder; +mod check; +pub use check::CheckMenuItemBuilder; +mod icon; +pub use icon::IconMenuItemBuilder; diff --git a/core/tauri/src/menu/builders/normal.rs b/core/tauri/src/menu/builders/normal.rs new file mode 100644 index 000000000000..3e7ec3229ea4 --- /dev/null +++ b/core/tauri/src/menu/builders/normal.rs @@ -0,0 +1,52 @@ +// Copyright 2019-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{menu::MenuItem, Manager, Runtime}; + +/// A builder type for [`MenuItem`] +pub struct MenuItemBuilder { + text: String, + enabled: bool, + accelerator: Option, +} + +impl Default for MenuItemBuilder { + fn default() -> Self { + Self::new("") + } +} + +impl MenuItemBuilder { + /// Create a new menu item builder. + pub fn new>(text: S) -> Self { + Self { + text: text.as_ref().to_string(), + enabled: true, + accelerator: None, + } + } + + /// Set the text for this menu item. + pub fn text>(mut self, text: S) -> Self { + self.text = text.as_ref().to_string(); + self + } + + /// Set the enabled state for this menu item. + pub fn enabled(mut self, enabled: bool) -> Self { + self.enabled = enabled; + self + } + + /// Set the accelerator for this menu item. + pub fn accelerator>(mut self, accelerator: S) -> Self { + self.accelerator.replace(accelerator.as_ref().to_string()); + self + } + + /// Build the menu item + pub fn build>(self, manager: &M) -> MenuItem { + MenuItem::new(manager, self.text, self.enabled, self.accelerator) + } +} diff --git a/core/tauri/src/menu/builders/submenu.rs b/core/tauri/src/menu/builders/submenu.rs new file mode 100644 index 000000000000..464b20dc1332 --- /dev/null +++ b/core/tauri/src/menu/builders/submenu.rs @@ -0,0 +1,297 @@ +// Copyright 2019-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{menu::*, AppHandle, Icon, Manager, Runtime}; + +/// A builder type for [`Menu`] +/// +/// # Example +/// +/// ```no_run +/// # let icon1 = Icon::Rgba { +/// # rgba: Vec::new(), +/// # width: 0, +/// # height: 0, +/// # }; +/// # let icon2 = icon1.clone(); +/// SubmenuBuilder::new(handle) +/// .item(&MenuItem::new(handle, "MenuItem 1", true, None))? +/// .items(&[ +/// &CheckMenuItem::new(handle, "CheckMenuItem 1", true, true, None), +/// &IconMenuItem::new(handle, "IconMenuItem 1", true, Some(icon1), None), +/// ])? +/// .separator()? +/// .cut()? +/// .copy()? +/// .paste()? +/// .separator()? +/// .text("MenuItem 2")? +/// .check("CheckMenuItem 2")? +/// .icon("IconMenuItem 2", icon2)? +/// .build(); +/// ``` +pub struct SubmenuBuilder { + submenu: Submenu, + app_handle: AppHandle, +} + +impl SubmenuBuilder { + /// Create a new menu builder. + pub fn new, S: AsRef>(manager: &M, text: S) -> Self { + Self { + submenu: Submenu::new(manager, text, true), + app_handle: manager.app_handle(), + } + } + + /// Set the enabled state for submenu. + pub fn enabled(self, enabled: bool) -> crate::Result { + self.submenu.set_enabled(enabled)?; + Ok(self) + } + + /// Add this item to the submenu. + pub fn item(self, item: &dyn IsMenuItem) -> crate::Result { + self.submenu.append(item)?; + Ok(self) + } + + /// Add these items to the submenu. + pub fn items(self, items: &[&dyn IsMenuItem]) -> crate::Result { + self.submenu.append_items(items)?; + Ok(self) + } + + /// Add a [MenuItem] to the submenu. + pub fn text>(self, text: S) -> crate::Result { + self + .submenu + .append(&MenuItem::new(&self.app_handle, text, true, None))?; + Ok(self) + } + + /// Add a [CheckMenuItem] to the submenu. + pub fn check>(self, text: S) -> crate::Result { + self.submenu.append(&CheckMenuItem::new( + &self.app_handle, + text, + true, + true, + None, + ))?; + Ok(self) + } + + /// Add an [IconMenuItem] to the submenu. + pub fn icon>(self, text: S, icon: Icon) -> crate::Result { + self.submenu.append(&IconMenuItem::new( + &self.app_handle, + text, + true, + Some(icon), + None, + ))?; + Ok(self) + } + + /// Add an [IconMenuItem] with a native icon to the submenu. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux**: Unsupported. + pub fn native_icon>(self, text: S, icon: NativeIcon) -> crate::Result { + self.submenu.append(&IconMenuItem::with_native_icon( + &self.app_handle, + text, + true, + Some(icon), + None, + ))?; + Ok(self) + } + + /// Add Separator menu item to the submenu. + pub fn separator(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::separator(&self.app_handle))?; + Ok(self) + } + + /// Add Copy menu item to the submenu. + pub fn copy(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::copy(&self.app_handle, None))?; + Ok(self) + } + + /// Add Cut menu item to the submenu. + pub fn cut(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::cut(&self.app_handle, None))?; + Ok(self) + } + + /// Add Paste menu item to the submenu. + pub fn paste(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::paste(&self.app_handle, None))?; + Ok(self) + } + + /// Add SelectAll menu item to the submenu. + pub fn select_all(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::select_all(&self.app_handle, None))?; + Ok(self) + } + + /// Add Undo menu item to the submenu. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux:** Unsupported. + pub fn undo(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::undo(&self.app_handle, None))?; + Ok(self) + } + /// Add Redo menu item to the submenu. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux:** Unsupported. + pub fn redo(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::redo(&self.app_handle, None))?; + Ok(self) + } + + /// Add Minimize window menu item to the submenu. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn minimize(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::minimize(&self.app_handle, None))?; + Ok(self) + } + + /// Add Maximize window menu item to the submenu. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn maximize(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::maximize(&self.app_handle, None))?; + Ok(self) + } + + /// Add Fullscreen menu item to the submenu. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux:** Unsupported. + pub fn fullscreen(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::fullscreen(&self.app_handle, None))?; + Ok(self) + } + + /// Add Hide window menu item to the submenu. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn hide(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::hide(&self.app_handle, None))?; + Ok(self) + } + + /// Add Hide other windows menu item to the submenu. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn hide_others(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::hide_others(&self.app_handle, None))?; + Ok(self) + } + + /// Add Show all app windows menu item to the submenu. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux:** Unsupported. + pub fn show_all(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::show_all(&self.app_handle, None))?; + Ok(self) + } + + /// Add Close window menu item to the submenu. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn close_window(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::close_window(&self.app_handle, None))?; + Ok(self) + } + + /// Add Quit app menu item to the submenu. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn quit(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::quit(&self.app_handle, None))?; + Ok(self) + } + + /// Add About app menu item to the submenu. + pub fn about(self, metadata: Option) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::about(&self.app_handle, None, metadata))?; + Ok(self) + } + + /// Add Services menu item to the submenu. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux:** Unsupported. + pub fn services(self) -> crate::Result { + self + .submenu + .append(&PredefinedMenuItem::services(&self.app_handle, None))?; + Ok(self) + } + + /// Builds this menu + pub fn build(self) -> Submenu { + self.submenu + } +}