From 2d4531013d64bbc0ae7d9fdcb10a16aa1365af1c Mon Sep 17 00:00:00 2001 From: lm Date: Sun, 19 Oct 2025 21:16:55 +0200 Subject: [PATCH] Fix folder navigation and restyle navigation arrows --- app/qt/image_processor.py | 30 ++++++++++----------- app/qt/main_window.py | 57 ++++++++++++++++++++++++++------------- 2 files changed, 53 insertions(+), 34 deletions(-) diff --git a/app/qt/image_processor.py b/app/qt/image_processor.py index 6164494..c2b75b5 100644 --- a/app/qt/image_processor.py +++ b/app/qt/image_processor.py @@ -84,38 +84,38 @@ class QtImageProcessor: # image handling -------------------------------------------------------- - def load_single_image(self, path: Path) -> None: + def load_single_image(self, path: Path, *, reset_collection: bool = True) -> Path: image = Image.open(path).convert("RGBA") self.orig_img = image - self.preview_paths = [path] - self.current_index = 0 + if reset_collection: + self.preview_paths = [path] + self.current_index = 0 self._build_preview() - if self.reset_exclusions_on_switch: - self.exclude_shapes = [] self._rebuild_overlay() + return path - def load_folder(self, paths: Iterable[Path], start_index: int = 0) -> None: + def load_folder(self, paths: Iterable[Path], start_index: int = 0) -> Path: self.preview_paths = list(paths) if not self.preview_paths: raise ValueError("No images in folder.") self.current_index = max(0, min(start_index, len(self.preview_paths) - 1)) - self._load_current() + return self._load_image_at_current() - def next_image(self) -> None: + def next_image(self) -> Path | None: if not self.preview_paths: - return + return None self.current_index = (self.current_index + 1) % len(self.preview_paths) - self._load_current() + return self._load_image_at_current() - def previous_image(self) -> None: + def previous_image(self) -> Path | None: if not self.preview_paths: - return + return None self.current_index = (self.current_index - 1) % len(self.preview_paths) - self._load_current() + return self._load_image_at_current() - def _load_current(self) -> None: + def _load_image_at_current(self) -> Path: path = self.preview_paths[self.current_index] - self.load_single_image(path) + return self.load_single_image(path, reset_collection=False) # preview/overlay ------------------------------------------------------- diff --git a/app/qt/main_window.py b/app/qt/main_window.py index 6fe4959..8eccee9 100644 --- a/app/qt/main_window.py +++ b/app/qt/main_window.py @@ -672,9 +672,12 @@ class MainWindow(QtWidgets.QMainWindow, I18nMixin): layout.setHorizontalSpacing(16) self.prev_button = QtWidgets.QToolButton() - self.prev_button.setText("◀") self.prev_button.setCursor(QtCore.Qt.PointingHandCursor) - self.prev_button.setFixedSize(44, 44) + self.prev_button.setAutoRaise(True) + self.prev_button.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly) + self.prev_button.setIcon(self.style().standardIcon(QtWidgets.QStyle.SP_ArrowBack)) + self.prev_button.setIconSize(QtCore.QSize(20, 20)) + self.prev_button.setFixedSize(38, 38) self.prev_button.clicked.connect(lambda: self._invoke_action("show_previous_image")) layout.addWidget(self.prev_button, 0, 0, QtCore.Qt.AlignVCenter) @@ -687,9 +690,12 @@ class MainWindow(QtWidgets.QMainWindow, I18nMixin): layout.addWidget(self.overlay_view, 0, 2) self.next_button = QtWidgets.QToolButton() - self.next_button.setText("▶") self.next_button.setCursor(QtCore.Qt.PointingHandCursor) - self.next_button.setFixedSize(44, 44) + self.next_button.setAutoRaise(True) + self.next_button.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly) + self.next_button.setIcon(self.style().standardIcon(QtWidgets.QStyle.SP_ArrowForward)) + self.next_button.setIconSize(QtCore.QSize(20, 20)) + self.next_button.setFixedSize(38, 38) self.next_button.clicked.connect(lambda: self._invoke_action("show_next_image")) layout.addWidget(self.next_button, 0, 3, QtCore.Qt.AlignVCenter) layout.setColumnStretch(1, 1) @@ -742,11 +748,11 @@ class MainWindow(QtWidgets.QMainWindow, I18nMixin): return path = Path(path_str) try: - self.processor.load_single_image(path) + loaded_path = self.processor.load_single_image(path) except Exception as exc: # pragma: no cover - user feedback QtWidgets.QMessageBox.warning(self, self._t("dialog.error_title"), str(exc)) return - self._current_image_path = path + self._current_image_path = loaded_path if self.processor.reset_exclusions_on_switch: self.image_view.clear_shapes() self.processor.set_exclusions([]) @@ -765,19 +771,21 @@ class MainWindow(QtWidgets.QMainWindow, I18nMixin): QtWidgets.QMessageBox.information(self, self._t("dialog.info_title"), self._t("dialog.folder_empty")) return try: - self.processor.load_folder(paths) + loaded_path = self.processor.load_folder(paths) except ValueError as exc: QtWidgets.QMessageBox.information(self, self._t("dialog.info_title"), str(exc)) return - self._current_image_path = paths[0] + self._current_image_path = loaded_path self._refresh_views() def show_previous_image(self) -> None: if not self.processor.preview_paths: QtWidgets.QMessageBox.information(self, self._t("dialog.info_title"), self._t("dialog.no_image_loaded")) return - self.processor.previous_image() - self._current_image_path = self.processor.preview_paths[self.processor.current_index] + path = self.processor.previous_image() + if path is None: + return + self._current_image_path = path if self.processor.reset_exclusions_on_switch: self.image_view.clear_shapes() self.processor.set_exclusions([]) @@ -787,8 +795,10 @@ class MainWindow(QtWidgets.QMainWindow, I18nMixin): if not self.processor.preview_paths: QtWidgets.QMessageBox.information(self, self._t("dialog.info_title"), self._t("dialog.no_image_loaded")) return - self.processor.next_image() - self._current_image_path = self.processor.preview_paths[self.processor.current_index] + path = self.processor.next_image() + if path is None: + return + self._current_image_path = path if self.processor.reset_exclusions_on_switch: self.image_view.clear_shapes() self.processor.set_exclusions([]) @@ -895,13 +905,8 @@ class MainWindow(QtWidgets.QMainWindow, I18nMixin): for control in self._slider_controls.values(): control.apply_theme(colours) - style_button = ( - f"QToolButton {{ border-radius: 22px; background-color: {colours['panel_bg']}; " - f"border: 1px solid {colours['border']}; color: {colours['text']}; }}" - f"QToolButton:hover {{ background-color: {colours['accent_secondary']}; color: white; }}" - ) - self.prev_button.setStyleSheet(style_button) - self.next_button.setStyleSheet(style_button) + self._style_nav_button(self.prev_button) + self._style_nav_button(self.next_button) self.title_bar.apply_theme(colours) @@ -917,6 +922,20 @@ class MainWindow(QtWidgets.QMainWindow, I18nMixin): return self._t(title_key) return key + def _style_nav_button(self, button: QtWidgets.QToolButton) -> None: + colours = THEMES[self.current_theme] + button.setStyleSheet( + f"QToolButton {{ border-radius: 19px; background-color: {colours['panel_bg']}; " + f"border: 1px solid {colours['border']}; color: {colours['text']}; }}" + f"QToolButton:hover {{ background-color: {colours['accent_secondary']}; color: white; }}" + ) + button.setIconSize(QtCore.QSize(20, 20)) + if button is getattr(self, "prev_button", None): + button.setIcon(self.style().standardIcon(QtWidgets.QStyle.SP_ArrowBack)) + elif button is getattr(self, "next_button", None): + button.setIcon(self.style().standardIcon(QtWidgets.QStyle.SP_ArrowForward)) + + def _refresh_views(self) -> None: preview_pix = self.processor.preview_pixmap() overlay_pix = self.processor.overlay_pixmap()