diff --git a/dzgui/const/enum.py b/dzgui/const/enum.py index 224a5b9..aa0dc9c 100644 --- a/dzgui/const/enum.py +++ b/dzgui/const/enum.py @@ -77,15 +77,15 @@ class Preferences(EnumWithAttrs): class NotebookPage(EnumWithAttrs): - CHANGELOG = {"crumbs": strings.crumbs.changelog,} - KEYS = {"crumbs": strings.crumbs.keys,} - LOG = {"crumbs": strings.crumbs.log,} - HELP = {"crumbs": strings.crumbs._help,} - MODS = {"crumbs": strings.crumbs.mods,} - OPTIONS = {"crumbs": strings.crumbs.options,} - SERVERS = {"crumbs": strings.crumbs.servers,} - THANKS = {"crumbs": strings.crumbs.thanks,} - DEVELOPERS = {"crumbs": strings.crumbs.developers,} + CHANGELOG = {"crumbs": strings.crumbs.changelog, "statusbar": False} + KEYS = {"crumbs": strings.crumbs.keys, "statusbar": False} + LOG = {"crumbs": strings.crumbs.log, "statusbar": False} + HELP = {"crumbs": strings.crumbs._help, "statusbar": True} + MODS = {"crumbs": strings.crumbs.mods, "statusbar": True} + OPTIONS = {"crumbs": strings.crumbs.options, "statusbar": False} + SERVERS = {"crumbs": strings.crumbs.servers, "statusbar": True} + THANKS = {"crumbs": strings.crumbs.thanks, "statusbar": False} + DEVELOPERS = {"crumbs": strings.crumbs.developers, "statusbar": False} class RowType(EnumWithAttrs): diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index 06e1a51..2d747f0 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -155,13 +155,6 @@ class Controller: def append_map(self, map_row: list) -> None: self.model_manager.append_map(map_row) - # TODO: drop - # def set_mediator(self, mediator: "AppNavigation") -> None: - # self.mediator = mediator - - # def get_mediator(self) -> "AppNavigation": - # return self.mediator - def unblock_signals(self) -> None: self.block_signals(False) @@ -643,6 +636,7 @@ class Controller: model = treeview.get_model() model.clear() data = func() + # TODO: threading model.append(data) treeview.set_loaded(True) self.update_server_status() @@ -656,3 +650,19 @@ class Controller: self.update_server_status() crumbs = self.mediator.servers.get_cached_label() self.set_crumbs(crumbs) + + def toggle_check(self, event: Gdk.EventKey) -> None: + keyname = Gdk.keyval_name(event.keyval) + if keyname.isnumeric() and int(keyname) > 0: + digit = int(keyname) - 1 + self.mediator.grid.right_panel.filters_vbox.toggle_check(digit) + else: + match event.keyval: + case Gdk.KEY_0: + self.mediator.grid.right_panel.filters_vbox.toggle_check(9) + case Gdk.KEY_minus: + self.mediator.grid.right_panel.filters_vbox.toggle_check(10) + case Gdk.KEY_backslash: + self.mediator.grid.right_panel.filters_vbox.toggle_check(11) + case _: + return False diff --git a/dzgui/util/keys.py b/dzgui/util/keys.py index 04f291d..4f20038 100644 --- a/dzgui/util/keys.py +++ b/dzgui/util/keys.py @@ -23,3 +23,22 @@ def is_ctrl_mask(event: Gdk.EventKey) -> bool: return True else: return False + +def is_filterkey(key: int) -> bool: + keys = ( + Gdk.KEY_0, + Gdk.KEY_1, + Gdk.KEY_2, + Gdk.KEY_3, + Gdk.KEY_4, + Gdk.KEY_5, + Gdk.KEY_6, + Gdk.KEY_7, + Gdk.KEY_8, + Gdk.KEY_9, + Gdk.KEY_backslash, + Gdk.KEY_minus, + ) + if key in keys: + return True + return False diff --git a/dzgui/views/base.py b/dzgui/views/base.py index 0376152..41919e4 100644 --- a/dzgui/views/base.py +++ b/dzgui/views/base.py @@ -277,27 +277,27 @@ class Notebook(ScrollableMixin, Gtk.Notebook): MainController.register_widget("notebook", self) self.help = Help(MainController) - self.change = Changelog(MainController) - self.clog = ScrollableNote(self.change, back_button=False) - self.clog.scrollable.set_propagate_natural_width(False) + self.clog = Changelog(MainController) - # TODO: scrollable internally # TODO: make all treeviews internally scrollable in base class - self.keys = ScrollableNote(Keybindings()) + self.keys = Keybindings() self.settings = Options(MainController) # NOTE: server and quad tables should have hexpand property set to True self.servers = ServerNotebook(MainController) self.mods = Mods(MainController) + # TODO: change this class to scrolledwindow self.scroll_log = Gtk.ScrolledWindow() self.scroll_log.set_hexpand(True) self.log_table = LogTreeView(MainController) self.scroll_log.add(self.log_table) + # TODO: change this class to scrolledwindow self.thanks = ScrollableNote(Thanks(), back_button=False) developers = Developers(MainController) + # TODO: change this class to scrolledwindow self.developers = ScrollableNote(developers) self.pages = { @@ -328,8 +328,6 @@ class Notebook(ScrollableMixin, Gtk.Notebook): self.connect("key-press-event", self._on_keypress) def _on_keypress(self, widget: Gtk.Widget, event: Gdk.EventKey) -> None: - page = self.get_page() - match event.keyval: case Gdk.KEY_Right | Gdk.KEY_l: if event.state is Gdk.ModifierType.CONTROL_MASK: @@ -338,23 +336,6 @@ class Notebook(ScrollableMixin, Gtk.Notebook): case Gdk.KEY_question: self.toggle_keybindings() - # NOTE: abort on non scrollable pages - # TODO: deprecated - #allowed = (NotebookPage.KEYS, NotebookPage.CHANGELOG, NotebookPage.THANKS) - #if self.pages[page] not in allowed: - # return - - # FIXME: may already be delegated to some pages (e.g. keys) - #match event.keyval: - # case Gdk.KEY_k | Gdk.KEY_Up: - # page._set_adjustment(VAdjustment.UP) - # case Gdk.KEY_Down | Gdk.KEY_j: - # page._set_adjustment(VAdjustment.DOWN) - # case Gdk.KEY_g: - # page._set_adjustment(VAdjustment.TOP) - # case Gdk.KEY_G: - # page._set_adjustment(VAdjustment.BOTTOM) - def return_prior(self) -> None: """ Gtk.Notebook focuses the first input field when changing pages; @@ -423,6 +404,7 @@ class Notebook(ScrollableMixin, Gtk.Notebook): enum = self.get_page_by_enum() if enum is not None: crumbs = enum.dict["crumbs"] + status = enum.dict["statusbar"] MainController.set_crumbs(crumbs) is_mods = True if enum is NotebookPage.MODS else False @@ -431,13 +413,10 @@ class Notebook(ScrollableMixin, Gtk.Notebook): MainController.toggle_mod_panel(is_mods) MainController.toggle_server_panels(is_servers) - match enum: - case NotebookPage.KEYS | NotebookPage.OPTIONS: - MainController.set_statusbar("") - case NotebookPage.SERVERS: - MainController.present_servers() - case _: - pass + if status is False: + MainController.set_statusbar("") + if enum is NotebookPage.SERVERS: + MainController.present_servers() class Grid(Gtk.Grid): @@ -459,7 +438,6 @@ class Grid(Gtk.Grid): self.notebook = Notebook() self.conpan = ConnectPanel() - self.attach(self.notebook, 0, 0, MAX_COLS, 1) els = ( diff --git a/dzgui/views/components/filter_panel.py b/dzgui/views/components/filter_panel.py index 623c7a7..ad51ac7 100644 --- a/dzgui/views/components/filter_panel.py +++ b/dzgui/views/components/filter_panel.py @@ -2,10 +2,11 @@ import logging import gi # noqa E402 gi.require_version("Gtk", "3.0") -from gi.repository import Gtk, Gdk, Pango +from gi.repository import Gtk, Gdk, Pango, GLib from typing import Literal from dzgui.util import strings +from dzgui.util.format import embolden from dzgui.util.margins import set_surrounding_margins from dzgui.const.enum import FilterMode from dzgui.const.constants import NO_EXPAND, NO_FILL, NO_PADDING @@ -71,8 +72,9 @@ class FilterPanel(Gtk.Box): self.set_margin_top(1) # TODO: strings - # TODO: embolden - self.filters_label = Gtk.Label(label="Filters") + text = embolden("Filters") + self.filters_label = Gtk.Label() + self.filters_label.set_markup(text) self.keyword_entry = Gtk.Entry() self.keyword_entry.set_placeholder_text("Filter by keyword") @@ -262,9 +264,6 @@ class FilterPanel(Gtk.Box): def _on_check_toggled(self, button: Gtk.CheckButton) -> None: treeview = self.controller.get_active_treeview() - # TODO: drop - if not treeview.is_server_context(self.AppNav.treeview.view): - return label = button.get_label() state = button.get_active() logger.info(f"User toggled button '{label}' to {state}") diff --git a/dzgui/views/mixins/scrollable_mixin.py b/dzgui/views/mixins/scrollable_mixin.py index 735c061..4d9e406 100644 --- a/dzgui/views/mixins/scrollable_mixin.py +++ b/dzgui/views/mixins/scrollable_mixin.py @@ -3,11 +3,22 @@ from dzgui.const.constants import SCROLL_INCREMENT import gi gi.require_version("Gtk", "3.0") -from gi.repository import Gdk # noqa +from gi.repository import Gtk, Gdk # noqa class ScrollableMixin: - def _set_adjustment(self, adjustment = VAdjustment) -> None: - vadj = self.scrollable.get_vadjustment() + def _on_keypress(self, widget: Gtk.Widget, event: Gdk.EventKey) -> None: + match event.keyval: + case Gdk.KEY_k | Gdk.KEY_Up: + self._set_adjustment(VAdjustment.UP) + case Gdk.KEY_Down | Gdk.KEY_j: + self._set_adjustment(VAdjustment.DOWN) + case Gdk.KEY_g: + self._set_adjustment(VAdjustment.TOP) + case Gdk.KEY_G: + self._set_adjustment(VAdjustment.BOTTOM) + + def _set_adjustment(self, adjustment: VAdjustment) -> None: + vadj = self.get_vadjustment() match adjustment: case VAdjustment.TOP: adj = vadj.get_lower() diff --git a/dzgui/views/pages/changelog.py b/dzgui/views/pages/changelog.py index 2caa366..d145a50 100644 --- a/dzgui/views/pages/changelog.py +++ b/dzgui/views/pages/changelog.py @@ -5,6 +5,7 @@ from importlib import resources from dzgui.const.constants import APP_NAME_LOWER from dzgui.util.format import format_pango +from dzgui.views.mixins.scrollable_mixin import ScrollableMixin import gi gi.require_version("Gtk", "3.0") @@ -16,9 +17,9 @@ logger = logging.getLogger(__name__) if TYPE_CHECKING: from dzgui.controllers.mc import Controller -class Changelog(Gtk.Box): +class Changelog(ScrollableMixin, Gtk.ScrolledWindow): def __init__(self, controller: "Controller"): - super().__init__() + super().__init__(propagate_natural_width=False) try: changelog = resources.read_text(APP_NAME_LOWER, "data/CHANGELOG.md") @@ -30,4 +31,8 @@ class Changelog(Gtk.Box): formatted = format_pango(changelog) self.changelog_label = Gtk.Label(valign=Gtk.Align.START, margin=15) self.changelog_label.set_markup(formatted) - self.add(self.changelog_label) + self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + self.box.add(self.changelog_label) + self.add(self.box) + + self.connect("key-press-event", self._on_keypress) diff --git a/dzgui/views/pages/keys.py b/dzgui/views/pages/keys.py index 2b12f62..9fa357b 100644 --- a/dzgui/views/pages/keys.py +++ b/dzgui/views/pages/keys.py @@ -1,25 +1,31 @@ +from dzgui.views.mixins.scrollable_mixin import ScrollableMixin from dzgui.util.strings import navigation, servers, vim, key_header, key_contexts from dzgui.util.css import add_class import gi gi.require_version("Gtk", "3.0") -from gi.repository import Gtk # noqa E402 +from gi.repository import Gtk, Gdk # noqa E402 -class Keybindings(Gtk.Box): +class Keybindings(ScrollableMixin, Gtk.ScrolledWindow): """ Notebook page holding a prearranged grid of keybindings and their descriptions """ def __init__(self) -> None: - super().__init__(orientation=Gtk.Orientation.VERTICAL) + super().__init__() + + self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) label = Gtk.Label(label=key_header) add_class(label, "page-heading") - self.add(label) grid = self.build_grid([servers, navigation, vim]) - self.add(grid) + self.box.add(label) + self.box.add(grid) + self.add(self.box) + + self.connect("key-press-event", self._on_keypress) def build_keys(self, items: list) -> Gtk.Grid: grid = Gtk.Grid(row_spacing=10, column_homogeneous=True) diff --git a/dzgui/views/trees/tree_base.py b/dzgui/views/trees/tree_base.py index 1b50607..1e8c9ce 100644 --- a/dzgui/views/trees/tree_base.py +++ b/dzgui/views/trees/tree_base.py @@ -67,6 +67,11 @@ class TreeView(CursorMixin, Gtk.TreeView): it = self.get_selection().get_selected()[1] return it + def get_focused_row_iter(self) -> Gtk.TreeIter: + path = self.get_focused_row_path() + model = self.get_model() + return model.get_iter(path) + def get_focused_row_path(self) -> Gtk.TreePath: return self.get_cursor().path @@ -84,15 +89,11 @@ class TreeView(CursorMixin, Gtk.TreeView): if is_navkey(event.keyval): # TODO: investigate this - # TODO: get active tree if server view is open - servers = self.controller.mediator.notebook.servers - tv = servers.get_active_treeview() + tv = self.controller.get_active_treeview() if self.sel_blocked is False: self.controller.suppress_signal( tv, tv.selected_row, - #self.controller.mediator.treeview, - #self.controller.mediator.treeview.selected_row, "_on_tree_selection_changed", True, ) @@ -106,6 +107,11 @@ class TreeView(CursorMixin, Gtk.TreeView): """ Suppresses spamming on keydown """ + #if event.keyval is Gdk.KEY_space: + # it = self.get_focused_row_iter() + # self.get_selection().select_iter(it) + # return True + if is_navkey(event.keyval): if self.sel_blocked is True: self.controller.suppress_signal( diff --git a/dzgui/views/trees/tree_mods.py b/dzgui/views/trees/tree_mods.py index b7417d4..b7a39f0 100644 --- a/dzgui/views/trees/tree_mods.py +++ b/dzgui/views/trees/tree_mods.py @@ -43,7 +43,7 @@ class ModTreeView(ModsMixin, ContextMixin, TreeView): column.set_fixed_width(500) else: column.set_fixed_width(150) - # hidden color property column + # NOTE: hidden color property column column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) column.set_sort_column_id(i) if i != 4: @@ -61,6 +61,13 @@ class ModTreeView(ModsMixin, ContextMixin, TreeView): self.s = self.get_selection().get_selected_rows() def _on_mods_keypress(self, widget: Gtk.Widget, event: Gdk.EventKey) -> None: + #if event.keyval is Gdk.KEY_space: + # it = self.get_focused_row_iter() + # self.get_selection().select_iter(it) + # path = self.get_focused_row_path() + # self.set_cursor(path) + # return False + # TODO: parse keys self.present_menu(widget, event) def _on_mods_button_press(self, diff --git a/dzgui/views/trees/tree_servers.py b/dzgui/views/trees/tree_servers.py index de04c6f..b24afff 100644 --- a/dzgui/views/trees/tree_servers.py +++ b/dzgui/views/trees/tree_servers.py @@ -171,7 +171,6 @@ class ServerTreeView(TreeView): def _on_server_keypress( self, treeview: Gtk.TreeView, event: Gdk.EventKey ) -> bool | None: - # TODO: rewrite AppNav # TODO: use mixins # CONTROL_MASK + KEY_l if event.state is Gdk.ModifierType.CONTROL_MASK: @@ -181,28 +180,15 @@ class ServerTreeView(TreeView): case Gdk.KEY_r: self.refresh_player_count() case Gdk.KEY_f: - AppNav.right_panel.filters_vbox.keyword_entry.grab_focus() + self.controller.mediator.grid.right_panel.filters_vbox.keyword_entry.grab_focus() case Gdk.KEY_m: - AppNav.right_panel.filters_vbox.maps_entry.grab_focus() + self.controller.mediator.grid.right_panel.filters_vbox.maps_entry.grab_focus() else: - keyname = Gdk.keyval_name(event.keyval) - if keyname.isnumeric() and int(keyname) > 0: - digit = int(keyname) - 1 - AppNav.grid.right_panel.filters_vbox.toggle_check(digit) - return False match event.keyval: case Gdk.KEY_l | Gdk.KEY_Right: - #if event.state is Gdk.ModifierType.CONTROL_MASK: - # return self.controller.mediator.right_panel.focus_button_box() - case Gdk.KEY_0: - grid.right_panel.filters_vbox.toggle_check(9) - case Gdk.KEY_minus: - grid.right_panel.filters_vbox.toggle_check(10) - case Gdk.KEY_backslash: - grid.right_panel.filters_vbox.toggle_check(11) case _: - return False + self.controller.toggle_check(event) def set_context_menu(self, items: ContextMenuGroup) -> None: # TODO: if debug is on, add raw command