From 441ffce4a3a4cb5fb96613cc394a69960153c97e Mon Sep 17 00:00:00 2001 From: SkeleyM <86805089+SkeleyM@users.noreply.github.com> Date: Wed, 22 Jan 2025 23:56:54 +0000 Subject: [PATCH] feat(ui): port "create and add tag" to main branch (#711) * Port create & add tag * Fix Name Conflict * Add translation keys * unify uses of BuildTagPanel * replace tabs with spaces * Add tag on creation * Add Suggestions * Trigger on return --------- Co-authored-by: bjorn-out --- tagstudio/resources/translations/en.json | 1 + tagstudio/resources/translations/fr.json | 1 + tagstudio/src/qt/modals/tag_search.py | 92 +++++++++++++++++++++--- 3 files changed, 84 insertions(+), 10 deletions(-) diff --git a/tagstudio/resources/translations/en.json b/tagstudio/resources/translations/en.json index 0f96a4c4..bed30fe8 100644 --- a/tagstudio/resources/translations/en.json +++ b/tagstudio/resources/translations/en.json @@ -200,6 +200,7 @@ "tag.color": "Color", "tag.confirm_delete": "Are you sure you want to delete the tag \"{tag_name}\"?", "tag.create": "Create Tag", + "tag.create_add": "Create && Add \"{query}\"", "tag.edit": "Edit Tag", "tag.name": "Name", "tag.new": "New Tag", diff --git a/tagstudio/resources/translations/fr.json b/tagstudio/resources/translations/fr.json index f6c7617e..22b1774c 100644 --- a/tagstudio/resources/translations/fr.json +++ b/tagstudio/resources/translations/fr.json @@ -130,6 +130,7 @@ "tag.add_to_search": "Ajouter à la Recherche", "tag.aliases": "Alias", "tag.color": "Couleur", + "tag.create_add": "Créer && Adjouter \"{query}\"" "tag.name": "Nom", "tag.new": "Nouveau Label", "tag.parent_tags": "Labels Parent", diff --git a/tagstudio/src/qt/modals/tag_search.py b/tagstudio/src/qt/modals/tag_search.py index b6579ac4..cf16a665 100644 --- a/tagstudio/src/qt/modals/tag_search.py +++ b/tagstudio/src/qt/modals/tag_search.py @@ -5,6 +5,7 @@ import math +import src.qt.modals.build_tag as build_tag import structlog from PySide6.QtCore import QSize, Qt, Signal from PySide6.QtGui import QShowEvent @@ -19,6 +20,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 TagColor from src.core.palette import ColorType, get_tag_color from src.qt.translations import Translations from src.qt.widgets.panel import PanelModal, PanelWidget @@ -117,6 +119,71 @@ class TagSearchPanel(PanelWidget): row.addWidget(add_button) return container + def construct_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) + + 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(math.ceil(22 * 1.5), 22) + + create_button.setStyleSheet( + f"QPushButton{{" + f"background: {get_tag_color(ColorType.PRIMARY, TagColor.DEFAULT)};" + f"color: {get_tag_color(ColorType.TEXT, TagColor.DEFAULT)};" + f"font-weight: 600;" + f"border-color:{get_tag_color(ColorType.BORDER, TagColor.DEFAULT)};" + f"border-radius: 6px;" + f"border-style:solid;" + f"border-width: {math.ceil(self.devicePixelRatio())}px;" + f"padding-right: 4px;" + f"padding-bottom: 1px;" + f"padding-left: 4px;" + f"font-size: 13px" + f"}}" + f"QPushButton::hover{{" + f"border-color:{get_tag_color(ColorType.LIGHT_ACCENT, TagColor.DEFAULT)};" + f"}}" + ) + + create_button.clicked.connect(lambda: self.create_and_add_tag(query)) + row.addWidget(create_button) + + return container + + def create_and_add_tag(self, name: str): + """Opens "Create Tag" panel to create and add a new tag with given name.""" + logger.info("Create and Add Tag", name=name) + + def on_tag_modal_saved(): + """Callback for actions to perform when a new tag is confirmed created.""" + tag: Tag = self.build_tag_modal.build_tag() + self.lib.add_tag(tag) + self.add_tag_modal.hide() + + self.tag_chosen.emit(tag.id) + self.search_field.setText("") + self.update_tags() + + self.build_tag_modal: build_tag.BuildTagPanel = build_tag.BuildTagPanel(self.lib) + self.add_tag_modal: PanelModal = PanelModal(self.build_tag_modal, has_save=True) + Translations.translate_with_setter(self.add_tag_modal.setTitle, "tag.new") + Translations.translate_with_setter(self.add_tag_modal.setWindowTitle, "tag.add") + + 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") @@ -134,14 +201,22 @@ class TagSearchPanel(PanelWidget): if tag.id not in self.exclude: self.scroll_layout.addWidget(self.__build_row_item_widget(tag)) + # If query doesnt exist add create button + if len(tag_results) == 0: + c = self.construct_tag_button(query) + self.scroll_layout.addWidget(c) + self.search_field.setFocus() def on_return(self, text: str): - if text and self.first_tag_id is not None: - if self.is_tag_chooser: - self.tag_chosen.emit(self.first_tag_id) - self.search_field.setText("") - self.update_tags() + if text: + if self.first_tag_id is not None: + if self.is_tag_chooser: + self.tag_chosen.emit(self.first_tag_id) + self.search_field.setText("") + self.update_tags() + else: + self.create_and_add_tag(text) else: self.search_field.setFocus() self.parentWidget().hide() @@ -156,16 +231,13 @@ class TagSearchPanel(PanelWidget): pass def edit_tag(self, tag: Tag): - # only import here because of circular imports - from src.qt.modals.build_tag import BuildTagPanel - - def callback(btp: BuildTagPanel): + def callback(btp: build_tag.BuildTagPanel): self.lib.update_tag( btp.build_tag(), set(btp.parent_ids), set(btp.alias_names), set(btp.alias_ids) ) self.update_tags(self.search_field.text()) - build_tag_panel = BuildTagPanel(self.lib, tag=tag) + build_tag_panel = build_tag.BuildTagPanel(self.lib, tag=tag) self.edit_modal = PanelModal( build_tag_panel,