From 6f40ed64bd0c3f38614be454452f3921f986311a Mon Sep 17 00:00:00 2001 From: Tyrannicodin Date: Fri, 6 Sep 2024 01:26:37 +0100 Subject: [PATCH 1/9] Open file on thumbnail double click --- tagstudio/src/qt/widgets/item_thumb.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tagstudio/src/qt/widgets/item_thumb.py b/tagstudio/src/qt/widgets/item_thumb.py index 05a02d060..7e4aef480 100644 --- a/tagstudio/src/qt/widgets/item_thumb.py +++ b/tagstudio/src/qt/widgets/item_thumb.py @@ -218,6 +218,9 @@ def __init__( self.thumb_button.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu) self.opener = FileOpenerHelper("") + self.thumb_button.clicked.connect( + lambda: self.opener.open_file() if self.thumb_button.selected else None + ) open_file_action = QAction("Open file", self) open_file_action.triggered.connect(self.opener.open_file) open_explorer_action = QAction("Open file in explorer", self) From 0df714e40f2b4fa81efe7e0da9e09df3da591345 Mon Sep 17 00:00:00 2001 From: Tyrannicodin Date: Fri, 6 Sep 2024 01:27:34 +0100 Subject: [PATCH 2/9] Add open file shortcut (ctrl+shift+O) --- tagstudio/src/qt/widgets/preview_panel.py | 8 +++++++- tagstudio/src/qt/widgets/video_player.py | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/tagstudio/src/qt/widgets/preview_panel.py b/tagstudio/src/qt/widgets/preview_panel.py index 386fa9ddc..fb124fae8 100644 --- a/tagstudio/src/qt/widgets/preview_panel.py +++ b/tagstudio/src/qt/widgets/preview_panel.py @@ -13,7 +13,7 @@ import structlog from PIL import Image, UnidentifiedImageError from PIL.Image import DecompressionBombError -from PySide6.QtCore import Signal, Qt, QSize +from PySide6.QtCore import Signal, Qt, QSize, QKeyCombination from PySide6.QtGui import QResizeEvent, QAction from PySide6.QtWidgets import ( QWidget, @@ -99,6 +99,12 @@ def __init__(self, library: Library, driver: "QtDriver"): image_layout.setContentsMargins(0, 0, 0, 0) self.open_file_action = QAction("Open file", self) + self.open_file_action.setShortcut( + QKeyCombination( + Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier, + Qt.Key.Key_O, + ) + ) self.open_explorer_action = QAction("Open file in explorer", self) self.preview_img = QPushButtonWrapper() diff --git a/tagstudio/src/qt/widgets/video_player.py b/tagstudio/src/qt/widgets/video_player.py index 9fc65604c..af9bba690 100644 --- a/tagstudio/src/qt/widgets/video_player.py +++ b/tagstudio/src/qt/widgets/video_player.py @@ -14,6 +14,7 @@ QObject, QEvent, QRectF, + QKeyCombination, ) from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput, QMediaDevices from PySide6.QtMultimediaWidgets import QGraphicsVideoItem @@ -128,6 +129,12 @@ def __init__(self, driver: "QtDriver") -> None: open_file_action = QAction("Open file", self) open_file_action.triggered.connect(self.opener.open_file) + open_file_action.setShortcut( + QKeyCombination( + Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier, + Qt.Key.Key_O, + ) + ) open_explorer_action = QAction("Open file in explorer", self) open_explorer_action.triggered.connect(self.opener.open_explorer) self.addAction(open_file_action) From 7290909422e218aabc3fd1ced51f7e9281e924a0 Mon Sep 17 00:00:00 2001 From: Tyrannicodin Date: Wed, 11 Sep 2024 15:00:54 +0100 Subject: [PATCH 3/9] Update shortcut to Ctrl/Cmd + Down --- tagstudio/src/qt/widgets/preview_panel.py | 4 ++-- tagstudio/src/qt/widgets/video_player.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tagstudio/src/qt/widgets/preview_panel.py b/tagstudio/src/qt/widgets/preview_panel.py index fb124fae8..032ffe77a 100644 --- a/tagstudio/src/qt/widgets/preview_panel.py +++ b/tagstudio/src/qt/widgets/preview_panel.py @@ -101,8 +101,8 @@ def __init__(self, library: Library, driver: "QtDriver"): self.open_file_action = QAction("Open file", self) self.open_file_action.setShortcut( QKeyCombination( - Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier, - Qt.Key.Key_O, + Qt.KeyboardModifier.ControlModifier, + Qt.Key.Key_Down, ) ) self.open_explorer_action = QAction("Open file in explorer", self) diff --git a/tagstudio/src/qt/widgets/video_player.py b/tagstudio/src/qt/widgets/video_player.py index af9bba690..5acca2a5c 100644 --- a/tagstudio/src/qt/widgets/video_player.py +++ b/tagstudio/src/qt/widgets/video_player.py @@ -131,8 +131,8 @@ def __init__(self, driver: "QtDriver") -> None: open_file_action.triggered.connect(self.opener.open_file) open_file_action.setShortcut( QKeyCombination( - Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier, - Qt.Key.Key_O, + Qt.KeyboardModifier.ControlModifier, + Qt.Key.Key_Down, ) ) open_explorer_action = QAction("Open file in explorer", self) From f4fe27976ce9c218853120e29b58f103e5089515 Mon Sep 17 00:00:00 2001 From: Tyrannicodin Date: Mon, 16 Sep 2024 20:17:49 +0100 Subject: [PATCH 4/9] Improve selected files opener This attaches the shortcut to the main window, allowing several files to be opened at once and also localises the shortcuts for the host machine. --- tagstudio/src/qt/ts_qt.py | 17 +++++++++++++++++ tagstudio/src/qt/widgets/preview_panel.py | 8 +------- tagstudio/src/qt/widgets/video_player.py | 8 +------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index 8ecd4e7a6..28aefe212 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -318,6 +318,23 @@ def start(self) -> None: add_new_files_action.setStatusTip("Ctrl+R") # file_menu.addAction(refresh_lib_action) file_menu.addAction(add_new_files_action) + + open_selected_action = QAction("Open selected files", self) + open_selected_action.triggered.connect( + lambda: ( + [self.item_thumbs[selection].opener.open_file() for selection in self.selected], + logger.info("Opening files", count=len(self.selected)), + ) + ) + shortcut = QtCore.QKeyCombination( + QtCore.Qt.KeyboardModifier(QtCore.Qt.KeyboardModifier.ControlModifier), + QtCore.Qt.Key.Key_Down, + ) + if sys.platform == "win32": + shortcut = Qt.Key.Key_Return + + open_selected_action.setShortcut(shortcut) + file_menu.addAction(open_selected_action) file_menu.addSeparator() close_library_action = QAction("&Close Library", menu_bar) diff --git a/tagstudio/src/qt/widgets/preview_panel.py b/tagstudio/src/qt/widgets/preview_panel.py index 6edfaf75c..f595644f3 100644 --- a/tagstudio/src/qt/widgets/preview_panel.py +++ b/tagstudio/src/qt/widgets/preview_panel.py @@ -14,7 +14,7 @@ from humanfriendly import format_size from PIL import Image, UnidentifiedImageError from PIL.Image import DecompressionBombError -from PySide6.QtCore import QSize, Qt, Signal, QKeyCombination +from PySide6.QtCore import QSize, Qt, Signal from PySide6.QtGui import QAction, QResizeEvent from PySide6.QtWidgets import ( QFrame, @@ -96,12 +96,6 @@ def __init__(self, library: Library, driver: "QtDriver"): image_layout.setContentsMargins(0, 0, 0, 0) self.open_file_action = QAction("Open file", self) - self.open_file_action.setShortcut( - QKeyCombination( - Qt.KeyboardModifier.ControlModifier, - Qt.Key.Key_Down, - ) - ) self.open_explorer_action = QAction("Open file in explorer", self) self.preview_img = QPushButtonWrapper() diff --git a/tagstudio/src/qt/widgets/video_player.py b/tagstudio/src/qt/widgets/video_player.py index 21f245a23..a4ce5c929 100644 --- a/tagstudio/src/qt/widgets/video_player.py +++ b/tagstudio/src/qt/widgets/video_player.py @@ -14,7 +14,6 @@ QTimer, QUrl, QVariantAnimation, - QKeyCombination, ) from PySide6.QtGui import ( QAction, @@ -123,12 +122,7 @@ def __init__(self, driver: "QtDriver") -> None: open_file_action = QAction("Open file", self) open_file_action.triggered.connect(self.opener.open_file) - open_file_action.setShortcut( - QKeyCombination( - Qt.KeyboardModifier.ControlModifier, - Qt.Key.Key_Down, - ) - ) + open_explorer_action = QAction("Open file in explorer", self) open_explorer_action.triggered.connect(self.opener.open_explorer) self.addAction(open_file_action) From 2cf7030940e0bbc69c0b8fc3958e437de1ff1514 Mon Sep 17 00:00:00 2001 From: Tyrannicodin Date: Mon, 16 Sep 2024 20:22:28 +0100 Subject: [PATCH 5/9] Make the double click shortcut an actual double click shortcut --- tagstudio/src/qt/widgets/item_thumb.py | 2 +- tagstudio/src/qt/widgets/thumb_button.py | 28 ++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/tagstudio/src/qt/widgets/item_thumb.py b/tagstudio/src/qt/widgets/item_thumb.py index fec486a7d..ecd04bf23 100644 --- a/tagstudio/src/qt/widgets/item_thumb.py +++ b/tagstudio/src/qt/widgets/item_thumb.py @@ -196,7 +196,7 @@ def __init__( self.thumb_button.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu) self.opener = FileOpenerHelper("") - self.thumb_button.clicked.connect( + self.thumb_button.double_clicked.connect( lambda: self.opener.open_file() if self.thumb_button.selected else None ) open_file_action = QAction("Open file", self) diff --git a/tagstudio/src/qt/widgets/thumb_button.py b/tagstudio/src/qt/widgets/thumb_button.py index e56408b7f..4cfb36ba4 100644 --- a/tagstudio/src/qt/widgets/thumb_button.py +++ b/tagstudio/src/qt/widgets/thumb_button.py @@ -4,19 +4,31 @@ from PySide6 import QtCore -from PySide6.QtCore import QEvent -from PySide6.QtGui import QColor, QEnterEvent, QPainter, QPainterPath, QPaintEvent, QPen +from PySide6.QtCore import QEvent, Signal +from PySide6.QtGui import ( + QColor, + QEnterEvent, + QMouseEvent, + QPainter, + QPainterPath, + QPaintEvent, + QPen, +) from PySide6.QtWidgets import QWidget from src.qt.helpers.qbutton_wrapper import QPushButtonWrapper class ThumbButton(QPushButtonWrapper): + double_clicked = Signal() + def __init__(self, parent: QWidget, thumb_size: tuple[int, int]) -> None: super().__init__(parent) self.thumb_size: tuple[int, int] = thumb_size self.hovered = False self.selected = False + self.double_click = False + # self.clicked.connect(lambda checked: self.set_selected(True)) def paintEvent(self, event: QPaintEvent) -> None: # noqa: N802 @@ -81,3 +93,15 @@ def leaveEvent(self, event: QEvent) -> None: # noqa: N802 def set_selected(self, value: bool) -> None: self.selected = value self.repaint() + + def mousePressEvent(self, e: QMouseEvent) -> None: # noqa: N802 + self.double_click = False + + def mouseDoubleClickEvent(self, e: QMouseEvent) -> None: # noqa: N802 + self.double_click = True + + def mouseReleaseEvent(self, e: QMouseEvent) -> None: # noqa: N802 + if self.double_click: + self.double_clicked.emit() + else: + self.clicked.emit() From 57223d3e3a7914f9febddc0018a81a729c98971a Mon Sep 17 00:00:00 2001 From: Tyrannicodin Date: Mon, 16 Sep 2024 20:35:30 +0100 Subject: [PATCH 6/9] Remove unnecessary condition to open file --- tagstudio/src/qt/widgets/item_thumb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tagstudio/src/qt/widgets/item_thumb.py b/tagstudio/src/qt/widgets/item_thumb.py index ecd04bf23..1fba15081 100644 --- a/tagstudio/src/qt/widgets/item_thumb.py +++ b/tagstudio/src/qt/widgets/item_thumb.py @@ -197,7 +197,7 @@ def __init__( self.opener = FileOpenerHelper("") self.thumb_button.double_clicked.connect( - lambda: self.opener.open_file() if self.thumb_button.selected else None + lambda: self.opener.open_file() ) open_file_action = QAction("Open file", self) open_file_action.triggered.connect(self.opener.open_file) From ca9adffdbae38803e5e4436bec64340bd3ff206e Mon Sep 17 00:00:00 2001 From: Tyrannicodin Date: Mon, 16 Sep 2024 20:39:52 +0100 Subject: [PATCH 7/9] Format, prevent opening when other widgets in focus --- tagstudio/src/qt/ts_qt.py | 6 +++++- tagstudio/src/qt/widgets/item_thumb.py | 4 +--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index 28aefe212..b12d81fc5 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -322,7 +322,11 @@ def start(self) -> None: open_selected_action = QAction("Open selected files", self) open_selected_action.triggered.connect( lambda: ( - [self.item_thumbs[selection].opener.open_file() for selection in self.selected], + ( + [self.item_thumbs[selection].opener.open_file() for selection in self.selected] + if QApplication.focusWidget() == self.main_window.scrollArea + else None + ), logger.info("Opening files", count=len(self.selected)), ) ) diff --git a/tagstudio/src/qt/widgets/item_thumb.py b/tagstudio/src/qt/widgets/item_thumb.py index 1fba15081..56bf62d62 100644 --- a/tagstudio/src/qt/widgets/item_thumb.py +++ b/tagstudio/src/qt/widgets/item_thumb.py @@ -196,9 +196,7 @@ def __init__( self.thumb_button.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu) self.opener = FileOpenerHelper("") - self.thumb_button.double_clicked.connect( - lambda: self.opener.open_file() - ) + self.thumb_button.double_clicked.connect(lambda: self.opener.open_file()) open_file_action = QAction("Open file", self) open_file_action.triggered.connect(self.opener.open_file) open_explorer_action = QAction("Open file in explorer", self) From c2b5070e5954c9e07d887ea2f36638d0d6dc536b Mon Sep 17 00:00:00 2001 From: Tyrannicodin Date: Wed, 18 Sep 2024 15:48:28 +0100 Subject: [PATCH 8/9] Add confirm modal for over 15 files --- tagstudio/src/qt/ts_qt.py | 40 +++++++++++++++++++------- tagstudio/src/qt/widgets/item_thumb.py | 2 +- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index b12d81fc5..d8531ac76 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -50,6 +50,7 @@ QLineEdit, QMenu, QMenuBar, + QMessageBox, QPushButton, QScrollArea, QSplashScreen, @@ -89,6 +90,7 @@ from src.qt.widgets.panel import PanelModal from src.qt.widgets.preview_panel import PreviewPanel from src.qt.widgets.progress import ProgressWidget +from src.qt.widgets.thumb_button import ThumbButton from src.qt.widgets.thumb_renderer import ThumbRenderer # SIGQUIT is not defined on Windows @@ -320,16 +322,7 @@ def start(self) -> None: file_menu.addAction(add_new_files_action) open_selected_action = QAction("Open selected files", self) - open_selected_action.triggered.connect( - lambda: ( - ( - [self.item_thumbs[selection].opener.open_file() for selection in self.selected] - if QApplication.focusWidget() == self.main_window.scrollArea - else None - ), - logger.info("Opening files", count=len(self.selected)), - ) - ) + open_selected_action.triggered.connect(self.open_selected_files) shortcut = QtCore.QKeyCombination( QtCore.Qt.KeyboardModifier(QtCore.Qt.KeyboardModifier.ControlModifier), QtCore.Qt.Key.Key_Down, @@ -1107,3 +1100,30 @@ def open_library(self, path: Path | str): self.filter_items() self.main_window.toggle_landing_page(enabled=False) + + def open_selected_files(self): + if not ( + QApplication.focusWidget() == self.main_window.scrollArea + or isinstance(QApplication.focusWidget(), ThumbButton) + ): + return + file_count = len(self.selected) + result = QMessageBox.ButtonRole.ActionRole + + if file_count >= 15: # Only confirm if we have lots of files + confirm_open = QMessageBox() + confirm_open.setText(f"Open {file_count} files?") + confirm_open.setWindowTitle("Open files") + confirm_open.setIcon(QMessageBox.Icon.Question) + + cancel_button = confirm_open.addButton("&Cancel", QMessageBox.ButtonRole.RejectRole) + confirm_open.setEscapeButton(cancel_button) + + open_button = confirm_open.addButton("&Open", QMessageBox.ButtonRole.ActionRole) + confirm_open.setDefaultButton(open_button) + + result = confirm_open.exec() + + if result == QMessageBox.ButtonRole.ActionRole.value: + for selection in self.selected: + self.item_thumbs[selection].opener.open_file() diff --git a/tagstudio/src/qt/widgets/item_thumb.py b/tagstudio/src/qt/widgets/item_thumb.py index 56bf62d62..4008435b9 100644 --- a/tagstudio/src/qt/widgets/item_thumb.py +++ b/tagstudio/src/qt/widgets/item_thumb.py @@ -196,7 +196,7 @@ def __init__( self.thumb_button.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu) self.opener = FileOpenerHelper("") - self.thumb_button.double_clicked.connect(lambda: self.opener.open_file()) + self.thumb_button.double_clicked.connect(self.opener.open_file) open_file_action = QAction("Open file", self) open_file_action.triggered.connect(self.opener.open_file) open_explorer_action = QAction("Open file in explorer", self) From 5808bc9a9e42952d0c8c24644bbe3f4cae0bb73e Mon Sep 17 00:00:00 2001 From: Tyrannicodin Date: Sat, 21 Sep 2024 13:59:51 +0100 Subject: [PATCH 9/9] Fix mypy --- 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 d8531ac76..ec3a9f689 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -323,7 +323,7 @@ def start(self) -> None: open_selected_action = QAction("Open selected files", self) open_selected_action.triggered.connect(self.open_selected_files) - shortcut = QtCore.QKeyCombination( + shortcut: QtCore.QKeyCombination | Qt.Key = QtCore.QKeyCombination( QtCore.Qt.KeyboardModifier(QtCore.Qt.KeyboardModifier.ControlModifier), QtCore.Qt.Key.Key_Down, ) @@ -1122,8 +1122,8 @@ def open_selected_files(self): open_button = confirm_open.addButton("&Open", QMessageBox.ButtonRole.ActionRole) confirm_open.setDefaultButton(open_button) - result = confirm_open.exec() + result = QMessageBox.ButtonRole(confirm_open.exec()) - if result == QMessageBox.ButtonRole.ActionRole.value: + if result == QMessageBox.ButtonRole.ActionRole: for selection in self.selected: self.item_thumbs[selection].opener.open_file()