From f53a9249f04a9367778a78a8d9385e44d305161d Mon Sep 17 00:00:00 2001 From: Theasacraft <91694323+Thesacraft@users.noreply.github.com> Date: Sun, 28 Apr 2024 01:51:09 +0200 Subject: [PATCH 01/18] Build script for windows Adds a build script for windows --- Build_win.bat | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Build_win.bat diff --git a/Build_win.bat b/Build_win.bat new file mode 100644 index 00000000..4b91a2f6 --- /dev/null +++ b/Build_win.bat @@ -0,0 +1,15 @@ +@echo off +echo Building windows executable... + + +set TAGSTUDIO_NAME=TagStudio +set TAGSTUDIO_DIR=tagstudio +set TAGSTUDIO_DIR_RESOURCES=%TAGSTUDIO_DIR%/resources +set TAGSTUDIO_ICON=%TAGSTUDIO_DIR%/resources/icon.ico +set TAGSTUDIO_SRC=%TAGSTUDIO_DIR%/src +set TAGSTUDIO_MAIN=%TAGSTUDIO_DIR%/tag_studio.py + +set COMMAND=PyInstaller --name "%TAGSTUDIO_NAME%" --icon "%TAGSTUDIO_ICON%" --add-data "%TAGSTUDIO_DIR_RESOURCES%:./resources" --add-data "%TAGSTUDIO_SRC%:./src" --distpath "%DIST_PATH%" -p "%TAGSTUDIO_DIR%" --console --onefile "%TAGSTUDIO_MAIN%" -y +call .venv\Scripts\activate.bat +%COMMAND% +deactivate \ No newline at end of file From 329c23e23c53e03bd3316f40c555130269f89de2 Mon Sep 17 00:00:00 2001 From: Theasacraft <91694323+Thesacraft@users.noreply.github.com> Date: Sun, 28 Apr 2024 01:54:17 +0200 Subject: [PATCH 02/18] Update requirements.txt to include pyinstaller Pyinstaller is used to build the windows executable --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 0456b920..7a144c43 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,4 @@ PySide6_Addons>=6.5.1.1,<=6.6.3.1 PySide6_Essentials>=6.5.1.1,<=6.6.3.1 typing_extensions>=3.10.0.0,<=4.11.0 ujson>=5.8.0,<=5.9.0 +Pyinstaller From 4f00a8ac88b97ce0e4a9e79e04041b7b3ce7b89e Mon Sep 17 00:00:00 2001 From: Theasacraft <91694323+Thesacraft@users.noreply.github.com> Date: Sun, 28 Apr 2024 01:56:13 +0200 Subject: [PATCH 03/18] Update .gitignore to ignore build specific files and folders --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 0a5d8271..2aab2c25 100644 --- a/.gitignore +++ b/.gitignore @@ -251,4 +251,9 @@ compile_commands.json .TagStudio TagStudio.ini +build +dist +TagStudio.spec + + # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,python,qt From 9959eb1049ee63674ff6422a7bb0c21d61721237 Mon Sep 17 00:00:00 2001 From: Theasacraft <91694323+Thesacraft@users.noreply.github.com> Date: Sun, 28 Apr 2024 02:00:17 +0200 Subject: [PATCH 04/18] Update .gitignore to revert doubled entrys --- .gitignore | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 2aab2c25..8c0029f0 100644 --- a/.gitignore +++ b/.gitignore @@ -251,9 +251,7 @@ compile_commands.json .TagStudio TagStudio.ini -build -dist -TagStudio.spec + # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,python,qt From 049582487861787a7427ba80d3626ca1db8eddfc Mon Sep 17 00:00:00 2001 From: Theasacraft <91694323+Thesacraft@users.noreply.github.com> Date: Sun, 28 Apr 2024 04:54:02 +0200 Subject: [PATCH 05/18] Update requirements.txt to use last tested pyinstaller version Thanks to @williamtcastro for pointing it out --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7a144c43..7c1b4c35 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,4 @@ PySide6_Addons>=6.5.1.1,<=6.6.3.1 PySide6_Essentials>=6.5.1.1,<=6.6.3.1 typing_extensions>=3.10.0.0,<=4.11.0 ujson>=5.8.0,<=5.9.0 -Pyinstaller +Pyinstaller==6.6.0 From 260583cfeb07a08a605baa5d8fa1c5dcd4559dd3 Mon Sep 17 00:00:00 2001 From: Theasacraft <91694323+Thesacraft@users.noreply.github.com> Date: Sun, 28 Apr 2024 21:52:16 +0200 Subject: [PATCH 06/18] Update Build_win.bat for faster start of executable I changed it to output an executable and a _internals dir because this makes it, atleast from my experience, much faster (12s -> 1-2s). This is probably because the decompression that has to happen before startup if its in one file --- Build_win.bat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Build_win.bat b/Build_win.bat index 4b91a2f6..2d2ec782 100644 --- a/Build_win.bat +++ b/Build_win.bat @@ -9,7 +9,7 @@ set TAGSTUDIO_ICON=%TAGSTUDIO_DIR%/resources/icon.ico set TAGSTUDIO_SRC=%TAGSTUDIO_DIR%/src set TAGSTUDIO_MAIN=%TAGSTUDIO_DIR%/tag_studio.py -set COMMAND=PyInstaller --name "%TAGSTUDIO_NAME%" --icon "%TAGSTUDIO_ICON%" --add-data "%TAGSTUDIO_DIR_RESOURCES%:./resources" --add-data "%TAGSTUDIO_SRC%:./src" --distpath "%DIST_PATH%" -p "%TAGSTUDIO_DIR%" --console --onefile "%TAGSTUDIO_MAIN%" -y +set COMMAND=PyInstaller --name "%TAGSTUDIO_NAME%" --icon "%TAGSTUDIO_ICON%" --add-data "%TAGSTUDIO_DIR_RESOURCES%:./resources" --add-data "%TAGSTUDIO_SRC%:./src" --distpath "%DIST_PATH%" -p "%TAGSTUDIO_DIR%" --console --onedir "%TAGSTUDIO_MAIN%" -y call .venv\Scripts\activate.bat %COMMAND% -deactivate \ No newline at end of file +deactivate From 44106e2c59fa697d36435173560d48859a76f8e6 Mon Sep 17 00:00:00 2001 From: Theasacraft <91694323+Thesacraft@users.noreply.github.com> Date: Mon, 29 Apr 2024 00:13:48 +0200 Subject: [PATCH 07/18] Updates Build_win.bat to not delete source and be able to build portable version --- Build_win.bat | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Build_win.bat b/Build_win.bat index 2d2ec782..3e99fdcf 100644 --- a/Build_win.bat +++ b/Build_win.bat @@ -1,15 +1,31 @@ @echo off -echo Building windows executable... - - set TAGSTUDIO_NAME=TagStudio set TAGSTUDIO_DIR=tagstudio set TAGSTUDIO_DIR_RESOURCES=%TAGSTUDIO_DIR%/resources set TAGSTUDIO_ICON=%TAGSTUDIO_DIR%/resources/icon.ico set TAGSTUDIO_SRC=%TAGSTUDIO_DIR%/src set TAGSTUDIO_MAIN=%TAGSTUDIO_DIR%/tag_studio.py +set BUILD_MODE=--onedir -set COMMAND=PyInstaller --name "%TAGSTUDIO_NAME%" --icon "%TAGSTUDIO_ICON%" --add-data "%TAGSTUDIO_DIR_RESOURCES%:./resources" --add-data "%TAGSTUDIO_SRC%:./src" --distpath "%DIST_PATH%" -p "%TAGSTUDIO_DIR%" --console --onedir "%TAGSTUDIO_MAIN%" -y + +if "%1" == "--help" ( + echo run "%~nx0" for normal Build + echo run "%~nx0 --portable" for Build packaged into one file + goto end +) +if "%1" == "--portable" ( + echo Building portable executable... + set BUILD_MODE=--onefile + goto run +) +if not "%1" == "" ( + echo Invalid argument run "%~nx0 --help" for help + goto end +) +:run +echo Building executable... +set COMMAND=PyInstaller --name "%TAGSTUDIO_NAME%" --icon "%TAGSTUDIO_ICON%" --add-data "%TAGSTUDIO_DIR_RESOURCES%:./resources" --add-data "%TAGSTUDIO_SRC%:./src" -p "%TAGSTUDIO_DIR%" --console %BUILD_MODE% "%TAGSTUDIO_MAIN%" -y call .venv\Scripts\activate.bat %COMMAND% deactivate +:end From 0e621011fc7b3744d4cce5117e71ec55d7af8f15 Mon Sep 17 00:00:00 2001 From: yedpodtrzitko Date: Wed, 8 May 2024 11:10:43 +0800 Subject: [PATCH 08/18] dont run job threads needlessly --- tagstudio/src/qt/ts_qt.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index eabafdb5..f2dc760a 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -132,19 +132,20 @@ class NavigationState: class Consumer(QThread): + MARKER_QUIT = "MARKER_QUIT" + def __init__(self, queue) -> None: self.queue = queue QThread.__init__(self) def run(self): - self.active = True - while self.active: + while True: try: - job = self.queue.get(timeout=0.2) - # print('Running job...') - # logging.info(*job[1]) + job = self.queue.get() + if job == self.MARKER_QUIT: + break job[0](*job[1]) - except (Empty, RuntimeError): + except RuntimeError: pass def set_page_count(self, count: int): @@ -179,7 +180,7 @@ class QtDriver(QObject): # self.title_text: str = self.base_title # self.buffer = {} self.thumb_job_queue: Queue = Queue() - self.thumb_threads = [] + self.thumb_threads: list[Consumer] = [] self.thumb_cutoff: float = time.time() # self.selected: list[tuple[int,int]] = [] # (Thumb Index, Page Index) self.selected: list[tuple[ItemType, int]] = [] # (Item Type, Item ID) @@ -545,10 +546,9 @@ class QtDriver(QObject): self.settings.setValue("last_library", self.lib.library_dir) self.settings.sync() logging.info("[SHUTDOWN] Ending Thumbnail Threads...") - for thread in self.thumb_threads: - thread.active = False - thread.quit() - thread.wait() + for _ in self.thumb_threads: + self.thumb_job_queue.put(Consumer.MARKER_QUIT) + QApplication.quit() def save_library(self, show_status=True): From 48ad4aaad23d74bdca055885e44e327015358c33 Mon Sep 17 00:00:00 2001 From: arthniwa <123327761+arthniwa@users.noreply.github.com> Date: Wed, 8 May 2024 00:42:16 -0500 Subject: [PATCH 09/18] Add action to help menu Add "Go to GitHub Repository" to the help menu. --- tagstudio/src/qt/ts_qt.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index eabafdb5..8529eaea 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -13,6 +13,7 @@ import math import os import sys import time +import webbrowser from datetime import datetime as dt from pathlib import Path from queue import Empty, Queue @@ -415,6 +416,11 @@ class QtDriver(QObject): folders_to_tags_action.triggered.connect(lambda: ftt_modal.show()) macros_menu.addAction(folders_to_tags_action) + # Help Menu ========================================================== + self.repo_action = QAction("Go to GitHub Repository", menu_bar) + self.repo_action.triggered.connect(lambda: webbrowser.open('https://github.com/TagStudioDev/TagStudio')) + help_menu.addAction(self.repo_action) + self.set_macro_menu_viability() menu_bar.addMenu(file_menu) From e803f6adcbdb69adaf3f81992d2b822c6878d354 Mon Sep 17 00:00:00 2001 From: yedpodtrzitko Date: Wed, 8 May 2024 22:47:47 +0800 Subject: [PATCH 10/18] wait for threads to finish --- tagstudio/src/qt/ts_qt.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index f2dc760a..fa5778b7 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -549,6 +549,11 @@ class QtDriver(QObject): for _ in self.thumb_threads: self.thumb_job_queue.put(Consumer.MARKER_QUIT) + # wait for threads to quit + for thread in self.thumb_threads: + thread.quit() + thread.wait() + QApplication.quit() def save_library(self, show_status=True): From 7f776f4c8615606d8af71999be6ee00011be3f10 Mon Sep 17 00:00:00 2001 From: arthniwa <123327761+arthniwa@users.noreply.github.com> Date: Wed, 8 May 2024 10:57:48 -0500 Subject: [PATCH 11/18] Fix format required by Ruff --- tagstudio/src/qt/ts_qt.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index 8529eaea..5dd1b361 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -418,7 +418,9 @@ class QtDriver(QObject): # Help Menu ========================================================== self.repo_action = QAction("Go to GitHub Repository", menu_bar) - self.repo_action.triggered.connect(lambda: webbrowser.open('https://github.com/TagStudioDev/TagStudio')) + self.repo_action.triggered.connect( + lambda: webbrowser.open("https://github.com/TagStudioDev/TagStudio") + ) help_menu.addAction(self.repo_action) self.set_macro_menu_viability() From b6ccb88a95aedd4b0ae7d056279eb51550babe7e Mon Sep 17 00:00:00 2001 From: Travis Abendshien Date: Wed, 8 May 2024 11:39:03 -0700 Subject: [PATCH 12/18] Fixed Some Images Breaking Thumbnailer Fixed images that were considered to be "truncated" from breaking the thumbnail renderer when trying to transpose via an EXIF flag. This was happening with certain panorama photos. --- tagstudio/src/qt/widgets/thumb_renderer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tagstudio/src/qt/widgets/thumb_renderer.py b/tagstudio/src/qt/widgets/thumb_renderer.py index 37630324..5a49911d 100644 --- a/tagstudio/src/qt/widgets/thumb_renderer.py +++ b/tagstudio/src/qt/widgets/thumb_renderer.py @@ -19,11 +19,13 @@ from PIL import ( ImageFont, ImageEnhance, ImageOps, + ImageFile, ) from PySide6.QtCore import QObject, Signal, QSize from PySide6.QtGui import QPixmap from src.core.ts_core import PLAINTEXT_TYPES, VIDEO_TYPES, IMAGE_TYPES +ImageFile.LOAD_TRUNCATED_IMAGES = True ERROR = f"[ERROR]" WARNING = f"[WARNING]" From f9ea20e29caecdcc480de81901f965af22092750 Mon Sep 17 00:00:00 2001 From: Sylvia K <40416079+SylviaSK@users.noreply.github.com> Date: Wed, 8 May 2024 14:07:58 -0500 Subject: [PATCH 13/18] Refactor: Deduplication in pagination.py's "Set Elipses Sizes" section (#141) --- tagstudio/src/qt/pagination.py | 217 ++++----------------------------- 1 file changed, 22 insertions(+), 195 deletions(-) diff --git a/tagstudio/src/qt/pagination.py b/tagstudio/src/qt/pagination.py index bf4a8b57..64b159fa 100644 --- a/tagstudio/src/qt/pagination.py +++ b/tagstudio/src/qt/pagination.py @@ -133,6 +133,10 @@ class Pagination(QWidget, QObject): # self.update_buttons(page_count=9, index=0) def update_buttons(self, page_count: int, index: int, emit: bool = True): + # Guard + if index < 0: + raise ValueError("Negative index detected") + # Screw it for i in range(0, 10): if self.start_buffer_layout.itemAt(i): @@ -140,6 +144,8 @@ class Pagination(QWidget, QObject): if self.end_buffer_layout.itemAt(i): self.end_buffer_layout.itemAt(i).widget().setHidden(True) + end_page = page_count - 1 + if page_count <= 1: # Hide everything if there are only one or less pages. # [-------------- HIDDEN --------------] @@ -172,7 +178,7 @@ class Pagination(QWidget, QObject): # self.start_buffer_layout.setContentsMargins(3,0,3,0) self._assign_click(self.prev_button, index - 1) self.prev_button.setDisabled(False) - if index == page_count - 1: + if index == end_page: self.next_button.setDisabled(True) # self.end_buffer_layout.setContentsMargins(0,0,0,0) else: @@ -181,201 +187,22 @@ class Pagination(QWidget, QObject): self.next_button.setDisabled(False) # Set Ellipses Sizes - if page_count == 8: - if index == 0: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 2 + 3) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 2 + 3) - else: - self.end_ellipses.setMinimumWidth(self.button_size.width()) - self.end_ellipses.setMaximumWidth(self.button_size.width()) - if index == page_count - 1: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 2 + 3 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 2 + 3 - ) - else: - self.start_ellipses.setMinimumWidth(self.button_size.width()) - self.start_ellipses.setMaximumWidth(self.button_size.width()) - elif page_count == 9: - if index == 0: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 3 + 6) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 3 + 6) - elif index == 1: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 2 + 3) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 2 + 3) - else: - self.end_ellipses.setMinimumWidth(self.button_size.width()) - self.end_ellipses.setMaximumWidth(self.button_size.width()) - if index == page_count - 1: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 3 + 6 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 3 + 6 - ) - elif index == page_count - 2: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 2 + 3 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 2 + 3 - ) - else: - self.start_ellipses.setMinimumWidth(self.button_size.width()) - self.start_ellipses.setMaximumWidth(self.button_size.width()) - elif page_count == 10: - if index == 0: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 4 + 9) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 4 + 9) - elif index == 1: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 3 + 6) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 3 + 6) - elif index == 2: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 2 + 3) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 2 + 3) - else: - self.end_ellipses.setMinimumWidth(self.button_size.width()) - self.end_ellipses.setMaximumWidth(self.button_size.width()) - if index == page_count - 1: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 4 + 9 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 4 + 9 - ) - elif index == page_count - 2: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 3 + 6 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 3 + 6 - ) - elif index == page_count - 3: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 2 + 3 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 2 + 3 - ) - else: - self.start_ellipses.setMinimumWidth(self.button_size.width()) - self.start_ellipses.setMaximumWidth(self.button_size.width()) - elif page_count == 11: - if index == 0: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 5 + 12) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 5 + 12) - elif index == 1: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 4 + 9) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 4 + 9) - elif index == 2: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 3 + 6) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 3 + 6) - elif index == 3: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 2 + 3) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 2 + 3) - else: - self.end_ellipses.setMinimumWidth(self.button_size.width()) - self.end_ellipses.setMaximumWidth(self.button_size.width()) - if index == page_count - 1: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 5 + 12 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 5 + 12 - ) - elif index == page_count - 2: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 4 + 9 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 4 + 9 - ) - elif index == page_count - 3: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 3 + 6 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 3 + 6 - ) - elif index == page_count - 4: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 2 + 3 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 2 + 3 - ) - else: - self.start_ellipses.setMinimumWidth(self.button_size.width()) - self.start_ellipses.setMaximumWidth(self.button_size.width()) + # I do not know where these magic values were derived from, but + # this is better than the chain elif's that were here before + if 8 <= page_count <= 11: + end_scale = max(1, page_count - index - 6) + srt_scale = max(1, index - 5) elif page_count > 11: - if index == 0: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 7 + 18) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 7 + 18) - elif index == 1: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 6 + 15) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 6 + 15) - elif index == 2: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 5 + 12) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 5 + 12) - elif index == 3: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 4 + 9) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 4 + 9) - elif index == 4: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 3 + 6) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 3 + 6) - elif index == 5: - self.end_ellipses.setMinimumWidth(self.button_size.width() * 2 + 3) - self.end_ellipses.setMaximumWidth(self.button_size.width() * 2 + 3) - else: - self.end_ellipses.setMinimumWidth(self.button_size.width()) - self.end_ellipses.setMaximumWidth(self.button_size.width()) - if index == page_count - 1: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 7 + 18 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 7 + 18 - ) - elif index == page_count - 2: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 6 + 15 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 6 + 15 - ) - elif index == page_count - 3: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 5 + 12 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 5 + 12 - ) - elif index == page_count - 4: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 4 + 9 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 4 + 9 - ) - elif index == page_count - 5: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 3 + 6 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 3 + 6 - ) - elif index == page_count - 6: - self.start_ellipses.setMinimumWidth( - self.button_size.width() * 2 + 3 - ) - self.start_ellipses.setMaximumWidth( - self.button_size.width() * 2 + 3 - ) - else: - self.start_ellipses.setMinimumWidth(self.button_size.width()) - self.start_ellipses.setMaximumWidth(self.button_size.width()) + end_scale = max(1, 7 - index) + srt_scale = max(1, (7 - (end_page - index))) + + if page_count >= 8: + end_size = self.button_size.width() * end_scale + (3 * (end_scale - 1)) + srt_size = self.button_size.width() * srt_scale + (3 * (srt_scale - 1)) + self.end_ellipses.setMinimumWidth(end_size) + self.end_ellipses.setMaximumWidth(end_size) + self.start_ellipses.setMinimumWidth(srt_size) + self.start_ellipses.setMaximumWidth(srt_size) # Enable/Disable Ellipses # if index <= max(self.buffer_page_count, 5)+1: From 8321f43d6e1cdb98a0f33bd854032d1a708a2bd6 Mon Sep 17 00:00:00 2001 From: William de Castro Date: Thu, 9 May 2024 05:22:51 -0300 Subject: [PATCH 14/18] Add Build Script for mac os systems (#76) * chore: add TagStudio.spec to gitignore Prevent TagStudio.spec to be added to repo in the future * chore: add Build Script for macos Create script using pyinstaller to generate a macos app for tagstudio * chore: revert duplicated files * chore: rename build file naming --- .gitignore | 4 --- Build_MacOS_app.sh | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 4 deletions(-) create mode 100755 Build_MacOS_app.sh diff --git a/.gitignore b/.gitignore index 8c0029f0..5f5f4002 100644 --- a/.gitignore +++ b/.gitignore @@ -250,8 +250,4 @@ compile_commands.json # TagStudio .TagStudio TagStudio.ini - - - - # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,python,qt diff --git a/Build_MacOS_app.sh b/Build_MacOS_app.sh new file mode 100755 index 00000000..eeed6b7c --- /dev/null +++ b/Build_MacOS_app.sh @@ -0,0 +1,69 @@ +#! /usr/bin/env bash +# GETTING BASE DIR +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +# SETTING UP CONSTANTS +TAGSTUDIO_NAME="TagStudio" +TAGSTUDIO_DIR="$SCRIPT_DIR/tagstudio" +TAGSTUDIO_DIR_RESOURCES="$TAGSTUDIO_DIR/resources" +TAGSTUDIO_ICON="$TAGSTUDIO_DIR/resources/icon.ico" +TAGSTUDIO_SRC="$TAGSTUDIO_DIR/src" +TAGSTUDIO_MAIN="$TAGSTUDIO_DIR/tag_studio.py" +DIST_PATH="$SCRIPT_DIR/dist" +BUILD_PATH="$SCRIPT_DIR/build" +LOGS_PATH="$BUILD_PATH/logs" + +printf -- "🏁 Starting Script \n" + +# CREATE VENV AND INSTALL REQUIREMENTS +printf -- "🐍 Creating Python virtual env\n" +python3 -m venv .venv +source .venv/bin/activate + +if [ ! -d $LOGS_PATH ]; then + printf -- "📁 Creating Logs folder\n" + mkdir -p $LOGS_PATH; +fi + +printf -- "💻 Installing Requirements \n" +pip install -r requirements.txt > "$LOGS_PATH/pip.log" 2>&1 +pip install PyInstaller > "$LOGS_PATH/pip.log" 2>&1 + + +if [[ "$OSTYPE" == "darwin"* ]]; then + printf -- "🍏 MacOS Detected \n" + SYS_CMD="--windowed" + OS=0 +fi + +SECONDS=0 + +# CREATE COMMAND +printf -- "⏳ Building App \n" + +COMMAND=$( python -m PyInstaller \ + --name "$TAGSTUDIO_NAME" \ + --icon "$TAGSTUDIO_ICON" \ + --add-data "$TAGSTUDIO_DIR_RESOURCES:./resources" \ + --add-data "$TAGSTUDIO_SRC:./src" \ + --distpath "$DIST_PATH" \ + -p "$TAGSTUDIO_DIR" \ + --noconsole \ + --workpath "$BUILD_PATH" \ + -y "$SYS_CMD" "$TAGSTUDIO_MAIN" \ + > "$LOGS_PATH/pyinstaller.log" 2>&1 ) + +duration=$SECONDS + +if $COMMAND; then + printf -- "✅ Build Successfull \n" + printf -- "⌛ $((duration)) seconds of build\n" + if [[ "$OS" == 0 ]]; then + printf -- "📁 Opening App folder \n" + open $DIST_PATH + fi +else + printf -- "❌ Error Building the app\nPlease read the logs\navailable at build/logs\n" +fi + +printf -- "🏁 END OF TRANSMISSION" From b8d72a65c8198d0840af3afd6ad33c1d67e378b0 Mon Sep 17 00:00:00 2001 From: yed podtrzitko Date: Fri, 10 May 2024 08:39:46 +0800 Subject: [PATCH 15/18] misc: remove duplicate code for tags updating (#135) --- tagstudio/src/qt/widgets/item_thumb.py | 124 ++++++++----------------- 1 file changed, 38 insertions(+), 86 deletions(-) diff --git a/tagstudio/src/qt/widgets/item_thumb.py b/tagstudio/src/qt/widgets/item_thumb.py index 1c5f4057..589f4fe0 100644 --- a/tagstudio/src/qt/widgets/item_thumb.py +++ b/tagstudio/src/qt/widgets/item_thumb.py @@ -23,7 +23,7 @@ from PySide6.QtWidgets import ( QCheckBox, ) -from src.core.library import ItemType, Library +from src.core.library import ItemType, Library, Entry from src.core.ts_core import AUDIO_TYPES, VIDEO_TYPES, IMAGE_TYPES from src.qt.flowlayout import FlowWidget from src.qt.helpers import FileOpenerHelper @@ -32,11 +32,14 @@ from src.qt.widgets import ThumbRenderer, ThumbButton if typing.TYPE_CHECKING: from src.qt.widgets import PreviewPanel - ERROR = f"[ERROR]" WARNING = f"[WARNING]" INFO = f"[INFO]" +DEFAULT_META_TAG_FIELD = 8 +TAG_FAVORITE = 1 +TAG_ARCHIVED = 0 + logging.basicConfig(format="%(message)s", level=logging.INFO) @@ -453,91 +456,40 @@ class ItemThumb(FlowWidget): self.show_check_badges(False) return super().leaveEvent(event) - def on_archived_check(self, value: bool): - # logging.info(f'Archived Check: {value}, Mode: {self.mode}') + def on_archived_check(self, toggle_value: bool): if self.mode == ItemType.ENTRY: - self.isArchived = value - DEFAULT_META_TAG_FIELD = 8 - temp = (ItemType.ENTRY, self.item_id) - if ( - list(self.panel.driver.selected).count(temp) > 0 - ): # Is the archived badge apart of the selection? - # Yes, then add archived tag to all selected. - for x in self.panel.driver.selected: - e = self.lib.get_entry(x[1]) - if value: - self.archived_badge.setHidden(False) - e.add_tag( - self.panel.driver.lib, - 0, - field_id=DEFAULT_META_TAG_FIELD, - field_index=-1, - ) - else: - e.remove_tag(self.panel.driver.lib, 0) - else: - # No, then add archived tag to the entry this badge is on. - e = self.lib.get_entry(self.item_id) - if value: - self.favorite_badge.setHidden(False) - e.add_tag( - self.panel.driver.lib, - 0, - field_id=DEFAULT_META_TAG_FIELD, - field_index=-1, - ) - else: - e.remove_tag(self.panel.driver.lib, 0) - if self.panel.isOpen: - self.panel.update_widgets() - self.panel.driver.update_badges() + self.isArchived = toggle_value + self.toggle_item_tag(toggle_value, TAG_ARCHIVED) - # def on_archived_uncheck(self): - # if self.mode == SearchItemType.ENTRY: - # self.isArchived = False - # e = self.lib.get_entry(self.item_id) - - def on_favorite_check(self, value: bool): - # logging.info(f'Favorite Check: {value}, Mode: {self.mode}') + def on_favorite_check(self, toggle_value: bool): if self.mode == ItemType.ENTRY: - self.isFavorite = value - DEFAULT_META_TAG_FIELD = 8 - temp = (ItemType.ENTRY, self.item_id) - if ( - list(self.panel.driver.selected).count(temp) > 0 - ): # Is the favorite badge apart of the selection? - # Yes, then add favorite tag to all selected. - for x in self.panel.driver.selected: - e = self.lib.get_entry(x[1]) - if value: - self.favorite_badge.setHidden(False) - e.add_tag( - self.panel.driver.lib, - 1, - field_id=DEFAULT_META_TAG_FIELD, - field_index=-1, - ) - else: - e.remove_tag(self.panel.driver.lib, 1) - else: - # No, then add favorite tag to the entry this badge is on. - e = self.lib.get_entry(self.item_id) - if value: - self.favorite_badge.setHidden(False) - e.add_tag( - self.panel.driver.lib, - 1, - field_id=DEFAULT_META_TAG_FIELD, - field_index=-1, - ) - else: - e.remove_tag(self.panel.driver.lib, 1) - if self.panel.isOpen: - self.panel.update_widgets() - self.panel.driver.update_badges() + self.isFavorite = toggle_value + self.toggle_item_tag(toggle_value, TAG_FAVORITE) - # def on_favorite_uncheck(self): - # if self.mode == SearchItemType.ENTRY: - # self.isFavorite = False - # e = self.lib.get_entry(self.item_id) - # e.remove_tag(1) + def toggle_item_tag(self, toggle_value: bool, tag_id: int): + def toggle_tag(entry: Entry): + if toggle_value: + self.favorite_badge.setHidden(False) + entry.add_tag( + self.panel.driver.lib, + tag_id, + field_id=DEFAULT_META_TAG_FIELD, + field_index=-1, + ) + else: + entry.remove_tag(self.panel.driver.lib, tag_id) + + # Is the badge a part of the selection? + if (ItemType.ENTRY, self.item_id) in self.panel.driver.selected: + # Yes, add chosen tag to all selected. + for _, item_id in self.panel.driver.selected: + entry = self.lib.get_entry(item_id) + toggle_tag(entry) + else: + # No, add tag to the entry this badge is on. + entry = self.lib.get_entry(self.item_id) + toggle_tag(entry) + + if self.panel.isOpen: + self.panel.update_widgets() + self.panel.driver.update_badges() From 03a46ae57b33b1a467edf7e499d44cc6893f5e4a Mon Sep 17 00:00:00 2001 From: Travis Abendshien Date: Fri, 10 May 2024 15:29:28 -0700 Subject: [PATCH 16/18] Style Changes - Removed legacy style experiments, including strange translucent widgets and indigo default tags - Renamed "Folders To Tags" to "Create Tags From Folders" - Edited formatting of "Create Tags From Folders" modal - Renamed "Tag Database" to "Manage Tags"/"Library Tags" - Tweaked names of other menubar actions - Removed some commented-out code --- tagstudio/src/core/palette.py | 8 +-- tagstudio/src/qt/main_window.py | 41 ------------ tagstudio/src/qt/modals/folders_to_tags.py | 29 +++++---- tagstudio/src/qt/resources_rc.py | 11 +--- tagstudio/src/qt/ts_qt.py | 10 +-- tagstudio/src/qt/widgets/item_thumb.py | 4 +- tagstudio/src/qt/widgets/panel.py | 4 +- tagstudio/src/qt/widgets/preview_panel.py | 74 +++++++--------------- tagstudio/src/qt/widgets/tag_box.py | 9 +-- tagstudio/src/qt/widgets/thumb_renderer.py | 8 +-- 10 files changed, 63 insertions(+), 135 deletions(-) diff --git a/tagstudio/src/core/palette.py b/tagstudio/src/core/palette.py index 0faf3277..dc67b093 100644 --- a/tagstudio/src/core/palette.py +++ b/tagstudio/src/core/palette.py @@ -15,11 +15,11 @@ class ColorType(Enum): _TAG_COLORS = { "": { - ColorType.PRIMARY: "#1E1A33", + ColorType.PRIMARY: "#1e1e1e", ColorType.TEXT: ColorType.LIGHT_ACCENT, - ColorType.BORDER: "#2B2547", - ColorType.LIGHT_ACCENT: "#CDA7F7", - ColorType.DARK_ACCENT: "#1E1A33", + ColorType.BORDER: "#333333", + ColorType.LIGHT_ACCENT: "#FFFFFF", + ColorType.DARK_ACCENT: "#222222", }, "black": { ColorType.PRIMARY: "#111018", diff --git a/tagstudio/src/qt/main_window.py b/tagstudio/src/qt/main_window.py index 8055d930..e285b48b 100644 --- a/tagstudio/src/qt/main_window.py +++ b/tagstudio/src/qt/main_window.py @@ -38,54 +38,29 @@ class Ui_MainWindow(QMainWindow): # # self.setStyleSheet( # # 'background:#EE000000;' # # ) - def setupUi(self, MainWindow): if not MainWindow.objectName(): MainWindow.setObjectName(u"MainWindow") MainWindow.resize(1300, 720) - - # self._createMenuBar(MainWindow) - # print(type(MainWindow)) self.centralwidget = QWidget(MainWindow) self.centralwidget.setObjectName(u"centralwidget") self.gridLayout = QGridLayout(self.centralwidget) self.gridLayout.setObjectName(u"gridLayout") - # self.gridLayout.setContentsMargins(0, 0, 0, 0) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setObjectName(u"horizontalLayout") - - - # tb = StandardTitleBar(MainWindow) - # tb.setObjectName('TitleBar') - # # # self.setTitleBar(tb) - # hor = QVBoxLayout() - # self.gridLayout.setContentsMargins(0,0,0,0) - # self.gridLayout.addLayout(hor, 0, 0, 1, 1) - - - - # hor.addWidget(tb) - self.splitter = QSplitter() self.splitter.setObjectName(u"splitter") self.splitter.setHandleWidth(12) self.frame_container = QWidget() - # self.frame_container.setStyleSheet('background:red;') self.frame_layout = QVBoxLayout(self.frame_container) - # self.frame_container.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum) - self.frame_layout.setSpacing(0) - - self.scrollArea = QScrollArea() - # self.scrollArea.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) - # self.scrollArea.setStyleSheet('background:green;') self.scrollArea.setObjectName(u"scrollArea") self.scrollArea.setFocusPolicy(Qt.WheelFocus) self.scrollArea.setFrameShape(QFrame.NoFrame) @@ -102,12 +77,6 @@ class Ui_MainWindow(QMainWindow): self.scrollArea.setWidget(self.scrollAreaWidgetContents) self.frame_layout.addWidget(self.scrollArea) - self.scrollArea.setAttribute(Qt.WidgetAttribute.WA_NoSystemBackground) - # self.scrollArea.setWindowFlag(Qt.WindowType.FramelessWindowHint) - self.scrollArea.setAttribute( - Qt.WidgetAttribute.WA_TranslucentBackground) - self.scrollArea.setStyleSheet('background:#00000000;') - # self.page_bar_controls = QWidget() # self.page_bar_controls.setStyleSheet('background:blue;') # self.page_bar_controls.setMinimumHeight(32) @@ -118,7 +87,6 @@ class Ui_MainWindow(QMainWindow): # self.frame_layout.addWidget(self.page_bar_controls) # self.frame_layout.addWidget(self.page_bar_controls) - # self.horizontalLayout.addWidget(self.scrollArea) self.horizontalLayout.addWidget(self.splitter) self.splitter.addWidget(self.frame_container) self.splitter.setStretchFactor(0, 1) @@ -154,13 +122,6 @@ class Ui_MainWindow(QMainWindow): self.searchField = QLineEdit(self.centralwidget) self.searchField.setObjectName(u"searchField") self.searchField.setMinimumSize(QSize(0, 32)) - self.searchField.setStyleSheet( - 'background:#55000000;' - 'border-radius:6px;' - 'border-style:solid;' - 'border-width:1px;' - 'border-color:#11FFFFFF;' - ) font2 = QFont() font2.setPointSize(11) font2.setBold(False) @@ -174,7 +135,6 @@ class Ui_MainWindow(QMainWindow): self.searchButton.setFont(font2) self.horizontalLayout_2.addWidget(self.searchButton) - self.gridLayout.addLayout(self.horizontalLayout_2, 3, 0, 1, 1) self.comboBox = QComboBox(self.centralwidget) @@ -213,7 +173,6 @@ class Ui_MainWindow(QMainWindow): self.frame_layout.addWidget(menu_bar) self.retranslateUi(MainWindow) - # self.dumpObjectTree() QMetaObject.connectSlotsByName(MainWindow) # setupUi diff --git a/tagstudio/src/qt/modals/folders_to_tags.py b/tagstudio/src/qt/modals/folders_to_tags.py index bfb0f8d6..5163e412 100644 --- a/tagstudio/src/qt/modals/folders_to_tags.py +++ b/tagstudio/src/qt/modals/folders_to_tags.py @@ -165,25 +165,26 @@ class FoldersToTagsModal(QWidget): self.count = -1 self.filename = "" - self.setWindowTitle(f"Folders To Tags") + self.setWindowTitle(f"Create Tags From Folders") self.setWindowModality(Qt.WindowModality.ApplicationModal) - self.setMinimumSize(500, 800) + self.setMinimumSize(640, 640) self.root_layout = QVBoxLayout(self) self.root_layout.setContentsMargins(6, 6, 6, 6) + self.title_widget = QLabel() + 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.setText("Create Tags From Folders") + self.title_widget.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.desc_widget = QLabel() self.desc_widget.setObjectName("descriptionLabel") self.desc_widget.setWordWrap(True) - self.desc_widget.setStyleSheet( - # 'background:blue;' - "text-align:left;" - # 'font-weight:bold;' - "font-size:18px;" - # 'padding-top: 6px' - "" - ) self.desc_widget.setText( - """Creates tags based on the folder structure and applies them to entries.\n The Structure below shows all the tags that would be added and to which files they would be added. It being empty means that there are no Tag to be created or assigned""" + """Creates tags based on your folder structure and applies them to your entries.\n The structure below shows all the tags that will be created and what entries they will be applied to.""" ) self.desc_widget.setAlignment(Qt.AlignmentFlag.AlignCenter) @@ -216,14 +217,18 @@ class FoldersToTagsModal(QWidget): self.apply_button = QPushButton() self.apply_button.setText("&Apply") + self.apply_button.setMinimumWidth(100) self.apply_button.clicked.connect(self.on_apply) self.showEvent = self.on_open + self.root_layout.addWidget(self.title_widget) self.root_layout.addWidget(self.desc_widget) self.root_layout.addWidget(self.open_close_button_w) self.root_layout.addWidget(self.scroll_area) - self.root_layout.addWidget(self.apply_button) + self.root_layout.addWidget( + self.apply_button, alignment=Qt.AlignmentFlag.AlignCenter + ) def on_apply(self, event): folders_to_tags(self.library) diff --git a/tagstudio/src/qt/resources_rc.py b/tagstudio/src/qt/resources_rc.py index 97845b94..aca38cd1 100644 --- a/tagstudio/src/qt/resources_rc.py +++ b/tagstudio/src/qt/resources_rc.py @@ -16901,17 +16901,10 @@ qt_resource_struct = b"\ \x00\x00\x01\x8a\xd2\x83?\x9d\ " - def qInitResources(): - QtCore.qRegisterResourceData( - 0x03, qt_resource_struct, qt_resource_name, qt_resource_data - ) - + QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) def qCleanupResources(): - QtCore.qUnregisterResourceData( - 0x03, qt_resource_struct, qt_resource_name, qt_resource_data - ) - + QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) qInitResources() diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index 8b286859..bd86a9b5 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -356,13 +356,13 @@ class QtDriver(QObject): edit_menu.addSeparator() - manage_file_extensions_action = QAction("Ignore File Extensions", menu_bar) + manage_file_extensions_action = QAction("Ignored File Extensions", menu_bar) manage_file_extensions_action.triggered.connect( lambda: self.show_file_extension_modal() ) edit_menu.addAction(manage_file_extensions_action) - tag_database_action = QAction("Tag Database", menu_bar) + tag_database_action = QAction("Manage Tags", menu_bar) tag_database_action.triggered.connect(lambda: self.show_tag_database()) edit_menu.addAction(tag_database_action) @@ -412,13 +412,13 @@ class QtDriver(QObject): self.sort_fields_action.setToolTip("Alt+S") macros_menu.addAction(self.sort_fields_action) - folders_to_tags_action = QAction("Folders to Tags", menu_bar) + folders_to_tags_action = QAction("Create Tags From Folders", menu_bar) ftt_modal = FoldersToTagsModal(self.lib, self) folders_to_tags_action.triggered.connect(lambda: ftt_modal.show()) macros_menu.addAction(folders_to_tags_action) # Help Menu ========================================================== - self.repo_action = QAction("Go to GitHub Repository", menu_bar) + self.repo_action = QAction("Visit GitHub Repository", menu_bar) self.repo_action.triggered.connect( lambda: webbrowser.open("https://github.com/TagStudioDev/TagStudio") ) @@ -643,7 +643,7 @@ class QtDriver(QObject): def show_tag_database(self): self.modal = PanelModal( - TagDatabasePanel(self.lib), "Tag Database", "Tag Database", has_save=False + TagDatabasePanel(self.lib), "Library Tags", "Library Tags", has_save=False ) self.modal.show() diff --git a/tagstudio/src/qt/widgets/item_thumb.py b/tagstudio/src/qt/widgets/item_thumb.py index 589f4fe0..91db88b3 100644 --- a/tagstudio/src/qt/widgets/item_thumb.py +++ b/tagstudio/src/qt/widgets/item_thumb.py @@ -65,7 +65,7 @@ class ItemThumb(FlowWidget): tag_group_icon_128.load() small_text_style = ( - f"background-color:rgba(0, 0, 0, 128);" + f"background-color:rgba(0, 0, 0, 192);" f"font-family:Oxanium;" f"font-weight:bold;" f"font-size:12px;" @@ -77,7 +77,7 @@ class ItemThumb(FlowWidget): ) med_text_style = ( - f"background-color:rgba(17, 15, 27, 192);" + f"background-color:rgba(0, 0, 0, 192);" f"font-family:Oxanium;" f"font-weight:bold;" f"font-size:18px;" diff --git a/tagstudio/src/qt/widgets/panel.py b/tagstudio/src/qt/widgets/panel.py index 7ba3d4d2..7221e73d 100644 --- a/tagstudio/src/qt/widgets/panel.py +++ b/tagstudio/src/qt/widgets/panel.py @@ -38,9 +38,7 @@ class PanelModal(QWidget): self.title_widget.setObjectName("fieldTitle") self.title_widget.setWordWrap(True) self.title_widget.setStyleSheet( - # 'background:blue;' - # 'text-align:center;' - "font-weight:bold;" "font-size:14px;" "padding-top: 6px" "" + "font-weight:bold;" "font-size:14px;" "padding-top: 6px" ) self.title_widget.setText(title) self.title_widget.setAlignment(Qt.AlignmentFlag.AlignCenter) diff --git a/tagstudio/src/qt/widgets/preview_panel.py b/tagstudio/src/qt/widgets/preview_panel.py index 5ede8bd4..da71eb25 100644 --- a/tagstudio/src/qt/widgets/preview_panel.py +++ b/tagstudio/src/qt/widgets/preview_panel.py @@ -136,19 +136,20 @@ class PreviewPanel(QWidget): self.dimensions_label.setWordWrap(True) # self.dim_label.setTextInteractionFlags( # Qt.TextInteractionFlag.TextSelectableByMouse) - self.dimensions_label.setStyleSheet(ItemThumb.small_text_style) - # small_text_style = ( - # f'background-color:rgba(17, 15, 27, 192);' - # f'font-family:Oxanium;' - # f'font-weight:bold;' - # f'font-size:12px;' - # f'border-radius:3px;' - # f'padding-top: 4px;' - # f'padding-right: 1px;' - # f'padding-bottom: 1px;' - # f'padding-left: 1px;' - # ) + properties_style = ( + f"background-color:#65000000;" + f"font-family:Oxanium;" + f"font-weight:bold;" + f"font-size:12px;" + f"border-radius:6px;" + f"padding-top: 4px;" + f"padding-right: 1px;" + f"padding-bottom: 1px;" + f"padding-left: 1px;" + ) + + self.dimensions_label.setStyleSheet(properties_style) self.scroll_layout = QVBoxLayout() self.scroll_layout.setAlignment(Qt.AlignmentFlag.AlignTop) @@ -157,20 +158,14 @@ class PreviewPanel(QWidget): scroll_container: QWidget = QWidget() scroll_container.setObjectName("entryScrollContainer") scroll_container.setLayout(self.scroll_layout) - # scroll_container.setStyleSheet('background:#080716; border-radius:12px;') - scroll_container.setStyleSheet( - "background:#00000000;" - "border-style:none;" - f"QScrollBar::{{background:red;}}" - ) info_section = QWidget() info_layout = QVBoxLayout(info_section) info_layout.setContentsMargins(0, 0, 0, 0) info_layout.setSpacing(6) - self.setStyleSheet("background:#00000000;" f"QScrollBar::{{background:red;}}") scroll_area = QScrollArea() + scroll_area.setObjectName("entryScrollArea") scroll_area.setSizePolicy( QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding ) @@ -178,15 +173,15 @@ class PreviewPanel(QWidget): scroll_area.setWidgetResizable(True) scroll_area.setFrameShadow(QFrame.Shadow.Plain) scroll_area.setFrameShape(QFrame.Shape.NoFrame) + # NOTE: I would rather have this style applied to the scroll_area + # background and NOT the scroll container background, so that the + # rounded corners are maintained when scrolling. I was unable to + # find the right trick to only select that particular element. scroll_area.setStyleSheet( - "background:#55000000;" - "border-radius:12px;" - "border-style:solid;" - "border-width:1px;" - "border-color:#11FFFFFF;" - # f'QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {{border: none;background: none;}}' - # f'QScrollBar::left-arrow:horizontal, QScrollBar::right-arrow:horizontal, QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {{border: none;background: none;color: none;}}' - f"QScrollBar::{{background:red;}}" + f"QWidget#entryScrollContainer{{" + "background:#65000000;" + "border-radius:6px;" + f"}}" ) scroll_area.setWidget(scroll_container) @@ -207,29 +202,6 @@ class PreviewPanel(QWidget): self.add_field_button.setMinimumSize(96, 28) self.add_field_button.setMaximumSize(96, 28) self.add_field_button.setText("Add Field") - self.add_field_button.setStyleSheet( - f"QPushButton{{" - # f'background: #1E1A33;' - # f'color: #CDA7F7;' - f"font-weight: bold;" - # f"border-color: #2B2547;" - f"border-radius: 6px;" - f"border-style:solid;" - # f'border-width:{math.ceil(1*self.devicePixelRatio())}px;' - "background:#55000000;" - "border-width:1px;" - "border-color:#11FFFFFF;" - # f'padding-top: 1.5px;' - # f'padding-right: 4px;' - # f'padding-bottom: 5px;' - # f'padding-left: 4px;' - f"font-size: 13px;" - f"}}" - f"QPushButton::hover" - f"{{" - f"background: #333333;" - f"}}" - ) self.afb_layout.addWidget(self.add_field_button) self.afm = AddFieldModal(self.lib) self.place_add_field_button() @@ -398,7 +370,7 @@ class PreviewPanel(QWidget): if extension in IMAGE_TYPES: image = Image.open(filepath) if image.mode == "RGBA": - new_bg = Image.new("RGB", image.size, color="#222222") + new_bg = Image.new("RGB", image.size, color="#1e1e1e") new_bg.paste(image, mask=image.getchannel(3)) image = new_bg if image.mode != "RGB": diff --git a/tagstudio/src/qt/widgets/tag_box.py b/tagstudio/src/qt/widgets/tag_box.py index a6fd71c0..86fc25b0 100644 --- a/tagstudio/src/qt/widgets/tag_box.py +++ b/tagstudio/src/qt/widgets/tag_box.py @@ -52,10 +52,10 @@ class TagBoxWidget(FieldWidget): self.add_button.setText("+") self.add_button.setStyleSheet( f"QPushButton{{" - # f'background: #1E1A33;' - # f'color: #CDA7F7;' + f"background: #1e1e1e;" + f"color: #FFFFFF;" f"font-weight: bold;" - # f"border-color: #2B2547;" + f"border-color: #333333;" f"border-radius: 6px;" f"border-style:solid;" f"border-width:{math.ceil(1*self.devicePixelRatio())}px;" @@ -67,7 +67,8 @@ class TagBoxWidget(FieldWidget): f"}}" f"QPushButton::hover" f"{{" - # f'background: #2B2547;' + f"border-color: #CCCCCC;" + f"background: #555555;" f"}}" ) tsp = TagSearchPanel(self.lib) diff --git a/tagstudio/src/qt/widgets/thumb_renderer.py b/tagstudio/src/qt/widgets/thumb_renderer.py index 5a49911d..815a15a3 100644 --- a/tagstudio/src/qt/widgets/thumb_renderer.py +++ b/tagstudio/src/qt/widgets/thumb_renderer.py @@ -142,7 +142,7 @@ class ThumbRenderer(QObject): # image = self.thumb_debug if image.mode == "RGBA": # logging.info(image.getchannel(3).tobytes()) - new_bg = Image.new("RGB", image.size, color="#222222") + new_bg = Image.new("RGB", image.size, color="#1e1e1e") new_bg.paste(image, mask=image.getchannel(3)) image = new_bg if image.mode != "RGB": @@ -173,7 +173,7 @@ class ThumbRenderer(QObject): text: str = extension with open(filepath, "r", encoding="utf-8") as text_file: text = text_file.read(256) - bg = Image.new("RGB", (256, 256), color="#222222") + bg = Image.new("RGB", (256, 256), color="#1e1e1e") draw = ImageDraw.Draw(bg) draw.text((16, 16), text, file=(255, 255, 255)) image = bg @@ -325,7 +325,7 @@ class ThumbRenderer(QObject): # image = self.thumb_debug if image.mode == "RGBA": # logging.info(image.getchannel(3).tobytes()) - new_bg = Image.new("RGB", image.size, color="#222222") + new_bg = Image.new("RGB", image.size, color="#1e1e1e") new_bg.paste(image, mask=image.getchannel(3)) image = new_bg if image.mode != "RGB": @@ -355,7 +355,7 @@ class ThumbRenderer(QObject): text: str = extension with open(filepath, "r", encoding="utf-8") as text_file: text = text_file.read(256) - bg = Image.new("RGB", (256, 256), color="#222222") + bg = Image.new("RGB", (256, 256), color="#1e1e1e") draw = ImageDraw.Draw(bg) draw.text((16, 16), text, file=(255, 255, 255)) image = bg From 94f929d12206503ac36f13cc120547a397849923 Mon Sep 17 00:00:00 2001 From: Travis Abendshien Date: Fri, 10 May 2024 15:43:26 -0700 Subject: [PATCH 17/18] Allow the use of the native macOS menu bar --- tagstudio/src/qt/ts_qt.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index bd86a9b5..6eaafa57 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -266,8 +266,11 @@ class QtDriver(QObject): self.splash.show() menu_bar = self.main_window.menuBar() - menu_bar.setNativeMenuBar(False) - # menu_bar.setStyleSheet('background:#00000000;') + + # Allow the use of the native macOS menu bar. + if sys.platform != "darwin": + menu_bar.setNativeMenuBar(False) + file_menu = QMenu("&File", menu_bar) edit_menu = QMenu("&Edit", menu_bar) tools_menu = QMenu("&Tools", menu_bar) From 3aa71d6f8abb67f309f6d66ef4e6c570332d82be Mon Sep 17 00:00:00 2001 From: Travis Abendshien Date: Fri, 10 May 2024 15:45:19 -0700 Subject: [PATCH 18/18] Formatted with Ruff --- tagstudio/src/qt/ts_qt.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index 6eaafa57..0d27f438 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -266,10 +266,10 @@ class QtDriver(QObject): self.splash.show() menu_bar = self.main_window.menuBar() - - # Allow the use of the native macOS menu bar. + + # Allow the use of the native macOS menu bar. if sys.platform != "darwin": - menu_bar.setNativeMenuBar(False) + menu_bar.setNativeMenuBar(False) file_menu = QMenu("&File", menu_bar) edit_menu = QMenu("&Edit", menu_bar)