Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/tagstudio/core/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ class ShowFilepathOption(int, enum.Enum):
DEFAULT = SHOW_RELATIVE_PATHS


class TagClickActionOption(int, enum.Enum):
"""Values representing the options for the "tag_click_action" setting."""

OPEN_EDIT = 0
SET_SEARCH = 1
ADD_TO_SEARCH = 2
DEFAULT = OPEN_EDIT


class Theme(str, enum.Enum):
COLOR_BG_DARK = "#65000000"
COLOR_BG_LIGHT = "#22000000"
Expand Down
3 changes: 2 additions & 1 deletion src/tagstudio/core/global_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import toml
from pydantic import BaseModel, Field

from tagstudio.core.enums import ShowFilepathOption
from tagstudio.core.enums import ShowFilepathOption, TagClickActionOption

if platform.system() == "Windows":
DEFAULT_GLOBAL_SETTINGS_PATH = (
Expand Down Expand Up @@ -50,6 +50,7 @@ class GlobalSettings(BaseModel):
page_size: int = Field(default=100)
show_filepath: ShowFilepathOption = Field(default=ShowFilepathOption.DEFAULT)
theme: Theme = Field(default=Theme.SYSTEM)
tag_click_action: TagClickActionOption = Field(default=TagClickActionOption.DEFAULT)

date_format: str = Field(default="%x")
hour_format: bool = Field(default=True)
Expand Down
3 changes: 3 additions & 0 deletions src/tagstudio/core/library/alchemy/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ def with_sorting_mode(self, mode: SortingModeEnum) -> "BrowsingState":
def with_sorting_direction(self, ascending: bool) -> "BrowsingState":
return replace(self, ascending=ascending)

def with_search_query(self, search_query: str) -> "BrowsingState":
return replace(self, query=search_query)


class FieldTypeEnum(enum.Enum):
TEXT_LINE = "Text Line"
Expand Down
57 changes: 45 additions & 12 deletions src/tagstudio/qt/modals/settings_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,19 @@
QWidget,
)

from tagstudio.core.enums import ShowFilepathOption
from tagstudio.core.enums import ShowFilepathOption, TagClickActionOption
from tagstudio.core.global_settings import Theme
from tagstudio.qt.translations import DEFAULT_TRANSLATION, LANGUAGES, Translations
from tagstudio.qt.widgets.panel import PanelModal, PanelWidget

if TYPE_CHECKING:
from tagstudio.qt.ts_qt import QtDriver

FILEPATH_OPTION_MAP: dict[ShowFilepathOption, str] = {
ShowFilepathOption.SHOW_FULL_PATHS: Translations["settings.filepath.option.full"],
ShowFilepathOption.SHOW_RELATIVE_PATHS: Translations["settings.filepath.option.relative"],
ShowFilepathOption.SHOW_FILENAMES_ONLY: Translations["settings.filepath.option.name"],
}
FILEPATH_OPTION_MAP: dict[ShowFilepathOption, str] = {}

THEME_MAP: dict[Theme, str] = {
Theme.DARK: Translations["settings.theme.dark"],
Theme.LIGHT: Translations["settings.theme.light"],
Theme.SYSTEM: Translations["settings.theme.system"],
}
THEME_MAP: dict[Theme, str] = {}

TAG_CLICK_ACTION_MAP: dict[TagClickActionOption, str] = {}

