1use std::collections::HashMap;
4use tauri::menu::*;
5use tauri::{AppHandle, Runtime};
6
7pub fn build_native_menu_bar<R: Runtime>(
9 handle: &AppHandle<R>,
10 strings: &HashMap<String, String>,
11) -> Result<Menu<R>, tauri::Error> {
12 let t = |key: &str, fallback: &str| -> String {
13 strings
14 .get(key)
15 .map(|s| s.as_str())
16 .filter(|s| !s.is_empty())
17 .unwrap_or(fallback)
18 .to_string()
19 };
20
21 let about_title = t("menu.about", "About AUDIO_HAXOR");
23 let app_about = PredefinedMenuItem::about(handle, Some(about_title.as_str()), None)?;
24 let app_sep1 = PredefinedMenuItem::separator(handle)?;
25 let app_prefs = MenuItem::with_id(
26 handle,
27 "open_prefs_app",
28 t("menu.preferences", "Preferences..."),
29 true,
30 Some("CmdOrCtrl+,"),
31 )?;
32 let app_sep2 = PredefinedMenuItem::separator(handle)?;
33 let app_services = PredefinedMenuItem::services(handle, None)?;
34 let app_sep3 = PredefinedMenuItem::separator(handle)?;
35 let app_hide = PredefinedMenuItem::hide(handle, None)?;
36 let app_hide_others = PredefinedMenuItem::hide_others(handle, None)?;
37 let app_show_all = PredefinedMenuItem::show_all(handle, None)?;
38 let app_sep4 = PredefinedMenuItem::separator(handle)?;
39 let app_quit = PredefinedMenuItem::quit(handle, None)?;
40
41 let app_menu = Submenu::with_id_and_items(
42 handle,
43 "app",
44 t("menu.app", "AUDIO_HAXOR"),
45 true,
46 &[
47 &app_about,
48 &app_sep1,
49 &app_prefs,
50 &app_sep2,
51 &app_services,
52 &app_sep3,
53 &app_hide,
54 &app_hide_others,
55 &app_show_all,
56 &app_sep4,
57 &app_quit,
58 ],
59 )?;
60
61 let scan_all = MenuItem::with_id(
63 handle,
64 "scan_all",
65 t("menu.scan_all", "Scan All"),
66 true,
67 Some("CmdOrCtrl+Shift+S"),
68 )?;
69 let stop_all = MenuItem::with_id(
70 handle,
71 "stop_all",
72 t("menu.stop_all", "Stop All"),
73 true,
74 Some("CmdOrCtrl+."),
75 )?;
76 let sep1 = PredefinedMenuItem::separator(handle)?;
77 let export_plugins = MenuItem::with_id(
78 handle,
79 "export_plugins",
80 t("menu.export_plugins", "Export Plugins..."),
81 true,
82 Some("CmdOrCtrl+E"),
83 )?;
84 let import_plugins = MenuItem::with_id(
85 handle,
86 "import_plugins",
87 t("menu.import_plugins", "Import Plugins..."),
88 true,
89 Some("CmdOrCtrl+I"),
90 )?;
91 let sep2 = PredefinedMenuItem::separator(handle)?;
92 let export_audio = MenuItem::with_id(
93 handle,
94 "export_audio",
95 t("menu.export_samples", "Export Samples..."),
96 true,
97 Some("CmdOrCtrl+Shift+E"),
98 )?;
99 let import_audio = MenuItem::with_id(
100 handle,
101 "import_audio",
102 t("menu.import_samples", "Import Samples..."),
103 true,
104 Some("CmdOrCtrl+Shift+I"),
105 )?;
106 let sep3 = PredefinedMenuItem::separator(handle)?;
107 let export_daw = MenuItem::with_id(
108 handle,
109 "export_daw",
110 t("menu.export_daw", "Export DAW Projects..."),
111 true,
112 Some("CmdOrCtrl+Shift+O"),
113 )?;
114 let import_daw = MenuItem::with_id(
115 handle,
116 "import_daw",
117 t("menu.import_daw", "Import DAW Projects..."),
118 true,
119 Some("CmdOrCtrl+Shift+J"),
120 )?;
121 let sep4 = PredefinedMenuItem::separator(handle)?;
122 let export_presets = MenuItem::with_id(
123 handle,
124 "export_presets",
125 t("menu.export_presets", "Export Presets..."),
126 true,
127 Some("CmdOrCtrl+Shift+Y"),
128 )?;
129 let import_presets = MenuItem::with_id(
130 handle,
131 "import_presets",
132 t("menu.import_presets", "Import Presets..."),
133 true,
134 Some("CmdOrCtrl+Shift+Z"),
135 )?;
136 let file_menu = Submenu::with_id_and_items(
137 handle,
138 "file",
139 t("menu.file", "File"),
140 true,
141 &[
142 &scan_all,
143 &stop_all,
144 &sep1,
145 &export_plugins,
146 &import_plugins,
147 &sep2,
148 &export_audio,
149 &import_audio,
150 &sep3,
151 &export_daw,
152 &import_daw,
153 &sep4,
154 &export_presets,
155 &import_presets,
156 ],
157 )?;
158
159 let edit_undo = PredefinedMenuItem::undo(handle, None)?;
161 let edit_redo = PredefinedMenuItem::redo(handle, None)?;
162 let edit_sep1 = PredefinedMenuItem::separator(handle)?;
163 let edit_cut = PredefinedMenuItem::cut(handle, None)?;
164 let edit_copy = PredefinedMenuItem::copy(handle, None)?;
165 let edit_paste = PredefinedMenuItem::paste(handle, None)?;
166 let edit_select_all = PredefinedMenuItem::select_all(handle, None)?;
167 let edit_sep2 = PredefinedMenuItem::separator(handle)?;
168 let find = MenuItem::with_id(
169 handle,
170 "find",
171 t("menu.find", "Find..."),
172 true,
173 Some("CmdOrCtrl+F"),
174 )?;
175
176 let edit_menu = Submenu::with_id_and_items(
177 handle,
178 "edit",
179 t("menu.edit", "Edit"),
180 true,
181 &[
182 &edit_undo,
183 &edit_redo,
184 &edit_sep1,
185 &edit_cut,
186 &edit_copy,
187 &edit_paste,
188 &edit_select_all,
189 &edit_sep2,
190 &find,
191 ],
192 )?;
193
194 let scan_plugins = MenuItem::with_id(
196 handle,
197 "scan_plugins",
198 t("menu.scan_plugins", "Scan Plugins"),
199 true,
200 Some("CmdOrCtrl+Shift+P"),
201 )?;
202 let scan_audio = MenuItem::with_id(
203 handle,
204 "scan_audio",
205 t("menu.scan_samples", "Scan Samples"),
206 true,
207 Some("CmdOrCtrl+Shift+A"),
208 )?;
209 let scan_daw = MenuItem::with_id(
210 handle,
211 "scan_daw",
212 t("menu.scan_daw", "Scan DAW Projects"),
213 true,
214 Some("CmdOrCtrl+Shift+D"),
215 )?;
216 let scan_presets = MenuItem::with_id(
217 handle,
218 "scan_presets",
219 t("menu.scan_presets", "Scan Presets"),
220 true,
221 Some("CmdOrCtrl+Shift+R"),
222 )?;
223 let scan_sep = PredefinedMenuItem::separator(handle)?;
224 let check_updates = MenuItem::with_id(
225 handle,
226 "check_updates",
227 t("menu.check_updates", "Check Updates"),
228 true,
229 Some("CmdOrCtrl+U"),
230 )?;
231
232 let scan_menu = Submenu::with_id_and_items(
233 handle,
234 "scan",
235 t("menu.scan", "Scan"),
236 true,
237 &[
238 &scan_plugins,
239 &scan_audio,
240 &scan_daw,
241 &scan_presets,
242 &scan_sep,
243 &check_updates,
244 ],
245 )?;
246
247 let tab_plugins = MenuItem::with_id(
249 handle,
250 "tab_plugins",
251 t("menu.tab_plugins", "Plugins"),
252 true,
253 Some("CmdOrCtrl+1"),
254 )?;
255 let tab_samples = MenuItem::with_id(
256 handle,
257 "tab_samples",
258 t("menu.tab_samples", "Samples"),
259 true,
260 Some("CmdOrCtrl+2"),
261 )?;
262 let tab_daw = MenuItem::with_id(
263 handle,
264 "tab_daw",
265 t("menu.tab_daw", "DAW Projects"),
266 true,
267 Some("CmdOrCtrl+3"),
268 )?;
269 let tab_presets = MenuItem::with_id(
270 handle,
271 "tab_presets",
272 t("menu.tab_presets", "Presets"),
273 true,
274 Some("CmdOrCtrl+4"),
275 )?;
276 let tab_favorites = MenuItem::with_id(
277 handle,
278 "tab_favorites",
279 t("menu.tab_favorites", "Favorites"),
280 true,
281 Some("CmdOrCtrl+5"),
282 )?;
283 let tab_notes = MenuItem::with_id(
284 handle,
285 "tab_notes",
286 t("menu.tab_notes", "Notes"),
287 true,
288 Some("CmdOrCtrl+6"),
289 )?;
290 let tab_history = MenuItem::with_id(
291 handle,
292 "tab_history",
293 t("menu.tab_history", "History"),
294 true,
295 Some("CmdOrCtrl+7"),
296 )?;
297 let tab_settings = MenuItem::with_id(
298 handle,
299 "tab_settings",
300 t("menu.tab_settings", "Settings"),
301 true,
302 Some("CmdOrCtrl+8"),
303 )?;
304 let tab_files = MenuItem::with_id(
305 handle,
306 "tab_files",
307 t("menu.tab_files", "Files"),
308 true,
309 Some("CmdOrCtrl+9"),
310 )?;
311 let tab_audio_engine = MenuItem::with_id(
312 handle,
313 "tab_audio_engine",
314 t("menu.tab_audio_engine", "Audio Engine"),
315 true,
316 Some("CmdOrCtrl+F6"),
317 )?;
318 let view_sep = PredefinedMenuItem::separator(handle)?;
319 let toggle_theme = MenuItem::with_id(
320 handle,
321 "toggle_theme",
322 t("menu.toggle_theme", "Toggle Light/Dark"),
323 true,
324 Some("CmdOrCtrl+T"),
325 )?;
326 let toggle_crt = MenuItem::with_id(
327 handle,
328 "toggle_crt",
329 t("menu.toggle_crt", "Toggle CRT Effects"),
330 true,
331 Some("F1"),
332 )?;
333 let view_sep2 = PredefinedMenuItem::separator(handle)?;
334 let reset_columns = MenuItem::with_id(
335 handle,
336 "reset_columns",
337 t("menu.reset_columns", "Reset Column Widths"),
338 true,
339 Some("CmdOrCtrl+Shift+W"),
340 )?;
341 let reset_tabs = MenuItem::with_id(
342 handle,
343 "reset_tabs",
344 t("menu.reset_tabs", "Reset Tab Order"),
345 true,
346 Some("CmdOrCtrl+Shift+T"),
347 )?;
348
349 let view_menu = Submenu::with_id_and_items(
350 handle,
351 "view",
352 t("menu.view", "View"),
353 true,
354 &[
355 &tab_plugins,
356 &tab_samples,
357 &tab_daw,
358 &tab_presets,
359 &tab_favorites,
360 &tab_notes,
361 &tab_history,
362 &tab_settings,
363 &tab_files,
364 &tab_audio_engine,
365 &view_sep,
366 &toggle_theme,
367 &toggle_crt,
368 &view_sep2,
369 &reset_columns,
370 &reset_tabs,
371 ],
372 )?;
373
374 let play_pause = MenuItem::with_id(
376 handle,
377 "play_pause",
378 t("menu.play_pause", "Play / Pause"),
379 true,
380 Some("Space"),
381 )?;
382 let toggle_loop = MenuItem::with_id(
383 handle,
384 "toggle_loop",
385 t("menu.toggle_loop", "Toggle Loop"),
386 true,
387 Some("CmdOrCtrl+L"),
388 )?;
389 let stop_playback = MenuItem::with_id(
390 handle,
391 "stop_playback",
392 t("menu.stop_playback", "Stop Playback"),
393 true,
394 Some("CmdOrCtrl+Shift+."),
395 )?;
396 let expand_player = MenuItem::with_id(
397 handle,
398 "expand_player",
399 t("menu.expand_player", "Expand / Collapse Player"),
400 true,
401 Some("CmdOrCtrl+Shift+M"),
402 )?;
403
404 let next_track = MenuItem::with_id(
405 handle,
406 "next_track",
407 t("menu.next_track", "Next Track"),
408 true,
409 Some("CmdOrCtrl+Right"),
410 )?;
411 let prev_track = MenuItem::with_id(
412 handle,
413 "prev_track",
414 t("menu.prev_track", "Previous Track"),
415 true,
416 Some("CmdOrCtrl+Left"),
417 )?;
418 let toggle_shuffle = MenuItem::with_id(
419 handle,
420 "toggle_shuffle",
421 t("menu.toggle_shuffle", "Toggle Shuffle"),
422 true,
423 Some("S"),
424 )?;
425 let toggle_mute = MenuItem::with_id(
426 handle,
427 "toggle_mute",
428 t("menu.toggle_mute", "Mute / Unmute"),
429 true,
430 Some("M"),
431 )?;
432 let playback_sep = PredefinedMenuItem::separator(handle)?;
433
434 let playback_menu = Submenu::with_id_and_items(
435 handle,
436 "playback",
437 t("menu.playback", "Playback"),
438 true,
439 &[
440 &play_pause,
441 &stop_playback,
442 &playback_sep,
443 &next_track,
444 &prev_track,
445 &toggle_loop,
446 &toggle_shuffle,
447 &toggle_mute,
448 &playback_sep,
449 &expand_player,
450 ],
451 )?;
452
453 let clear_history = MenuItem::with_id(
455 handle,
456 "clear_history",
457 t("menu.clear_history", "Clear All History..."),
458 true,
459 Some("CmdOrCtrl+Shift+Delete"),
460 )?;
461 let clear_all_databases = MenuItem::with_id(
462 handle,
463 "clear_all_databases",
464 t("menu.clear_all_databases", "Clear All Databases"),
465 true,
466 Some("CmdOrCtrl+Shift+Alt+D"),
467 )?;
468 let clear_kvr = MenuItem::with_id(
469 handle,
470 "clear_kvr",
471 t("menu.clear_kvr", "Clear KVR Cache..."),
472 true,
473 Some("CmdOrCtrl+Shift+Alt+K"),
474 )?;
475 let clear_favorites = MenuItem::with_id(
476 handle,
477 "clear_favorites",
478 t("menu.clear_favorites", "Clear Favorites..."),
479 true,
480 Some("CmdOrCtrl+Shift+Alt+F"),
481 )?;
482
483 let reset_all = MenuItem::with_id(
484 handle,
485 "reset_all",
486 t("menu.reset_all_scans", "Reset All Scans..."),
487 true,
488 Some("CmdOrCtrl+Shift+Backspace"),
489 )?;
490 let data_sep = PredefinedMenuItem::separator(handle)?;
491 let find_duplicates = MenuItem::with_id(
492 handle,
493 "find_duplicates",
494 t("menu.find_duplicates", "Find Duplicates"),
495 true,
496 Some("CmdOrCtrl+D"),
497 )?;
498 let dep_graph = MenuItem::with_id(
499 handle,
500 "dep_graph",
501 t("menu.dep_graph", "Dependency Graph"),
502 true,
503 Some("CmdOrCtrl+G"),
504 )?;
505 let cmd_palette = MenuItem::with_id(
506 handle,
507 "cmd_palette",
508 t("menu.cmd_palette", "Command Palette"),
509 true,
510 Some("CmdOrCtrl+K"),
511 )?;
512 let help_overlay = MenuItem::with_id(
513 handle,
514 "help_overlay",
515 t("menu.help_overlay", "Keyboard Shortcuts"),
516 true,
517 Some("CmdOrCtrl+Shift+/"),
518 )?;
519
520 let data_menu = Submenu::with_id_and_items(
521 handle,
522 "data",
523 t("menu.data", "Data"),
524 true,
525 &[
526 &clear_history,
527 &clear_all_databases,
528 &clear_kvr,
529 &clear_favorites,
530 &data_sep,
531 &reset_all,
532 ],
533 )?;
534
535 let tools_menu = Submenu::with_id_and_items(
536 handle,
537 "tools",
538 t("menu.tools", "Tools"),
539 true,
540 &[
541 &find_duplicates,
542 &dep_graph,
543 &data_sep,
544 &cmd_palette,
545 &help_overlay,
546 ],
547 )?;
548
549 let minimize = PredefinedMenuItem::minimize(handle, None)?;
551 let zoom = PredefinedMenuItem::maximize(handle, None)?;
552 let win_sep = PredefinedMenuItem::separator(handle)?;
553 let close_win = PredefinedMenuItem::close_window(handle, None)?;
554
555 let window_menu = Submenu::with_id_and_items(
556 handle,
557 "window",
558 t("menu.window", "Window"),
559 true,
560 &[&minimize, &zoom, &win_sep, &close_win],
561 )?;
562
563 let github = MenuItem::with_id(
565 handle,
566 "github",
567 t("menu.github", "GitHub Repository"),
568 true,
569 Some("CmdOrCtrl+Shift+G"),
570 )?;
571 let docs = MenuItem::with_id(
572 handle,
573 "docs",
574 t("menu.docs", "Documentation"),
575 true,
576 Some("CmdOrCtrl+Shift+Alt+P"),
577 )?;
578
579 let help_menu = Submenu::with_id_and_items(
580 handle,
581 "help",
582 t("menu.help", "Help"),
583 true,
584 &[&github, &docs],
585 )?;
586
587 Menu::with_items(
588 handle,
589 &[
590 &app_menu,
591 &file_menu,
592 &edit_menu,
593 &scan_menu,
594 &view_menu,
595 &playback_menu,
596 &data_menu,
597 &tools_menu,
598 &window_menu,
599 &help_menu,
600 ],
601 )
602}