Native macOS menu bar

- OpenPencil: About, Services, Hide, Quit
- File: New, Open, Save, Save As, Export, Close
- Edit: Undo, Redo, Cut, Copy, Paste, Paste in Place,
  Select All, Duplicate, Delete
- View: Zoom In/Out/Fit/100%, Toggle Rulers/Grid/UI, Fullscreen
- Object: Group, Ungroup, Frame Selection, Bring to Front,
  Send to Back, Flip H/V
- Window: Minimize, Maximize, Close
- Help: Keyboard Shortcuts

All with standard macOS accelerators.
This commit is contained in:
Danila Poyarkov 2026-02-28 10:00:37 +03:00
parent b0a35a4d24
commit bf45ac0f65

View file

@ -1,14 +1,220 @@
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
use tauri::menu::{MenuBuilder, MenuItemBuilder, PredefinedMenuItem, SubmenuBuilder};
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![greet])
.setup(|app| {
let app_menu = SubmenuBuilder::new(app, "OpenPencil")
.item(&PredefinedMenuItem::about(app, Some("About OpenPencil"), None)?)
.separator()
.item(&PredefinedMenuItem::services(app, None)?)
.separator()
.item(&PredefinedMenuItem::hide(app, None)?)
.item(&PredefinedMenuItem::hide_others(app, None)?)
.item(&PredefinedMenuItem::show_all(app, None)?)
.separator()
.item(&PredefinedMenuItem::quit(app, None)?)
.build()?;
let file_menu = SubmenuBuilder::new(app, "File")
.item(
&MenuItemBuilder::new("New File")
.id("new")
.accelerator("CmdOrCtrl+N")
.build(app)?,
)
.item(
&MenuItemBuilder::new("Open…")
.id("open")
.accelerator("CmdOrCtrl+O")
.build(app)?,
)
.separator()
.item(
&MenuItemBuilder::new("Save")
.id("save")
.accelerator("CmdOrCtrl+S")
.build(app)?,
)
.item(
&MenuItemBuilder::new("Save As…")
.id("save-as")
.accelerator("CmdOrCtrl+Shift+S")
.build(app)?,
)
.separator()
.item(
&MenuItemBuilder::new("Export…")
.id("export")
.accelerator("CmdOrCtrl+Shift+E")
.build(app)?,
)
.separator()
.item(
&MenuItemBuilder::new("Close Window")
.id("close")
.accelerator("CmdOrCtrl+W")
.build(app)?,
)
.build()?;
let edit_menu = SubmenuBuilder::new(app, "Edit")
.item(&PredefinedMenuItem::undo(app, None)?)
.item(&PredefinedMenuItem::redo(app, None)?)
.separator()
.item(&PredefinedMenuItem::cut(app, None)?)
.item(&PredefinedMenuItem::copy(app, None)?)
.item(&PredefinedMenuItem::paste(app, None)?)
.item(
&MenuItemBuilder::new("Paste in Place")
.id("paste-in-place")
.accelerator("CmdOrCtrl+Shift+V")
.build(app)?,
)
.item(&PredefinedMenuItem::select_all(app, None)?)
.separator()
.item(
&MenuItemBuilder::new("Duplicate")
.id("duplicate")
.accelerator("CmdOrCtrl+D")
.build(app)?,
)
.item(
&MenuItemBuilder::new("Delete")
.id("delete")
.accelerator("Backspace")
.build(app)?,
)
.build()?;
let view_menu = SubmenuBuilder::new(app, "View")
.item(
&MenuItemBuilder::new("Zoom In")
.id("zoom-in")
.accelerator("CmdOrCtrl+=")
.build(app)?,
)
.item(
&MenuItemBuilder::new("Zoom Out")
.id("zoom-out")
.accelerator("CmdOrCtrl+-")
.build(app)?,
)
.item(
&MenuItemBuilder::new("Zoom to Fit")
.id("zoom-fit")
.accelerator("CmdOrCtrl+1")
.build(app)?,
)
.item(
&MenuItemBuilder::new("Zoom to 100%")
.id("zoom-100")
.accelerator("CmdOrCtrl+0")
.build(app)?,
)
.separator()
.item(
&MenuItemBuilder::new("Toggle Rulers")
.id("toggle-rulers")
.accelerator("Shift+R")
.build(app)?,
)
.item(
&MenuItemBuilder::new("Toggle Grid")
.id("toggle-grid")
.accelerator("CmdOrCtrl+'")
.build(app)?,
)
.separator()
.item(
&MenuItemBuilder::new("Toggle UI")
.id("toggle-ui")
.accelerator("CmdOrCtrl+\\")
.build(app)?,
)
.item(&PredefinedMenuItem::fullscreen(app, None)?)
.build()?;
let object_menu = SubmenuBuilder::new(app, "Object")
.item(
&MenuItemBuilder::new("Group Selection")
.id("group")
.accelerator("CmdOrCtrl+G")
.build(app)?,
)
.item(
&MenuItemBuilder::new("Ungroup Selection")
.id("ungroup")
.accelerator("CmdOrCtrl+Shift+G")
.build(app)?,
)
.item(
&MenuItemBuilder::new("Frame Selection")
.id("frame-selection")
.accelerator("CmdOrCtrl+Alt+G")
.build(app)?,
)
.separator()
.item(
&MenuItemBuilder::new("Bring to Front")
.id("bring-front")
.accelerator("CmdOrCtrl+]")
.build(app)?,
)
.item(
&MenuItemBuilder::new("Send to Back")
.id("send-back")
.accelerator("CmdOrCtrl+[")
.build(app)?,
)
.separator()
.item(
&MenuItemBuilder::new("Flip Horizontal")
.id("flip-h")
.accelerator("Shift+H")
.build(app)?,
)
.item(
&MenuItemBuilder::new("Flip Vertical")
.id("flip-v")
.accelerator("Shift+V")
.build(app)?,
)
.build()?;
let window_menu = SubmenuBuilder::new(app, "Window")
.item(&PredefinedMenuItem::minimize(app, None)?)
.item(&PredefinedMenuItem::maximize(app, None)?)
.separator()
.item(&PredefinedMenuItem::close_window(app, None)?)
.build()?;
let help_menu = SubmenuBuilder::new(app, "Help")
.item(
&MenuItemBuilder::new("Keyboard Shortcuts")
.id("shortcuts")
.accelerator("CmdOrCtrl+/")
.build(app)?,
)
.build()?;
let menu = MenuBuilder::new(app)
.items(&[
&app_menu,
&file_menu,
&edit_menu,
&view_menu,
&object_menu,
&window_menu,
&help_menu,
])
.build()?;
app.set_menu(menu)?;
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}