feat: keep suggest boxes open by default

This commit is contained in:
Travis Abendshien
2026-08-12 12:06:54 -07:00
parent b29e612e7f
commit 058baf95d0
8 changed files with 66 additions and 33 deletions
@@ -36,10 +36,10 @@ class FieldSuggestBox(SuggestBox[BaseFieldTemplate]):
self.layout().search_field.addAction(edit_field_on_add_action)
edit_field_on_add_action.setChecked(self._settings.edit_field_on_add)
edit_field_on_add_action.triggered.connect(
lambda checked: self.toggle_edit_on_field_add(checked)
lambda checked: self._toggle_edit_on_field_add(checked)
)
def toggle_edit_on_field_add(self, checked: bool) -> None:
def _toggle_edit_on_field_add(self, checked: bool) -> None:
"""Toggle the setting for opening the edit window after adding a field."""
self._settings.edit_field_on_add = checked
self._settings.save()
@@ -77,7 +77,7 @@ class FieldSuggestBox(SuggestBox[BaseFieldTemplate]):
@override
def _on_item_chosen(self, item: BaseFieldTemplate) -> None:
self.item_chosen.emit(item)
self.done.emit()
self.done.emit("*")
@override
def _search_items(self, query: str) -> tuple[list[BaseFieldTemplate], list[BaseFieldTemplate]]:
@@ -49,6 +49,7 @@ class PreviewPanel(QWidget):
super().__init__()
self._driver = driver
self._lib = self._driver.lib
self._settings = self._driver.settings
self._selected: list[int]
self._current_stats: FileAttributeData | None = None
@@ -75,13 +76,13 @@ class PreviewPanel(QWidget):
# Tag Search
self.layout().add_tag_button.clicked.connect(lambda: self._set_item_mode(_ItemMode.TAG))
self._open_tag_search_action.activated.connect(self._open_tag_search_callback)
self.layout().tag_search_box.done.connect(self._tag_added_callback)
self.layout().tag_search_box.done.connect(partial(self._tag_added_callback))
self.layout().containers.on_tags_update.connect(self._update_added_callback)
# Field Search
self.layout().add_field_button.clicked.connect(lambda: self._set_item_mode(_ItemMode.FIELD))
self._open_field_search_action.activated.connect(self._open_field_search_callback)
self.layout().field_search_box.done.connect(self._field_added_callback)
self.layout().field_search_box.done.connect(partial(self._field_added_callback))
# Previews
self.layout().preview_thumb.stats_updated.connect(self._thumb_stats_updated_callback)
@@ -122,13 +123,20 @@ class PreviewPanel(QWidget):
self.layout().add_field_button.setFocus()
self.layout().add_field_button.click()
def _tag_added_callback(self):
self._set_item_mode(None)
self.layout().add_tag_button.setFocus()
def _tag_added_callback(self, query: str):
if not query or not self._settings.keep_suggest_boxes_open:
self._set_item_mode(None)
self.layout().add_tag_button.setFocus()
else:
self._update_added_callback()
self.layout().tag_search_box.layout().search_field.setFocus()
def _field_added_callback(self):
self._set_item_mode(None)
self.layout().add_field_button.setFocus()
def _field_added_callback(self, query: str):
if not query or not self._settings.keep_suggest_boxes_open:
self._set_item_mode(None)
self.layout().add_field_button.setFocus()
else:
self.layout().field_search_box.layout().search_field.setFocus()
def _update_added_callback(self):
self.layout().tag_search_box.added = self.layout().containers.tags
+26 -14
View File
@@ -5,7 +5,7 @@ from typing import Any, override
import structlog
from PySide6.QtCore import Signal
from PySide6.QtGui import QShowEvent
from PySide6.QtGui import QAction, QShowEvent, Qt
from PySide6.QtWidgets import QGraphicsOpacityEffect, QWidget
from tagstudio.core.library.alchemy.library import Library
@@ -13,6 +13,7 @@ from tagstudio.qt.controllers.autofill_line_edit import QtCore, QtGui
from tagstudio.qt.controllers.modal_content import ModalContent
from tagstudio.qt.controllers.underlined_widget import UnderlinedWidget
from tagstudio.qt.global_settings import GlobalSettings
from tagstudio.qt.translations import Translations
from tagstudio.qt.views.stylesheets.stylesheets import (
autofill_line_edit_style,
autofill_line_edit_top_style,
@@ -42,7 +43,7 @@ def _item_name(item: object) -> str:
class SuggestBox[T](QWidget):
item_chosen = Signal(object)
done = Signal()
done = Signal(str) # Query
def __init__(
self, library: Library, settings: GlobalSettings, placeholder_text: str = ""
@@ -57,8 +58,21 @@ class SuggestBox[T](QWidget):
self.excluded: list[int] = []
self.setLayout(SuggestBoxView(placeholder_text))
self.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu)
self._connect_callbacks()
self._keep_box_open_action = QAction(Translations["settings.keep_suggest_boxes_open"], self)
self._keep_box_open_action.setCheckable(True)
self.addAction(self._keep_box_open_action)
self.layout().search_field.addAction(self._keep_box_open_action)
self._keep_box_open_action.triggered.connect(
lambda checked: self._toggle_keep_open(checked)
)
def _toggle_keep_open(self, checked: bool) -> None:
self._settings.keep_suggest_boxes_open = checked
self._settings.save()
def set_placeholder_text(self, text: str) -> None:
self.layout().search_field.setPlaceholderText(text)
@@ -108,10 +122,8 @@ class SuggestBox[T](QWidget):
def _on_search_query_submitted(self, query: str, always_create: bool = False) -> None:
# Focus search field if no query
logger.info("Query submitted")
if not query:
self.done.emit()
self.hide_and_reset()
self.done.emit(query)
return
elif not self.isHidden():
self.layout().search_field.setFocus()
@@ -197,9 +209,10 @@ class SuggestBox[T](QWidget):
raise NotImplementedError()
def _editing_finished_callback(self) -> None:
if self.layout().search_field.text() == "":
self.done.emit()
self.hide_and_reset()
# Only trigger when the search field is clicked off of and there's no query.
# NOTE: The search field is already cleared by this point when pressing enter.
if self.layout().search_field.text() == "" and not self.layout().search_field.hasFocus():
self.done.emit("")
def _create_item_from_modal(self, edit_item_panel: ModalContent) -> None: # pyright: ignore[reportUnusedParameter]
raise NotImplementedError()
@@ -213,6 +226,7 @@ class SuggestBox[T](QWidget):
self._on_shift_held(held=False)
self.layout().search_field.setDisabled(False)
self._clear_search_query()
self._keep_box_open_action.setChecked(self._settings.keep_suggest_boxes_open)
return super().showEvent(event)
@override
@@ -222,9 +236,7 @@ class SuggestBox[T](QWidget):
@override
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None:
# When Escape is pressed, focus back on the search box.
if event.key() in {
QtCore.Qt.Key.Key_Escape,
QtCore.Qt.Key.Key_Enter,
QtCore.Qt.Key.Key_Return,
}:
self.hide_and_reset()
if event.key() in {QtCore.Qt.Key.Key_Enter, QtCore.Qt.Key.Key_Return}:
self.done.emit("*")
elif event.key() == QtCore.Qt.Key.Key_Escape:
self.done.emit("")
@@ -7,7 +7,7 @@ from warnings import catch_warnings
import structlog
from PySide6.QtCore import Signal
from PySide6.QtGui import QAction, Qt
from PySide6.QtGui import QAction
from PySide6.QtWidgets import QGraphicsOpacityEffect, QWidget
from tagstudio.core.library.alchemy.library import Library
@@ -33,18 +33,17 @@ class TagSuggestBox(SuggestBox[Tag]):
super().__init__(library, settings, placeholder_text)
# Context Menu Actions
edit_tag_on_create_action = QAction(Translations["settings.edit_tag_on_create"], self)
edit_tag_on_create_action.setCheckable(True)
self.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu)
self.addAction(edit_tag_on_create_action)
self.layout().search_field.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu)
self.layout().search_field.addAction(edit_tag_on_create_action)
edit_tag_on_create_action.setChecked(self._settings.edit_tag_on_create)
edit_tag_on_create_action.triggered.connect(
lambda checked: self.toggle_edit_on_tag_create(checked)
lambda checked: self._toggle_edit_on_tag_create(checked)
)
def toggle_edit_on_tag_create(self, checked: bool) -> None:
def _toggle_edit_on_tag_create(self, checked: bool) -> None:
"""Toggle the setting for opening the edit window after creating a tag."""
self._settings.edit_tag_on_create = checked
self._settings.save()
@@ -89,7 +88,8 @@ class TagSuggestBox(SuggestBox[Tag]):
@override
def _on_item_chosen(self, item: Tag) -> None:
self.item_chosen.emit(item.id)
self.done.emit()
self._clear_search_query()
self.done.emit("*") # The query does not matter
@override
def _search_items(self, query: str) -> tuple[list[Tag], list[Tag]]:
@@ -144,7 +144,6 @@ class TagSuggestBox(SuggestBox[Tag]):
tag, parent_ids=edit_item_panel.parent_ids, aliases=edit_item_panel.aliases
)
self._on_item_chosen(tag)
self._clear_search_query()
edit_item_panel.hide()
self._on_search_query_changed(self.layout().search_field.text())
+1
View File
@@ -76,6 +76,7 @@ class GlobalSettings(BaseModel):
tag_click_action: TagClickActionOption = Field(default=TagClickActionOption.DEFAULT)
edit_tag_on_create: bool = Field(default=False)
edit_field_on_add: bool = Field(default=True)
keep_suggest_boxes_open: bool = Field(default=True)
theme: Theme = Field(default=Theme.SYSTEM)
splash: Splash = Field(default=Splash.DEFAULT)
windows_start_command: bool = Field(default=False)
+11
View File
@@ -231,6 +231,15 @@ class SettingsPanel(ModalContent):
Translations["settings.edit_field_on_add"], self.edit_field_on_add_checkbox
)
# Keep Tag/Field Suggest Boxes Open After Adding Items
self.keep_suggest_boxes_open_checkbox = QCheckBox()
self.keep_suggest_boxes_open_checkbox.setChecked(
self.driver.settings.keep_suggest_boxes_open
)
form_layout.addRow(
Translations["settings.keep_suggest_boxes_open"], self.keep_suggest_boxes_open_checkbox
)
# TODO: Implement Library Settings
def __build_library_settings(self): # pyright: ignore[reportUnusedFunction]
form_layout = QFormLayout(self.library_settings_container)
@@ -383,6 +392,7 @@ class SettingsPanel(ModalContent):
"tag_click_action": self.tag_click_action_combobox.currentData(),
"edit_tag_on_create": self.edit_tag_on_create_checkbox.isChecked(),
"edit_field_on_add": self.edit_field_on_add_checkbox.isChecked(),
"keep_suggest_boxes_open": self.keep_suggest_boxes_open_checkbox.isChecked(),
"date_format": self.dateformat_combobox.currentData(),
"hour_format": self.hourformat_checkbox.isChecked(),
"zero_padding": self.zeropadding_checkbox.isChecked(),
@@ -407,6 +417,7 @@ class SettingsPanel(ModalContent):
driver.settings.tag_click_action = settings["tag_click_action"]
driver.settings.edit_tag_on_create = settings["edit_tag_on_create"]
driver.settings.edit_field_on_add = settings["edit_field_on_add"]
driver.settings.keep_suggest_boxes_open = settings["keep_suggest_boxes_open"]
driver.settings.date_format = settings["date_format"]
driver.settings.hour_format = settings["hour_format"]
driver.settings.zero_padding = settings["zero_padding"]
@@ -71,6 +71,7 @@ class SuggestBoxView(QVBoxLayout):
self.search_field.setMinimumHeight(28)
self.search_field.setPlaceholderText(placeholder_text)
self.scroll_area.setFocusProxy(self.search_field)
self.search_field.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu)
# Finalize Layout
self.addWidget(scroll_area_container)
+2 -1
View File
@@ -167,7 +167,7 @@
"home.search_or_create_fields": "Search or Create Fields…",
"home.search_or_create_tags": "Search or Create Tags…",
"home.search_tags": "Search Tags…",
"home.search.how_to_exit": "(Esc to Exit)",
"home.search.how_to_exit": "(Enter to Exit)",
"home.search.view_limit": "View Limit:",
"home.show_hidden_entries": "Show Hidden Entries",
"home.thumbnail_size": "Thumbnail Size",
@@ -329,6 +329,7 @@
"settings.global": "Global Settings",
"settings.hourformat.label": "24-Hour Time",
"settings.infinite_scroll": "Infinite Scrolling",
"settings.keep_suggest_boxes_open": "Keep Search Boxes Open After Adding Items",
"settings.language": "Language",
"settings.library": "Library Settings",
"settings.localization": "Localization",