mirror of
https://github.com/TagStudioDev/TagStudio.git
synced 2026-07-21 13:06:26 +02:00
feat(ui): add underline indicator for search bar items
This commit is contained in:
@@ -15,6 +15,7 @@ from tagstudio.core.library.alchemy.library import Library
|
||||
from tagstudio.qt.controllers.edit_field_template_modal import EditFieldTemplateModal
|
||||
from tagstudio.qt.controllers.field_template_widget_controller import FieldTemplateWidget
|
||||
from tagstudio.qt.controllers.suggest_box import SuggestBox
|
||||
from tagstudio.qt.controllers.underlined_widget import UnderlinedWidget
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.panel_modal import PanelModal, PanelWidget
|
||||
from tagstudio.qt.views.suggest_box_view import SuggestBoxView
|
||||
@@ -97,14 +98,19 @@ class FieldSuggestBox(SuggestBox[BaseFieldTemplate]):
|
||||
@override
|
||||
def _set_item_widget(self, item: BaseFieldTemplate | None, index: int) -> None:
|
||||
"""Set the field template of a field template widget at a specific index."""
|
||||
field_template_widget: FieldTemplateWidget = self._get_item_widget(index, self._lib)
|
||||
underlined_widget: UnderlinedWidget = self._get_item_widget(index, self._lib)
|
||||
field_template_widget = underlined_widget.widget
|
||||
assert isinstance(field_template_widget, FieldTemplateWidget)
|
||||
field_template_widget.has_remove = False
|
||||
field_template_widget.set_field_template(item)
|
||||
field_template_widget.setHidden(item is None)
|
||||
underlined_widget.setHidden(item is None)
|
||||
|
||||
if item is None:
|
||||
return
|
||||
|
||||
# TODO: Add tabbing to different items, and use underline to indicate which will be added
|
||||
underlined_widget.toggle_underline(index != 0)
|
||||
|
||||
# Disconnect previous callbacks
|
||||
with catch_warnings(record=True):
|
||||
field_template_widget.on_edit.disconnect()
|
||||
@@ -139,15 +145,16 @@ class FieldSuggestBox(SuggestBox[BaseFieldTemplate]):
|
||||
self._update_items(self.layout().search_field.text())
|
||||
|
||||
@override
|
||||
def _get_item_widget(self, index: int, library: Library | None) -> FieldTemplateWidget:
|
||||
def _get_item_widget(self, index: int, library: Library | None) -> UnderlinedWidget:
|
||||
"""Gets the item widget at a specific index."""
|
||||
# Create any new item widgets needed up to the given index
|
||||
if self.layout().content_layout.count() <= index:
|
||||
while self.layout().content_layout.count() <= index:
|
||||
pad_field_template_widget = FieldTemplateWidget()
|
||||
pad_field_template_widget.setHidden(True)
|
||||
self.layout().content_layout.addWidget(pad_field_template_widget)
|
||||
field_template_widget = FieldTemplateWidget()
|
||||
widget = UnderlinedWidget(field_template_widget)
|
||||
widget.setHidden(True)
|
||||
self.layout().content_layout.addWidget(widget)
|
||||
|
||||
field_template_widget: QWidget = self.layout().content_layout.itemAt(index).widget()
|
||||
assert isinstance(field_template_widget, FieldTemplateWidget)
|
||||
return field_template_widget
|
||||
widget_: QWidget = self.layout().content_layout.itemAt(index).widget()
|
||||
assert isinstance(widget_, UnderlinedWidget)
|
||||
return widget_
|
||||
|
||||
@@ -10,6 +10,7 @@ from PySide6.QtWidgets import QGraphicsOpacityEffect, QWidget
|
||||
|
||||
from tagstudio.core.library.alchemy.library import Library
|
||||
from tagstudio.qt.controllers.autofill_line_edit import QtCore, QtGui
|
||||
from tagstudio.qt.controllers.underlined_widget import UnderlinedWidget
|
||||
from tagstudio.qt.views.panel_modal import PanelWidget
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import (
|
||||
autofill_line_edit_style,
|
||||
@@ -82,11 +83,15 @@ class SuggestBox[T](QWidget):
|
||||
opacity_effect = QGraphicsOpacityEffect(self)
|
||||
opacity_effect.setOpacity(0.3)
|
||||
if self.layout().content_layout.count() > 0:
|
||||
self.layout().content_layout.itemAt(0).widget().setGraphicsEffect(opacity_effect)
|
||||
underlined_widget = self.layout().content_layout.itemAt(0).widget()
|
||||
assert isinstance(underlined_widget, UnderlinedWidget)
|
||||
underlined_widget.widget.setGraphicsEffect(opacity_effect)
|
||||
else:
|
||||
self._is_shift_held = False
|
||||
if self.layout().content_layout.count() > 0:
|
||||
self.layout().content_layout.itemAt(0).widget().setGraphicsEffect(None) # pyright: ignore[reportArgumentType]
|
||||
underlined_widget = self.layout().content_layout.itemAt(0).widget()
|
||||
assert isinstance(underlined_widget, UnderlinedWidget)
|
||||
underlined_widget.widget.setGraphicsEffect(None) # pyright: ignore[reportArgumentType]
|
||||
|
||||
def _clear_search_query(self) -> None:
|
||||
self.layout().search_field.setText("")
|
||||
|
||||
@@ -14,6 +14,7 @@ from tagstudio.core.library.alchemy.enums import BrowsingState
|
||||
from tagstudio.core.library.alchemy.library import Library
|
||||
from tagstudio.core.library.alchemy.models import Tag
|
||||
from tagstudio.qt.controllers.suggest_box import SuggestBox
|
||||
from tagstudio.qt.controllers.underlined_widget import UnderlinedWidget
|
||||
from tagstudio.qt.mixed.build_tag import BuildTagPanel
|
||||
from tagstudio.qt.mixed.tag_widget import TagWidget
|
||||
from tagstudio.qt.translations import Translations
|
||||
@@ -109,10 +110,12 @@ class TagSuggestBox(SuggestBox[Tag]):
|
||||
@override
|
||||
def _set_item_widget(self, item: Tag | None, index: int) -> None:
|
||||
"""Set the tag of a tag widget at a specific index."""
|
||||
tag_widget: TagWidget = self._get_item_widget(index, self._lib)
|
||||
underlined_widget: UnderlinedWidget = self._get_item_widget(index, self._lib)
|
||||
tag_widget = underlined_widget.widget
|
||||
assert isinstance(tag_widget, TagWidget)
|
||||
tag_widget.has_remove = False
|
||||
tag_widget.set_tag(item)
|
||||
tag_widget.setHidden(item is None)
|
||||
underlined_widget.setHidden(item is None)
|
||||
opacity_effect = QGraphicsOpacityEffect(self)
|
||||
opacity_effect.setOpacity(0.3)
|
||||
if item and item.id in self.added:
|
||||
@@ -123,6 +126,9 @@ class TagSuggestBox(SuggestBox[Tag]):
|
||||
if item is None:
|
||||
return
|
||||
|
||||
# TODO: Add tabbing to different items, and use underline to indicate which will be added
|
||||
underlined_widget.toggle_underline(index != 0)
|
||||
|
||||
# Disconnect previous callbacks
|
||||
with catch_warnings(record=True):
|
||||
tag_widget.on_edit.disconnect()
|
||||
@@ -165,16 +171,17 @@ class TagSuggestBox(SuggestBox[Tag]):
|
||||
self._update_items(self.layout().search_field.text())
|
||||
|
||||
@override
|
||||
def _get_item_widget(self, index: int, library: Library | None) -> TagWidget:
|
||||
def _get_item_widget(self, index: int, library: Library | None) -> UnderlinedWidget:
|
||||
"""Gets the item widget at a specific index."""
|
||||
# Create any new item widgets needed up to the given index
|
||||
if self.layout().content_layout.count() <= index:
|
||||
while self.layout().content_layout.count() <= index:
|
||||
tag_widget = TagWidget(tag=None, has_edit=True, has_remove=True, library=library)
|
||||
tag_widget.on_remove.connect(self._update_items)
|
||||
tag_widget.setHidden(True)
|
||||
self.layout().content_layout.addWidget(tag_widget)
|
||||
widget = UnderlinedWidget(tag_widget)
|
||||
widget.setHidden(True)
|
||||
self.layout().content_layout.addWidget(widget)
|
||||
|
||||
tag_widget: QWidget = self.layout().content_layout.itemAt(index).widget()
|
||||
assert isinstance(tag_widget, TagWidget)
|
||||
return tag_widget
|
||||
widget_: QWidget = self.layout().content_layout.itemAt(index).widget()
|
||||
assert isinstance(widget_, UnderlinedWidget)
|
||||
return widget_
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# SPDX-FileCopyrightText: (c) TagStudio Contributors
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
|
||||
from typing import override
|
||||
|
||||
from PySide6.QtWidgets import QWidget
|
||||
|
||||
from tagstudio.qt.views.underlined_widget_view import UnderlinedWidgetView
|
||||
|
||||
|
||||
class UnderlinedWidget(QWidget):
|
||||
def __init__(self, widget: QWidget) -> None:
|
||||
super().__init__()
|
||||
view = UnderlinedWidgetView(widget)
|
||||
self.setLayout(view)
|
||||
|
||||
def toggle_underline(self, is_hidden: bool) -> None:
|
||||
self.layout().underline.setHidden(is_hidden)
|
||||
|
||||
@property
|
||||
def widget(self) -> QWidget:
|
||||
return self.layout().itemAt(0).widget()
|
||||
|
||||
@override
|
||||
def layout(self) -> UnderlinedWidgetView:
|
||||
"""Return the typed layout for this widget."""
|
||||
return super().layout() # pyright: ignore[reportReturnType]
|
||||
@@ -410,6 +410,13 @@ def tag_remove_button_style(
|
||||
"""
|
||||
|
||||
|
||||
def widget_underline_style() -> str:
|
||||
return f"""
|
||||
background: {Palette.accent()};
|
||||
border-radius: 2px;
|
||||
"""
|
||||
|
||||
|
||||
def title_line_edit_style() -> str:
|
||||
"""Used to mimic an H3-like header style inside a QLineEdit."""
|
||||
return """
|
||||
|
||||
@@ -59,7 +59,9 @@ class SuggestBoxView(QVBoxLayout):
|
||||
self.scroll_area.setStyleSheet(scroll_area_style)
|
||||
scroll_area_container_layout.addWidget(self.scroll_area)
|
||||
self.scroll_area.setWidget(contents)
|
||||
self.scroll_area.setMaximumHeight(28)
|
||||
search_bar_height = 28
|
||||
underline_padding = 7
|
||||
self.scroll_area.setMaximumHeight(search_bar_height + underline_padding)
|
||||
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||
self.scroll_area.verticalScrollBar().setEnabled(False)
|
||||
self.scroll_area.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# SPDX-FileCopyrightText: (c) TagStudio Contributors
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QPushButton, QVBoxLayout, QWidget
|
||||
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import widget_underline_style
|
||||
|
||||
|
||||
class UnderlinedWidgetView(QVBoxLayout):
|
||||
def __init__(self, widget: QWidget) -> None:
|
||||
super().__init__()
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
self.setSpacing(3)
|
||||
self.setAlignment(Qt.AlignmentFlag.AlignTop)
|
||||
|
||||
# HACK: I don't know why I can't just use a QFrame for the outline.
|
||||
# The styling and sizing only seems to work if it's something like a QPushButton.
|
||||
self.underline = QPushButton()
|
||||
self.underline.setFlat(True)
|
||||
self.underline.setDisabled(True)
|
||||
self.underline.setMaximumHeight(4)
|
||||
self.underline.setStyleSheet(widget_underline_style())
|
||||
|
||||
self.addWidget(widget)
|
||||
self.addWidget(self.underline)
|
||||
Reference in New Issue
Block a user