diff --git a/dzgui/const/enum.py b/dzgui/const/enum.py index 798b855..fffb8b2 100644 --- a/dzgui/const/enum.py +++ b/dzgui/const/enum.py @@ -311,6 +311,7 @@ class ContextMenu(EnumWithAttrs): OPEN_WORKSHOP = {"label": strings.open_workshop} DELETE_MOD = {"label": strings.delete_mod} COPY_LOG_CLIPBOARD = {"label": strings.copy_log} + CONNECT = {"label": strings.connect} class ContextMenuGroup(Enum): @@ -324,6 +325,7 @@ class ContextMenuGroup(Enum): ContextMenu.COPY_LOG_CLIPBOARD, ) SERVER_BROWSER = ( + ContextMenu.CONNECT, ContextMenu.ADD_SERVER, ContextMenu.COPY_NAME, ContextMenu.COPY_CLIPBOARD, @@ -333,6 +335,7 @@ class ContextMenuGroup(Enum): ContextMenu.REFRESH_PLAYERS, ) SCAN_LAN = ( + ContextMenu.CONNECT, ContextMenu.COPY_NAME, ContextMenu.COPY_CLIPBOARD, ContextMenu.ADD_NOTE, @@ -341,6 +344,7 @@ class ContextMenuGroup(Enum): ContextMenu.REFRESH_PLAYERS, ) SAVED = ( + ContextMenu.CONNECT, ContextMenu.REMOVE_SERVER, ContextMenu.COPY_NAME, ContextMenu.COPY_CLIPBOARD, @@ -350,6 +354,7 @@ class ContextMenuGroup(Enum): ContextMenu.REFRESH_PLAYERS, ) RECENT = ( + ContextMenu.CONNECT, ContextMenu.ADD_SERVER, ContextMenu.REMOVE_HISTORY, ContextMenu.COPY_NAME, @@ -360,22 +365,6 @@ class ContextMenuGroup(Enum): ContextMenu.REFRESH_PLAYERS, ) - -HELP_MENU_ROWS = ( - RowType.CHANGELOG, - RowType.SHOW_LOG, - RowType.DUMP_LOG, - RowType.SEPARATOR, - RowType.DOCS, - RowType.DOCS_FALLBACK, - RowType.BUGS, - RowType.FORUM, - RowType.SPONSOR, - RowType.SEPARATOR, - RowType.THANKS, -) - - class ModButton(EnumWithAttrs): SELECT_ALL = { "label": strings.mod_panel.select_all, @@ -429,3 +418,18 @@ class ButtonType(EnumWithAttrs): "tooltip": strings.buttons.exit_tooltip, "opens": None, } + + +HELP_MENU_ROWS = ( + RowType.CHANGELOG, + RowType.SHOW_LOG, + RowType.DUMP_LOG, + RowType.SEPARATOR, + RowType.DOCS, + RowType.DOCS_FALLBACK, + RowType.BUGS, + RowType.FORUM, + RowType.SPONSOR, + RowType.SEPARATOR, + RowType.THANKS, +) diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index f71cc55..ae1174d 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -68,7 +68,7 @@ class Controller: def set_help_menu_crumbs(self) -> None: # TODO: going to be deprecated after server notebook is added - tip = self.mediator.treeview.get_model()[0][0] + tip = self.mediator.menu.get_model()[0][0] store = self.model_manager.get_help_store()[0][0] if tip == store: self.set_crumbs("Help") @@ -79,8 +79,17 @@ class Controller: def get_crumbs(self) -> str: return self.mediator.grid.get_breadcrumbs() - #def get_row_store(self) -> Gtk.ListStore: - # return self.model_manager.get_row_store() + def get_server_store(self) -> Gtk.ListStore: + return self.model_manager.get_server_store() + + def get_saved_store(self) -> Gtk.ListStore: + return self.model_manager.get_saved_store() + + def get_recent_store(self) -> Gtk.ListStore: + return self.model_manager.get_recent_store() + + def get_lan_store(self) -> Gtk.ListStore: + return self.model_manager.get_lan_store() def get_help_store(self) -> Gtk.ListStore: return self.model_manager.get_help_store() @@ -137,12 +146,12 @@ class Controller: state, ) self.suppress_signal( - self.mediator.treeview, - self.mediator.treeview.selected_row, + self.mediator.menu, + self.mediator.menu.selected_row, "_on_tree_selection_changed", state, ) - self.suppress_signal(self.mediator.treeview, self.mediator.treeview, "_on_keypress", state) + self.suppress_signal(self.mediator.menu, self.mediator.menu, "_on_keypress", state) for check in self.mediator.grid.right_panel.filters_vbox.checks: self.suppress_signal( self.mediator.grid.right_panel.filters_vbox, @@ -161,7 +170,7 @@ class Controller: else: widget.handler_unblock_by_func(func) # TODO - #self.mediator.treeview.sel_blocked = state + #self.mediator.menu.sel_blocked = state def toggle_debug_mode(self) -> None: self.toggle_config(Preferences.DEBUG) @@ -278,7 +287,6 @@ class Controller: self.mediator.grid.notebook.set_page_by_enum(page) def open_page_by_button(self, button: "ContextualButton") -> None: - print(button.context) match button.context: case ButtonType.EXIT: logger.info("Normal user exit") @@ -289,9 +297,7 @@ class Controller: case ButtonType.MODS: self.load_mods() case ButtonType.HELP: - help_store = self.model_manager.get_help_store() - # TODO: simply set this model once and open the page - self.mediator.treeview.set_model(help_store) + pass case ButtonType.SERVERS: self.mediator.notebook.set_page_by_enum(button.opens) # TODO: shorten this diff --git a/dzgui/controllers/model.py b/dzgui/controllers/model.py index f401c67..7550a1c 100644 --- a/dzgui/controllers/model.py +++ b/dzgui/controllers/model.py @@ -76,9 +76,10 @@ class ModelManager: self.log_store = self.new_model_from_class(LogCols) self.modlist_store = self.new_model_from_class(ServerModCols) - #for row in MAIN_MENU_ROWS: - # label = row.dict["label"] - # self.row_store.append([label, row]) + self.server_store = self.new_model() + self.saved_store = self.new_model() + self.recent_store = self.new_model() + self.lan_store = self.new_model() for row in HELP_MENU_ROWS: label = row.dict["label"] @@ -93,6 +94,18 @@ class ModelManager: cls.instance = super(ModelManager, cls).__new__(cls) return cls.instance + def get_recent_store(self) -> ListStore: + return self.recent_store + + def get_lan_store(self) -> ListStore: + return self.lan_store + + def get_saved_store(self) -> ListStore: + return self.saved_store + + def get_server_store(self) -> ListStore: + return self.server_store + def new_model_from_class(self, cls: type) -> ListStore: store = ListStore(*[ftype for field, ftype in cls.__annotations__.items()]) return store diff --git a/dzgui/util/keys.py b/dzgui/util/keys.py index bf8c363..04f291d 100644 --- a/dzgui/util/keys.py +++ b/dzgui/util/keys.py @@ -19,8 +19,7 @@ def is_navkey(key: int) -> bool: return False def is_ctrl_mask(event: Gdk.EventKey) -> bool: - if event.keyval is Gdk.KEY_l \ - and event.state is Gdk.ModifierType.CONTROL_MASK: - return True + if event.state is Gdk.ModifierType.CONTROL_MASK: + return True else: return False diff --git a/dzgui/util/strings.py b/dzgui/util/strings.py index de3f55c..c1eefc3 100644 --- a/dzgui/util/strings.py +++ b/dzgui/util/strings.py @@ -53,8 +53,9 @@ copy_name = "Copy name to clipboard" copy_ip = "Copy IP to clipboard" copy_log = "Copy record(s) to clipboard" add = "Add to my servers" -remove = "Remove from my servers" +remove = "Remove from Saved Servers" remove_history = "Remove from history" +connect = "Connect" # Columns server_mod_cols = ["Mod", "ID", "Installed"] @@ -496,3 +497,17 @@ developers = DevelopersPage( prefs_label="Boot preferences", columns=["Key", "Value"] ) + +@dataclass(slots=True, frozen=True) +class ServerLabels: + browser: str + saved: str + recent: str + lan: str + +server_labels = ServerLabels( + browser="Server Browser", + saved="Saved Servers", + recent="Recent", + lan="LAN", +) diff --git a/dzgui/views/base.py b/dzgui/views/base.py index c4418c6..a3c5f08 100644 --- a/dzgui/views/base.py +++ b/dzgui/views/base.py @@ -47,6 +47,7 @@ from dzgui.views.dialogs.generic import GenericDialog from dzgui.views.mixins.scrollable_mixin import ScrollableMixin # TREES +from dzgui.views.trees.tree_menu import MenuTreeView from dzgui.views.trees.tree_log import LogTreeView from dzgui.views.trees.tree_mods import ModTreeView from dzgui.views.trees.tree_servers import ServerTreeView @@ -308,21 +309,17 @@ class Notebook(ScrollableMixin, Gtk.Notebook): AppNav.notebook = self self.prior_page: int - # TODO: set static help page - #self.scrollable_treelist = ScrollableTree() - #self.scrollable_treelist.set_hexpand(False) - #self.scrollable_treelist.set_vexpand(True) - #self.scrollable_treelist.type = None + from dzgui.views.pages.help import Help + self.help = Help(MainController) + view = self.help.get_treeview() + AppNav.menu = view self.change = Changelog(MainController) self.clog = ScrollableNote(self.change, back_button=False) self.clog.scrollable.set_propagate_natural_width(False) - self.clog.type = RowType.CHANGELOG # TODO: scrollable internally self.keys = ScrollableNote(Keybindings()) - self.keys.type = RowType.KEYBINDINGS - self.settings = Options(MainController) # TODO: make all treeviews internally scrollable in base class @@ -354,6 +351,7 @@ class Notebook(ScrollableMixin, Gtk.Notebook): self.developers = ScrollableNote(developers) self.pages = { + self.help: NotebookPage.HELP, #self.scrollable_treelist: NotebookPage.MAIN, self.clog: NotebookPage.CHANGELOG, self.keys: NotebookPage.KEYS, @@ -452,14 +450,21 @@ class Notebook(ScrollableMixin, Gtk.Notebook): def focus_current(self) -> None: widget = self.get_page() - if widget: - w = widget.get_children()[0] - # NOTE: if item contains treeview, focus first cell - try: - w.focus_first_row() - w.grab_focus() - except Exception as e: - w.grab_focus() + if widget is None: + return + + if widget is self.servers: + view = self.servers.get_active_treeview() + view.grab_focus() + return + + w = widget.get_children()[0] + # NOTE: if item contains treeview, focus first cell + try: + w.focus_first_row() + w.grab_focus() + except Exception as e: + w.grab_focus() def get_page(self) -> Gtk.Widget | None: ind = self.get_current_page() @@ -491,13 +496,10 @@ class Notebook(ScrollableMixin, Gtk.Notebook): is_mods = True if enum is NotebookPage.MODS else False MainController.toggle_mod_panel(is_mods) + # TODO: crumbs = enum.dict["crumbs"] MainController.set_crumbs(crumbs) - # TODO: - # MainController.set_help_menu_crumbs() - - # TODO: move to components class Statusbar(Gtk.Statusbar): def __init__(self) -> None: @@ -570,6 +572,9 @@ class Grid(Gtk.Grid): AppNav.grid = self + self.breadcrumbs = Gtk.Label(halign=Gtk.Align.START) + self.set_breadcrumbs(strings.label_main_menu) + # FIXME: do not pass AppNav to right panel self.right_panel = RightPanel(AppNav, MainController) self.sel_panel = ModSelectionPanel(MainController) @@ -578,8 +583,6 @@ class Grid(Gtk.Grid): self.notebook = Notebook() self.statusbar = Statusbar() - self.breadcrumbs = Gtk.Label(halign=Gtk.Align.START) - self.set_breadcrumbs(strings.label_main_menu) self.attach(self.notebook, 0, 0, 3, 1) self.attach_next_to( @@ -649,7 +652,7 @@ class AppNavigation: window: OuterWindow notebook: Notebook right_panel: RightPanel - #treeview: MenuTreeView + menu: MenuTreeView servers: Gtk.ScrolledWindow browser: ServerTreeView saved: ServerTreeView diff --git a/dzgui/views/components/buttonbox.py b/dzgui/views/components/buttonbox.py index fefce37..65931c9 100644 --- a/dzgui/views/components/buttonbox.py +++ b/dzgui/views/components/buttonbox.py @@ -54,11 +54,13 @@ class ButtonBox(Gtk.Box): def _on_selection_button_clicked(self, button: Gtk.Button) -> None: + # # TODO: maybe drop this and just ensure buttons respond correctly self.controller.open_page_by_button(button) - button.set_sensitive(False) - for b in self.buttons: - if b != button: - b.set_sensitive(True) + # if button.context != ButtonType.HELP: + # button.set_sensitive(False) + # for b in self.buttons: + # if b != button: + # b.set_sensitive(True) def _walk_buttons(self, increment: int) -> None: for i, button in enumerate(self.buttons): diff --git a/dzgui/views/trees/tree_menu.py b/dzgui/views/trees/tree_menu.py index 0b91ff3..4ca8774 100644 --- a/dzgui/views/trees/tree_menu.py +++ b/dzgui/views/trees/tree_menu.py @@ -29,8 +29,8 @@ class MenuTreeView(TreeView): column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) self.append_column(column) - row_store = self.controller.get_row_store() - self.set_model(row_store) + help_store = self.controller.get_help_store() + self.set_model(help_store) self.selected_row = self.get_selection() diff --git a/dzgui/views/trees/tree_servers.py b/dzgui/views/trees/tree_servers.py index 672c053..98dcaa7 100644 --- a/dzgui/views/trees/tree_servers.py +++ b/dzgui/views/trees/tree_servers.py @@ -8,6 +8,7 @@ from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa from dzgui.const.enum import ( ContextMenu, + ContextMenuGroup, RowType, ) from dzgui.const.constants import UDP_PORT @@ -29,6 +30,12 @@ if TYPE_CHECKING: # TODO: add multiprocessing queue # TODO: fix cache +class EnumeratedMenuItem(Gtk.MenuItem): + def __init__(self, enum: ContextMenu): + super().__init__(label=enum.dict["label"]) + self.enum = enum + + class ServerTreeView(TreeView): __gsignals__ = { "on_distcalc_started": (GObject.SignalFlags.RUN_FIRST, None, ()) @@ -36,6 +43,7 @@ class ServerTreeView(TreeView): def __init__(self, controller: "Controller") -> None: super().__init__(controller) + self.menu = Gtk.Menu() self.controller = controller self.set_fixed_height_mode(True) @@ -62,9 +70,6 @@ class ServerTreeView(TreeView): column.set_resizable(True) column.set_sort_column_id(i) - # TODO: use index of column instead of name - # so literal name won't matter - # needs conversion logic for old configs if valid_json: try: saved_size = data["cols"][column_title] @@ -81,11 +86,8 @@ class ServerTreeView(TreeView): self.append_column(column) self.connect("on_distcalc_started", self._on_calclat_started) - - self.connect("button-release-event", self._on_server_button_release) self.connect("key-press-event", self._on_server_keypress) - self.connect("generic_row_activated", self._parent_row_activated) self.connect("generic_treesel_changed", self._parent_selection_changed) @@ -150,6 +152,18 @@ class ServerTreeView(TreeView): case _: return False + def set_context_menu(self, items: ContextMenuGroup) -> None: + # TODO: if debug is on, add raw command + for item in items.value: + menu_item = EnumeratedMenuItem(item) + menu_item.connect("activate", self._on_menu_click) + self.menu.append(menu_item) + self.menu.show_all() + + def _on_menu_click(self, item) -> None: + print(item.enum) + pass + def _on_server_button_release( self, widget: Gtk.Widget, event: Gdk.EventButton ) -> None: @@ -168,69 +182,23 @@ class ServerTreeView(TreeView): except AttributeError: pass - self.menu = Gtk.Menu() mod_context_items = [ContextMenu.OPEN_WORKSHOP, ContextMenu.DELETE_MOD] - # TODO: reimplement server context enums - # TODO: inherit from tree_servers.py - server_context_items = { - RowType.SERVER_BROWSER: [ - ContextMenu.ADD_SERVER, - ContextMenu.COPY_NAME, - ContextMenu.COPY_CLIPBOARD, - ContextMenu.ADD_NOTE, - ContextMenu.SHOW_MODS, - ContextMenu.SHOW_DETAILS, - ContextMenu.REFRESH_PLAYERS, - ], - RowType.SCAN_LAN: [ - ContextMenu.COPY_NAME, - ContextMenu.COPY_CLIPBOARD, - ContextMenu.ADD_NOTE, - ContextMenu.SHOW_MODS, - ContextMenu.SHOW_DETAILS, - ContextMenu.REFRESH_PLAYERS, - ], - RowType.SAVED_SERVERS: [ - ContextMenu.REMOVE_SERVER, - ContextMenu.COPY_NAME, - ContextMenu.COPY_CLIPBOARD, - ContextMenu.ADD_NOTE, - ContextMenu.SHOW_MODS, - ContextMenu.SHOW_DETAILS, - ContextMenu.REFRESH_PLAYERS, - ], - RowType.RECENT_SERVERS: [ - ContextMenu.ADD_SERVER, - ContextMenu.REMOVE_HISTORY, - ContextMenu.COPY_NAME, - ContextMenu.ADD_NOTE, - ContextMenu.COPY_CLIPBOARD, - ContextMenu.SHOW_MODS, - ContextMenu.SHOW_DETAILS, - ContextMenu.REFRESH_PLAYERS, - ], - } - # TODO: how to get current server context - items = server_context_items[self.subpage] - - for row in items: - if row == ContextMenu.ADD_SERVER: - if self.is_in_favs(): - row = ContextMenu.REMOVE_SERVER - item = Gtk.MenuItem(label=row.dict["label"]) - item.type = row - item.action = row.dict["action"] - item.connect("activate", self._on_menu_click) - self.menu.append(item) - if row == ContextMenu.SHOW_MODS: - if not self.has_mods(): - item.set_sensitive(False) - if row == ContextMenu.ADD_NOTE: - if self.get_record_string() in notes_cache: - item.set_label(strings.edit_note) - - self.menu.show_all() + # TODO: dynamic menu entries + #for row in items: + # if row == ContextMenu.ADD_SERVER: + # if self.is_in_favs(): + # row = ContextMenu.REMOVE_SERVER + # item = Gtk.MenuItem(label=row.dict["label"]) + # item.type = row + # item.action = row.dict["action"] + # self.menu.append(item) + # if row == ContextMenu.SHOW_MODS: + # if not self.has_mods(): + # item.set_sensitive(False) + # if row == ContextMenu.ADD_NOTE: + # if self.get_record_string() in notes_cache: + # item.set_label(strings.edit_note) if event.type is Gdk.EventType.KEY_PRESS and event.keyval is Gdk.KEY_l: if self.is_selection_empty():