mirror of
https://github.com/TagStudioDev/TagStudio.git
synced 2026-08-31 00:01:34 +02:00
refactor: move stylesheets to central file
This commit is contained in:
@@ -4,7 +4,10 @@
|
||||
|
||||
VERSION: str = "9.5.7" # Major.Minor.Patch
|
||||
VERSION_BRANCH: str = "" # Usually "" or "Pre-Release"
|
||||
GITHUB_REPO_URL = "https://github.com/TagStudioDev/TagStudio"
|
||||
GITHUB_RELEASE_URL = "https://github.com/TagStudioDev/TagStudio/releases/latest"
|
||||
DOCS_URL = "https://docs.tagstud.io"
|
||||
DISCORD_URL = "https://discord.com/invite/hRNnVKhF2G"
|
||||
|
||||
# The folder & file names where TagStudio keeps its data relative to a library.
|
||||
TS_FOLDER_NAME: str = ".TagStudio"
|
||||
@@ -13,9 +16,7 @@ COLLAGE_FOLDER_NAME: str = "collages"
|
||||
IGNORE_NAME: str = ".ts_ignore"
|
||||
THUMB_CACHE_NAME: str = "thumbs"
|
||||
|
||||
FONT_SAMPLE_TEXT: str = (
|
||||
"""ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!?@$%(){}[]"""
|
||||
)
|
||||
FONT_SAMPLE_TEXT: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!?@$%(){}[]"
|
||||
FONT_SAMPLE_SIZES: list[int] = [10, 15, 20]
|
||||
|
||||
# NOTE: These were the field IDs used for the "Tags", "Content Tags", and "Meta Tags" fields inside
|
||||
@@ -27,5 +28,4 @@ TAG_FAVORITE = 1
|
||||
TAG_META = 2
|
||||
RESERVED_TAG_START = 0
|
||||
RESERVED_TAG_END = 999
|
||||
|
||||
RESERVED_NAMESPACE_PREFIX = "tagstudio"
|
||||
|
||||
@@ -9,9 +9,9 @@ from tagstudio.core.library.alchemy.fields import (
|
||||
DatetimeFieldTemplate,
|
||||
TextFieldTemplate,
|
||||
)
|
||||
from tagstudio.qt.models.palette import ColorType, UiColor, get_ui_color
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.edit_field_template_modal_view import EditFieldTemplateModalView
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import line_edit_style
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -71,11 +71,7 @@ class EditFieldTemplateModal(EditFieldTemplateModalView):
|
||||
def __on_name_changed(self):
|
||||
is_empty = not self.name_field.text().strip()
|
||||
|
||||
self.name_field.setStyleSheet(
|
||||
f"border: 1px solid {get_ui_color(ColorType.PRIMARY, UiColor.RED)}; border-radius: 2px"
|
||||
if is_empty
|
||||
else ""
|
||||
)
|
||||
self.name_field.setStyleSheet(line_edit_style() if is_empty else "")
|
||||
|
||||
if self.panel_save_button is not None:
|
||||
self.panel_save_button.setDisabled(is_empty)
|
||||
|
||||
@@ -13,6 +13,7 @@ from tagstudio.qt.mixed.progress_bar import ProgressWidget
|
||||
from tagstudio.qt.mixed.remove_ignored_modal import RemoveIgnoredModal
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.fix_ignored_modal_view import FixIgnoredEntriesModalView
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import header
|
||||
|
||||
# Only import for type checking/autocompletion, will not be imported at runtime.
|
||||
if TYPE_CHECKING:
|
||||
@@ -78,7 +79,7 @@ class FixIgnoredEntriesModal(FixIgnoredEntriesModalView):
|
||||
count_text: str = Translations.format(
|
||||
"entries.ignored.ignored_count", count=count if count >= 0 else "—"
|
||||
)
|
||||
self.ignored_count_label.setText(f"<h3>{count_text}</h3>")
|
||||
self.ignored_count_label.setText(header(count_text, 3))
|
||||
|
||||
def update_driver_widgets(self):
|
||||
if (
|
||||
|
||||
@@ -22,6 +22,7 @@ from tagstudio.core.utils.types import unwrap
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.utils import file_opener
|
||||
from tagstudio.qt.views.library_info_window_view import LibraryInfoWindowView
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import header
|
||||
|
||||
# Only import for type checking/autocompletion, will not be imported at runtime.
|
||||
if TYPE_CHECKING:
|
||||
@@ -61,7 +62,7 @@ class LibraryInfoWindow(LibraryInfoWindowView):
|
||||
title: str = Translations.format(
|
||||
"library_info.title", library_dir=self.lib.library_dir.stem
|
||||
)
|
||||
self.title_label.setText(f"<h2>{title}</h2>")
|
||||
self.title_label.setText(header(title, 2))
|
||||
|
||||
def update_stats(self):
|
||||
self.entry_count_label.setText(f"<b>{self.lib.entries_count}</b>")
|
||||
|
||||
@@ -10,6 +10,7 @@ from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QHBoxLayout, QLabel, QVBoxLayout, QWidget
|
||||
|
||||
from tagstudio.qt.controllers.paged_panel_state import PagedPanelState
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import header
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -89,7 +90,7 @@ class PagedPanel(QWidget):
|
||||
|
||||
# Update Title
|
||||
self.setWindowTitle(frame.title)
|
||||
self.title_label.setText(f"<h1>{frame.title}</h1>")
|
||||
self.title_label.setText(header(frame.title, 1))
|
||||
|
||||
# Update Body Widget
|
||||
if self.body_layout.itemAt(0):
|
||||
@@ -107,7 +108,7 @@ class PagedPanel(QWidget):
|
||||
if isinstance(item, QWidget):
|
||||
self.button_nav_layout.addWidget(item)
|
||||
item.setHidden(False)
|
||||
elif isinstance(item, int):
|
||||
elif isinstance(item, int): # pyright: ignore[reportUnnecessaryIsInstance]
|
||||
self.button_nav_layout.addStretch(item)
|
||||
|
||||
@override
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
|
||||
|
||||
import math
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import ImageQt
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QGuiApplication, QPixmap
|
||||
from PySide6.QtGui import QPixmap
|
||||
from PySide6.QtWidgets import (
|
||||
QFormLayout,
|
||||
QHBoxLayout,
|
||||
@@ -17,35 +18,29 @@ from PySide6.QtWidgets import (
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from tagstudio.core.constants import VERSION, VERSION_BRANCH
|
||||
from tagstudio.core.enums import Theme
|
||||
from tagstudio.core.constants import (
|
||||
DISCORD_URL,
|
||||
DOCS_URL,
|
||||
GITHUB_REPO_URL,
|
||||
VERSION,
|
||||
VERSION_BRANCH,
|
||||
)
|
||||
from tagstudio.core.ts_core import TagStudioCore
|
||||
from tagstudio.core.utils.types import unwrap
|
||||
from tagstudio.qt.models.palette import ColorType, UiColor, get_ui_color
|
||||
from tagstudio.qt.previews.vendored import ffmpeg
|
||||
from tagstudio.qt.resource_manager import ResourceManager
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import form_content_style, header
|
||||
|
||||
|
||||
class AboutModal(QWidget):
|
||||
def __init__(self, config_path):
|
||||
def __init__(self, config_path: Path | str):
|
||||
super().__init__()
|
||||
self.setWindowTitle(Translations["about.title"])
|
||||
|
||||
self.rm: ResourceManager = ResourceManager()
|
||||
|
||||
# TODO: There should be a global button theme somewhere.
|
||||
self.form_content_style = (
|
||||
f"background-color:{
|
||||
Theme.COLOR_BG.value
|
||||
if QGuiApplication.styleHints().colorScheme() is Qt.ColorScheme.Dark
|
||||
else Theme.COLOR_BG_LIGHT.value
|
||||
};"
|
||||
"border-radius:3px;"
|
||||
"font-weight: 500;"
|
||||
"padding: 2px;"
|
||||
)
|
||||
|
||||
self.setWindowModality(Qt.WindowModality.ApplicationModal)
|
||||
self.setMinimumSize(360, 540)
|
||||
self.setMaximumSize(600, 600)
|
||||
@@ -72,7 +67,8 @@ class AboutModal(QWidget):
|
||||
|
||||
# Title ----------------------------------------------------------------
|
||||
branch: str = (" (" + VERSION_BRANCH + ")") if VERSION_BRANCH else ""
|
||||
self.title_label = QLabel(f"<h2>TagStudio Alpha {VERSION}{branch}</h2>")
|
||||
# NOTE: Do not localize program name.
|
||||
self.title_label = QLabel(header(f"TagStudio Alpha {VERSION}{branch}", 2))
|
||||
self.title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
# Description ----------------------------------------------------------
|
||||
@@ -105,14 +101,18 @@ class AboutModal(QWidget):
|
||||
self.system_info_layout.setLabelAlignment(Qt.AlignmentFlag.AlignRight)
|
||||
|
||||
# Version
|
||||
version_title = QLabel("Version")
|
||||
most_recent_release = unwrap(TagStudioCore.get_most_recent_release_version(), "UNKNOWN")
|
||||
version_content_style = self.form_content_style
|
||||
if most_recent_release == VERSION:
|
||||
version_title = QLabel(Translations["about.version"])
|
||||
latest_version = unwrap(TagStudioCore.get_most_recent_release_version(), "?")
|
||||
version_content_style = form_content_style()
|
||||
if latest_version == VERSION:
|
||||
version_content = QLabel(f"{VERSION}")
|
||||
else:
|
||||
version_content = QLabel(f"{VERSION} (Latest Release: {most_recent_release})")
|
||||
version_content_style += "color: #d9534f;"
|
||||
version_content = QLabel(
|
||||
Translations.format(
|
||||
"about.version.latest", built_version=VERSION, latest_version=latest_version
|
||||
)
|
||||
)
|
||||
version_content_style += f"color: {red};"
|
||||
version_content.setStyleSheet(version_content_style)
|
||||
version_content.setMaximumWidth(version_content.sizeHint().width())
|
||||
self.system_info_layout.addRow(version_title, version_content)
|
||||
@@ -120,40 +120,37 @@ class AboutModal(QWidget):
|
||||
# License
|
||||
license_title = QLabel(f"{Translations['about.license']}")
|
||||
license_content = QLabel("GPLv3")
|
||||
license_content.setStyleSheet(self.form_content_style)
|
||||
license_content.setStyleSheet(form_content_style())
|
||||
license_content.setMaximumWidth(license_content.sizeHint().width())
|
||||
self.system_info_layout.addRow(license_title, license_content)
|
||||
|
||||
# Config Path
|
||||
config_path_title = QLabel(f"{Translations['about.config_path']}")
|
||||
config_path_content = QLabel(f"{config_path}")
|
||||
config_path_content.setStyleSheet(self.form_content_style)
|
||||
config_path_content.setStyleSheet(form_content_style())
|
||||
config_path_content.setWordWrap(True)
|
||||
self.system_info_layout.addRow(config_path_title, config_path_content)
|
||||
|
||||
# FFmpeg Status
|
||||
ffmpeg_path_title = QLabel("FFmpeg")
|
||||
ffmpeg_path_content = QLabel(f"{ffmpeg_status}")
|
||||
ffmpeg_path_content.setStyleSheet(self.form_content_style)
|
||||
ffmpeg_path_content.setStyleSheet(form_content_style())
|
||||
ffmpeg_path_content.setMaximumWidth(ffmpeg_path_content.sizeHint().width())
|
||||
self.system_info_layout.addRow(ffmpeg_path_title, ffmpeg_path_content)
|
||||
|
||||
# FFprobe Status
|
||||
ffprobe_path_title = QLabel("FFprobe")
|
||||
ffprobe_path_content = QLabel(f"{ffprobe_status}")
|
||||
ffprobe_path_content.setStyleSheet(self.form_content_style)
|
||||
ffprobe_path_content.setStyleSheet(form_content_style())
|
||||
ffprobe_path_content.setMaximumWidth(ffprobe_path_content.sizeHint().width())
|
||||
self.system_info_layout.addRow(ffprobe_path_title, ffprobe_path_content)
|
||||
|
||||
# Links ----------------------------------------------------------------
|
||||
repo_link = "https://github.com/TagStudioDev/TagStudio"
|
||||
docs_link = "https://docs.tagstud.io"
|
||||
discord_link = "https://discord.com/invite/hRNnVKhF2G"
|
||||
|
||||
self.links_label = QLabel(
|
||||
f'<p><a href="{repo_link}">GitHub</a> | '
|
||||
f'<a href="{docs_link}">{Translations["about.documentation"]}</a> | '
|
||||
f'<a href="{discord_link}">Discord</a></p>'
|
||||
f'<p><a href="{GITHUB_REPO_URL}">GitHub</a> | '
|
||||
f'<a href="{DOCS_URL}">{Translations["about.documentation"]}</a> | '
|
||||
f'<a href="{DISCORD_URL}">Discord</a></p>'
|
||||
)
|
||||
self.links_label.setWordWrap(True)
|
||||
self.links_label.setOpenExternalLinks(True)
|
||||
|
||||
@@ -19,6 +19,7 @@ from PySide6.QtWidgets import (
|
||||
|
||||
from tagstudio.core.library.alchemy.library import Library
|
||||
from tagstudio.qt.translations import FIELD_TYPE_KEYS, Translations
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import header
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -39,10 +40,9 @@ class AddFieldModal(QWidget):
|
||||
self.root_layout = QVBoxLayout(self)
|
||||
self.root_layout.setContentsMargins(6, 6, 6, 6)
|
||||
|
||||
self.title_widget = QLabel(Translations["field.add"])
|
||||
self.title_widget = QLabel(header(Translations["field.add"], 3))
|
||||
self.title_widget.setObjectName("fieldTitle")
|
||||
self.title_widget.setWordWrap(True)
|
||||
self.title_widget.setStyleSheet("font-weight:bold;font-size:14px;padding-top: 6px;")
|
||||
self.title_widget.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.list_widget = QListWidget()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
import contextlib
|
||||
from typing import override
|
||||
|
||||
import structlog
|
||||
from PySide6.QtCore import Qt, Signal
|
||||
@@ -24,15 +25,14 @@ from tagstudio.core.library.alchemy.library import Library, slugify
|
||||
from tagstudio.core.library.alchemy.models import TagColorGroup
|
||||
from tagstudio.core.utils.types import unwrap
|
||||
from tagstudio.qt.mixed.tag_color_preview import TagColorPreview
|
||||
from tagstudio.qt.mixed.tag_widget import (
|
||||
get_border_color,
|
||||
get_highlight_color,
|
||||
get_text_color,
|
||||
)
|
||||
from tagstudio.qt.models.palette import ColorType, UiColor, get_tag_color, get_ui_color
|
||||
from tagstudio.qt.models.palette import ColorType, get_tag_color
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.panel_modal import PanelWidget
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import checkbox_style
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import (
|
||||
checkbox_style,
|
||||
line_edit_style,
|
||||
list_button_style,
|
||||
)
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -130,7 +130,6 @@ class BuildColorPanel(PanelWidget):
|
||||
color=QColor(unwrap(self.preview_button.tag_color_group).secondary)
|
||||
if unwrap(self.preview_button.tag_color_group).secondary
|
||||
else None,
|
||||
color_border=checked,
|
||||
)
|
||||
)
|
||||
self.border_layout.addWidget(self.border_checkbox)
|
||||
@@ -193,89 +192,20 @@ class BuildColorPanel(PanelWidget):
|
||||
def update_primary(self, color: QColor):
|
||||
logger.info("[BuildColorPanel] Updating Primary", primary_color=color)
|
||||
|
||||
highlight_color = get_highlight_color(color)
|
||||
text_color = get_text_color(color, highlight_color)
|
||||
border_color = get_border_color(color)
|
||||
|
||||
hex_code = color.name().upper()
|
||||
|
||||
self.primary_button.setText(hex_code)
|
||||
self.primary_button.setStyleSheet(
|
||||
f"QPushButton{{"
|
||||
f"background: rgba{color.toTuple()};"
|
||||
f"color: rgba{text_color.toTuple()};"
|
||||
f"font-weight: 600;"
|
||||
f"border-color: rgba{border_color.toTuple()};"
|
||||
f"border-radius: 6px;"
|
||||
f"border-style:solid;"
|
||||
f"border-width: 2px;"
|
||||
f"padding-right: 4px;"
|
||||
f"padding-bottom: 1px;"
|
||||
f"padding-left: 4px;"
|
||||
f"font-size: 13px"
|
||||
f"}}"
|
||||
f"QPushButton::hover{{"
|
||||
f"border-color: rgba{highlight_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QPushButton::pressed{{"
|
||||
f"background: rgba{highlight_color.toTuple()};"
|
||||
f"color: rgba{color.toTuple()};"
|
||||
f"border-color: rgba{color.toTuple()};"
|
||||
f"}}"
|
||||
f"QPushButton::focus{{"
|
||||
f"padding-right: 0px;"
|
||||
f"padding-left: 0px;"
|
||||
f"outline-style: solid;"
|
||||
f"outline-width: 1px;"
|
||||
f"outline-radius: 4px;"
|
||||
f"outline-color: rgba{text_color.toTuple()};"
|
||||
f"}}"
|
||||
)
|
||||
self.primary_button.setStyleSheet(list_button_style(color))
|
||||
self.preview_button.set_tag_color_group(self.build_color()[1])
|
||||
|
||||
def update_secondary(self, color: QColor | None = None, color_border: bool = False):
|
||||
def update_secondary(self, color: QColor | None = None):
|
||||
logger.info("[BuildColorPanel] Updating Secondary", color=color)
|
||||
|
||||
color_ = color or QColor(get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT))
|
||||
|
||||
highlight_color = get_highlight_color(color_)
|
||||
text_color = get_text_color(color_, highlight_color)
|
||||
border_color = get_border_color(color_)
|
||||
|
||||
hex_code = "" if not color else color.name().upper()
|
||||
self.secondary_button.setText(
|
||||
Translations["color.title.no_color"] if not color else hex_code
|
||||
)
|
||||
self.secondary_button.setStyleSheet(
|
||||
f"QPushButton{{"
|
||||
f"background: rgba{color_.toTuple()};"
|
||||
f"color: rgba{text_color.toTuple()};"
|
||||
f"font-weight: 600;"
|
||||
f"border-color: rgba{border_color.toTuple()};"
|
||||
f"border-radius: 6px;"
|
||||
f"border-style:solid;"
|
||||
f"border-width: 2px;"
|
||||
f"padding-right: 4px;"
|
||||
f"padding-bottom: 1px;"
|
||||
f"padding-left: 4px;"
|
||||
f"font-size: 13px"
|
||||
f"}}"
|
||||
f"QPushButton::hover{{"
|
||||
f"border-color: rgba{highlight_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QPushButton::pressed{{"
|
||||
f"background: rgba{highlight_color.toTuple()};"
|
||||
f"color: rgba{color_.toTuple()};"
|
||||
f"border-color: rgba{color_.toTuple()};"
|
||||
f"}}"
|
||||
f"QPushButton::focus{{"
|
||||
f"padding-right: 0px;"
|
||||
f"padding-left: 0px;"
|
||||
f"outline-style: solid;"
|
||||
f"outline-width: 1px;"
|
||||
f"outline-radius: 4px;"
|
||||
f"outline-color: rgba{text_color.toTuple()};"
|
||||
f"}}"
|
||||
)
|
||||
|
||||
self.secondary_button.setText(hex_code if color else Translations["color.title.no_color"])
|
||||
self.secondary_button.setStyleSheet(list_button_style(color_))
|
||||
self.preview_button.set_tag_color_group(self.build_color()[1])
|
||||
|
||||
def update_known_colors(self):
|
||||
@@ -317,17 +247,9 @@ class BuildColorPanel(PanelWidget):
|
||||
is_slug_empty = not slug
|
||||
is_invalid = False
|
||||
|
||||
self.name_field.setStyleSheet(
|
||||
f"border: 1px solid {get_ui_color(ColorType.PRIMARY, UiColor.RED)}; border-radius: 2px"
|
||||
if is_name_empty
|
||||
else ""
|
||||
)
|
||||
self.name_field.setStyleSheet(line_edit_style() if is_name_empty else "")
|
||||
|
||||
self.slug_field.setStyleSheet(
|
||||
f"border: 1px solid {get_ui_color(ColorType.PRIMARY, UiColor.RED)}; border-radius: 2px"
|
||||
if is_slug_empty or is_invalid
|
||||
else ""
|
||||
)
|
||||
self.slug_field.setStyleSheet(line_edit_style() if is_slug_empty or is_invalid else "")
|
||||
|
||||
self.slug_field.setText(slug)
|
||||
self.update_preview_text()
|
||||
@@ -364,13 +286,7 @@ class BuildColorPanel(PanelWidget):
|
||||
)
|
||||
return (self.color_group, new_color)
|
||||
|
||||
@override
|
||||
def parent_post_init(self):
|
||||
# self.setTabOrder(self.name_field, self.shorthand_field)
|
||||
# self.setTabOrder(self.shorthand_field, self.aliases_add_button)
|
||||
# self.setTabOrder(self.aliases_add_button, self.parent_tags_add_button)
|
||||
# self.setTabOrder(self.parent_tags_add_button, self.color_button)
|
||||
# self.setTabOrder(self.color_button, 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()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
import contextlib
|
||||
from typing import override
|
||||
from uuid import uuid4
|
||||
|
||||
import structlog
|
||||
@@ -12,9 +13,9 @@ from PySide6.QtWidgets import QLabel, QLineEdit, QVBoxLayout, QWidget
|
||||
from tagstudio.core.constants import RESERVED_NAMESPACE_PREFIX
|
||||
from tagstudio.core.library.alchemy.library import Library, ReservedNamespaceError, slugify
|
||||
from tagstudio.core.library.alchemy.models import Namespace
|
||||
from tagstudio.qt.models.palette import ColorType, UiColor, get_ui_color
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.panel_modal import PanelWidget
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import line_edit_style
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -111,17 +112,9 @@ class BuildNamespacePanel(PanelWidget):
|
||||
is_slug_empty = not slug
|
||||
is_invalid = False
|
||||
|
||||
self.name_field.setStyleSheet(
|
||||
f"border: 1px solid {get_ui_color(ColorType.PRIMARY, UiColor.RED)}; border-radius: 2px"
|
||||
if is_name_empty
|
||||
else ""
|
||||
)
|
||||
self.name_field.setStyleSheet(line_edit_style() if is_name_empty else "")
|
||||
|
||||
self.slug_field.setStyleSheet(
|
||||
f"border: 1px solid {get_ui_color(ColorType.PRIMARY, UiColor.RED)}; border-radius: 2px"
|
||||
if is_slug_empty or is_invalid
|
||||
else ""
|
||||
)
|
||||
self.slug_field.setStyleSheet(line_edit_style() if is_slug_empty or is_invalid else "")
|
||||
|
||||
self.slug_field.setText(slug)
|
||||
|
||||
@@ -156,6 +149,7 @@ class BuildNamespacePanel(PanelWidget):
|
||||
logger.info("[BuildNamespacePanel] Built Namespace", slug=slug, name=name)
|
||||
return namespace
|
||||
|
||||
@override
|
||||
def parent_post_init(self):
|
||||
self.setTabOrder(self.name_field, self.slug_field)
|
||||
self.name_field.selectAll()
|
||||
|
||||
@@ -33,15 +33,19 @@ from tagstudio.qt.mixed.tag_color_preview import TagColorPreview
|
||||
from tagstudio.qt.mixed.tag_color_selection import TagColorSelection
|
||||
from tagstudio.qt.mixed.tag_widget import (
|
||||
TagWidget,
|
||||
get_border_color,
|
||||
get_highlight_color,
|
||||
get_primary_color,
|
||||
get_text_color,
|
||||
get_tag_border_color,
|
||||
get_tag_highlight_color,
|
||||
get_tag_primary_color,
|
||||
get_tag_text_color,
|
||||
)
|
||||
from tagstudio.qt.models.palette import ColorType, UiColor, get_ui_color
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.panel_modal import PanelModal, PanelWidget
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import checkbox_style
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import (
|
||||
checkbox_style,
|
||||
colored_radio_button_style,
|
||||
header,
|
||||
line_edit_style,
|
||||
)
|
||||
from tagstudio.qt.views.tag_search_panel_view import TagSearchPanelView
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
@@ -244,7 +248,7 @@ class BuildTagPanel(PanelWidget):
|
||||
self.root_layout.addWidget(self.aliases_add_button)
|
||||
self.root_layout.addWidget(self.parent_tags_widget)
|
||||
self.root_layout.addWidget(self.color_widget)
|
||||
self.root_layout.addWidget(QLabel("<h3>Properties</h3>"))
|
||||
self.root_layout.addWidget(QLabel(header(Translations["tag.properties"], 3)))
|
||||
self.root_layout.addWidget(self.cat_widget)
|
||||
self.root_layout.addWidget(self.hidden_widget)
|
||||
|
||||
@@ -357,13 +361,13 @@ class BuildTagPanel(PanelWidget):
|
||||
row.setSpacing(3)
|
||||
|
||||
# Init Colors
|
||||
primary_color = get_primary_color(tag)
|
||||
primary_color = get_tag_primary_color(tag)
|
||||
border_color = (
|
||||
get_border_color(primary_color)
|
||||
get_tag_border_color(primary_color)
|
||||
if not (tag.color and tag.color.secondary and tag.color.color_border)
|
||||
else (QColor(tag.color.secondary))
|
||||
)
|
||||
highlight_color = get_highlight_color(
|
||||
highlight_color = get_tag_highlight_color(
|
||||
primary_color
|
||||
if not (tag.color and tag.color.secondary)
|
||||
else QColor(tag.color.secondary)
|
||||
@@ -372,7 +376,7 @@ class BuildTagPanel(PanelWidget):
|
||||
if tag.color and tag.color.secondary:
|
||||
text_color = QColor(tag.color.secondary)
|
||||
else:
|
||||
text_color = get_text_color(primary_color, highlight_color)
|
||||
text_color = get_tag_text_color(primary_color, highlight_color)
|
||||
|
||||
# Add Tag Widget
|
||||
tag_widget = TagWidget(
|
||||
@@ -395,35 +399,7 @@ class BuildTagPanel(PanelWidget):
|
||||
disam_button.setFixedSize(22, 22)
|
||||
disam_button.setToolTip(Translations["tag.disambiguation.tooltip"])
|
||||
disam_button.setStyleSheet(
|
||||
f"QRadioButton{{"
|
||||
f"background: rgba{primary_color.toTuple()};"
|
||||
f"color: rgba{text_color.toTuple()};"
|
||||
f"border-color: rgba{border_color.toTuple()};"
|
||||
f"border-radius: 6px;"
|
||||
f"border-style:solid;"
|
||||
f"border-width: 2px;"
|
||||
f"}}"
|
||||
f"QRadioButton::indicator{{"
|
||||
f"width: 10px;"
|
||||
f"height: 10px;"
|
||||
f"border-radius: 2px;"
|
||||
f"margin: 4px;"
|
||||
f"}}"
|
||||
f"QRadioButton::indicator:checked{{"
|
||||
f"background: rgba{text_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QRadioButton::hover{{"
|
||||
f"border-color: rgba{highlight_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QRadioButton::pressed{{"
|
||||
f"background: rgba{border_color.toTuple()};"
|
||||
f"color: rgba{primary_color.toTuple()};"
|
||||
f"border-color: rgba{primary_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QRadioButton::focus{{"
|
||||
f"border-color: rgba{highlight_color.toTuple()};"
|
||||
f"outline:none;"
|
||||
f"}}"
|
||||
colored_radio_button_style(primary_color, text_color, border_color, highlight_color)
|
||||
)
|
||||
|
||||
self.disam_button_group.addButton(disam_button)
|
||||
@@ -543,11 +519,7 @@ class BuildTagPanel(PanelWidget):
|
||||
def on_name_changed(self):
|
||||
is_empty = not self.name_field.text().strip()
|
||||
|
||||
self.name_field.setStyleSheet(
|
||||
f"border: 1px solid {get_ui_color(ColorType.PRIMARY, UiColor.RED)}; border-radius: 2px"
|
||||
if is_empty
|
||||
else ""
|
||||
)
|
||||
self.name_field.setStyleSheet(line_edit_style() if is_empty else "")
|
||||
|
||||
if self.panel_save_button is not None:
|
||||
self.panel_save_button.setDisabled(is_empty)
|
||||
|
||||
@@ -10,16 +10,15 @@ from PySide6.QtCore import Signal
|
||||
from PySide6.QtWidgets import QMessageBox, QPushButton
|
||||
|
||||
from tagstudio.core.constants import RESERVED_NAMESPACE_PREFIX
|
||||
from tagstudio.core.library.alchemy.enums import TagColorEnum
|
||||
from tagstudio.core.library.alchemy.models import TagColorGroup
|
||||
from tagstudio.core.utils.types import unwrap
|
||||
from tagstudio.qt.mixed.build_color import BuildColorPanel
|
||||
from tagstudio.qt.mixed.field_widget import FieldWidget
|
||||
from tagstudio.qt.mixed.tag_color_label import TagColorLabel
|
||||
from tagstudio.qt.models.palette import ColorType, get_tag_color
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.layouts.flow_layout import FlowLayout
|
||||
from tagstudio.qt.views.panel_modal import PanelModal
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import add_button_style
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from tagstudio.core.library.alchemy.library import Library
|
||||
@@ -43,34 +42,6 @@ class ColorBoxWidget(FieldWidget):
|
||||
title = "" if not self.lib.engine else self.lib.get_namespace_name(group)
|
||||
super().__init__(title)
|
||||
|
||||
self.add_button_stylesheet = (
|
||||
f"QPushButton{{"
|
||||
f"background: {get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT)};"
|
||||
f"color: {get_tag_color(ColorType.TEXT, TagColorEnum.DEFAULT)};"
|
||||
f"font-weight: 600;"
|
||||
f"border-color:{get_tag_color(ColorType.BORDER, TagColorEnum.DEFAULT)};"
|
||||
f"border-radius: 6px;"
|
||||
f"border-style:solid;"
|
||||
f"border-width: 2px;"
|
||||
f"padding-right: 4px;"
|
||||
f"padding-bottom: 2px;"
|
||||
f"padding-left: 4px;"
|
||||
f"font-size: 15px"
|
||||
f"}}"
|
||||
f"QPushButton::hover{{"
|
||||
f"border-color:{get_tag_color(ColorType.LIGHT_ACCENT, TagColorEnum.DEFAULT)};"
|
||||
f"}}"
|
||||
f"QPushButton::pressed{{"
|
||||
f"background: {get_tag_color(ColorType.LIGHT_ACCENT, TagColorEnum.DEFAULT)};"
|
||||
f"color: {get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT)};"
|
||||
f"border-color: {get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT)};"
|
||||
f"}}"
|
||||
f"QPushButton::focus{{"
|
||||
f"border-color: {get_tag_color(ColorType.LIGHT_ACCENT, TagColorEnum.DEFAULT)};"
|
||||
f"outline:none;"
|
||||
f"}}"
|
||||
)
|
||||
|
||||
self.setObjectName("colorBox")
|
||||
self.base_layout = FlowLayout()
|
||||
self.base_layout.enable_grid_optimizations(value=True)
|
||||
@@ -114,7 +85,7 @@ class ColorBoxWidget(FieldWidget):
|
||||
add_button.setText("+")
|
||||
add_button.setFlat(True)
|
||||
add_button.setFixedSize(22, 22)
|
||||
add_button.setStyleSheet(self.add_button_stylesheet)
|
||||
add_button.setStyleSheet(add_button_style())
|
||||
add_button.clicked.connect(
|
||||
lambda: self.edit_color(
|
||||
TagColorGroup(
|
||||
|
||||
@@ -10,6 +10,7 @@ from PySide6.QtCore import QDateTime
|
||||
from PySide6.QtWidgets import QDateTimeEdit, QLineEdit, QVBoxLayout
|
||||
|
||||
from tagstudio.qt.views.panel_modal import PanelWidget
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import title_line_edit_style
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from tagstudio.qt.ts_qt import QtDriver
|
||||
@@ -46,7 +47,7 @@ class DatetimePicker(PanelWidget):
|
||||
self.root_layout.setContentsMargins(6, 0, 6, 0)
|
||||
|
||||
self.name_field = QLineEdit()
|
||||
self.name_field.setStyleSheet("font-weight:bold;font-size:14px;padding-top:6px")
|
||||
self.name_field.setStyleSheet(title_line_edit_style())
|
||||
self.name_field.setText(name)
|
||||
|
||||
if isinstance(datetime, str):
|
||||
|
||||
@@ -434,7 +434,7 @@ class FieldContainers(QWidget):
|
||||
)
|
||||
else:
|
||||
text = f"<i>{Translations['field.mixed_data']}</i>"
|
||||
inner_widget = TextContainerWidget("Mixed Tags", text)
|
||||
inner_widget = TextContainerWidget("Mixed Tags", text) # NOTE: Unlocalized but unused
|
||||
container.set_inner_widget(inner_widget)
|
||||
|
||||
container.set_edit_callback()
|
||||
|
||||
@@ -14,7 +14,7 @@ from PySide6.QtCore import QEvent, Qt
|
||||
from PySide6.QtGui import QEnterEvent, QPixmap, QResizeEvent
|
||||
from PySide6.QtWidgets import QHBoxLayout, QLabel, QPushButton, QVBoxLayout, QWidget
|
||||
|
||||
from tagstudio.core.enums import Theme
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import container_style, header
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -37,17 +37,6 @@ class FieldContainer(QWidget):
|
||||
trash_icon_128.load()
|
||||
|
||||
# TODO: There should be a global button theme somewhere.
|
||||
container_style = (
|
||||
f"QWidget#fieldContainer{{"
|
||||
"border-radius:4px;"
|
||||
f"}}"
|
||||
f"QWidget#fieldContainer::hover{{"
|
||||
f"background-color:{Theme.COLOR_HOVER.value};"
|
||||
f"}}"
|
||||
f"QWidget#fieldContainer::pressed{{"
|
||||
f"background-color:{Theme.COLOR_PRESSED.value};"
|
||||
f"}}"
|
||||
)
|
||||
|
||||
def __init__(self, title: str = "Field", inline: bool = True) -> None:
|
||||
super().__init__()
|
||||
@@ -126,7 +115,7 @@ class FieldContainer(QWidget):
|
||||
self.inner_layout.addWidget(self.field)
|
||||
|
||||
self.set_title(title)
|
||||
self.setStyleSheet(FieldContainer.container_style)
|
||||
self.setStyleSheet(container_style())
|
||||
|
||||
def set_copy_callback(self, callback: Callable[[], None] | None = None) -> None:
|
||||
with catch_warnings(record=True):
|
||||
@@ -166,7 +155,7 @@ class FieldContainer(QWidget):
|
||||
return None
|
||||
|
||||
def set_title(self, title: str) -> None:
|
||||
self.title = self.title = f"<h4>{title}</h4>"
|
||||
self.title = header(title, 4)
|
||||
self.title_widget.setText(self.title)
|
||||
|
||||
@override
|
||||
|
||||
@@ -11,13 +11,12 @@ from datetime import timedelta
|
||||
from pathlib import Path
|
||||
|
||||
import structlog
|
||||
from humanfriendly import format_size
|
||||
from humanfriendly import format_size # pyright: ignore[reportUnknownVariableType]
|
||||
from PIL import ImageFont
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QGuiApplication
|
||||
from PySide6.QtWidgets import QLabel, QVBoxLayout, QWidget
|
||||
|
||||
from tagstudio.core.enums import ShowFilepathOption, Theme
|
||||
from tagstudio.core.enums import ShowFilepathOption
|
||||
from tagstudio.core.library.alchemy.library import Library
|
||||
from tagstudio.core.library.ignore import Ignore
|
||||
from tagstudio.core.media_types import MediaCategories
|
||||
@@ -25,6 +24,7 @@ from tagstudio.core.utils.types import unwrap
|
||||
from tagstudio.qt.models.palette import ColorType, UiColor, get_ui_color
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.utils.file_opener import FileOpenerHelper, FileOpenerLabel
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import properties_style
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from tagstudio.qt.ts_qt import QtDriver
|
||||
@@ -48,26 +48,8 @@ class FileAttributes(QWidget):
|
||||
root_layout.setContentsMargins(0, 0, 0, 0)
|
||||
root_layout.setSpacing(0)
|
||||
|
||||
label_bg_color = (
|
||||
Theme.COLOR_BG_DARK.value
|
||||
if QGuiApplication.styleHints().colorScheme() is Qt.ColorScheme.Dark
|
||||
else Theme.COLOR_DARK_LABEL.value
|
||||
)
|
||||
|
||||
self.date_style = "font-size:12px;"
|
||||
self.date_style = "font-size: 12px;"
|
||||
self.file_label_style = "font-size: 12px"
|
||||
self.properties_style = (
|
||||
f"background-color:{label_bg_color};"
|
||||
"color:#FFFFFF;"
|
||||
"font-family:Oxanium;"
|
||||
"font-weight:bold;"
|
||||
"font-size:12px;"
|
||||
"border-radius:3px;"
|
||||
"padding-top: 4px;"
|
||||
"padding-right: 1px;"
|
||||
"padding-bottom: 1px;"
|
||||
"padding-left: 1px;"
|
||||
)
|
||||
|
||||
self.file_label = FileOpenerLabel()
|
||||
self.file_label.setObjectName("filenameLabel")
|
||||
@@ -93,7 +75,7 @@ class FileAttributes(QWidget):
|
||||
self.dimensions_label = QLabel()
|
||||
self.dimensions_label.setObjectName("dimensionsLabel")
|
||||
self.dimensions_label.setWordWrap(True)
|
||||
self.dimensions_label.setStyleSheet(self.properties_style)
|
||||
self.dimensions_label.setStyleSheet(properties_style())
|
||||
self.dimensions_label.setHidden(True)
|
||||
|
||||
self.date_container = QWidget()
|
||||
|
||||
@@ -19,6 +19,7 @@ from tagstudio.core.library.alchemy.library import Library
|
||||
from tagstudio.core.library.alchemy.registries.dupe_files_registry import DupeFilesRegistry
|
||||
from tagstudio.qt.mixed.mirror_entries_modal import MirrorEntriesModal
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import header
|
||||
|
||||
# Only import for type checking/autocompletion, will not be imported at runtime.
|
||||
if TYPE_CHECKING:
|
||||
@@ -49,7 +50,6 @@ class FixDupeFilesModal(QWidget):
|
||||
|
||||
self.dupe_count = QLabel()
|
||||
self.dupe_count.setObjectName("dupeCountLabel")
|
||||
self.dupe_count.setStyleSheet("font-weight:bold;font-size:14px;")
|
||||
self.dupe_count.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.file_label = QLabel(Translations["file.duplicates.dupeguru.no_file"])
|
||||
@@ -119,13 +119,19 @@ class FixDupeFilesModal(QWidget):
|
||||
def set_dupe_count(self, count: int):
|
||||
if count < 0:
|
||||
self.mirror_button.setDisabled(True)
|
||||
self.dupe_count.setText(Translations["file.duplicates.matches_uninitialized"])
|
||||
self.dupe_count.setText(
|
||||
header(Translations["file.duplicates.matches_uninitialized"], 4)
|
||||
)
|
||||
elif count == 0:
|
||||
self.mirror_button.setDisabled(True)
|
||||
self.dupe_count.setText(Translations.format("file.duplicates.matches", count=count))
|
||||
self.dupe_count.setText(
|
||||
header(Translations.format("file.duplicates.matches", count=count), 4)
|
||||
)
|
||||
else:
|
||||
self.mirror_button.setDisabled(False)
|
||||
self.dupe_count.setText(Translations.format("file.duplicates.matches", count=count))
|
||||
self.dupe_count.setText(
|
||||
header(Translations.format("file.duplicates.matches", count=count), 4)
|
||||
)
|
||||
|
||||
@override
|
||||
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: # noqa N802
|
||||
|
||||
@@ -15,6 +15,7 @@ from tagstudio.qt.mixed.progress_bar import ProgressWidget
|
||||
from tagstudio.qt.mixed.relink_entries_modal import RelinkUnlinkedEntries
|
||||
from tagstudio.qt.mixed.remove_unlinked_modal import RemoveUnlinkedEntriesModal
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import header
|
||||
|
||||
# Only import for type checking/autocompletion, will not be imported at runtime.
|
||||
if TYPE_CHECKING:
|
||||
@@ -148,7 +149,7 @@ class FixUnlinkedEntriesModal(QWidget):
|
||||
count_text: str = Translations.format(
|
||||
"entries.unlinked.unlinked_count", count=count if count >= 0 else "—"
|
||||
)
|
||||
self.unlinked_count_label.setText(f"<h3>{count_text}</h3>")
|
||||
self.unlinked_count_label.setText(header(count_text, 3))
|
||||
|
||||
@override
|
||||
def showEvent(self, event: QtGui.QShowEvent) -> None:
|
||||
|
||||
@@ -29,6 +29,7 @@ from tagstudio.core.utils.types import unwrap
|
||||
from tagstudio.qt.models.palette import ColorType, get_tag_color
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.layouts.flow_layout import FlowLayout
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import header
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from tagstudio.qt.ts_qt import QtDriver
|
||||
@@ -56,7 +57,7 @@ def add_folders_to_tree(library: Library, tree: BranchData, items: tuple[str, ..
|
||||
return branch
|
||||
|
||||
|
||||
@deprecated("Will be replaced with upcoming 'Macros' feature before v9.6")
|
||||
@deprecated("Will be replaced with upcoming 'Macros' feature.")
|
||||
def folders_to_tags(library: Library):
|
||||
logger.info("Converting folders to Tags")
|
||||
tree = BranchData()
|
||||
@@ -177,10 +178,9 @@ class FoldersToTagsModal(QWidget):
|
||||
self.root_layout = QVBoxLayout(self)
|
||||
self.root_layout.setContentsMargins(6, 6, 6, 6)
|
||||
|
||||
self.title_widget = QLabel(Translations["folders_to_tags.title"])
|
||||
self.title_widget = QLabel(header(Translations["folders_to_tags.title"], 3))
|
||||
self.title_widget.setObjectName("title")
|
||||
self.title_widget.setWordWrap(True)
|
||||
self.title_widget.setStyleSheet("font-weight:bold;font-size:14px;padding-top: 6px")
|
||||
self.title_widget.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.desc_widget = QLabel()
|
||||
|
||||
@@ -48,6 +48,7 @@ from tagstudio.qt.utils.custom_runnable import CustomRunnable
|
||||
from tagstudio.qt.utils.function_iterator import FunctionIterator
|
||||
from tagstudio.qt.views.paged_body_wrapper import PagedBodyWrapper
|
||||
from tagstudio.qt.views.qbutton_wrapper import QPushButtonWrapper
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import header
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -364,7 +365,7 @@ class JsonMigrationModal(QObject):
|
||||
iterator = FunctionIterator(self.migration_iterator)
|
||||
iterator.value.connect(
|
||||
lambda x: (
|
||||
pb.setLabelText(f"<h4>{x}</h4>"),
|
||||
pb.setLabelText(header(x, 4)),
|
||||
self.update_sql_value_ui(show_msg_box=False)
|
||||
if x == Translations["json_migration.checking_for_parity"]
|
||||
else (),
|
||||
@@ -386,7 +387,7 @@ class JsonMigrationModal(QObject):
|
||||
QThreadPool.globalInstance().start(r)
|
||||
except Exception as e:
|
||||
logger.error("[MigrationModal][Iterator] Error:", error=e)
|
||||
pb.setLabelText(f"<h4>{type(e).__name__}</h4>")
|
||||
pb.setLabelText(header(type(e).__name__, 4))
|
||||
pb.setMinimum(1)
|
||||
pb.setValue(1)
|
||||
|
||||
@@ -410,7 +411,7 @@ class JsonMigrationModal(QObject):
|
||||
)
|
||||
self.sql_lib.migrate_json_to_sqlite(self.json_lib)
|
||||
yield Translations["json_migration.checking_for_parity"]
|
||||
check_set = set()
|
||||
check_set: set[bool] = set()
|
||||
check_set.add(self.check_field_parity())
|
||||
check_set.add(self.check_path_parity())
|
||||
check_set.add(self.check_name_parity())
|
||||
@@ -522,7 +523,7 @@ class JsonMigrationModal(QObject):
|
||||
def assert_ignore_parity(self) -> None:
|
||||
compiled_pats = fnmatch.compile(
|
||||
ignore_to_glob(
|
||||
Ignore._load_ignore_file(
|
||||
Ignore._load_ignore_file( # pyright: ignore[reportPrivateUsage]
|
||||
unwrap(self.json_lib.library_dir) / TS_FOLDER_NAME / IGNORE_NAME
|
||||
)
|
||||
),
|
||||
|
||||
@@ -11,12 +11,14 @@ from PySide6.QtWidgets import QHBoxLayout, QPushButton, QVBoxLayout, QWidget
|
||||
|
||||
from tagstudio.core.library.alchemy.models import TagColorGroup
|
||||
from tagstudio.qt.helpers.escape_text import escape_text
|
||||
from tagstudio.qt.mixed.tag_widget import (
|
||||
get_border_color,
|
||||
get_highlight_color,
|
||||
get_text_color,
|
||||
)
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import (
|
||||
get_tag_border_color,
|
||||
get_tag_highlight_color,
|
||||
get_tag_text_color,
|
||||
tag_remove_button_style,
|
||||
tag_style,
|
||||
)
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -101,76 +103,25 @@ class TagColorLabel(QWidget):
|
||||
|
||||
primary_color = self._get_primary_color(color)
|
||||
border_color = (
|
||||
get_border_color(primary_color)
|
||||
get_tag_border_color(primary_color)
|
||||
if not (color and color.secondary and color.color_border)
|
||||
else (QColor(color.secondary))
|
||||
)
|
||||
highlight_color = get_highlight_color(
|
||||
highlight_color = get_tag_highlight_color(
|
||||
primary_color if not (color and color.secondary) else QColor(color.secondary)
|
||||
)
|
||||
text_color: QColor
|
||||
if color and color.secondary:
|
||||
text_color = QColor(color.secondary)
|
||||
else:
|
||||
text_color = get_text_color(primary_color, highlight_color)
|
||||
text_color = get_tag_text_color(primary_color, highlight_color)
|
||||
|
||||
self.bg_button.setStyleSheet(
|
||||
f"QPushButton{{"
|
||||
f"background: rgba{primary_color.toTuple()};"
|
||||
f"color: rgba{text_color.toTuple()};"
|
||||
f"font-weight: 600;"
|
||||
f"border-color: rgba{border_color.toTuple()};"
|
||||
f"border-radius: 6px;"
|
||||
f"border-style:solid;"
|
||||
f"border-width: 2px;"
|
||||
f"padding-right: 4px;"
|
||||
f"padding-left: 4px;"
|
||||
f"font-size: 13px"
|
||||
f"}}"
|
||||
f"QPushButton::hover{{"
|
||||
f"border-color: rgba{highlight_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QPushButton::pressed{{"
|
||||
f"background: rgba{highlight_color.toTuple()};"
|
||||
f"color: rgba{primary_color.toTuple()};"
|
||||
f"border-color: rgba{primary_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QPushButton::focus{{"
|
||||
f"padding-right: 0px;"
|
||||
f"padding-left: 0px;"
|
||||
f"outline-style: solid;"
|
||||
f"outline-width: 1px;"
|
||||
f"outline-radius: 4px;"
|
||||
f"outline-color: rgba{text_color.toTuple()};"
|
||||
f"}}"
|
||||
tag_style(primary_color, text_color, border_color, highlight_color)
|
||||
)
|
||||
|
||||
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"}}"
|
||||
tag_remove_button_style(primary_color, text_color, border_color, highlight_color)
|
||||
)
|
||||
|
||||
self.bg_button.setText(escape_text(color.name))
|
||||
@@ -183,13 +134,15 @@ class TagColorLabel(QWidget):
|
||||
def set_has_remove(self, has_remove: bool):
|
||||
self.has_remove = has_remove
|
||||
|
||||
def enterEvent(self, event: QEnterEvent) -> None: # noqa: N802
|
||||
@typing.override
|
||||
def enterEvent(self, event: QEnterEvent) -> None:
|
||||
if self.has_remove:
|
||||
self.remove_button.setHidden(False)
|
||||
self.update()
|
||||
return super().enterEvent(event)
|
||||
|
||||
def leaveEvent(self, event: QEvent) -> None: # noqa: N802
|
||||
@typing.override
|
||||
def leaveEvent(self, event: QEvent) -> None:
|
||||
if self.has_remove:
|
||||
self.remove_button.setHidden(True)
|
||||
self.update()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
|
||||
from collections.abc import Callable
|
||||
from typing import TYPE_CHECKING, override
|
||||
from typing import TYPE_CHECKING, Any, override
|
||||
|
||||
import structlog
|
||||
from PySide6 import QtCore, QtGui
|
||||
@@ -28,6 +28,7 @@ from tagstudio.qt.mixed.color_box import ColorBoxWidget
|
||||
from tagstudio.qt.mixed.field_widget import FieldContainer
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.panel_modal import PanelModal
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import header
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -62,7 +63,7 @@ class TagColorManager(QWidget):
|
||||
self.title_label = QLabel()
|
||||
self.title_label.setObjectName("titleLabel")
|
||||
self.title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
self.title_label.setText(f"<h3>{Translations['color_manager.title']}</h3>")
|
||||
self.title_label.setText(header(Translations["color_manager.title"], 3))
|
||||
|
||||
self.scroll_layout = QVBoxLayout()
|
||||
self.scroll_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
|
||||
@@ -189,7 +190,7 @@ class TagColorManager(QWidget):
|
||||
|
||||
self.create_namespace_modal.show()
|
||||
|
||||
def delete_namespace_dialog(self, prompt: str, callback: Callable) -> None:
|
||||
def delete_namespace_dialog(self, prompt: str, callback: Callable[..., Any]) -> None: # pyright: ignore[reportExplicitAny]
|
||||
message_box = QMessageBox()
|
||||
message_box.setText(prompt)
|
||||
message_box.setWindowTitle(Translations["color.namespace.delete.title"])
|
||||
@@ -207,13 +208,13 @@ class TagColorManager(QWidget):
|
||||
callback()
|
||||
|
||||
@override
|
||||
def showEvent(self, event: QtGui.QShowEvent) -> None: # noqa N802
|
||||
def showEvent(self, event: QtGui.QShowEvent) -> None:
|
||||
if not self.is_initialized:
|
||||
self.setup_color_groups()
|
||||
return super().showEvent(event)
|
||||
|
||||
@override
|
||||
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: # noqa N802
|
||||
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None:
|
||||
if event.key() == QtCore.Qt.Key.Key_Escape: # noqa SIM114
|
||||
self.done_button.click()
|
||||
elif event.key() == Qt.Key.Key_Return or event.key() == Qt.Key.Key_Enter:
|
||||
|
||||
@@ -11,9 +11,14 @@ from PySide6.QtWidgets import QPushButton, QVBoxLayout, QWidget
|
||||
|
||||
from tagstudio.core.library.alchemy.enums import TagColorEnum
|
||||
from tagstudio.core.library.alchemy.models import TagColorGroup
|
||||
from tagstudio.qt.mixed.tag_widget import get_border_color, get_highlight_color, get_text_color
|
||||
from tagstudio.qt.models.palette import ColorType, get_tag_color
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import (
|
||||
get_tag_border_color,
|
||||
get_tag_highlight_color,
|
||||
get_tag_text_color,
|
||||
tag_style,
|
||||
)
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from tagstudio.core.library.alchemy.library import Library
|
||||
@@ -66,11 +71,11 @@ class TagColorPreview(QWidget):
|
||||
|
||||
primary_color = self._get_primary_color(color_group)
|
||||
border_color = (
|
||||
get_border_color(primary_color)
|
||||
get_tag_border_color(primary_color)
|
||||
if not (color_group and color_group.secondary and color_group.color_border)
|
||||
else (QColor(color_group.secondary))
|
||||
)
|
||||
highlight_color = get_highlight_color(
|
||||
highlight_color = get_tag_highlight_color(
|
||||
primary_color
|
||||
if not (color_group and color_group.secondary)
|
||||
else QColor(color_group.secondary)
|
||||
@@ -79,32 +84,10 @@ class TagColorPreview(QWidget):
|
||||
if color_group and color_group.secondary:
|
||||
text_color = QColor(color_group.secondary)
|
||||
else:
|
||||
text_color = get_text_color(primary_color, highlight_color)
|
||||
text_color = get_tag_text_color(primary_color, highlight_color)
|
||||
|
||||
self.button.setStyleSheet(
|
||||
f"QPushButton{{"
|
||||
f"background: rgba{primary_color.toTuple()};"
|
||||
f"color: rgba{text_color.toTuple()};"
|
||||
f"font-weight: 600;"
|
||||
f"border-color: rgba{border_color.toTuple()};"
|
||||
f"border-radius: 6px;"
|
||||
f"border-style:solid;"
|
||||
f"border-width: 2px;"
|
||||
f"padding-right: 8px;"
|
||||
f"padding-left: 8px;"
|
||||
f"font-size: 14px"
|
||||
f"}}"
|
||||
f"QPushButton::hover{{"
|
||||
f"border-color: rgba{highlight_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QPushButton::focus{{"
|
||||
f"padding-right: 0px;"
|
||||
f"padding-left: 0px;"
|
||||
f"outline-style: solid;"
|
||||
f"outline-width: 1px;"
|
||||
f"outline-radius: 4px;"
|
||||
f"outline-color: rgba{text_color.toTuple()};"
|
||||
f"}}"
|
||||
tag_style(primary_color, text_color, border_color, highlight_color)
|
||||
)
|
||||
# Add back the padding if the hint is generated while the button has focus (no padding)
|
||||
self.button.setMinimumWidth(
|
||||
|
||||
@@ -20,11 +20,16 @@ from PySide6.QtWidgets import (
|
||||
from tagstudio.core.library.alchemy.enums import TagColorEnum
|
||||
from tagstudio.core.library.alchemy.library import Library
|
||||
from tagstudio.core.library.alchemy.models import TagColorGroup
|
||||
from tagstudio.qt.mixed.tag_widget import get_border_color, get_highlight_color, get_text_color
|
||||
from tagstudio.qt.mixed.tag_widget import (
|
||||
get_tag_border_color,
|
||||
get_tag_highlight_color,
|
||||
get_tag_text_color,
|
||||
)
|
||||
from tagstudio.qt.models.palette import ColorType, get_tag_color
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.layouts.flow_layout import FlowLayout
|
||||
from tagstudio.qt.views.panel_modal import PanelWidget
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import color_swatch_style, header
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -67,9 +72,7 @@ class TagColorSelection(PanelWidget):
|
||||
self.scroll_layout.addSpacerItem(QSpacerItem(1, 6))
|
||||
for group, colors in tag_color_groups.items():
|
||||
display_name: str = self.lib.get_namespace_name(group)
|
||||
self.scroll_layout.addWidget(
|
||||
QLabel(f"<h4>{display_name if display_name else group}</h4>")
|
||||
)
|
||||
self.scroll_layout.addWidget(QLabel(header(display_name if display_name else group, 4)))
|
||||
color_box_widget = QWidget()
|
||||
color_group_layout = FlowLayout()
|
||||
color_group_layout.setSpacing(4)
|
||||
@@ -79,54 +82,31 @@ class TagColorSelection(PanelWidget):
|
||||
for color in colors:
|
||||
primary_color = self._get_primary_color(color)
|
||||
border_color = (
|
||||
get_border_color(primary_color)
|
||||
get_tag_border_color(primary_color)
|
||||
if not (color and color.secondary and color.color_border)
|
||||
else (QColor(color.secondary))
|
||||
)
|
||||
highlight_color = get_highlight_color(
|
||||
highlight_color = get_tag_highlight_color(
|
||||
primary_color if not (color and color.secondary) else QColor(color.secondary)
|
||||
)
|
||||
text_color: QColor
|
||||
if color and color.secondary:
|
||||
text_color = QColor(color.secondary)
|
||||
else:
|
||||
text_color = get_text_color(primary_color, highlight_color)
|
||||
text_color = get_tag_text_color(primary_color, highlight_color)
|
||||
|
||||
radio_button = QRadioButton()
|
||||
radio_button.setObjectName(f"{color.namespace}.{color.slug}")
|
||||
radio_button.setToolTip(color.name)
|
||||
radio_button.setFixedSize(24, 24)
|
||||
bottom_color: str = (
|
||||
f"border-bottom-color: rgba{text_color.toTuple()};" if color.secondary else ""
|
||||
)
|
||||
radio_button.setStyleSheet(
|
||||
f"QRadioButton{{"
|
||||
f"background: rgba{primary_color.toTuple()};"
|
||||
f"color: rgba{text_color.toTuple()};"
|
||||
f"border-color: rgba{border_color.toTuple()};"
|
||||
f"{bottom_color}"
|
||||
f"border-radius: 3px;"
|
||||
f"border-style:solid;"
|
||||
f"border-width: 2px;"
|
||||
f"}}"
|
||||
f"QRadioButton::indicator{{"
|
||||
f"width: 12px;"
|
||||
f"height: 12px;"
|
||||
f"border-radius: 1px;"
|
||||
f"margin: 4px;"
|
||||
f"}}"
|
||||
f"QRadioButton::indicator:checked{{"
|
||||
f"background: rgba{text_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QRadioButton::hover{{"
|
||||
f"border-color: rgba{highlight_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QRadioButton::focus{{"
|
||||
f"outline-style: solid;"
|
||||
f"outline-width: 2px;"
|
||||
f"outline-radius: 3px;"
|
||||
f"outline-color: rgba{highlight_color.toTuple()};"
|
||||
f"}}"
|
||||
color_swatch_style(
|
||||
primary_color,
|
||||
text_color,
|
||||
border_color,
|
||||
highlight_color,
|
||||
text_color if color.secondary else None,
|
||||
)
|
||||
)
|
||||
radio_button.clicked.connect(lambda checked=False, x=color: self.select_color(x))
|
||||
color_group_layout.addWidget(radio_button)
|
||||
@@ -136,7 +116,7 @@ class TagColorSelection(PanelWidget):
|
||||
|
||||
def add_no_color_widget(self):
|
||||
no_color_str: str = Translations["color.title.no_color"]
|
||||
self.scroll_layout.addWidget(QLabel(f"<h4>{no_color_str}</h4>"))
|
||||
self.scroll_layout.addWidget(QLabel(header(no_color_str, 4)))
|
||||
color_box_widget = QWidget()
|
||||
color_group_layout = FlowLayout()
|
||||
color_group_layout.setSpacing(4)
|
||||
@@ -145,45 +125,20 @@ class TagColorSelection(PanelWidget):
|
||||
color_box_widget.setLayout(color_group_layout)
|
||||
color = None
|
||||
primary_color = self._get_primary_color(color)
|
||||
border_color = get_border_color(primary_color)
|
||||
highlight_color = get_highlight_color(primary_color)
|
||||
border_color = get_tag_border_color(primary_color)
|
||||
highlight_color = get_tag_highlight_color(primary_color)
|
||||
text_color: QColor
|
||||
if color and color.secondary and color.color_border:
|
||||
text_color = QColor(color.secondary)
|
||||
else:
|
||||
text_color = get_text_color(primary_color, highlight_color)
|
||||
text_color = get_tag_text_color(primary_color, highlight_color)
|
||||
|
||||
radio_button = QRadioButton()
|
||||
radio_button.setObjectName("None") # NOTE: Internal use, no translation needed.
|
||||
radio_button.setObjectName("None")
|
||||
radio_button.setToolTip(no_color_str)
|
||||
radio_button.setFixedSize(24, 24)
|
||||
radio_button.setStyleSheet(
|
||||
f"QRadioButton{{"
|
||||
f"background: rgba{primary_color.toTuple()};"
|
||||
f"color: rgba{text_color.toTuple()};"
|
||||
f"border-color: rgba{border_color.toTuple()};"
|
||||
f"border-radius: 3px;"
|
||||
f"border-style:solid;"
|
||||
f"border-width: 2px;"
|
||||
f"}}"
|
||||
f"QRadioButton::indicator{{"
|
||||
f"width: 12px;"
|
||||
f"height: 12px;"
|
||||
f"border-radius: 1px;"
|
||||
f"margin: 4px;"
|
||||
f"}}"
|
||||
f"QRadioButton::indicator:checked{{"
|
||||
f"background: rgba{text_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QRadioButton::hover{{"
|
||||
f"border-color: rgba{highlight_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QRadioButton::focus{{"
|
||||
f"outline-style: solid;"
|
||||
f"outline-width: 2px;"
|
||||
f"outline-radius: 3px;"
|
||||
f"outline-color: rgba{highlight_color.toTuple()};"
|
||||
f"}}"
|
||||
color_swatch_style(primary_color, text_color, border_color, highlight_color)
|
||||
)
|
||||
radio_button.clicked.connect(lambda checked=False, x=color: self.select_color(x))
|
||||
color_group_layout.addWidget(radio_button)
|
||||
|
||||
@@ -15,6 +15,14 @@ from tagstudio.core.library.alchemy.models import Tag
|
||||
from tagstudio.qt.helpers.escape_text import escape_text
|
||||
from tagstudio.qt.models.palette import ColorType, get_tag_color
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import (
|
||||
get_tag_border_color,
|
||||
get_tag_highlight_color,
|
||||
get_tag_primary_color,
|
||||
get_tag_text_color,
|
||||
tag_remove_button_style,
|
||||
tag_style,
|
||||
)
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -188,13 +196,13 @@ class TagWidget(QWidget):
|
||||
if not tag:
|
||||
return
|
||||
|
||||
primary_color = get_primary_color(tag)
|
||||
primary_color = get_tag_primary_color(tag)
|
||||
border_color = (
|
||||
get_border_color(primary_color)
|
||||
get_tag_border_color(primary_color)
|
||||
if not (tag.color and tag.color.secondary and tag.color.color_border)
|
||||
else (QColor(tag.color.secondary))
|
||||
)
|
||||
highlight_color = get_highlight_color(
|
||||
highlight_color = get_tag_highlight_color(
|
||||
primary_color
|
||||
if not (tag.color and tag.color.secondary)
|
||||
else QColor(tag.color.secondary)
|
||||
@@ -203,65 +211,14 @@ class TagWidget(QWidget):
|
||||
if tag.color and tag.color.secondary:
|
||||
text_color = QColor(tag.color.secondary)
|
||||
else:
|
||||
text_color = get_text_color(primary_color, highlight_color)
|
||||
text_color = get_tag_text_color(primary_color, highlight_color)
|
||||
|
||||
self.bg_button.setStyleSheet(
|
||||
f"QPushButton{{"
|
||||
f"background: rgba{primary_color.toTuple()};"
|
||||
f"color: rgba{text_color.toTuple()};"
|
||||
f"font-weight: 600;"
|
||||
f"border-color: rgba{border_color.toTuple()};"
|
||||
f"border-radius: 6px;"
|
||||
f"border-style:solid;"
|
||||
f"border-width: 2px;"
|
||||
f"padding-right: 4px;"
|
||||
f"padding-left: 4px;"
|
||||
f"font-size: 13px"
|
||||
f"}}"
|
||||
f"QPushButton::hover{{"
|
||||
f"border-color: rgba{highlight_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QPushButton::pressed{{"
|
||||
f"background: rgba{highlight_color.toTuple()};"
|
||||
f"color: rgba{primary_color.toTuple()};"
|
||||
f"border-color: rgba{primary_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QPushButton::focus{{"
|
||||
f"padding-right: 0px;"
|
||||
f"padding-left: 0px;"
|
||||
f"outline-style: solid;"
|
||||
f"outline-width: 1px;"
|
||||
f"outline-radius: 4px;"
|
||||
f"outline-color: rgba{text_color.toTuple()};"
|
||||
f"}}"
|
||||
tag_style(primary_color, text_color, border_color, highlight_color)
|
||||
)
|
||||
|
||||
self._delete_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"}}"
|
||||
tag_remove_button_style(primary_color, text_color, border_color, highlight_color)
|
||||
)
|
||||
|
||||
if self.lib:
|
||||
@@ -285,42 +242,3 @@ class TagWidget(QWidget):
|
||||
self._delete_button.setHidden(True)
|
||||
self.update()
|
||||
return super().leaveEvent(event)
|
||||
|
||||
|
||||
def get_primary_color(tag: Tag) -> QColor:
|
||||
primary_color = QColor(
|
||||
get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT)
|
||||
if not tag.color
|
||||
else tag.color.primary
|
||||
)
|
||||
|
||||
return primary_color
|
||||
|
||||
|
||||
def get_border_color(primary_color: QColor) -> QColor:
|
||||
border_color: QColor = QColor(primary_color)
|
||||
border_color.setRed(min(border_color.red() + 20, 255))
|
||||
border_color.setGreen(min(border_color.green() + 20, 255))
|
||||
border_color.setBlue(min(border_color.blue() + 20, 255))
|
||||
|
||||
return border_color
|
||||
|
||||
|
||||
def get_highlight_color(primary_color: QColor) -> QColor:
|
||||
highlight_color: QColor = QColor(primary_color)
|
||||
highlight_color = highlight_color.toHsl()
|
||||
highlight_color.setHsl(highlight_color.hue(), min(highlight_color.saturation(), 200), 225, 255)
|
||||
highlight_color = highlight_color.toRgb()
|
||||
|
||||
return highlight_color
|
||||
|
||||
|
||||
def get_text_color(primary_color: QColor, highlight_color: QColor) -> QColor:
|
||||
# logger.info("[TagWidget] Evaluating tag text color", lightness=primary_color.lightness())
|
||||
if primary_color.lightness() > 120:
|
||||
text_color = QColor(primary_color)
|
||||
text_color = text_color.toHsl()
|
||||
text_color.setHsl(text_color.hue(), text_color.saturation(), 50, 255)
|
||||
return text_color.toRgb()
|
||||
else:
|
||||
return highlight_color
|
||||
|
||||
@@ -99,6 +99,7 @@ from tagstudio.qt.views.field_template_search_panel_view import FieldTemplateSea
|
||||
from tagstudio.qt.views.main_window import MainWindow
|
||||
from tagstudio.qt.views.panel_modal import PanelModal
|
||||
from tagstudio.qt.views.splash import SplashScreen
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import header
|
||||
from tagstudio.qt.views.tag_search_panel_view import TagSearchPanelView
|
||||
|
||||
BADGE_TAGS = {
|
||||
@@ -1014,9 +1015,8 @@ class QtDriver(DriverMixin, QObject):
|
||||
perm_warning_msg = Translations.format(
|
||||
"trash.dialog.permanent_delete_warning", trash_term=trash_term()
|
||||
)
|
||||
perm_warning: str = (
|
||||
f"<h4 style='color: {get_ui_color(ColorType.PRIMARY, UiColor.RED)}'>"
|
||||
f"{perm_warning_msg}</h4>"
|
||||
perm_warning: str = header(
|
||||
perm_warning_msg, 4, get_ui_color(ColorType.PRIMARY, UiColor.RED)
|
||||
)
|
||||
|
||||
msg = QMessageBox()
|
||||
@@ -1033,8 +1033,8 @@ class QtDriver(DriverMixin, QObject):
|
||||
"trash.dialog.move.confirmation.singular", trash_term=trash_term()
|
||||
)
|
||||
msg.setText(
|
||||
f"<h3>{msg_text}</h3>"
|
||||
f"<h4>{Translations['trash.dialog.disambiguation_warning.singular']}</h4>"
|
||||
f"{header(msg_text, 3)}"
|
||||
f"{header(Translations['trash.dialog.disambiguation_warning.singular'], 4)}"
|
||||
f"{filename if filename else ''}"
|
||||
f"{perm_warning}<br>"
|
||||
)
|
||||
@@ -1045,8 +1045,8 @@ class QtDriver(DriverMixin, QObject):
|
||||
trash_term=trash_term(),
|
||||
)
|
||||
msg.setText(
|
||||
f"<h3>{msg_text}</h3>"
|
||||
f"<h4>{Translations['trash.dialog.disambiguation_warning.plural']}</h4>"
|
||||
f"{header(msg_text, 3)}"
|
||||
f"{header(Translations['trash.dialog.disambiguation_warning.plural'], 4)}"
|
||||
f"{perm_warning}<br>"
|
||||
)
|
||||
|
||||
@@ -1069,9 +1069,7 @@ class QtDriver(DriverMixin, QObject):
|
||||
pw.update_label(Translations["library.refresh.scanning_preparing"])
|
||||
pw.show()
|
||||
|
||||
iterator = FunctionIterator(
|
||||
lambda lib=unwrap(self.lib.library_dir): tracker.refresh_dir(lib) # noqa: B008
|
||||
)
|
||||
iterator = FunctionIterator(lambda lib=self.lib.library_dir: tracker.refresh_dir(lib))
|
||||
iterator.value.connect(
|
||||
lambda x: (
|
||||
pw.update_progress(x + 1),
|
||||
|
||||
@@ -16,7 +16,7 @@ from PySide6.QtWidgets import (
|
||||
from tagstudio.qt.controllers.clickable_label import ClickableLabel
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.panel_modal import PanelWidget
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import checkbox_style
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import checkbox_style, title_line_edit_style
|
||||
|
||||
|
||||
class EditTextView(PanelWidget):
|
||||
@@ -27,7 +27,7 @@ class EditTextView(PanelWidget):
|
||||
self.root_layout.setContentsMargins(6, 0, 6, 0)
|
||||
|
||||
self.name_field = QLineEdit()
|
||||
self.name_field.setStyleSheet("font-weight:bold;font-size:14px;padding-top:6px")
|
||||
self.name_field.setStyleSheet(title_line_edit_style())
|
||||
|
||||
self.text_box = QPlainTextEdit()
|
||||
self.text_line = QLineEdit()
|
||||
|
||||
@@ -5,41 +5,19 @@ from PySide6.QtCore import Signal
|
||||
from PySide6.QtGui import QColor
|
||||
from PySide6.QtWidgets import QHBoxLayout, QPushButton, QVBoxLayout, QWidget
|
||||
|
||||
from tagstudio.core.enums import Theme
|
||||
from tagstudio.core.library.alchemy.enums import TagColorEnum
|
||||
from tagstudio.qt.mixed.tag_widget import get_border_color, get_highlight_color, get_text_color
|
||||
from tagstudio.qt.models.palette import ColorType, UiColor, get_tag_color, get_ui_color
|
||||
from tagstudio.qt.models.palette import ColorType, get_tag_color
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import (
|
||||
get_tag_border_color,
|
||||
get_tag_highlight_color,
|
||||
get_tag_text_color,
|
||||
list_button_style,
|
||||
)
|
||||
|
||||
primary_color: QColor = QColor(get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT))
|
||||
border_color: QColor = get_border_color(primary_color)
|
||||
highlight_color: QColor = get_highlight_color(primary_color)
|
||||
text_color: QColor = get_text_color(primary_color, highlight_color)
|
||||
|
||||
FIELD_TEMPLATE_BUTTON_STYLESHEET = f"""
|
||||
QPushButton{{
|
||||
background-color: {Theme.COLOR_BG.value};
|
||||
font-weight: 600;
|
||||
border-radius: 6px;
|
||||
padding-right: 4px;
|
||||
padding-left: 4px;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
}}
|
||||
|
||||
QPushButton::hover{{
|
||||
background-color: {Theme.COLOR_HOVER.value};
|
||||
border-color: {get_ui_color(ColorType.BORDER, UiColor.THEME_DARK)};
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
}}
|
||||
|
||||
QPushButton::pressed{{
|
||||
background-color: {Theme.COLOR_PRESSED.value};
|
||||
border-color: {get_ui_color(ColorType.LIGHT_ACCENT, UiColor.THEME_DARK)};
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
}}
|
||||
"""
|
||||
border_color: QColor = get_tag_border_color(primary_color)
|
||||
highlight_color: QColor = get_tag_highlight_color(primary_color)
|
||||
text_color: QColor = get_tag_text_color(primary_color, highlight_color)
|
||||
|
||||
|
||||
class FieldTemplateWidgetView(QWidget):
|
||||
@@ -63,7 +41,7 @@ class FieldTemplateWidgetView(QWidget):
|
||||
self._bg_button.setMinimumSize(44, 22)
|
||||
self._bg_button.setMinimumHeight(22)
|
||||
self._bg_button.setMaximumHeight(22)
|
||||
self._bg_button.setStyleSheet(FIELD_TEMPLATE_BUTTON_STYLESHEET)
|
||||
self._bg_button.setStyleSheet(list_button_style())
|
||||
|
||||
self.__inner_layout = QHBoxLayout()
|
||||
self.__inner_layout.setObjectName("inner_layout")
|
||||
|
||||
@@ -24,6 +24,7 @@ from PySide6.QtWidgets import (
|
||||
from tagstudio.qt.helpers.color_overlay import theme_fg_overlay
|
||||
from tagstudio.qt.platform_strings import open_file_str
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import header
|
||||
|
||||
# Only import for type checking/autocompletion, will not be imported at runtime.
|
||||
if TYPE_CHECKING:
|
||||
@@ -65,7 +66,7 @@ class LibraryInfoWindowView(QWidget):
|
||||
self.stats_layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.stats_layout.setSpacing(12)
|
||||
|
||||
self.stats_label = QLabel(f"<h3>{Translations['library_info.stats']}</h3>")
|
||||
self.stats_label = QLabel(header(Translations["library_info.stats"], 3))
|
||||
self.stats_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.stats_grid: QWidget = QWidget()
|
||||
@@ -223,7 +224,7 @@ class LibraryInfoWindowView(QWidget):
|
||||
self.cleanup_layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.cleanup_layout.setSpacing(12)
|
||||
|
||||
self.cleanup_label = QLabel(f"<h3>{Translations['library_info.cleanup']}</h3>")
|
||||
self.cleanup_label = QLabel(header(Translations["library_info.cleanup"], 3))
|
||||
self.cleanup_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.cleanup_grid: QWidget = QWidget()
|
||||
|
||||
@@ -16,45 +16,20 @@ from PySide6.QtWidgets import (
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from tagstudio.core.enums import Theme
|
||||
from tagstudio.core.library.alchemy.library import Library
|
||||
from tagstudio.core.library.alchemy.models import Entry
|
||||
from tagstudio.core.utils.types import unwrap
|
||||
from tagstudio.qt.controllers.preview_thumb_controller import PreviewThumb
|
||||
from tagstudio.qt.mixed.field_containers import FieldContainers
|
||||
from tagstudio.qt.mixed.file_attributes import FileAttributeData, FileAttributes
|
||||
from tagstudio.qt.models.palette import ColorType, UiColor, get_ui_color
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import button_style
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from tagstudio.qt.ts_qt import QtDriver
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
BUTTON_STYLE: str = f"""
|
||||
QPushButton{{
|
||||
background-color: {Theme.COLOR_BG.value};
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
}}
|
||||
QPushButton::hover{{
|
||||
background-color: {Theme.COLOR_HOVER.value};
|
||||
border-color: {get_ui_color(ColorType.BORDER, UiColor.THEME_DARK)};
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
}}
|
||||
QPushButton::pressed{{
|
||||
background-color: {Theme.COLOR_PRESSED.value};
|
||||
border-color: {get_ui_color(ColorType.LIGHT_ACCENT, UiColor.THEME_DARK)};
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
}}
|
||||
QPushButton::disabled{{
|
||||
background-color: {Theme.COLOR_DISABLED_BG.value};
|
||||
}}
|
||||
"""
|
||||
|
||||
|
||||
class PreviewPanelView(QWidget):
|
||||
lib: Library
|
||||
@@ -94,13 +69,13 @@ class PreviewPanelView(QWidget):
|
||||
self.__add_tag_button.setEnabled(False)
|
||||
self.__add_tag_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
self.__add_tag_button.setMinimumHeight(28)
|
||||
self.__add_tag_button.setStyleSheet(BUTTON_STYLE)
|
||||
self.__add_tag_button.setStyleSheet(button_style())
|
||||
|
||||
self.__add_field_button = QPushButton(Translations["field.add"])
|
||||
self.__add_field_button.setEnabled(False)
|
||||
self.__add_field_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
self.__add_field_button.setMinimumHeight(28)
|
||||
self.__add_field_button.setStyleSheet(BUTTON_STYLE)
|
||||
self.__add_field_button.setStyleSheet(button_style())
|
||||
|
||||
add_buttons_layout.addWidget(self.__add_tag_button)
|
||||
add_buttons_layout.addWidget(self.__add_field_button)
|
||||
|
||||
@@ -16,46 +16,14 @@ from PySide6.QtWidgets import (
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from tagstudio.core.library.alchemy.enums import TagColorEnum
|
||||
from tagstudio.core.library.alchemy.library import Library
|
||||
from tagstudio.qt.models.palette import ColorType, get_tag_color
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.panel_modal import PanelWidget
|
||||
from tagstudio.qt.views.stylesheets.stylesheets import list_button_style
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from tagstudio.qt.controllers.search_panel_controller import SearchPanel
|
||||
|
||||
CREATE_BUTTON_STYLESHEET: str = f"""
|
||||
QPushButton{{
|
||||
background: {get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT)};
|
||||
color: {get_tag_color(ColorType.TEXT, TagColorEnum.DEFAULT)};
|
||||
font-weight: 600;
|
||||
border-color:{get_tag_color(ColorType.BORDER, TagColorEnum.DEFAULT)};
|
||||
border-radius: 6px;
|
||||
border-style: dashed;
|
||||
border-width: 2px;
|
||||
padding-right: 4px;
|
||||
padding-bottom: 1px;
|
||||
padding-left: 4px;
|
||||
font-size: 13px
|
||||
}}
|
||||
|
||||
QPushButton::hover{{
|
||||
border-color: {get_tag_color(ColorType.LIGHT_ACCENT, TagColorEnum.DEFAULT)};
|
||||
}}
|
||||
|
||||
QPushButton::pressed{{
|
||||
background: {get_tag_color(ColorType.LIGHT_ACCENT, TagColorEnum.DEFAULT)};
|
||||
color: {get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT)};
|
||||
border-color: {get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT)};
|
||||
}}
|
||||
|
||||
QPushButton::focus{{
|
||||
border-color: {get_tag_color(ColorType.LIGHT_ACCENT, TagColorEnum.DEFAULT)};
|
||||
outline: none;
|
||||
}}
|
||||
"""
|
||||
|
||||
|
||||
class SearchPanelView(PanelWidget):
|
||||
def __init__(self, is_chooser: bool) -> None:
|
||||
@@ -120,7 +88,7 @@ class SearchPanelView(PanelWidget):
|
||||
self.create_and_add_button = QPushButton()
|
||||
self.create_and_add_button.setFlat(True)
|
||||
self.create_and_add_button.setMinimumSize(22, 22)
|
||||
self.create_and_add_button.setStyleSheet(CREATE_BUTTON_STYLESHEET)
|
||||
self.create_and_add_button.setStyleSheet(list_button_style(border_style="dashed"))
|
||||
|
||||
@property
|
||||
def scroll_layout(self) -> QVBoxLayout:
|
||||
|
||||
@@ -1,41 +1,431 @@
|
||||
# SPDX-FileCopyrightText: (c) TagStudio Contributors
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
from PySide6.QtGui import QColor
|
||||
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QColor, QGuiApplication
|
||||
|
||||
from tagstudio.core.enums import Theme
|
||||
from tagstudio.core.library.alchemy.enums import TagColorEnum
|
||||
from tagstudio.qt.mixed.tag_widget import get_border_color, get_highlight_color, get_text_color
|
||||
from tagstudio.qt.models.palette import ColorType, get_tag_color
|
||||
from tagstudio.core.library.alchemy.models import Tag
|
||||
from tagstudio.qt.models.palette import ColorType, UiColor, get_tag_color, get_ui_color
|
||||
|
||||
# TODO: There's plenty of good opportunities here to consolidate similar styles.
|
||||
# Work should be done to more closely use Qt's theming systems rather than override them.
|
||||
|
||||
|
||||
def add_button_style() -> str:
|
||||
"""Style used for tag-like "Add" buttons [+]."""
|
||||
return f"""
|
||||
QPushButton{{
|
||||
background: {get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT)};
|
||||
color: {get_tag_color(ColorType.TEXT, TagColorEnum.DEFAULT)};
|
||||
font-weight: 600;
|
||||
border-color: {get_tag_color(ColorType.BORDER, TagColorEnum.DEFAULT)};
|
||||
border-radius: 6px;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
padding-right: 4px;
|
||||
padding-bottom: 2px;
|
||||
padding-left: 4px;
|
||||
font-size: 15px
|
||||
}}
|
||||
QPushButton::hover{{
|
||||
border-color: {get_tag_color(ColorType.LIGHT_ACCENT, TagColorEnum.DEFAULT)};
|
||||
}}
|
||||
QPushButton::pressed{{
|
||||
background: {get_tag_color(ColorType.LIGHT_ACCENT, TagColorEnum.DEFAULT)};
|
||||
color: {get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT)};
|
||||
border-color: {get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT)};
|
||||
}}
|
||||
QPushButton::focus{{
|
||||
border-color: {get_tag_color(ColorType.LIGHT_ACCENT, TagColorEnum.DEFAULT)};
|
||||
outline: none;
|
||||
}}
|
||||
"""
|
||||
|
||||
|
||||
def button_style() -> str:
|
||||
"""Style used for common QPushButtons."""
|
||||
return f"""
|
||||
QPushButton{{
|
||||
background-color: {Theme.COLOR_BG.value};
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
}}
|
||||
QPushButton::hover{{
|
||||
background-color: {Theme.COLOR_HOVER.value};
|
||||
border-color: {get_ui_color(ColorType.BORDER, UiColor.THEME_DARK)};
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
}}
|
||||
QPushButton::pressed{{
|
||||
background-color: {Theme.COLOR_PRESSED.value};
|
||||
border-color: {get_ui_color(ColorType.LIGHT_ACCENT, UiColor.THEME_DARK)};
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
}}
|
||||
QPushButton::disabled{{
|
||||
background-color: {Theme.COLOR_DISABLED_BG.value};
|
||||
}}
|
||||
"""
|
||||
|
||||
|
||||
def checkbox_style() -> str:
|
||||
"""Style used for QCheckBoxes."""
|
||||
primary_color = QColor(get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT))
|
||||
border_color = get_border_color(primary_color)
|
||||
highlight_color = get_highlight_color(primary_color)
|
||||
text_color: QColor = get_text_color(primary_color, highlight_color)
|
||||
return (
|
||||
f"QCheckBox{{"
|
||||
f"background: rgba{primary_color.toTuple()};"
|
||||
f"color: rgba{text_color.toTuple()};"
|
||||
f"border-color: rgba{border_color.toTuple()};"
|
||||
f"border-radius: 6px;"
|
||||
f"border-style:solid;"
|
||||
f"border-width: 2px;"
|
||||
f"}}"
|
||||
f"QCheckBox::indicator{{"
|
||||
f"width: 10px;"
|
||||
f"height: 10px;"
|
||||
f"border-radius: 2px;"
|
||||
f"margin: 4px;"
|
||||
f"}}"
|
||||
f"QCheckBox::indicator:checked{{"
|
||||
f"background: rgba{text_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QCheckBox::hover{{"
|
||||
f"border-color: rgba{highlight_color.toTuple()};"
|
||||
f"}}"
|
||||
f"QCheckBox::focus{{"
|
||||
f"border-color: rgba{highlight_color.toTuple()};"
|
||||
f"outline:none;"
|
||||
f"}}"
|
||||
border_color = get_tag_border_color(primary_color)
|
||||
highlight_color = get_tag_highlight_color(primary_color)
|
||||
text_color: QColor = get_tag_text_color(primary_color, highlight_color)
|
||||
return f"""
|
||||
QCheckBox{{
|
||||
background: rgba{primary_color.toTuple()};
|
||||
color: rgba{text_color.toTuple()};
|
||||
border-color: rgba{border_color.toTuple()};
|
||||
border-radius: 6px;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
}}
|
||||
QCheckBox::indicator{{
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 2px;
|
||||
margin: 4px;
|
||||
}}
|
||||
QCheckBox::indicator:checked{{
|
||||
background: rgba{text_color.toTuple()};
|
||||
}}
|
||||
QCheckBox::hover{{
|
||||
border-color: rgba{highlight_color.toTuple()};
|
||||
}}
|
||||
QCheckBox::focus{{
|
||||
border-color: rgba{highlight_color.toTuple()};
|
||||
outline: none;
|
||||
}}
|
||||
"""
|
||||
|
||||
|
||||
def colored_radio_button_style(
|
||||
primary_color: QColor,
|
||||
text_color: QColor,
|
||||
border_color: QColor,
|
||||
highlight_color: QColor,
|
||||
) -> str:
|
||||
return f"""
|
||||
QRadioButton{{
|
||||
background: rgba{primary_color.toTuple()};
|
||||
color: rgba{text_color.toTuple()};
|
||||
border-color: rgba{border_color.toTuple()};
|
||||
border-radius: 6px;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
}}
|
||||
QRadioButton::indicator{{
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 2px;
|
||||
margin: 4px;
|
||||
}}
|
||||
QRadioButton::indicator:checked{{
|
||||
background: rgba{text_color.toTuple()};
|
||||
}}
|
||||
QRadioButton::hover{{
|
||||
border-color: rgba{highlight_color.toTuple()};
|
||||
}}
|
||||
QRadioButton::pressed{{
|
||||
background: rgba{border_color.toTuple()};
|
||||
color: rgba{primary_color.toTuple()};
|
||||
border-color: rgba{primary_color.toTuple()};
|
||||
}}
|
||||
QRadioButton::focus{{
|
||||
border-color: rgba{highlight_color.toTuple()};
|
||||
outline: none;
|
||||
}}
|
||||
"""
|
||||
|
||||
|
||||
def color_swatch_style(
|
||||
primary_color: QColor,
|
||||
text_color: QColor,
|
||||
border_color: QColor,
|
||||
highlight_color: QColor,
|
||||
bottom_color: QColor | None = None,
|
||||
) -> str:
|
||||
"""A style used for color swatches (aka special QRadioButtons)."""
|
||||
bottom_color_str: str = (
|
||||
f"border-bottom-color: rgba{bottom_color.toTuple()};" if bottom_color else ""
|
||||
)
|
||||
|
||||
return f"""
|
||||
QRadioButton{{
|
||||
background: rgba{primary_color.toTuple()};
|
||||
color: rgba{text_color.toTuple()};
|
||||
border-color: rgba{border_color.toTuple()};
|
||||
{bottom_color_str}
|
||||
border-radius: 3px;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
}}
|
||||
QRadioButton::indicator{{
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 1px;
|
||||
margin: 4px;
|
||||
}}
|
||||
QRadioButton::indicator:checked{{
|
||||
background: rgba{text_color.toTuple()};
|
||||
}}
|
||||
QRadioButton::hover{{
|
||||
border-color: rgba{highlight_color.toTuple()};
|
||||
}}
|
||||
QRadioButton::focus{{
|
||||
outline-style: solid;
|
||||
outline-width: 2px;
|
||||
outline-radius: 3px;
|
||||
outline-color: rgba{highlight_color.toTuple()};
|
||||
}}
|
||||
"""
|
||||
|
||||
|
||||
def container_style() -> str:
|
||||
"""Style used for field containers."""
|
||||
return f"""
|
||||
QWidget#fieldContainer{{
|
||||
border-radius: 4px;
|
||||
}}
|
||||
QWidget#fieldContainer::hover{{
|
||||
background-color: {Theme.COLOR_HOVER.value};
|
||||
}}
|
||||
QWidget#fieldContainer::pressed{{
|
||||
background-color: {Theme.COLOR_PRESSED.value};
|
||||
}}
|
||||
"""
|
||||
|
||||
|
||||
def form_content_style() -> str:
|
||||
return f"""
|
||||
background-color: {
|
||||
Theme.COLOR_BG.value
|
||||
if QGuiApplication.styleHints().colorScheme() is Qt.ColorScheme.Dark
|
||||
else Theme.COLOR_BG_LIGHT.value
|
||||
};
|
||||
border-radius: 3px;
|
||||
font-weight: 500;
|
||||
padding: 1px;
|
||||
"""
|
||||
|
||||
|
||||
def line_edit_style() -> str:
|
||||
"""Style used for QLineEdits."""
|
||||
return f"""
|
||||
border: 1px solid {get_ui_color(ColorType.PRIMARY, UiColor.RED)};
|
||||
border-radius: 2px
|
||||
"""
|
||||
|
||||
|
||||
def list_button_style(
|
||||
color: QColor | None = None,
|
||||
border_style: str = "solid",
|
||||
) -> str:
|
||||
"""Style used for special QPushButtons found in lists."""
|
||||
if color is None:
|
||||
color = QColor(get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT))
|
||||
|
||||
highlight_color = get_tag_highlight_color(color)
|
||||
text_color = get_tag_text_color(color, highlight_color)
|
||||
border_color = get_tag_border_color(color)
|
||||
|
||||
return f"""
|
||||
QPushButton{{
|
||||
background: rgba{color.toTuple()};
|
||||
color: rgba{text_color.toTuple()};
|
||||
font-weight: 600;
|
||||
border-color: rgba{border_color.toTuple()};
|
||||
border-radius: 6px;
|
||||
border-style: {border_style};
|
||||
border-width: 2px;
|
||||
padding-right: 4px;
|
||||
padding-bottom: 1px;
|
||||
padding-left: 4px;
|
||||
font-size: 13px
|
||||
}}
|
||||
QPushButton::hover{{
|
||||
border-color: rgba{highlight_color.toTuple()};
|
||||
}}
|
||||
QPushButton::pressed{{
|
||||
background: rgba{highlight_color.toTuple()};
|
||||
color: rgba{color.toTuple()};
|
||||
border-color: rgba{color.toTuple()};
|
||||
}}
|
||||
QPushButton::focus{{
|
||||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
outline-style: solid;
|
||||
outline-width: 1px;
|
||||
outline-radius: 4px;
|
||||
outline-color: rgba{text_color.toTuple()};
|
||||
}}
|
||||
"""
|
||||
|
||||
|
||||
def properties_style() -> str:
|
||||
"""Style used for small labels such as file properties."""
|
||||
label_bg_color = (
|
||||
Theme.COLOR_BG_DARK.value
|
||||
if QGuiApplication.styleHints().colorScheme() is Qt.ColorScheme.Dark
|
||||
else Theme.COLOR_DARK_LABEL.value
|
||||
)
|
||||
|
||||
return f"""
|
||||
background-color: {label_bg_color};
|
||||
color: #FFFFFF;
|
||||
font-family: Oxanium;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
border-radius: 3px;
|
||||
padding-top: 4px;
|
||||
padding-right: 1px;
|
||||
padding-bottom: 1px;
|
||||
padding-left: 1px;
|
||||
"""
|
||||
|
||||
|
||||
def tag_style(
|
||||
primary_color: QColor,
|
||||
text_color: QColor,
|
||||
border_color: QColor,
|
||||
highlight_color: QColor,
|
||||
border_style: str = "solid",
|
||||
) -> str:
|
||||
"""Style used for TagWidgets."""
|
||||
return f"""
|
||||
QPushButton{{
|
||||
background: rgba{primary_color.toTuple()};
|
||||
color: rgba{text_color.toTuple()};
|
||||
font-weight: 600;
|
||||
border-color: rgba{border_color.toTuple()};
|
||||
border-radius: 6px;
|
||||
border-style: {border_style};
|
||||
border-width: 2px;
|
||||
padding-right: 4px;
|
||||
padding-left: 4px;
|
||||
font-size: 13px
|
||||
}}
|
||||
QPushButton::hover{{
|
||||
border-color: rgba{highlight_color.toTuple()};
|
||||
}}
|
||||
QPushButton::pressed{{
|
||||
background: rgba{highlight_color.toTuple()};
|
||||
color: rgba{primary_color.toTuple()};
|
||||
border-color: rgba{primary_color.toTuple()};
|
||||
}}
|
||||
QPushButton::focus{{
|
||||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
outline-style: solid;
|
||||
outline-width: 1px;
|
||||
outline-radius: 4px;
|
||||
outline-color: rgba{text_color.toTuple()};
|
||||
}}
|
||||
"""
|
||||
|
||||
|
||||
def tag_remove_button_style(
|
||||
primary_color: QColor, text_color: QColor, border_color: QColor, highlight_color: QColor
|
||||
) -> str:
|
||||
"""Style used for "Remove" buttons on TagWidgets [-]."""
|
||||
return f"""
|
||||
QPushButton{{
|
||||
color: rgba{primary_color.toTuple()};
|
||||
background: rgba{text_color.toTuple()};
|
||||
font-weight: 800;
|
||||
border-radius: 5px;
|
||||
border-width: 4;
|
||||
border-color: rgba(0,0,0,0);
|
||||
padding-bottom: 4px;
|
||||
font-size: 14px
|
||||
}}
|
||||
QPushButton::hover{{
|
||||
background: rgba{primary_color.toTuple()};
|
||||
color: rgba{text_color.toTuple()};
|
||||
border-color: rgba{highlight_color.toTuple()};
|
||||
border-width: 2;
|
||||
border-radius: 6px;
|
||||
}}
|
||||
QPushButton::pressed{{
|
||||
background: rgba{border_color.toTuple()};
|
||||
color: rgba{highlight_color.toTuple()};
|
||||
}}
|
||||
QPushButton::focus{{
|
||||
background: rgba{border_color.toTuple()};
|
||||
outline: none;
|
||||
}}
|
||||
"""
|
||||
|
||||
|
||||
def title_line_edit_style() -> str:
|
||||
"""Used to mimic an H3-like header style inside a QLineEdit."""
|
||||
return """
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
"""
|
||||
|
||||
|
||||
def header(string: str, level: int, color: str | None = None) -> str:
|
||||
"""Wrap a string in HTML header tags.
|
||||
|
||||
Args:
|
||||
string (str): The string to format.
|
||||
level (int): A value between 1 and 6 denoting the header level.
|
||||
For example, "1" will create <h1> tags, "6" will create <h6> tags, etc.
|
||||
color: Optional color string to pass as an inline HTML style.
|
||||
"""
|
||||
if level < 1:
|
||||
level = 1
|
||||
elif level > 6:
|
||||
level = 6
|
||||
|
||||
style_tag: str = ""
|
||||
if color is not None:
|
||||
style_tag = f" style='color: {color}'"
|
||||
|
||||
return f"<h{level}{style_tag}>{string}</h{level}>"
|
||||
|
||||
|
||||
def get_tag_primary_color(tag: Tag) -> QColor:
|
||||
primary_color = QColor(
|
||||
get_tag_color(ColorType.PRIMARY, TagColorEnum.DEFAULT)
|
||||
if not tag.color
|
||||
else tag.color.primary
|
||||
)
|
||||
|
||||
return primary_color
|
||||
|
||||
|
||||
def get_tag_border_color(primary_color: QColor) -> QColor:
|
||||
border_color: QColor = QColor(primary_color)
|
||||
border_color.setRed(min(border_color.red() + 20, 255))
|
||||
border_color.setGreen(min(border_color.green() + 20, 255))
|
||||
border_color.setBlue(min(border_color.blue() + 20, 255))
|
||||
|
||||
return border_color
|
||||
|
||||
|
||||
def get_tag_highlight_color(primary_color: QColor) -> QColor:
|
||||
highlight_color: QColor = QColor(primary_color)
|
||||
highlight_color = highlight_color.toHsl()
|
||||
highlight_color.setHsl(highlight_color.hue(), min(highlight_color.saturation(), 200), 225, 255)
|
||||
highlight_color = highlight_color.toRgb()
|
||||
|
||||
return highlight_color
|
||||
|
||||
|
||||
def get_tag_text_color(primary_color: QColor, highlight_color: QColor) -> QColor:
|
||||
if primary_color.lightness() > 120:
|
||||
text_color = QColor(primary_color)
|
||||
text_color = text_color.toHsl()
|
||||
text_color.setHsl(text_color.hue(), text_color.saturation(), 50, 255)
|
||||
return text_color.toRgb()
|
||||
else:
|
||||
return highlight_color
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
"about.license": "License",
|
||||
"about.module.found": "Found",
|
||||
"about.title": "About TagStudio",
|
||||
"about.version": "Version",
|
||||
"about.version.latest": "{built_version} (Latest Release: {latest_version})",
|
||||
"about.website": "Website",
|
||||
"app.git": "Git Commit",
|
||||
"app.pre_release": "Pre-Release",
|
||||
@@ -352,6 +354,7 @@
|
||||
"tag.parent_tags": "Parent Tags",
|
||||
"tag.parent_tags.add": "Add Parent Tag(s)",
|
||||
"tag.parent_tags.description": "This tag can be treated as a substitute for any of these Parent Tags in searches.",
|
||||
"tag.properties": "Properties",
|
||||
"tag.remove": "Remove Tag",
|
||||
"tag.search_for_tag": "Search for Tag",
|
||||
"tag.shorthand": "Shorthand",
|
||||
|
||||
Reference in New Issue
Block a user