menu.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. // Copyright 2019-2024 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. use crate::{image::Image, menu::*, Manager, Runtime};
  5. /// A builder type for [`Menu`]
  6. ///
  7. /// ## Platform-specific:
  8. ///
  9. /// - **macOS**: if using [`MenuBuilder`] for the global menubar, it can only contain [`Submenu`]s
  10. ///
  11. /// # Example
  12. ///
  13. /// ```no_run
  14. /// use tauri::menu::*;
  15. /// tauri::Builder::default()
  16. /// .setup(move |app| {
  17. /// let handle = app.handle();
  18. /// # let icon1 = tauri::image::Image::new(&[], 0, 0);
  19. /// let menu = MenuBuilder::new(handle)
  20. /// .item(&MenuItem::new(handle, "MenuItem 1", true, None::<&str>)?)
  21. /// .items(&[
  22. /// &CheckMenuItem::new(handle, "CheckMenuItem 1", true, true, None::<&str>)?,
  23. /// &IconMenuItem::new(handle, "IconMenuItem 1", true, Some(icon1), None::<&str>)?,
  24. /// ])
  25. /// .separator()
  26. /// .cut()
  27. /// .copy()
  28. /// .paste()
  29. /// .separator()
  30. /// .text("item2", "MenuItem 2")
  31. /// .check("checkitem2", "CheckMenuItem 2")
  32. /// .icon("iconitem2", "IconMenuItem 2", app.default_window_icon().cloned().unwrap())
  33. /// .build()?;
  34. /// app.set_menu(menu);
  35. /// Ok(())
  36. /// });
  37. /// ```
  38. pub struct MenuBuilder<'m, R: Runtime, M: Manager<R>> {
  39. pub(crate) id: Option<MenuId>,
  40. pub(crate) manager: &'m M,
  41. pub(crate) items: Vec<crate::Result<MenuItemKind<R>>>,
  42. }
  43. impl<'m, R: Runtime, M: Manager<R>> MenuBuilder<'m, R, M> {
  44. /// Create a new menu builder.
  45. pub fn new(manager: &'m M) -> Self {
  46. Self {
  47. id: None,
  48. items: Vec::new(),
  49. manager,
  50. }
  51. }
  52. /// Create a new menu builder with the specified id.
  53. pub fn with_id<I: Into<MenuId>>(manager: &'m M, id: I) -> Self {
  54. Self {
  55. id: Some(id.into()),
  56. items: Vec::new(),
  57. manager,
  58. }
  59. }
  60. /// Builds this menu
  61. pub fn build(self) -> crate::Result<Menu<R>> {
  62. let menu = if let Some(id) = self.id {
  63. Menu::with_id(self.manager, id)?
  64. } else {
  65. Menu::new(self.manager)?
  66. };
  67. for item in self.items {
  68. let item = item?;
  69. menu.append(&item)?;
  70. }
  71. Ok(menu)
  72. }
  73. }
  74. /// A builder type for [`Submenu`]
  75. ///
  76. /// # Example
  77. ///
  78. /// ```no_run
  79. /// use tauri::menu::*;
  80. /// tauri::Builder::default()
  81. /// .setup(move |app| {
  82. /// let handle = app.handle();
  83. /// # let icon1 = tauri::image::Image::new(&[], 0, 0);
  84. /// # let icon2 = icon1.clone();
  85. /// let menu = Menu::new(handle)?;
  86. /// let submenu = SubmenuBuilder::new(handle, "File")
  87. /// .item(&MenuItem::new(handle, "MenuItem 1", true, None::<&str>)?)
  88. /// .items(&[
  89. /// &CheckMenuItem::new(handle, "CheckMenuItem 1", true, true, None::<&str>)?,
  90. /// &IconMenuItem::new(handle, "IconMenuItem 1", true, Some(icon1), None::<&str>)?,
  91. /// ])
  92. /// .separator()
  93. /// .cut()
  94. /// .copy()
  95. /// .paste()
  96. /// .separator()
  97. /// .text("item2", "MenuItem 2")
  98. /// .check("checkitem2", "CheckMenuItem 2")
  99. /// .icon("iconitem2", "IconMenuItem 2", app.default_window_icon().cloned().unwrap())
  100. /// .build()?;
  101. /// menu.append(&submenu)?;
  102. /// app.set_menu(menu);
  103. /// Ok(())
  104. /// });
  105. /// ```
  106. pub struct SubmenuBuilder<'m, R: Runtime, M: Manager<R>> {
  107. pub(crate) id: Option<MenuId>,
  108. pub(crate) manager: &'m M,
  109. pub(crate) text: String,
  110. pub(crate) enabled: bool,
  111. pub(crate) items: Vec<crate::Result<MenuItemKind<R>>>,
  112. }
  113. impl<'m, R: Runtime, M: Manager<R>> SubmenuBuilder<'m, R, M> {
  114. /// Create a new submenu builder.
  115. ///
  116. /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic
  117. /// for this menu item. To display a `&` without assigning a mnemenonic, use `&&`.
  118. pub fn new<S: AsRef<str>>(manager: &'m M, text: S) -> Self {
  119. Self {
  120. id: None,
  121. items: Vec::new(),
  122. text: text.as_ref().to_string(),
  123. enabled: true,
  124. manager,
  125. }
  126. }
  127. /// Create a new submenu builder with the specified id.
  128. ///
  129. /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic
  130. /// for this menu item. To display a `&` without assigning a mnemenonic, use `&&`.
  131. pub fn with_id<I: Into<MenuId>, S: AsRef<str>>(manager: &'m M, id: I, text: S) -> Self {
  132. Self {
  133. id: Some(id.into()),
  134. text: text.as_ref().to_string(),
  135. enabled: true,
  136. items: Vec::new(),
  137. manager,
  138. }
  139. }
  140. /// Set the enabled state for the submenu.
  141. pub fn enabled(mut self, enabled: bool) -> Self {
  142. self.enabled = enabled;
  143. self
  144. }
  145. /// Builds this submenu
  146. pub fn build(self) -> crate::Result<Submenu<R>> {
  147. let submenu = if let Some(id) = self.id {
  148. Submenu::with_id(self.manager, id, self.text, self.enabled)?
  149. } else {
  150. Submenu::new(self.manager, self.text, self.enabled)?
  151. };
  152. for item in self.items {
  153. let item = item?;
  154. submenu.append(&item)?;
  155. }
  156. Ok(submenu)
  157. }
  158. }
  159. macro_rules! shared_menu_builder {
  160. ($menu: ty) => {
  161. impl<'m, R: Runtime, M: Manager<R>> $menu {
  162. /// Set the id for this menu.
  163. pub fn id<I: Into<MenuId>>(mut self, id: I) -> Self {
  164. self.id.replace(id.into());
  165. self
  166. }
  167. /// Add this item to the menu.
  168. pub fn item(mut self, item: &dyn IsMenuItem<R>) -> Self {
  169. self.items.push(Ok(item.kind()));
  170. self
  171. }
  172. /// Add these items to the menu.
  173. pub fn items(mut self, items: &[&dyn IsMenuItem<R>]) -> Self {
  174. for item in items {
  175. self = self.item(*item);
  176. }
  177. self
  178. }
  179. /// Add a [MenuItem] to the menu.
  180. pub fn text<I: Into<MenuId>, S: AsRef<str>>(mut self, id: I, text: S) -> Self {
  181. self
  182. .items
  183. .push(MenuItem::with_id(self.manager, id, text, true, None::<&str>).map(|i| i.kind()));
  184. self
  185. }
  186. /// Add a [CheckMenuItem] to the menu.
  187. pub fn check<I: Into<MenuId>, S: AsRef<str>>(mut self, id: I, text: S) -> Self {
  188. self.items.push(
  189. CheckMenuItem::with_id(self.manager, id, text, true, true, None::<&str>)
  190. .map(|i| i.kind()),
  191. );
  192. self
  193. }
  194. /// Add an [IconMenuItem] to the menu.
  195. pub fn icon<I: Into<MenuId>, S: AsRef<str>>(
  196. mut self,
  197. id: I,
  198. text: S,
  199. icon: Image<'_>,
  200. ) -> Self {
  201. self.items.push(
  202. IconMenuItem::with_id(self.manager, id, text, true, Some(icon), None::<&str>)
  203. .map(|i| i.kind()),
  204. );
  205. self
  206. }
  207. /// Add an [IconMenuItem] with a native icon to the menu.
  208. ///
  209. /// ## Platform-specific:
  210. ///
  211. /// - **Windows / Linux**: Unsupported.
  212. pub fn native_icon<I: Into<MenuId>, S: AsRef<str>>(
  213. mut self,
  214. id: I,
  215. text: S,
  216. icon: NativeIcon,
  217. ) -> Self {
  218. self.items.push(
  219. IconMenuItem::with_id_and_native_icon(
  220. self.manager,
  221. id,
  222. text,
  223. true,
  224. Some(icon),
  225. None::<&str>,
  226. )
  227. .map(|i| i.kind()),
  228. );
  229. self
  230. }
  231. /// Add Separator menu item to the menu.
  232. pub fn separator(mut self) -> Self {
  233. self
  234. .items
  235. .push(PredefinedMenuItem::separator(self.manager).map(|i| i.kind()));
  236. self
  237. }
  238. /// Add Copy menu item to the menu.
  239. pub fn copy(mut self) -> Self {
  240. self
  241. .items
  242. .push(PredefinedMenuItem::copy(self.manager, None).map(|i| i.kind()));
  243. self
  244. }
  245. /// Add Copy menu item with specified text to the menu.
  246. pub fn copy_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  247. self
  248. .items
  249. .push(PredefinedMenuItem::copy(self.manager, Some(text.as_ref())).map(|i| i.kind()));
  250. self
  251. }
  252. /// Add Cut menu item to the menu.
  253. pub fn cut(mut self) -> Self {
  254. self
  255. .items
  256. .push(PredefinedMenuItem::cut(self.manager, None).map(|i| i.kind()));
  257. self
  258. }
  259. /// Add Cut menu item with specified text to the menu.
  260. pub fn cut_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  261. self
  262. .items
  263. .push(PredefinedMenuItem::cut(self.manager, Some(text.as_ref())).map(|i| i.kind()));
  264. self
  265. }
  266. /// Add Paste menu item to the menu.
  267. pub fn paste(mut self) -> Self {
  268. self
  269. .items
  270. .push(PredefinedMenuItem::paste(self.manager, None).map(|i| i.kind()));
  271. self
  272. }
  273. /// Add Paste menu item with specified text to the menu.
  274. pub fn paste_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  275. self
  276. .items
  277. .push(PredefinedMenuItem::paste(self.manager, Some(text.as_ref())).map(|i| i.kind()));
  278. self
  279. }
  280. /// Add SelectAll menu item to the menu.
  281. pub fn select_all(mut self) -> Self {
  282. self
  283. .items
  284. .push(PredefinedMenuItem::select_all(self.manager, None).map(|i| i.kind()));
  285. self
  286. }
  287. /// Add SelectAll menu item with specified text to the menu.
  288. pub fn select_all_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  289. self.items.push(
  290. PredefinedMenuItem::select_all(self.manager, Some(text.as_ref())).map(|i| i.kind()),
  291. );
  292. self
  293. }
  294. /// Add Undo menu item to the menu.
  295. ///
  296. /// ## Platform-specific:
  297. ///
  298. /// - **Windows / Linux:** Unsupported.
  299. pub fn undo(mut self) -> Self {
  300. self
  301. .items
  302. .push(PredefinedMenuItem::undo(self.manager, None).map(|i| i.kind()));
  303. self
  304. }
  305. /// Add Undo menu item with specified text to the menu.
  306. ///
  307. /// ## Platform-specific:
  308. ///
  309. /// - **Windows / Linux:** Unsupported.
  310. pub fn undo_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  311. self
  312. .items
  313. .push(PredefinedMenuItem::undo(self.manager, Some(text.as_ref())).map(|i| i.kind()));
  314. self
  315. }
  316. /// Add Redo menu item to the menu.
  317. ///
  318. /// ## Platform-specific:
  319. ///
  320. /// - **Windows / Linux:** Unsupported.
  321. pub fn redo(mut self) -> Self {
  322. self
  323. .items
  324. .push(PredefinedMenuItem::redo(self.manager, None).map(|i| i.kind()));
  325. self
  326. }
  327. /// Add Redo menu item with specified text to the menu.
  328. ///
  329. /// ## Platform-specific:
  330. ///
  331. /// - **Windows / Linux:** Unsupported.
  332. pub fn redo_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  333. self
  334. .items
  335. .push(PredefinedMenuItem::redo(self.manager, Some(text.as_ref())).map(|i| i.kind()));
  336. self
  337. }
  338. /// Add Minimize window menu item to the menu.
  339. ///
  340. /// ## Platform-specific:
  341. ///
  342. /// - **Linux:** Unsupported.
  343. pub fn minimize(mut self) -> Self {
  344. self
  345. .items
  346. .push(PredefinedMenuItem::minimize(self.manager, None).map(|i| i.kind()));
  347. self
  348. }
  349. /// Add Minimize window menu item with specified text to the menu.
  350. ///
  351. /// ## Platform-specific:
  352. ///
  353. /// - **Linux:** Unsupported.
  354. pub fn minimize_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  355. self
  356. .items
  357. .push(PredefinedMenuItem::minimize(self.manager, Some(text.as_ref())).map(|i| i.kind()));
  358. self
  359. }
  360. /// Add Maximize window menu item to the menu.
  361. ///
  362. /// ## Platform-specific:
  363. ///
  364. /// - **Linux:** Unsupported.
  365. pub fn maximize(mut self) -> Self {
  366. self
  367. .items
  368. .push(PredefinedMenuItem::maximize(self.manager, None).map(|i| i.kind()));
  369. self
  370. }
  371. /// Add Maximize window menu item with specified text to the menu.
  372. ///
  373. /// ## Platform-specific:
  374. ///
  375. /// - **Linux:** Unsupported.
  376. pub fn maximize_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  377. self
  378. .items
  379. .push(PredefinedMenuItem::maximize(self.manager, Some(text.as_ref())).map(|i| i.kind()));
  380. self
  381. }
  382. /// Add Fullscreen menu item to the menu.
  383. ///
  384. /// ## Platform-specific:
  385. ///
  386. /// - **Windows / Linux:** Unsupported.
  387. pub fn fullscreen(mut self) -> Self {
  388. self
  389. .items
  390. .push(PredefinedMenuItem::fullscreen(self.manager, None).map(|i| i.kind()));
  391. self
  392. }
  393. /// Add Fullscreen menu item with specified text to the menu.
  394. ///
  395. /// ## Platform-specific:
  396. ///
  397. /// - **Windows / Linux:** Unsupported.
  398. pub fn fullscreen_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  399. self.items.push(
  400. PredefinedMenuItem::fullscreen(self.manager, Some(text.as_ref())).map(|i| i.kind()),
  401. );
  402. self
  403. }
  404. /// Add Hide window menu item to the menu.
  405. ///
  406. /// ## Platform-specific:
  407. ///
  408. /// - **Linux:** Unsupported.
  409. pub fn hide(mut self) -> Self {
  410. self
  411. .items
  412. .push(PredefinedMenuItem::hide(self.manager, None).map(|i| i.kind()));
  413. self
  414. }
  415. /// Add Hide window menu item with specified text to the menu.
  416. ///
  417. /// ## Platform-specific:
  418. ///
  419. /// - **Linux:** Unsupported.
  420. pub fn hide_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  421. self
  422. .items
  423. .push(PredefinedMenuItem::hide(self.manager, Some(text.as_ref())).map(|i| i.kind()));
  424. self
  425. }
  426. /// Add Hide other windows menu item to the menu.
  427. ///
  428. /// ## Platform-specific:
  429. ///
  430. /// - **Linux:** Unsupported.
  431. pub fn hide_others(mut self) -> Self {
  432. self
  433. .items
  434. .push(PredefinedMenuItem::hide_others(self.manager, None).map(|i| i.kind()));
  435. self
  436. }
  437. /// Add Hide other windows menu item with specified text to the menu.
  438. ///
  439. /// ## Platform-specific:
  440. ///
  441. /// - **Linux:** Unsupported.
  442. pub fn hide_others_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  443. self.items.push(
  444. PredefinedMenuItem::hide_others(self.manager, Some(text.as_ref())).map(|i| i.kind()),
  445. );
  446. self
  447. }
  448. /// Add Show all app windows menu item to the menu.
  449. ///
  450. /// ## Platform-specific:
  451. ///
  452. /// - **Windows / Linux:** Unsupported.
  453. pub fn show_all(mut self) -> Self {
  454. self
  455. .items
  456. .push(PredefinedMenuItem::show_all(self.manager, None).map(|i| i.kind()));
  457. self
  458. }
  459. /// Add Show all app windows menu item with specified text to the menu.
  460. ///
  461. /// ## Platform-specific:
  462. ///
  463. /// - **Windows / Linux:** Unsupported.
  464. pub fn show_all_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  465. self
  466. .items
  467. .push(PredefinedMenuItem::show_all(self.manager, Some(text.as_ref())).map(|i| i.kind()));
  468. self
  469. }
  470. /// Add Close window menu item to the menu.
  471. ///
  472. /// ## Platform-specific:
  473. ///
  474. /// - **Linux:** Unsupported.
  475. pub fn close_window(mut self) -> Self {
  476. self
  477. .items
  478. .push(PredefinedMenuItem::close_window(self.manager, None).map(|i| i.kind()));
  479. self
  480. }
  481. /// Add Close window menu item with specified text to the menu.
  482. ///
  483. /// ## Platform-specific:
  484. ///
  485. /// - **Linux:** Unsupported.
  486. pub fn close_window_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  487. self.items.push(
  488. PredefinedMenuItem::close_window(self.manager, Some(text.as_ref())).map(|i| i.kind()),
  489. );
  490. self
  491. }
  492. /// Add Quit app menu item to the menu.
  493. ///
  494. /// ## Platform-specific:
  495. ///
  496. /// - **Linux:** Unsupported.
  497. pub fn quit(mut self) -> Self {
  498. self
  499. .items
  500. .push(PredefinedMenuItem::quit(self.manager, None).map(|i| i.kind()));
  501. self
  502. }
  503. /// Add Quit app menu item with specified text to the menu.
  504. ///
  505. /// ## Platform-specific:
  506. ///
  507. /// - **Linux:** Unsupported.
  508. pub fn quit_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  509. self
  510. .items
  511. .push(PredefinedMenuItem::quit(self.manager, Some(text.as_ref())).map(|i| i.kind()));
  512. self
  513. }
  514. /// Add About app menu item to the menu.
  515. pub fn about(mut self, metadata: Option<AboutMetadata<'_>>) -> Self {
  516. self
  517. .items
  518. .push(PredefinedMenuItem::about(self.manager, None, metadata).map(|i| i.kind()));
  519. self
  520. }
  521. /// Add About app menu item with specified text to the menu.
  522. pub fn about_with_text<S: AsRef<str>>(
  523. mut self,
  524. text: S,
  525. metadata: Option<AboutMetadata<'_>>,
  526. ) -> Self {
  527. self.items.push(
  528. PredefinedMenuItem::about(self.manager, Some(text.as_ref()), metadata).map(|i| i.kind()),
  529. );
  530. self
  531. }
  532. /// Add Services menu item to the menu.
  533. ///
  534. /// ## Platform-specific:
  535. ///
  536. /// - **Windows / Linux:** Unsupported.
  537. pub fn services(mut self) -> Self {
  538. self
  539. .items
  540. .push(PredefinedMenuItem::services(self.manager, None).map(|i| i.kind()));
  541. self
  542. }
  543. /// Add Services menu item with specified text to the menu.
  544. ///
  545. /// ## Platform-specific:
  546. ///
  547. /// - **Windows / Linux:** Unsupported.
  548. pub fn services_with_text<S: AsRef<str>>(mut self, text: S) -> Self {
  549. self
  550. .items
  551. .push(PredefinedMenuItem::services(self.manager, Some(text.as_ref())).map(|i| i.kind()));
  552. self
  553. }
  554. }
  555. };
  556. }
  557. shared_menu_builder!(MenuBuilder<'m, R, M>);
  558. shared_menu_builder!(SubmenuBuilder<'m, R, M>);