Skip to content

fix(ui): expand usage of esc for closing modals #793

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 10, 2025
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
28 changes: 15 additions & 13 deletions tagstudio/src/qt/modals/add_field.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Copyright (C) 2024 Travis Abendshien (CyanVoxel).
# Copyright (C) 2025 Travis Abendshien (CyanVoxel).
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio


import structlog
from PySide6 import QtCore, QtGui
from PySide6.QtCore import Qt, Signal
from PySide6.QtWidgets import (
QHBoxLayout,
Expand All @@ -16,7 +18,10 @@
from src.core.library import Library
from src.qt.translations import Translations

logger = structlog.get_logger(__name__)


# NOTE: This class doesn't inherit from PanelWidget? Seems like it predates that system?
class AddFieldModal(QWidget):
done = Signal(list)

Expand All @@ -35,11 +40,7 @@ def __init__(self, library: Library):
self.title_widget = QLabel()
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" ""
)
self.title_widget.setStyleSheet("font-weight:bold;" "font-size:14px;" "padding-top: 6px;")
Translations.translate_qobject(self.title_widget, "library.field.add")
self.title_widget.setAlignment(Qt.AlignmentFlag.AlignCenter)

Expand All @@ -50,18 +51,13 @@ def __init__(self, library: Library):
self.button_layout.setContentsMargins(6, 6, 6, 6)
self.button_layout.addStretch(1)

# self.cancel_button = QPushButton()
# self.cancel_button.setText('Cancel')

self.cancel_button = QPushButton()
Translations.translate_qobject(self.cancel_button, "generic.cancel")
self.cancel_button.clicked.connect(self.hide)
# self.cancel_button.clicked.connect(widget.reset)
self.button_layout.addWidget(self.cancel_button)

self.save_button = QPushButton()
Translations.translate_qobject(self.save_button, "generic.add")
# self.save_button.setAutoDefault(True)
self.save_button.setDefault(True)
self.save_button.clicked.connect(self.hide)
self.save_button.clicked.connect(
Expand All @@ -74,8 +70,6 @@ def __init__(self, library: Library):

self.root_layout.addWidget(self.title_widget)
self.root_layout.addWidget(self.list_widget)
# self.root_layout.setStretch(1,2)

self.root_layout.addStretch(1)
self.root_layout.addWidget(self.button_container)

Expand All @@ -85,5 +79,13 @@ def show(self):
item = QListWidgetItem(f"{df.name} ({df.type.value})")
item.setData(Qt.ItemDataRole.UserRole, df.key)
self.list_widget.addItem(item)
self.list_widget.setFocus()

super().show()

def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: # noqa N802
if event.key() == QtCore.Qt.Key.Key_Escape:
self.cancel_button.click()
else: # Other key presses
pass
return super().keyPressEvent(event)
15 changes: 12 additions & 3 deletions tagstudio/src/qt/modals/delete_unlinked.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Copyright (C) 2024 Travis Abendshien (CyanVoxel).
# Copyright (C) 2025 Travis Abendshien (CyanVoxel).
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio

import typing
from typing import TYPE_CHECKING, override

from PySide6 import QtCore, QtGui
from PySide6.QtCore import Qt, QThreadPool, Signal
from PySide6.QtGui import QStandardItem, QStandardItemModel
from PySide6.QtWidgets import (
Expand All @@ -20,7 +21,7 @@
from src.qt.widgets.progress import ProgressWidget

# Only import for type checking/autocompletion, will not be imported at runtime.
if typing.TYPE_CHECKING:
if TYPE_CHECKING:
from src.qt.ts_qt import QtDriver


Expand Down Expand Up @@ -111,3 +112,11 @@ def displayed_text(x):
self.done.emit(),
)
)

@override
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: # noqa N802
if event.key() == QtCore.Qt.Key.Key_Escape:
self.cancel_button.click()
else: # Other key presses
pass
return super().keyPressEvent(event)
12 changes: 11 additions & 1 deletion tagstudio/src/qt/modals/drop_import.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# Copyright (C) 2025
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio

import enum
import shutil
from pathlib import Path
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, override

import structlog
from PySide6 import QtCore, QtGui
from PySide6.QtCore import Qt, QUrl
from PySide6.QtGui import QStandardItem, QStandardItemModel
from PySide6.QtWidgets import (
Expand Down Expand Up @@ -232,3 +234,11 @@ def _get_renamed_duplicate_filename(self, filepath: Path) -> str:
)
index += 1
return filepath.name

