diff --git a/tagstudio/resources/translations/en.json b/tagstudio/resources/translations/en.json index 8b954278..4776c1a0 100644 --- a/tagstudio/resources/translations/en.json +++ b/tagstudio/resources/translations/en.json @@ -212,6 +212,7 @@ "tag.add.plural": "Add Tags", "tag.add": "Add Tag", "tag.aliases": "Aliases", + "tag.all_tags": "All Tags", "tag.choose_color": "Choose Tag Color", "tag.color": "Color", "tag.confirm_delete": "Are you sure you want to delete the tag \"{tag_name}\"?", @@ -228,6 +229,7 @@ "tag.search_for_tag": "Search for Tag", "tag.shorthand": "Shorthand", "tag.tag_name_required": "Tag Name (Required)", + "tag.view_limit": "View Limit:", "view.size.0": "Mini", "view.size.1": "Small", "view.size.2": "Medium", diff --git a/tagstudio/src/core/library/alchemy/library.py b/tagstudio/src/core/library/alchemy/library.py index ef31928e..f3472442 100644 --- a/tagstudio/src/core/library/alchemy/library.py +++ b/tagstudio/src/core/library/alchemy/library.py @@ -765,16 +765,16 @@ class Library: return res - def search_tags(self, name: str | None) -> list[set[Tag]]: + def search_tags(self, name: str | None, limit: int = 100) -> list[set[Tag]]: """Return a list of Tag records matching the query.""" - tag_limit = 100 - with Session(self.engine) as session: - query = select(Tag).outerjoin(TagAlias) + query = select(Tag).outerjoin(TagAlias).order_by(func.lower(Tag.name)) query = query.options( selectinload(Tag.parent_tags), selectinload(Tag.aliases), - ).limit(tag_limit) + ) + if limit > 0: + query = query.limit(limit) if name: query = query.where( @@ -806,6 +806,7 @@ class Library: logger.info( "searching tags", search=name, + limit=limit, statement=str(query), results=len(res), ) diff --git a/tagstudio/src/qt/modals/tag_database.py b/tagstudio/src/qt/modals/tag_database.py index ad8e7b80..3143fbc3 100644 --- a/tagstudio/src/qt/modals/tag_database.py +++ b/tagstudio/src/qt/modals/tag_database.py @@ -18,19 +18,19 @@ logger = structlog.get_logger(__name__) # TODO: Once this class is removed, the `is_tag_chooser` option of `TagSearchPanel` # will most likely be enabled in every case -# and the possibilty of disabling it can therefore be removed +# and the possibility of disabling it can therefore be removed class TagDatabasePanel(TagSearchPanel): - def __init__(self, library: Library): + def __init__(self, driver, library: Library): super().__init__(library, is_tag_chooser=False) + self.driver = driver self.create_tag_button = QPushButton() Translations.translate_qobject(self.create_tag_button, "tag.create") self.create_tag_button.clicked.connect(lambda: self.build_tag(self.search_field.text())) self.root_layout.addWidget(self.create_tag_button) - self.update_tags() def build_tag(self, name: str): panel = BuildTagPanel(self.lib) @@ -39,7 +39,7 @@ class TagDatabasePanel(TagSearchPanel): has_save=True, ) Translations.translate_with_setter(self.modal.setTitle, "tag.new") - Translations.translate_with_setter(self.modal.setWindowTitle, "tag.add") + Translations.translate_with_setter(self.modal.setWindowTitle, "tag.new") if name.strip(): panel.name_field.setText(name) diff --git a/tagstudio/src/qt/modals/tag_search.py b/tagstudio/src/qt/modals/tag_search.py index a50fc1e3..d3021f98 100644 --- a/tagstudio/src/qt/modals/tag_search.py +++ b/tagstudio/src/qt/modals/tag_search.py @@ -3,7 +3,9 @@ # Created for TagStudio: https://github.com/CyanVoxel/TagStudio +import contextlib import typing +from warnings import catch_warnings import src.qt.modals.build_tag as build_tag import structlog @@ -11,8 +13,10 @@ from PySide6 import QtCore, QtGui from PySide6.QtCore import QSize, Qt, Signal from PySide6.QtGui import QShowEvent from PySide6.QtWidgets import ( + QComboBox, QFrame, QHBoxLayout, + QLabel, QLineEdit, QPushButton, QScrollArea, @@ -21,7 +25,7 @@ from PySide6.QtWidgets import ( ) from src.core.constants import RESERVED_TAG_END, RESERVED_TAG_START from src.core.library import Library, Tag -from src.core.library.alchemy.enums import TagColorEnum +from src.core.library.alchemy.enums import FilterState, TagColorEnum from src.core.palette import ColorType, get_tag_color from src.qt.translations import Translations from src.qt.widgets.panel import PanelModal, PanelWidget @@ -44,6 +48,11 @@ class TagSearchPanel(PanelWidget): is_tag_chooser: bool exclude: list[int] + _limit_items: list[int | str] = [25, 50, 100, 250, 500, Translations["tag.all_tags"]] + _default_limit_idx: int = 0 # 50 Tag Limit (Default) + cur_limit_idx: int = _default_limit_idx + tag_limit: int | str = _limit_items[_default_limit_idx] + def __init__( self, library: Library, @@ -52,14 +61,37 @@ class TagSearchPanel(PanelWidget): ): super().__init__() self.lib = library + self.driver = None self.exclude = exclude or [] self.is_tag_chooser = is_tag_chooser + self.create_button_in_layout: bool = False self.setMinimumSize(300, 400) self.root_layout = QVBoxLayout(self) self.root_layout.setContentsMargins(6, 0, 6, 0) + self.limit_container = QWidget() + self.limit_layout = QHBoxLayout(self.limit_container) + self.limit_layout.setContentsMargins(0, 0, 0, 0) + self.limit_layout.setSpacing(12) + self.limit_layout.addStretch(1) + + self.limit_title = QLabel() + Translations.translate_qobject(self.limit_title, "tag.view_limit") + self.limit_layout.addWidget(self.limit_title) + + self.limit_combobox = QComboBox() + self.limit_combobox.setEditable(False) + self.limit_combobox.addItems([str(x) for x in TagSearchPanel._limit_items]) + self.limit_combobox.setCurrentIndex(TagSearchPanel._default_limit_idx) + self.limit_combobox.currentIndexChanged.connect(self.update_limit) + self.previous_limit: int = ( + TagSearchPanel.tag_limit if isinstance(TagSearchPanel.tag_limit, int) else -1 + ) + self.limit_layout.addWidget(self.limit_combobox) + self.limit_layout.addStretch(1) + self.search_field = QLineEdit() self.search_field.setObjectName("searchField") self.search_field.setMinimumSize(QSize(0, 32)) @@ -79,53 +111,19 @@ class TagSearchPanel(PanelWidget): self.scroll_area.setFrameShape(QFrame.Shape.NoFrame) self.scroll_area.setWidget(self.scroll_contents) + self.root_layout.addWidget(self.limit_container) self.root_layout.addWidget(self.search_field) self.root_layout.addWidget(self.scroll_area) - def __build_tag_widget(self, tag: Tag): - has_remove_button = False - if not self.is_tag_chooser: - has_remove_button = tag.id not in range(RESERVED_TAG_START, RESERVED_TAG_END) - - tag_widget = TagWidget( - tag, - library=self.lib, - has_edit=True, - has_remove=has_remove_button, - ) - - tag_widget.on_edit.connect(lambda t=tag: self.edit_tag(t)) - tag_widget.on_remove.connect(lambda t=tag: self.remove_tag(t)) - - # NOTE: A solution to this would be to pass the driver to TagSearchPanel, however that - # creates an exponential amount of work trying to fix the preexisting tests. - - # tag_widget.search_for_tag_action.triggered.connect( - # lambda checked=False, tag_id=tag.id: ( - # self.driver.main_window.searchField.setText(f"tag_id:{tag_id}"), - # self.driver.filter_items(FilterState.from_tag_id(tag_id)), - # ) - # ) - - tag_id = tag.id - tag_widget.bg_button.clicked.connect(lambda: self.tag_chosen.emit(tag_id)) - return tag_widget - - def build_create_tag_button(self, query: str | None): - """Constructs a Create Tag Button.""" - container = QWidget() - row = QHBoxLayout(container) - row.setContentsMargins(0, 0, 0, 0) - row.setSpacing(3) + def set_driver(self, driver): + """Set the QtDriver for this search panel. Used for main window operations.""" + self.driver = driver + def build_create_button(self, query: str | None): + """Constructs a "Create & Add Tag" QPushButton.""" create_button = QPushButton(self) - Translations.translate_qobject(create_button, "tag.create_add", query=query) create_button.setFlat(True) - inner_layout = QHBoxLayout() - inner_layout.setObjectName("innerLayout") - inner_layout.setContentsMargins(2, 2, 2, 2) - create_button.setLayout(inner_layout) create_button.setMinimumSize(22, 22) create_button.setStyleSheet( @@ -156,10 +154,7 @@ class TagSearchPanel(PanelWidget): f"}}" ) - create_button.clicked.connect(lambda: self.create_and_add_tag(query)) - row.addWidget(create_button) - - return container + return create_button def create_and_add_tag(self, name: str): """Opens "Create Tag" panel to create and add a new tag with given name.""" @@ -188,26 +183,34 @@ class TagSearchPanel(PanelWidget): self.build_tag_modal.name_field.setText(name) self.add_tag_modal.saved.connect(on_tag_modal_saved) - self.add_tag_modal.save_button.setFocus() self.add_tag_modal.show() def update_tags(self, query: str | None = None): - logger.info("[Tag Search Super Class] Updating Tags") + """Update the tag list given a search query.""" + logger.info("[TagSearchPanel] Updating Tags") - # TODO: Look at recycling rather than deleting and re-initializing - while self.scroll_layout.count(): - self.scroll_layout.takeAt(0).widget().deleteLater() + # Remove the "Create & Add" button if one exists + create_button: QPushButton | None = None + if self.create_button_in_layout and self.scroll_layout.count(): + create_button = self.scroll_layout.takeAt(self.scroll_layout.count() - 1).widget() # type: ignore + create_button.deleteLater() + self.create_button_in_layout = False + # Get results for the search query query_lower = "" if not query else query.lower() - tag_results: list[set[Tag]] = self.lib.search_tags(name=query) - tag_results[0] = {t for t in tag_results[0] if t.id not in self.exclude} - tag_results[1] = {t for t in tag_results[1] if t.id not in self.exclude} + # Only use the tag limit if it's an actual number (aka not "All Tags") + tag_limit = TagSearchPanel.tag_limit if isinstance(TagSearchPanel.tag_limit, int) else -1 + tag_results: list[set[Tag]] = self.lib.search_tags(name=query, limit=tag_limit) + if self.exclude: + tag_results[0] = {t for t in tag_results[0] if t.id not in self.exclude} + tag_results[1] = {t for t in tag_results[1] if t.id not in self.exclude} + # Sort and prioritize the results results_0 = list(tag_results[0]) results_0.sort(key=lambda tag: tag.name.lower()) results_1 = list(tag_results[1]) results_1.sort(key=lambda tag: tag.name.lower()) - raw_results = list(results_0 + results_1)[:100] + raw_results = list(results_0 + results_1) priority_results: set[Tag] = set() all_results: list[Tag] = [] @@ -219,18 +222,99 @@ class TagSearchPanel(PanelWidget): all_results = sorted(list(priority_results), key=lambda tag: len(tag.name)) + [ r for r in raw_results if r not in priority_results ] + if tag_limit > 0: + all_results = all_results[:tag_limit] if all_results: self.first_tag_id = None self.first_tag_id = all_results[0].id if len(all_results) > 0 else all_results[0].id - for tag in all_results: - self.scroll_layout.addWidget(self.__build_tag_widget(tag)) + else: self.first_tag_id = None + # Update every tag widget with the new search result data + norm_previous = self.previous_limit if self.previous_limit > 0 else len(self.lib.tags) + norm_limit = tag_limit if tag_limit > 0 else len(self.lib.tags) + range_limit = max(norm_previous, norm_limit) + for i in range(0, range_limit): + tag = None + with contextlib.suppress(IndexError): + tag = all_results[i] + self.set_tag_widget(tag=tag, index=i) + self.previous_limit = tag_limit + + # Add back the "Create & Add" button if query and query.strip(): - c = self.build_create_tag_button(query) - self.scroll_layout.addWidget(c) + cb: QPushButton = self.build_create_button(query) + with catch_warnings(record=True): + cb.clicked.disconnect() + cb.clicked.connect(lambda: self.create_and_add_tag(query or "")) + Translations.translate_qobject(cb, "tag.create_add", query=query) + self.scroll_layout.addWidget(cb) + self.create_button_in_layout = True + + def set_tag_widget(self, tag: Tag | None, index: int): + """Set the tag of a tag widget at a specific index.""" + # Create any new tag widgets needed up to the given index + if self.scroll_layout.count() <= index: + while self.scroll_layout.count() <= index: + new_tw = TagWidget(tag=None, has_edit=True, has_remove=True, library=self.lib) + new_tw.setHidden(True) + self.scroll_layout.addWidget(new_tw) + + # Assign the tag to the widget at the given index. + tag_widget: TagWidget = self.scroll_layout.itemAt(index).widget() # type: ignore + tag_widget.set_tag(tag) + + # Set tag widget viability and potentially return early + tag_widget.setHidden(bool(not tag)) + if not tag: + return + + # Configure any other aspects of the tag widget + has_remove_button = False + if not self.is_tag_chooser: + has_remove_button = tag.id not in range(RESERVED_TAG_START, RESERVED_TAG_END) + tag_widget.has_remove = has_remove_button + + with catch_warnings(record=True): + tag_widget.on_edit.disconnect() + tag_widget.on_remove.disconnect() + tag_widget.bg_button.clicked.disconnect() + + tag_id = tag.id + tag_widget.on_edit.connect(lambda t=tag: self.edit_tag(t)) + tag_widget.on_remove.connect(lambda t=tag: self.remove_tag(t)) + tag_widget.bg_button.clicked.connect(lambda: self.tag_chosen.emit(tag_id)) + + if self.driver: + tag_widget.search_for_tag_action.triggered.connect( + lambda checked=False, tag_id=tag.id: ( + self.driver.main_window.searchField.setText(f"tag_id:{tag_id}"), + self.driver.filter_items(FilterState.from_tag_id(tag_id)), + ) + ) + tag_widget.search_for_tag_action.setEnabled(True) + else: + tag_widget.search_for_tag_action.setEnabled(False) + + def update_limit(self, index: int): + logger.info("[TagSearchPanel] Updating tag limit") + TagSearchPanel.cur_limit_idx = index + + if index < len(self._limit_items) - 1: + TagSearchPanel.tag_limit = int(self._limit_items[index]) + else: + TagSearchPanel.tag_limit = -1 + + # Method was called outside the limit_combobox callback + if index != self.limit_combobox.currentIndex(): + self.limit_combobox.setCurrentIndex(index) + + if self.previous_limit == TagSearchPanel.tag_limit: + return + + self.update_tags(self.search_field.text()) def on_return(self, text: str): if text: @@ -246,7 +330,9 @@ class TagSearchPanel(PanelWidget): self.parentWidget().hide() def showEvent(self, event: QShowEvent) -> None: # noqa N802 + self.update_limit(TagSearchPanel.cur_limit_idx) self.update_tags() + self.scroll_area.verticalScrollBar().setValue(0) self.search_field.setText("") self.search_field.setFocus() return super().showEvent(event) diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index c6363a31..9c732b1c 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -16,6 +16,7 @@ import sys import time from pathlib import Path from queue import Queue +from warnings import catch_warnings # this import has side-effect of import PySide resources import src.qt.resources_rc # noqa: F401 @@ -136,6 +137,8 @@ class QtDriver(DriverMixin, QObject): SIGTERM = Signal() preview_panel: PreviewPanel + tag_manager_panel: PanelModal + file_extension_panel: PanelModal | None = None tag_search_panel: TagSearchPanel add_tag_modal: PanelModal @@ -291,8 +294,20 @@ class QtDriver(DriverMixin, QObject): icon.addFile(str(icon_path)) app.setWindowIcon(icon) - # Initialize the main window's tag search panel + # Initialize the Tag Manager panel + self.tag_manager_panel = PanelModal( + widget=TagDatabasePanel(self, self.lib), + done_callback=lambda: self.preview_panel.update_widgets(update_preview=False), + has_save=False, + ) + Translations.translate_with_setter(self.tag_manager_panel.setTitle, "tag_manager.title") + Translations.translate_with_setter( + self.tag_manager_panel.setWindowTitle, "tag_manager.title" + ) + + # Initialize the Tag Search panel self.tag_search_panel = TagSearchPanel(self.lib, is_tag_chooser=True) + self.tag_search_panel.set_driver(self) self.add_tag_modal = PanelModal( widget=self.tag_search_panel, title=Translations.translate_formatted("tag.add.plural"), @@ -487,13 +502,12 @@ class QtDriver(DriverMixin, QObject): Translations.translate_qobject( self.manage_file_ext_action, "menu.edit.manage_file_extensions" ) - self.manage_file_ext_action.triggered.connect(self.show_file_extension_modal) edit_menu.addAction(self.manage_file_ext_action) self.manage_file_ext_action.setEnabled(False) self.tag_manager_action = QAction(menu_bar) Translations.translate_qobject(self.tag_manager_action, "menu.edit.manage_tags") - self.tag_manager_action.triggered.connect(lambda: self.show_tag_manager()) + self.tag_manager_action.triggered.connect(self.tag_manager_panel.show) self.tag_manager_action.setShortcut( QtCore.QKeyCombination( QtCore.Qt.KeyboardModifier(QtCore.Qt.KeyboardModifier.ControlModifier), @@ -750,6 +764,27 @@ class QtDriver(DriverMixin, QObject): self.splash.finish(self.main_window) + def init_file_extension_manager(self): + """Initialize the File Extension panel.""" + if self.file_extension_panel: + with catch_warnings(record=True): + self.manage_file_ext_action.triggered.disconnect() + self.file_extension_panel.saved.disconnect() + self.file_extension_panel.deleteLater() + self.file_extension_panel = None + + panel = FileExtensionModal(self.lib) + self.file_extension_panel = PanelModal( + panel, + has_save=True, + ) + Translations.translate_with_setter(self.file_extension_panel.setTitle, "ignore_list.title") + Translations.translate_with_setter( + self.file_extension_panel.setWindowTitle, "ignore_list.title" + ) + self.file_extension_panel.saved.connect(lambda: (panel.save(), self.filter_items())) + self.manage_file_ext_action.triggered.connect(self.file_extension_panel.show) + def show_grid_filenames(self, value: bool): for thumb in self.item_thumbs: thumb.set_filename_visibility(value) @@ -902,28 +937,6 @@ class QtDriver(DriverMixin, QObject): for entry_id in self.selected: self.lib.add_tags_to_entry(entry_id, tag_ids) - def show_tag_manager(self): - self.modal = PanelModal( - widget=TagDatabasePanel(self.lib), - done_callback=lambda: self.preview_panel.update_widgets(update_preview=False), - has_save=False, - ) - Translations.translate_with_setter(self.modal.setTitle, "tag_manager.title") - Translations.translate_with_setter(self.modal.setWindowTitle, "tag_manager.title") - self.modal.show() - - def show_file_extension_modal(self): - panel = FileExtensionModal(self.lib) - self.modal = PanelModal( - panel, - has_save=True, - ) - Translations.translate_with_setter(self.modal.setTitle, "ignore_list.title") - Translations.translate_with_setter(self.modal.setWindowTitle, "ignore_list.title") - - self.modal.saved.connect(lambda: (panel.save(), self.filter_items())) - self.modal.show() - def add_new_files_callback(self): """Run when user initiates adding new files to the Library.""" tracker = RefreshDirTracker(self.lib) @@ -1668,6 +1681,8 @@ class QtDriver(DriverMixin, QObject): ) self.main_window.setAcceptDrops(True) + self.init_file_extension_manager() + self.selected.clear() self.set_select_actions_visibility() self.save_library_backup_action.setEnabled(True) diff --git a/tagstudio/src/qt/widgets/preview_panel.py b/tagstudio/src/qt/widgets/preview_panel.py index ef1ff99a..ab1791a9 100644 --- a/tagstudio/src/qt/widgets/preview_panel.py +++ b/tagstudio/src/qt/widgets/preview_panel.py @@ -211,9 +211,4 @@ class PreviewPanel(QWidget): ) ) - self.add_tag_button.clicked.connect( - lambda: ( - self.tag_search_panel.update_tags(), - self.add_tag_modal.show(), - ) - ) + self.add_tag_button.clicked.connect(self.add_tag_modal.show) diff --git a/tagstudio/src/qt/widgets/tag.py b/tagstudio/src/qt/widgets/tag.py index 60afd8f0..8f1f405e 100644 --- a/tagstudio/src/qt/widgets/tag.py +++ b/tagstudio/src/qt/widgets/tag.py @@ -105,7 +105,7 @@ class TagWidget(QWidget): def __init__( self, - tag: Tag, + tag: Tag | None, has_edit: bool, has_remove: bool, library: "Library | None" = None, @@ -127,10 +127,7 @@ class TagWidget(QWidget): self.bg_button = QPushButton(self) self.bg_button.setFlat(True) - if self.lib: - self.bg_button.setText(escape_text(self.lib.tag_display_name(tag.id))) - else: - self.bg_button.setText(escape_text(tag.name)) + if has_edit: edit_action = QAction(self) edit_action.setText(Translations.translate_formatted("generic.edit")) @@ -153,9 +150,38 @@ class TagWidget(QWidget): self.inner_layout.setObjectName("innerLayout") self.inner_layout.setContentsMargins(0, 0, 0, 0) + self.remove_button = QPushButton(self) + self.remove_button.setFlat(True) + self.remove_button.setText("–") + self.remove_button.setHidden(True) + self.remove_button.setMinimumSize(22, 22) + self.remove_button.setMaximumSize(22, 22) + self.remove_button.clicked.connect(self.on_remove.emit) + self.remove_button.setHidden(True) + self.inner_layout.addWidget(self.remove_button) + self.inner_layout.addStretch(1) + self.bg_button.setLayout(self.inner_layout) self.bg_button.setMinimumSize(44, 22) + self.bg_button.setMinimumHeight(22) + self.bg_button.setMaximumHeight(22) + + self.base_layout.addWidget(self.bg_button) + + # NOTE: Do this if you don't want the tag to stretch, like in a search. + # self.bg_button.setMaximumWidth(self.bg_button.sizeHint().width()) + + self.bg_button.clicked.connect(self.on_click.emit) + + self.set_tag(tag) + + def set_tag(self, tag: Tag | None) -> None: + self.tag = tag + + if not tag: + return + primary_color = get_primary_color(tag) border_color = ( get_border_color(primary_color) @@ -200,55 +226,42 @@ class TagWidget(QWidget): f"outline:none;" f"}}" ) - self.bg_button.setMinimumHeight(22) - self.bg_button.setMaximumHeight(22) - self.base_layout.addWidget(self.bg_button) + self.remove_button.setStyleSheet( + f"QPushButton{{" + f"color: rgba{primary_color.toTuple()};" + f"background: rgba{text_color.toTuple()};" + f"font-weight: 800;" + f"border-radius: 5px;" + f"border-width: 4;" + f"border-color: rgba(0,0,0,0);" + f"padding-bottom: 4px;" + f"font-size: 14px" + f"}}" + f"QPushButton::hover{{" + f"background: rgba{primary_color.toTuple()};" + f"color: rgba{text_color.toTuple()};" + f"border-color: rgba{highlight_color.toTuple()};" + f"border-width: 2;" + f"border-radius: 6px;" + f"}}" + f"QPushButton::pressed{{" + f"background: rgba{border_color.toTuple()};" + f"color: rgba{highlight_color.toTuple()};" + f"}}" + f"QPushButton::focus{{" + f"background: rgba{border_color.toTuple()};" + f"outline:none;" + f"}}" + ) - if has_remove: - self.remove_button = QPushButton(self) - self.remove_button.setFlat(True) - self.remove_button.setText("–") - self.remove_button.setHidden(True) - self.remove_button.setStyleSheet( - f"QPushButton{{" - f"color: rgba{primary_color.toTuple()};" - f"background: rgba{text_color.toTuple()};" - f"font-weight: 800;" - f"border-radius: 5px;" - f"border-width: 4;" - f"border-color: rgba(0,0,0,0);" - f"padding-bottom: 4px;" - f"font-size: 14px" - f"}}" - f"QPushButton::hover{{" - f"background: rgba{primary_color.toTuple()};" - f"color: rgba{text_color.toTuple()};" - f"border-color: rgba{highlight_color.toTuple()};" - f"border-width: 2;" - f"border-radius: 6px;" - f"}}" - f"QPushButton::pressed{{" - f"background: rgba{border_color.toTuple()};" - f"color: rgba{highlight_color.toTuple()};" - f"}}" - f"QPushButton::focus{{" - f"background: rgba{border_color.toTuple()};" - f"outline:none;" - f"}}" - ) - self.remove_button.setMinimumSize(22, 22) - self.remove_button.setMaximumSize(22, 22) - self.remove_button.clicked.connect(self.on_remove.emit) + if self.lib: + self.bg_button.setText(escape_text(self.lib.tag_display_name(tag.id))) + else: + self.bg_button.setText(escape_text(tag.name)) - if has_remove: - self.inner_layout.addWidget(self.remove_button) - self.inner_layout.addStretch(1) - - # NOTE: Do this if you don't want the tag to stretch, like in a search. - # self.bg_button.setMaximumWidth(self.bg_button.sizeHint().width()) - - self.bg_button.clicked.connect(self.on_click.emit) + def set_has_remove(self, has_remove: bool): + self.has_remove = has_remove def enterEvent(self, event: QEnterEvent) -> None: # noqa: N802 if self.has_remove: