Files
dzgui/dzgui/views/mixins/context_mixin.py
T
aclist 0a310f0b70 change: normalize context menu keybind behavior for j,k keys
Normalized custom menu navigation keys to be in conformity with native
keybindings for Gdk.KEY_uparrow and Gdk.KEY_downarrow.
2026-08-20 14:15:47 +09:00

120 lines
3.9 KiB
Python

import logging
from dzgui.const.constants import APP_NAME
from dzgui.const.enum import ContextMenu
from dzgui.util.keys import is_ctrl_mask, is_navkey
from dzgui.util.strings import edit_note
from dzgui.views.trees.tree_base import TreeView
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa E402
logger = logging.getLogger(APP_NAME)
class ContextMixin(TreeView):
def present_menu(
self,
widget: Gtk.Widget,
event: Gdk.EventButton | Gdk.EventKey,
) -> bool:
if self.menu is None:
return False
if self.is_selection_empty():
return False
match event.type:
case Gdk.EventType.BUTTON_PRESS:
if event.button != 3:
return False
self._process_button_event(event) # type: ignore
case Gdk.EventType.KEY_PRESS:
if not is_ctrl_mask(event): # type: ignore
return False
if event.keyval is not Gdk.KEY_l: # type: ignore
return False
case _:
return False
group = self.menu
self.context_menu = Gtk.Menu()
self.context_menu.connect("key-press-event", self._on_key)
for row in group.value:
if row is None:
return False
item = self._process_dynamic_row(row)
self.context_menu.append(item)
self.context_menu.show_all()
match event.type:
case Gdk.EventType.KEY_PRESS:
self.context_menu.popup_at_widget(
widget, Gdk.Gravity.CENTER, Gdk.Gravity.WEST
)
case Gdk.EventType.BUTTON_PRESS | Gdk.EventType.BUTTON_RELEASE:
self.context_menu.popup_at_pointer(event)
self.context_menu.select_first(False)
return True
def _process_dynamic_row(self, row: ContextMenu) -> Gtk.MenuItem:
if row == ContextMenu.ADD_SERVER and self.is_in_favs(): # type: ignore
row = ContextMenu.REMOVE_SERVER
item = Gtk.MenuItem(label=row.dict["label"])
item.connect("activate", self._on_menu_click, row)
if row == ContextMenu.SHOW_MODS:
item.set_sensitive(self.is_modded()) # type: ignore
if row == ContextMenu.ADD_NOTE:
if self.controller.has_note():
item.set_label(edit_note)
return item
def _process_button_event(self, event: Gdk.EventButton) -> bool:
try:
pathinfo = self.get_path_at_pos(int(event.x), int(event.y))
if pathinfo is None:
return True
(path, col, cellx, celly) = pathinfo
if path is None:
return True
selection = self.get_selection()
model, selected_paths = selection.get_selected_rows()
if path not in selected_paths:
for p in selected_paths:
selection.unselect_path(p)
self.set_cursor(path, col, False)
return True
except AttributeError:
return False
def _on_menu_click(self, widget: Gtk.MenuItem, enum: ContextMenu) -> None:
self.controller.menu_action(enum, self) # type: ignore
def _on_key(self, menu: Gtk.Menu, event: Gdk.EventKey) -> bool | None:
if not is_navkey(event.keyval):
return False
menu = self.context_menu
children = menu.get_children()
match event.keyval:
case Gdk.KEY_j:
menu.emit("move-current", Gtk.MenuDirectionType.NEXT)
case Gdk.KEY_k:
menu.emit("move-current", Gtk.MenuDirectionType.PREV)
case Gdk.KEY_g:
menu.select_item(children[0])
case Gdk.KEY_G:
menu.select_item(children[-1])
case _:
return False
return True