Move menu definitions to YAML file

This commit is contained in:
Keith Edmunds 2025-02-21 14:16:34 +00:00
parent aef8cb5cb5
commit afd3be608c
2 changed files with 171 additions and 92 deletions

View File

@ -10,6 +10,7 @@ import subprocess
import sys
import urllib.parse
import webbrowser
import yaml
# PyQt imports
from PyQt6.QtCore import (
@ -38,6 +39,7 @@ from PyQt6.QtWidgets import (
QLineEdit,
QListWidgetItem,
QMainWindow,
QMenu,
QMessageBox,
QPushButton,
QVBoxLayout,
@ -475,104 +477,77 @@ class Window(QMainWindow):
return action
def create_menu_bar(self):
"""Dynamically creates the menu bar from a YAML file."""
menu_bar = self.menuBar()
# File Menu
file_menu = menu_bar.addMenu("&File")
file_menu.addAction(
self.create_action("Open Playlist", self.open_playlist, "Ctrl+O")
)
file_menu.addAction(self.create_action("New Playlist", self.new_playlist))
file_menu.addAction(
self.create_action("Close Playlist", self.close_playlist_tab)
)
file_menu.addAction(self.create_action("Rename Playlist", self.rename_playlist))
file_menu.addAction(self.create_action("Delete Playlist", self.delete_playlist))
file_menu.addSeparator()
file_menu.addAction(
self.create_action("Save as Template", self.save_as_template)
)
file_menu.addAction(
self.create_action("Manage Templates", self.manage_templates)
)
file_menu.addSeparator()
file_menu.addAction(
self.create_action(
"Import Files", self.import_files_wrapper, "Ctrl+Shift+I"
)
)
file_menu.addSeparator()
file_menu.addAction(self.create_action("Exit", self.close))
# Load menu structure from YAML file
with open("menu.yaml", "r") as file:
menu_data = yaml.safe_load(file)
# Playlist Menu
playlist_menu = menu_bar.addMenu("&Playlist")
playlist_menu.addSeparator()
playlist_menu.addAction(
self.create_action("Insert Track", self.insert_track, "Ctrl+T")
)
playlist_menu.addAction(
self.create_action("Insert Section Header", self.insert_header, "Ctrl+H")
)
playlist_menu.addSeparator()
playlist_menu.addAction(
self.create_action("Mark for Moving", self.mark_rows_for_moving, "Ctrl+C")
)
playlist_menu.addAction(self.create_action("Paste", self.paste_rows, "Ctrl+V"))
playlist_menu.addSeparator()
playlist_menu.addAction(
self.create_action("Export Playlist", self.export_playlist_tab)
)
playlist_menu.addAction(
self.create_action(
"Download CSV of Played Tracks", self.download_played_tracks
)
)
playlist_menu.addSeparator()
playlist_menu.addAction(
self.create_action(
"Select Duplicate Rows",
lambda: self.active_tab().select_duplicate_rows(),
)
)
playlist_menu.addAction(self.create_action("Move Selected", self.move_selected))
playlist_menu.addAction(self.create_action("Move Unplayed", self.move_unplayed))
# Store references for enabling/disabling actions later
self.menu_actions = {}
# Clear Selection with Escape key. Save in module so we can
# enable/disable it later
self.action_Clear_selection = self.create_action(
"Clear Selection", self.clear_selection, "Esc"
)
playlist_menu.addAction(self.action_Clear_selection)
for menu_item in menu_data["menus"]:
menu = menu_bar.addMenu(menu_item["title"])
# Music Menu
music_menu = menu_bar.addMenu("&Music")
music_menu.addAction(
self.create_action("Set Next", self.set_selected_track_next, "Ctrl+N")
)
music_menu.addAction(self.create_action("Play Next", self.play_next, "Return"))
music_menu.addAction(self.create_action("Fade", self.fade, "Ctrl+Z"))
music_menu.addAction(self.create_action("Stop", self.stop, "Ctrl+Alt+S"))
music_menu.addAction(self.create_action("Resume", self.resume, "Ctrl+R"))
music_menu.addAction(
self.create_action("Skip to Next", self.play_next, "Ctrl+Alt+Return")
)
music_menu.addSeparator()
music_menu.addAction(self.create_action("Search", self.search_playlist, "/"))
music_menu.addAction(
self.create_action(
"Search Title in Wikipedia", self.lookup_row_in_wikipedia, "Ctrl+W"
)
)
music_menu.addAction(
self.create_action(
"Search Title in Songfacts", self.lookup_row_in_songfacts, "Ctrl+S"
)
)
for action_item in menu_item["actions"]:
if "separator" in action_item and action_item["separator"]:
menu.addSeparator()
continue
# Help Menu
help_menu = menu_bar.addMenu("Help")
help_menu.addAction(self.create_action("About", self.about))
help_menu.addAction(self.create_action("Debug", self.debug))
# Handle external function calls via lambda
if action_item.get("use_lambda"):
handler = lambda: self.active_tab().select_duplicate_rows() # ✅ Keeps lambda logic
else:
handler = getattr(self, action_item["handler"], None)
if handler is None:
print(f"Warning: No handler found for {action_item['text']}")
continue # Skip adding the action if the handler is missing
action = self.create_action(
action_item["text"], handler, action_item.get("shortcut")
)
if action_item.get("store_reference"):
self.menu_actions[action_item["handler"]] = action # Store reference
menu.addAction(action)
# Handle dynamic submenu
if action_item.get("submenu"):
submenu = QMenu(action_item["text"], self)
action.setMenu(submenu)
menu.addMenu(submenu)
# Store submenu reference for dynamic population
self.dynamic_submenus = getattr(self, "dynamic_submenus", {})
self.dynamic_submenus[action_item["handler"]] = submenu
# Connect submenu aboutToShow signal to population function
submenu.aboutToShow.connect(self.populate_dynamic_submenu)
def populate_dynamic_submenu(self):
"""Dynamically populates the submenu when selected."""
submenu = self.dynamic_submenus["populate_dynamic_submenu"]
submenu.clear() # Remove previous items
# Example: Populate submenu with dynamically generated items
items = self.get_dynamic_menu_items() # Assume this method provides a list of items
for item in items:
action = QAction(item["text"], self)
action.triggered.connect(lambda _, i=item["handler"]: getattr(self, i)())
submenu.addAction(action)
def get_dynamic_menu_items(self):
"""Returns dynamically generated menu items (replace with real logic)."""
return [
{"text": "Dynamic Option 1", "handler": "dynamic_option_1"},
{"text": "Dynamic Option 2", "handler": "dynamic_option_2"},
{"text": "Dynamic Option 3", "handler": "dynamic_option_3"},
]
def about(self) -> None:
"""Get git tag and database name"""

104
menu.yaml Normal file
View File

@ -0,0 +1,104 @@
menus:
- title: "&File"
actions:
- text: "Open Playlist"
handler: "open_playlist"
shortcut: "Ctrl+O"
- text: "New Playlist"
handler: "new_playlist"
- text: "Close Playlist"
handler: "close_playlist_tab"
- text: "Rename Playlist"
handler: "rename_playlist"
- text: "Delete Playlist"
handler: "delete_playlist"
- separator: true
- text: "Save as Template"
handler: "save_as_template"
- text: "Manage Templates"
handler: "manage_templates"
- separator: true
- text: "Import Files"
handler: "import_files_wrapper"
shortcut: "Ctrl+Shift+I"
- separator: true
- text: "Dynamic Submenu"
handler: "populate_dynamic_submenu"
submenu: true
- separator: true
- text: "Exit"
handler: "close"
- title: "&Playlist"
actions:
- separator: true
- text: "Insert Track"
handler: "insert_track"
shortcut: "Ctrl+T"
- text: "Insert Section Header"
handler: "insert_header"
shortcut: "Ctrl+H"
- separator: true
- text: "Mark for Moving"
handler: "mark_rows_for_moving"
shortcut: "Ctrl+C"
- text: "Paste"
handler: "paste_rows"
shortcut: "Ctrl+V"
- separator: true
- text: "Export Playlist"
handler: "export_playlist_tab"
- text: "Download CSV of Played Tracks"
handler: "download_played_tracks"
- separator: true
- text: "Select Duplicate Rows"
handler: "select_duplicate_rows"
use_lambda: true
- text: "Move Selected"
handler: "move_selected"
- text: "Move Unplayed"
handler: "move_unplayed"
- separator: true
- text: "Clear Selection"
handler: "clear_selection"
shortcut: "Esc"
store_reference: true # So we can enable/disable later
- title: "&Music"
actions:
- text: "Set Next"
handler: "set_selected_track_next"
shortcut: "Ctrl+N"
- text: "Play Next"
handler: "play_next"
shortcut: "Return"
- text: "Fade"
handler: "fade"
shortcut: "Ctrl+Z"
- text: "Stop"
handler: "stop"
shortcut: "Ctrl+Alt+S"
- text: "Resume"
handler: "resume"
shortcut: "Ctrl+R"
- text: "Skip to Next"
handler: "play_next"
shortcut: "Ctrl+Alt+Return"
- separator: true
- text: "Search"
handler: "search_playlist"
shortcut: "/"
- text: "Search Title in Wikipedia"
handler: "lookup_row_in_wikipedia"
shortcut: "Ctrl+W"
- text: "Search Title in Songfacts"
handler: "lookup_row_in_songfacts"
shortcut: "Ctrl+S"
- title: "Help"
actions:
- text: "About"
handler: "about"
- text: "Debug"
handler: "debug"