@override
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: # noqa N802
if event.key() == QtCore.Qt.Key.Key_Escape:
self.cancel_button.click()
else: # Other key presses
pass
return super().keyPressEvent(event)
15 changes: 12 additions & 3 deletions tagstudio/src/qt/modals/fix_dupes.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Copyright (C) 2024 Travis Abendshien (CyanVoxel).
# Copyright (C) 2025 Travis Abendshien (CyanVoxel).
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio


import typing
from typing import TYPE_CHECKING, override

from PySide6 import QtCore, QtGui
from PySide6.QtCore import Qt
from PySide6.QtWidgets import (
QFileDialog,
Expand All @@ -20,7 +21,7 @@
from src.qt.translations import Translations

# Only import for type checking/autocompletion, will not be imported at runtime.
if typing.TYPE_CHECKING:
if TYPE_CHECKING:
from src.qt.ts_qt import QtDriver


Expand Down Expand Up @@ -135,3 +136,11 @@ def set_dupe_count(self, count: int):
self.dupe_count.setText(
Translations.translate_formatted("file.duplicates.matches", count=count)
)

@override
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: # noqa N802
if event.key() == QtCore.Qt.Key.Key_Escape:
self.done_button.click()
else: # Other key presses
pass
return super().keyPressEvent(event)
15 changes: 12 additions & 3 deletions tagstudio/src/qt/modals/fix_unlinked.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Copyright (C) 2024 Travis Abendshien (CyanVoxel).
# Copyright (C) 2025 Travis Abendshien (CyanVoxel).
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio


import typing
from typing import TYPE_CHECKING, override

from PySide6 import QtCore, QtGui
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QHBoxLayout, QLabel, QPushButton, QVBoxLayout, QWidget
from src.core.library import Library
Expand All @@ -16,7 +17,7 @@
from src.qt.widgets.progress import ProgressWidget

# Only import for type checking/autocompletion, will not be imported at runtime.
if typing.TYPE_CHECKING:
if TYPE_CHECKING:
from src.qt.ts_qt import QtDriver


Expand Down Expand Up @@ -144,3 +145,11 @@ def set_missing_count(self, count: int | None = None):
"entries.unlinked.missing_count.some", count=self.missing_count
)
)

@override
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: # noqa N802
if event.key() == QtCore.Qt.Key.Key_Escape:
self.done_button.click()
else: # Other key presses
pass
return super().keyPressEvent(event)
16 changes: 13 additions & 3 deletions tagstudio/src/qt/modals/folders_to_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@


import math
import typing
from collections.abc import Sequence
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, override

