diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index 8ecd4e7a6..ec3a9f689 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 @@ -318,6 +320,18 @@ 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(self.open_selected_files) + shortcut: QtCore.QKeyCombination | Qt.Key = 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) @@ -1086,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 = QMessageBox.ButtonRole(confirm_open.exec()) + + if result == QMessageBox.ButtonRole.ActionRole: + 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 005cf1b0a..4008435b9 100644 --- a/tagstudio/src/qt/widgets/item_thumb.py +++ b/tagstudio/src/qt/widgets/item_thumb.py @@ -196,6 +196,7 @@ def __init__( self.thumb_button.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu) self.opener = FileOpenerHelper("") + 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) 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() diff --git a/tagstudio/src/qt/widgets/video_player.py b/tagstudio/src/qt/widgets/video_player.py index 0d5928f51..a4ce5c929 100644 --- a/tagstudio/src/qt/widgets/video_player.py +++ b/tagstudio/src/qt/widgets/video_player.py @@ -122,6 +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_explorer_action = QAction("Open file in explorer", self) open_explorer_action.triggered.connect(self.opener.open_explorer) self.addAction(open_file_action)