DATE_FORMAT_MAP: dict[str, str] = {
"%d/%m/%y": "21/08/24",
Expand All @@ -61,6 +55,29 @@ class SettingsPanel(PanelWidget):

def __init__(self, driver: "QtDriver"):
super().__init__()
# set these "constants" because language will be loaded from config shortly after startup
# and we want to use the current language for the dropdowns
global FILEPATH_OPTION_MAP, THEME_MAP, TAG_CLICK_ACTION_MAP
FILEPATH_OPTION_MAP = {
ShowFilepathOption.SHOW_FULL_PATHS: Translations["settings.filepath.option.full"],
ShowFilepathOption.SHOW_RELATIVE_PATHS: Translations[
"settings.filepath.option.relative"
],
ShowFilepathOption.SHOW_FILENAMES_ONLY: Translations["settings.filepath.option.name"],
}
THEME_MAP = {
Theme.DARK: Translations["settings.theme.dark"],
Theme.LIGHT: Translations["settings.theme.light"],
Theme.SYSTEM: Translations["settings.theme.system"],
}
TAG_CLICK_ACTION_MAP = {
TagClickActionOption.OPEN_EDIT: Translations["settings.tag_click_action.open_edit"],
TagClickActionOption.SET_SEARCH: Translations["settings.tag_click_action.set_search"],
TagClickActionOption.ADD_TO_SEARCH: Translations[
"settings.tag_click_action.add_to_search"
],
}

self.driver = driver
self.setMinimumSize(400, 300)

Expand Down Expand Up @@ -158,13 +175,27 @@ def on_page_size_changed():
self.theme_combobox = QComboBox()
for k in THEME_MAP:
self.theme_combobox.addItem(THEME_MAP[k], k)
theme: Theme = self.driver.settings.theme
theme = self.driver.settings.theme
if theme not in THEME_MAP:
theme = Theme.DEFAULT
self.theme_combobox.setCurrentIndex(list(THEME_MAP.keys()).index(theme))
self.theme_combobox.currentIndexChanged.connect(self.__update_restart_label)
form_layout.addRow(Translations["settings.theme.label"], self.theme_combobox)

# Tag Click Action
self.tag_click_action_combobox = QComboBox()
for k in TAG_CLICK_ACTION_MAP:
self.tag_click_action_combobox.addItem(TAG_CLICK_ACTION_MAP[k], k)
tag_click_action = self.driver.settings.tag_click_action
if tag_click_action not in TAG_CLICK_ACTION_MAP:
tag_click_action = TagClickActionOption.DEFAULT
self.tag_click_action_combobox.setCurrentIndex(
list(TAG_CLICK_ACTION_MAP.keys()).index(tag_click_action)
)
form_layout.addRow(
Translations["settings.tag_click_action.label"], self.tag_click_action_combobox
)

# Date Format
self.dateformat_combobox = QComboBox()
for k in DATE_FORMAT_MAP:
Expand Down Expand Up @@ -206,6 +237,7 @@ def get_settings(self) -> dict:
"page_size": int(self.page_size_line_edit.text()),
"show_filepath": self.filepath_combobox.currentData(),
"theme": self.theme_combobox.currentData(),
"tag_click_action": self.tag_click_action_combobox.currentData(),
"date_format": self.dateformat_combobox.currentData(),
"hour_format": self.hourformat_checkbox.isChecked(),
"zero_padding": self.zeropadding_checkbox.isChecked(),
Expand All @@ -221,6 +253,7 @@ def update_settings(self, driver: "QtDriver"):
driver.settings.page_size = settings["page_size"]
driver.settings.show_filepath = settings["show_filepath"]
driver.settings.theme = settings["theme"]
driver.settings.tag_click_action = settings["tag_click_action"]
driver.settings.date_format = settings["date_format"]
driver.settings.hour_format = settings["hour_format"]
driver.settings.zero_padding = settings["zero_padding"]
Expand Down
18 changes: 14 additions & 4 deletions src/tagstudio/qt/widgets/tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,17 @@ class TagWidget(QWidget):
on_click = Signal()
on_edit = Signal()

tag: Tag | None

def __init__(
self,
tag: Tag | None,
has_edit: bool,
has_remove: bool,
library: "Library | None" = None,
on_remove_callback: FunctionType = None,
on_click_callback: FunctionType = None,
on_edit_callback: FunctionType = None,
on_remove_callback: FunctionType | None = None,
on_click_callback: FunctionType | None = None,
on_edit_callback: FunctionType | None = None,
) -> None:
super().__init__()
self.tag = tag
Expand All @@ -123,10 +125,18 @@ def __init__(
self.bg_button = QPushButton(self)
self.bg_button.setFlat(True)

# add callbacks
if on_remove_callback is not None:
self.on_remove.connect(on_remove_callback)
if on_click_callback is not None:
self.on_click.connect(on_click_callback)
if on_edit_callback is not None:
self.on_edit.connect(on_edit_callback)

# add edit action
if has_edit:
edit_action = QAction(self)
edit_action.setText(Translations["generic.edit"])
edit_action.triggered.connect(on_edit_callback)
edit_action.triggered.connect(self.on_edit.emit)
self.bg_button.addAction(edit_action)
# if on_click_callback:
Expand Down
27 changes: 25 additions & 2 deletions src/tagstudio/qt/widgets/tag_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import structlog
from PySide6.QtCore import Signal

from tagstudio.core.enums import TagClickActionOption
from tagstudio.core.library.alchemy.enums import BrowsingState
from tagstudio.core.library.alchemy.models import Tag
from tagstudio.qt.flowlayout import FlowLayout
Expand All @@ -26,6 +27,8 @@ class TagBoxWidget(FieldWidget):
updated = Signal()
error_occurred = Signal(Exception)

driver: "QtDriver"

def __init__(
self,
tags: set[Tag],
Expand All @@ -50,11 +53,11 @@ def set_tags(self, tags: typing.Iterable[Tag]):
tags_ = sorted(list(tags), key=lambda tag: self.driver.lib.tag_display_name(tag.id))
logger.info("[TagBoxWidget] Tags:", tags=tags)
while self.base_layout.itemAt(0):
self.base_layout.takeAt(0).widget().deleteLater()
self.base_layout.takeAt(0).widget().deleteLater() # pyright: ignore[reportOptionalMemberAccess]

for tag in tags_:
tag_widget = TagWidget(tag, library=self.driver.lib, has_edit=True, has_remove=True)
tag_widget.on_click.connect(lambda t=tag: self.edit_tag(t))
tag_widget.on_click.connect(lambda t=tag: self.__on_tag_clicked(t))

tag_widget.on_remove.connect(
lambda tag_id=tag.id: (
Expand All @@ -73,6 +76,26 @@ def set_tags(self, tags: typing.Iterable[Tag]):

self.base_layout.addWidget(tag_widget)

def __on_tag_clicked(self, tag: Tag):
match self.driver.settings.tag_click_action:
case TagClickActionOption.OPEN_EDIT:
self.edit_tag(tag)
case TagClickActionOption.SET_SEARCH:
self.driver.update_browsing_state(BrowsingState.from_tag_id(tag.id))
case TagClickActionOption.ADD_TO_SEARCH:
# NOTE: modifying the ast and then setting that would be nicer
# than this string manipulation, but also much more complex,
# due to needing to implement a visitor that turns an AST to a string
# So if that exists when you read this, change the following accordingly.
current = self.driver.browsing_history.current
suffix = BrowsingState.from_tag_id(tag.id).query
assert suffix is not None
self.driver.update_browsing_state(
current.with_search_query(
f"{current.query} {suffix}" if current.query else suffix
)
)

def edit_tag(self, tag: Tag):
assert isinstance(tag, Tag), f"tag is {type(tag)}"
build_tag_panel = BuildTagPanel(self.driver.lib, tag=tag)
Expand Down
4 changes: 4 additions & 0 deletions src/tagstudio/resources/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@
"settings.restart_required": "Bitte TagStudio neustarten, um Änderungen anzuwenden.",
"settings.show_filenames_in_grid": "Dateinamen in Raster darstellen",
"settings.show_recent_libraries": "Zuletzt verwendete Bibliotheken anzeigen",
"settings.tag_click_action.label": "Tag Klick Aktion",
"settings.tag_click_action.add_to_search": "Tag zu Suche hinzufügen",
"settings.tag_click_action.open_edit": "Tag bearbeiten",
"settings.tag_click_action.set_search": "Nach Tag suchen",
"settings.theme.dark": "Dunkel",
"settings.theme.label": "Design:",
"settings.theme.light": "Hell",
Expand Down
4 changes: 4 additions & 0 deletions src/tagstudio/resources/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@
"settings.restart_required": "Please restart TagStudio for changes to take effect.",
"settings.show_filenames_in_grid": "Show Filenames in Grid",
"settings.show_recent_libraries": "Show Recent Libraries",
"settings.tag_click_action.label": "Tag Click Action",
"settings.tag_click_action.add_to_search": "Add Tag to Search",
"settings.tag_click_action.open_edit": "Edit Tag",
"settings.tag_click_action.set_search": "Search for Tag",
"settings.theme.dark": "Dark",
"settings.theme.label": "Theme:",
"settings.theme.light": "Light",
Expand Down