import structlog
from PySide6 import QtCore, QtGui
from PySide6.QtCore import Qt
from PySide6.QtWidgets import (
QFrame,
Expand All @@ -25,7 +27,7 @@
from src.qt.flowlayout import FlowLayout
from src.qt.translations import Translations

if typing.TYPE_CHECKING:
if TYPE_CHECKING:
from src.qt.ts_qt import QtDriver

logger = structlog.get_logger(__name__)
Expand Down Expand Up @@ -104,7 +106,7 @@ def add_tag_to_tree(items: list[Tag]):
branch.dirs[tag.name] = BranchData(tag=tag)
branch = branch.dirs[tag.name]

def _add_folders_to_tree(items: typing.Sequence[str]) -> BranchData:
def _add_folders_to_tree(items: Sequence[str]) -> BranchData:
branch = tree
for folder in items:
if folder not in branch.dirs:
Expand Down Expand Up @@ -245,6 +247,14 @@ def set_all_branches(self, hidden: bool):
if isinstance(child, TreeItem):
child.set_all_branches(hidden)

@override
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: # noqa N802
if event.key() == QtCore.Qt.Key.Key_Escape:
self.close()
else: # Other key presses
pass
return super().keyPressEvent(event)


class TreeItem(QWidget):
def __init__(self, data: BranchData, parent_tag: Tag | None = None):
Expand Down
10 changes: 5 additions & 5 deletions tagstudio/src/qt/modals/tag_search.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Copyright (C) 2024 Travis Abendshien (CyanVoxel).
# Copyright (C) 2025 Travis Abendshien (CyanVoxel).
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio


import contextlib
import typing
from typing import TYPE_CHECKING, override
from warnings import catch_warnings

import src.qt.modals.build_tag as build_tag
Expand Down Expand Up @@ -36,7 +36,7 @@
logger = structlog.get_logger(__name__)

# Only import for type checking/autocompletion, will not be imported at runtime.
if typing.TYPE_CHECKING:
if TYPE_CHECKING:
from src.qt.modals.build_tag import BuildTagPanel


Expand Down Expand Up @@ -337,16 +337,16 @@ def showEvent(self, event: QShowEvent) -> None: # noqa N802
self.search_field.setFocus()
return super().showEvent(event)

@override
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: # noqa N802
# When Escape is pressed, focus back on the search box.
# If focus is already on the search box, close the modal.
if event.key() == QtCore.Qt.Key.Key_Escape:
if self.search_field.hasFocus():
self.parentWidget().hide()
return super().keyPressEvent(event)
else:
self.search_field.setFocus()
self.search_field.selectAll()
return super().keyPressEvent(event)

def remove_tag(self, tag: Tag):
pass
Expand Down
13 changes: 12 additions & 1 deletion tagstudio/src/qt/widgets/paged_panel/paged_panel.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# Copyright (C) 2024 Travis Abendshien (CyanVoxel).
# Copyright (C) 2025 Travis Abendshien (CyanVoxel).
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio

from typing import override

import structlog
from PySide6 import QtCore, QtGui
from PySide6.QtCore import Qt
from PySide6.QtWidgets import (
QHBoxLayout,
Expand Down Expand Up @@ -110,3 +113,11 @@ def update_frame(self):
item.setHidden(False)
elif isinstance(item, int):
self.button_nav_layout.addStretch(item)

@override
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: # noqa N802
if event.key() == QtCore.Qt.Key.Key_Escape:
self.close()
else: # Other key presses
pass
return super().keyPressEvent(event)
20 changes: 16 additions & 4 deletions tagstudio/src/qt/widgets/panel.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# Copyright (C) 2024 Travis Abendshien (CyanVoxel).
# Copyright (C) 2025 Travis Abendshien (CyanVoxel).
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio
import logging
from typing import Callable

import structlog
from PySide6 import QtCore, QtGui
from PySide6.QtCore import Qt, Signal
from PySide6.QtWidgets import QHBoxLayout, QLabel, QPushButton, QVBoxLayout, QWidget
from src.qt.translations import Translations

logger = structlog.get_logger(__name__)


class PanelModal(QWidget):
saved = Signal()
Expand Down Expand Up @@ -96,7 +98,10 @@ def __init__(
widget.parent_post_init()

def closeEvent(self, event): # noqa: N802
self.done_button.click()
if self.cancel_button:
self.cancel_button.click()
elif self.done_button:
self.done_button.click()
event.accept()

def setTitle(self, title: str): # noqa: N802
Expand Down Expand Up @@ -125,12 +130,19 @@ def parent_post_init(self):
pass

def add_callback(self, callback: Callable, event: str = "returnPressed"):
logging.warning(f"add_callback not implemented for {self.__class__.__name__}")
logger.warning(f"[PanelModal] add_callback not implemented for {self.__class__.__name__}")

def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: # noqa N802
if event.key() == QtCore.Qt.Key.Key_Escape:
if self.panel_cancel_button:
self.panel_cancel_button.click()
elif self.panel_done_button:
self.panel_done_button.click()
elif event.key() == Qt.Key.Key_Return or event.key() == Qt.Key.Key_Enter:
if self.panel_save_button:
self.panel_save_button.click()
elif self.panel_done_button:
self.panel_done_button.click()
else: # Other key presses
pass
return super().keyPressEvent(event)
3 changes: 1 addition & 2 deletions tagstudio/src/qt/widgets/preview/field_containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,10 +500,9 @@ def remove_message_box(self, prompt: str, callback: Callable) -> None:
Translations["generic.cancel_alt"], QMessageBox.ButtonRole.DestructiveRole
)
remove_mb.addButton("&Remove", QMessageBox.ButtonRole.RejectRole)
remove_mb.setDefaultButton(cancel_button)
remove_mb.setEscapeButton(cancel_button)
result = remove_mb.exec_()
if result == 3: # TODO - what is this magic number?
if result == QMessageBox.ButtonRole.ActionRole.value:
callback()

def emit_badge_signals(self, tag_ids: list[int] | set[int], emit_on_absent: bool = True):
Expand Down