Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add a default menu for tauri apps #2398

Closed
probablykasper opened this issue Aug 11, 2021 · 18 comments
Closed

feat: add a default menu for tauri apps #2398

probablykasper opened this issue Aug 11, 2021 · 18 comments

Comments

@probablykasper
Copy link
Member

On macOS, it's pretty much standard for every app to have a menu. Not having one looks very unusual, and basic shortcuts like copy/paste don't work (#2397). This could result in future issues being created, and unexpected surprises for people who develop on Windows/Linux.

To prevent that, I think it would make sense to have a default macOS menu.

Suggestion for what the default menu should be, and API for it:

impl Menu {
  pub fn default() -> Menu {
    Menu::new()
      .add_default_submenu(Submenu::App)
      .add_default_submenu(Submenu::File)
      .add_default_submenu(Submenu::Edit)
      .add_default_submenu(Submenu::View)
      .add_default_submenu(Submenu::Window)
      .add_default_submenu(Submenu::Help("https://tauri.studio"))
  }

  pub fn add_default_submenu(&mut self, submenu: Submenu) {
    match submenu {
      Submenu::App => {
        #[cfg(target_os = "macos")]
        self.add_submenu(Submenu::new(
          app_name,
          Menu::new()
            .add_native_item(MenuItem::About(app_name))
            .add_native_item(MenuItem::Separator)
            .add_native_item(MenuItem::Services)
            .add_native_item(MenuItem::Separator)
            .add_native_item(MenuItem::Hide)
            .add_native_item(MenuItem::HideOthers)
            .add_native_item(MenuItem::ShowAll)
            .add_native_item(MenuItem::Separator)
            .add_native_item(MenuItem::Quit),
        ));
      }

      Submenu::File => {
        self.add_submenu(Submenu::new(
          "File",
          if cfg!(target_os == "macos") {
            Menu::new().add_native_item(MenuItem::CloseWindow)
          } else {
            Menu::new().add_native_item(MenuItem::Quit)
          },
        ));
      }

      Submenu::Edit => {
        self.add_submenu(Submenu::new("Edit", {
          let mut menu = Menu::new();
          menu = menu.add_native_item(MenuItem::Undo);
          menu = menu.add_native_item(MenuItem::Redo);
          menu = menu.add_native_item(MenuItem::Separator);
          menu = menu.add_native_item(MenuItem::Cut);
          menu = menu.add_native_item(MenuItem::Copy);
          menu = menu.add_native_item(MenuItem::Paste);
          #[cfg(not(target_os = "macos"))]
          {
            menu = menu.add_native_item(MenuItem::Separator);
          }
          menu = menu.add_native_item(MenuItem::SelectAll);
          menu
        }));
      }

      Submenu::View => {
        self.add_submenu(Submenu::new(
          "View",
          Menu::new().add_native_item(MenuItem::EnterFullScreen),
        ));
      }

      Submenu::Window => {
        self.add_submenu(Submenu::new("Window", {
          let menu = Menu::new()
            .add_native_item(MenuItem::Minimize)
            .add_native_item(MenuItem::Zoom);
          if cfg!(target_os == "macos") {
            menu.add_native_item(MenuItem::Separator);
            // not yet supported:
            menu.add_native_item(MenuItem::BringAllToFront);
            // not yet supported (window selector):
            menu.add_native_item(MenuItem::Window);
          } else {
            menu.add_native_item(MenuItem::CloseWindow);
          }
        }));
      }

      Submenu::Help(url) => {
        self.add_submenu(Submenu::new(
          "Help",
          Menu::new()
            // should open url when clicked:
            .add_item(MenuItem::Url("Learn More", url)),
        ))
      }
    }
  }
}
@amrbashir
Copy link
Member

amrbashir commented Aug 11, 2021

I just talked with @lemarier a couple hours ago about this and I took some inspiration from electron.

Here is proposed changes which is breaking so @lucasfernog input here is vital.

Changes needed in tao:

  1. [MacOS only] tao should expose a MenuBarBuilder that is dependant on event loop rather than window and only one instance should be allowed.
  2. [Linux and Windows only] window.set_menu() should replace or remove current menu.

Changes in tauri:

  1. Remove menu hook on tauri::Builder and tauri by default will ship a default menu bar that includes default menus File, Edit, View, Window and Help for all platforms, on MacOS it is shown as the application menu in MacOS' menu bar and on Linux and Windows it is shown as each window's top menu. Ofc it can be overridden, see number 2 and 4.
  2. App and AppHandle should expose a method set_app_menu(), calling this will override the default menu or remove it if None is passed.
  3. App and AppHandle should expose a method get_app_menu() so users can extend default or current menu, if they wish.
  4. [Linux and Windows only] Window should expose a method set_menu() that overrides the window's menu or remove it if None is passed.
  5. [Linux and Windows only] Window should expose a method get_menu(), hide_menu(), and show_menu()
  6. [Linux and Windows only] Frameless/Borderless/Undecorated window will hide/remove the menu bar.

Example:

tauri::Builder::default()
  .setup(|app|{
    // get default menu or current one
    let app_menu = app.get_app_menu();
    // extend the menu
    app_menu.add_submenu("MyMenu");
    // set the updated app menu, or pass None to remove it
    app.set_app_menu(Some(app_menu));
  })
  .on_page_load(|win, _|{
    // get default menu or current one that is attached to the window, only linux and windows
    let menu = win.get_menu();
    // extend the menu
    menu.add_submenu("MyMenu");
    // set the updated menu, or pass None to remove it, only for linux and windows 
    win.set_menu(Some(menu));
  })
  .run(tauri.generate_context!())
  .expect("Error while running tauri application")

@amrbashir amrbashir changed the title Default macOS menu feat: add a default menu for tauri apps Aug 11, 2021
@probablykasper
Copy link
Member Author

Sounds like a great way to go about it :D

@Tragio
Copy link

Tragio commented Aug 12, 2021

I like this way @amrbashir. Thank you @probablykasper for raising this issue. I've been studying and using Tauri for the last week and this is a particular issue that is boring and that can become unaware for Windows and Linux Developers. I was surprised why I could quit my app using a Command + Q, or select all the text Command + A. Would be really useful to have this ready for Mac users, or at least a ready documentation for unexperienced people in Tauri like me 😄 ❤️

@tauri-apps tauri-apps deleted a comment from myphuong776 Aug 14, 2021
@lemarier
Copy link
Member

The more I'm thinking about it, the more I think it should go directly in tao.
In macOS, we do need a menu, and it'll bring uniformity in wry <-> Tauri.

If the user does not define a menu, we build the default menu.
If the user DONT want the menu, he should switch the activation policy.

Maybe we could also add a WindowExt function to force the default menu to be disabled, but I don't see any case where it can be useful.

I think we shouldn't overengineering here and if the user wants a custom menu he should create it from scratch. Allowing default menu extensions could bring a lot of weird bugs. We already expose all the native elements so it's a big plus.

The default menu should be the one suggested y the Apple developer guidelines.

What you think @amrbashir

@amrbashir
Copy link
Member

amrbashir commented Aug 16, 2021

@lemarier

The more I'm thinking about it, the more I think it should go directly in tao.
In macOS, we do need a menu, and it'll bring uniformity in wry <-> Tauri.

Tbh, I think Tao and Wry are low-level libraries and we shouldn't provide any default menus there as users of these libraries expect to be in full control so it makes sense to let them worry about menus.
Default menus should be in Tauri only.

I think we shouldn't overengineering here and if the user wants a custom menu he should create it from scratch. Allowing default menu extensions could bring a lot of weird bugs. We already expose all the native elements so it's a big plus.

I don't think that allowing menu extensions can bring bugs since we only need to allow adding new sub menus, it is just basic extension, if users want to delete menus or modify it then they should create their own menu from scratch.

Maybe we could also add a WindowExt function to force the default menu to be disabled, but I don't see any case where it can be useful.

default or non-default menu should be disabled through window.set_menu(None) this will delete menus in top of the window in Windows and Linux or app.set_app_menu(None) to remove it in all platforms.

The default menu should be the one suggested y the Apple developer guidelines.

I don't have an opinion about this, as long as the default menu is sensible across all platforms.

@amrbashir
Copy link
Member

amrbashir commented Aug 16, 2021

I don't think the changes needed in Tao are considered over engineering since they are minimal changes and tbh are necessary.

  1. macOS should have their menus set on the event loop level not window.
  2. window.set_menu() and macOS MenuBar::set_menu() (needs to be added to tao first) should be able to remove or replace the current menu.

@probablykasper
Copy link
Member Author

Tbh, I think Tao and Wry are low-level libraries and we shouldn't provide any default menus there as users of these libraries expect to be in full control so it makes sense to let them worry about menus.
Default menus should be in Tauri only.

@amrbashir I think it probably should be in tao. It's better to accidentally have a menu than to accidentally not have one

@amrbashir
Copy link
Member

amrbashir commented Oct 3, 2021

@amrbashir I think it probably should be in tao. It's better to accidentally have a menu than to accidentally not have one

As I said earlier, Tao/Wry users expected it to be bare-bones minimal, and they expect to build their app from ground up so I think Tao/Wry should only provide the means for them and not ship predefined designs for them but don't worry Tauri should and probably will ship a default menu for Tauri users as Tauri is considered more of a high-level tool than Tao/Wry.

@probablykasper
Copy link
Member Author

@lemarier suggested that if a user wants a custom menu, they should create it from scratch. After implementing submenu defaults in my template, I have to say it's extremely nice to have:
https://github.com/probablykasper/tauri-template/blob/14b51d4f8702f5fdcb54cf528bdbf3be61e36372/src-tauri/src/main.rs#L36-L45

Saves a nice 40 LOC and makes it all easier to manage, especially when it comes to cross-platform differences.

@lorenzolewis
Copy link
Member

Just wanted to add in my two cents that I think this would be a very nice default to add in. A lot of functionality you expect out of the box (like command-Q, copy, paste, cut, etc.) exist in every single macOS application. Would really help new developers (like myself) to get started prototyping with a lower barrier to entry in Tauri.

@VityaSchel
Copy link

Since default menu with basic copy/paste/undo/redo functionality is not presented in Tao and Tauri yet, maybe we should add it to the docs?

aviator-app bot pushed a commit to tari-project/tari that referenced this issue Feb 18, 2022
Description
---

- Adds Copy, Cut, Paste, SelectAll, Undo, Redo and Quit to menu items
- Command + ? keys are now working on Mac
- Upgraded Tauri lib to 1.0.0.rc.2

Motivation and Context
---
These are basic and expected features for desktop apps.

Not able to set the mac default menu title, seems that is not currently possible (Ref tauri-apps/tauri#2398)

How Has This Been Tested?
---
Manually
@kotx
Copy link

kotx commented May 8, 2022

This would be trivial to PR, since the issue itself provides almost all of the code necessary. I am willing to PR support for this (including docs), if it was to be merged?

@lorenzolewis
Copy link
Member

What would it take to start adding in a default menu building in tauri/tao now (even if we don't enable it for new projects by default)?

I'm thinking along the lines of how SvelteKit does a new project: you choose a skeleton project or a more feature-packed project. If in create-tauri-app we mimic this and then just add the default menu if a feature-packed option is chosen, then we give that flexibility to the user during init.

By building out a sort of option like this in create-tauri-app, would could also demo some of the APIs (thinking to have a simple rust function that returns a string and then have the frontend show that in a dialog) to give the user a concrete place to jump off from.

@amrbashir
Copy link
Member

amrbashir commented Jun 7, 2022

A default menu should be included directly in tauri core with the ability to override it. I am working on extracting out the menu system out of tao into its own crate with an improved API design and more features. Here is a tracking issue of missing features tauri-apps/muda#5 , Once that is finished, we can implement a default menu in tauri directly.

@lorenzolewis lorenzolewis modified the milestone: Default menu Jun 7, 2022
@lorenzolewis lorenzolewis changed the title feat: add a default menu for tauri apps feat: add a default menu for tauri app Jun 7, 2022
@lorenzolewis lorenzolewis changed the title feat: add a default menu for tauri app feat: add a default menu for tauri apps Jun 7, 2022
amrbashir added a commit that referenced this issue Jun 7, 2022
@schickling
Copy link

Nice improvement!

@augustsaintfreytag
Copy link

Wonderful addition and it seems this has been closed and (apparently) merged if I follow all the links but how do you actually use it?

Is it merged but not yet released? What version of the common @tauri-apps/api package does this correspond to? Can I build the latest state from source somehow and use it as a Node module as-is? This issue is the one you’ll be led to when searching for how to implement the expected macOS default app menu, even sample code links to it. However, with it being closed, I’d expect some helpful information on its usage or availability.

@amrbashir
Copy link
Member

@augustsaintfreytag

.menu(tauri::Menu::os_default(&context.package_info().name))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants