Skip to content

Commit

Permalink
ui: keyboard navigation for editing tags (TagStudioDev#407)
Browse files Browse the repository at this point in the history
* build_tag modal: make Tag Title selected when opening modal

* build_tag modal: Tab now changes focus when aliases field is in focus

* fix: unpredictable tab order in build tag modal

* feat: implement proper tab order

* ci: fix mypy errors

* fix: merge issue 1

* fix: merge issue 2

* refactor: TagDatabasePanel now inherits from TagSearchPanel for code deduplication

* Revert "refactor: TagDatabasePanel now inherits from TagSearchPanel for code deduplication"

This reverts commit fac589b.
  • Loading branch information
Computerdores authored Jan 14, 2025
1 parent 5caf869 commit 0cdb1a8
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 10 deletions.
28 changes: 26 additions & 2 deletions tagstudio/src/qt/modals/build_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ def __init__(self, library: Library, tag: Tag | None = None):
self.aliases_table.verticalHeader().setVisible(False)
self.aliases_table.horizontalHeader().setStretchLastSection(True)
self.aliases_table.setColumnWidth(0, 35)
self.aliases_table.setTabKeyNavigation(False)
self.aliases_table.setFocusPolicy(Qt.FocusPolicy.NoFocus)

self.alias_add_button = QPushButton()
self.alias_add_button.setText("+")
Expand All @@ -136,6 +138,7 @@ def __init__(self, library: Library, tag: Tag | None = None):
self.parent_tags_scroll_layout.setAlignment(Qt.AlignmentFlag.AlignTop)

self.scroll_area = QScrollArea()
self.scroll_area.setFocusPolicy(Qt.FocusPolicy.NoFocus)
# self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
self.scroll_area.setWidgetResizable(True)
self.scroll_area.setFrameShadow(QFrame.Shadow.Plain)
Expand Down Expand Up @@ -239,8 +242,6 @@ def __init__(self, library: Library, tag: Tag | None = None):
self.new_item_id = sys.maxsize

self.set_tag(tag or Tag(name=Translations["tag.new"]))
if tag is None:
self.name_field.selectAll()

def backspace(self):
focused_widget = QApplication.focusWidget()
Expand Down Expand Up @@ -305,6 +306,7 @@ def set_parent_tags(self):
while self.parent_tags_scroll_layout.itemAt(0):
self.parent_tags_scroll_layout.takeAt(0).widget().deleteLater()

last: QWidget = self.aliases_table.cellWidget(self.aliases_table.rowCount() - 1, 1)
c = QWidget()
layout = QVBoxLayout(c)
layout.setContentsMargins(0, 0, 0, 0)
Expand All @@ -314,6 +316,10 @@ def set_parent_tags(self):
tw = TagWidget(tag, has_edit=False, has_remove=True)
tw.on_remove.connect(lambda t=tag_id: self.remove_parent_tag_callback(t))
layout.addWidget(tw)
self.setTabOrder(last, tw.bg_button)
last = tw.bg_button
self.setTabOrder(last, self.name_field)

self.parent_tags_scroll_layout.addWidget(c)

def add_aliases(self):
Expand Down Expand Up @@ -349,6 +355,7 @@ def _set_aliases(self):

self.alias_names.clear()

last: QWidget = self.panel_save_button or self.color_field
for alias_id in self.alias_ids:
alias = self.lib.get_alias(self.tag.id, alias_id)

Expand All @@ -375,6 +382,12 @@ def _set_aliases(self):
self.aliases_table.setCellWidget(row, 1, new_item)
self.aliases_table.setCellWidget(row, 0, remove_btn)

self.setTabOrder(last, self.aliases_table.cellWidget(row, 1))
self.setTabOrder(
self.aliases_table.cellWidget(row, 1), self.aliases_table.cellWidget(row, 0)
)
last = self.aliases_table.cellWidget(row, 0)

def _alias_name_change(self, item: CustomTableItem):
self.new_alias_names[item.id] = item.text()

Expand Down Expand Up @@ -424,3 +437,14 @@ def build_tag(self) -> Tag:

logger.info("built tag", tag=tag)
return tag

def parent_post_init(self):
self.setTabOrder(self.name_field, self.shorthand_field)
self.setTabOrder(self.shorthand_field, self.alias_add_button)
self.setTabOrder(self.alias_add_button, self.parent_tags_add_button)
self.setTabOrder(self.parent_tags_add_button, self.color_field)
self.setTabOrder(self.color_field, self.panel_cancel_button)
self.setTabOrder(self.panel_cancel_button, self.panel_save_button)
self.setTabOrder(self.panel_save_button, self.aliases_table.cellWidget(0, 1))
self.name_field.selectAll()
self.name_field.setFocus()
4 changes: 2 additions & 2 deletions tagstudio/src/qt/ts_qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -706,14 +706,14 @@ def backup_library(self):
)

def add_tag_action_callback(self):
panel = BuildTagPanel(self.lib)
self.modal = PanelModal(
BuildTagPanel(self.lib),
panel,
has_save=True,
)
Translations.translate_with_setter(self.modal.setTitle, "tag.new")
Translations.translate_with_setter(self.modal.setWindowTitle, "tag.add")

panel: BuildTagPanel = self.modal.widget
self.modal.saved.connect(
lambda: (
self.lib.add_tag(
Expand Down
8 changes: 7 additions & 1 deletion tagstudio/src/qt/widgets/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class PanelModal(QWidget):
# figure out what you want from this.
def __init__(
self,
widget,
widget: "PanelWidget",
title: str = "",
window_title: str = "",
done_callback: Callable | None = None,
Expand Down Expand Up @@ -89,8 +89,10 @@ def __init__(

self.root_layout.addWidget(self.title_widget)
self.root_layout.addWidget(widget)
widget.parent_modal = self
self.root_layout.setStretch(1, 2)
self.root_layout.addWidget(self.button_container)
widget.parent_post_init()

def closeEvent(self, event): # noqa: N802
self.done_button.click()
Expand All @@ -104,6 +106,7 @@ class PanelWidget(QWidget):
"""Used for widgets that go in a modal panel, ex. for editing or searching."""

done = Signal()
parent_modal: PanelModal = None
panel_save_button: QPushButton | None = None
panel_cancel_button: QPushButton | None = None
panel_done_button: QPushButton | None = None
Expand All @@ -117,5 +120,8 @@ def get_content(self) -> str:
def reset(self):
pass

def parent_post_init(self):
pass

def add_callback(self, callback: Callable, event: str = "returnPressed"):
logging.warning(f"add_callback not implemented for {self.__class__.__name__}")
10 changes: 5 additions & 5 deletions tagstudio/src/qt/widgets/preview_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ def __init__(self, library: Library, driver: "QtDriver"):
self.file_attrs = FileAttributes(library, driver)
self.fields = FieldContainers(library, driver)

tag_search_panel = TagSearchPanel(self.driver.lib)
self.tag_search_panel = TagSearchPanel(self.driver.lib)
self.add_tag_modal = PanelModal(
tag_search_panel, Translations.translate_formatted("tag.add.plural")
self.tag_search_panel, Translations.translate_formatted("tag.add.plural")
)
Translations.translate_with_setter(self.add_tag_modal.setWindowTitle, "tag.add.plural")

Expand Down Expand Up @@ -195,10 +195,10 @@ def update_add_field_button(self, entry_id: int | None = None):

def update_add_tag_button(self, entry_id: int = None):
with catch_warnings(record=True):
self.add_tag_modal.widget.tag_chosen.disconnect()
self.tag_search_panel.tag_chosen.disconnect()
self.add_tag_button.clicked.disconnect()

self.add_tag_modal.widget.tag_chosen.connect(
self.tag_search_panel.tag_chosen.connect(
lambda t: (
self.fields.add_tags_to_selected(t),
(self.fields.update_from_entry(entry_id) if entry_id else ()),
Expand All @@ -207,7 +207,7 @@ def update_add_tag_button(self, entry_id: int = None):

self.add_tag_button.clicked.connect(
lambda: (
self.add_tag_modal.widget.update_tags(),
self.tag_search_panel.update_tags(),
self.add_tag_modal.show(),
)
)

0 comments on commit 0cdb1a8

Please sign in to comment.