feat: apply scrollable mixin to pages

This commit is contained in:
aclist 2026-01-01 23:49:16 +09:00
parent aba00f732a
commit 5f0c8f7654
11 changed files with 115 additions and 88 deletions

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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 = (

View File

@ -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}")

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -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(

View File

@ -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,

View File

@ -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