From 97986d5138d0089b49697c709bd432af61b3f5ee Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Mon, 13 Apr 2026 23:40:17 +0200 Subject: [PATCH] fix: save/restore scrollbar position to prevent playlist scroll jumping setCurrentRow, setHidden, and setText all trigger Qt internal scroll recalculation. Now save scrollbar value before these operations and restore it after, then use scrollToItem only to bring off-screen selections into view. Co-Authored-By: Claude Opus 4.6 --- main.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/main.py b/main.py index 7dc8d01..0244873 100755 --- a/main.py +++ b/main.py @@ -1525,6 +1525,8 @@ class PlaylistWidget(QListWidget): def _apply_visibility(self) -> None: """Centralized: item is hidden if profile-hidden OR (hide_exported AND done).""" + sb = self.verticalScrollBar() + pos = sb.value() if sb else 0 self.setUpdatesEnabled(False) for i, path in enumerate(self._paths): item = self.item(i) @@ -1534,10 +1536,8 @@ class PlaylistWidget(QListWidget): or (self._hide_exported and path in self._done_set)) item.setHidden(hidden) self.setUpdatesEnabled(True) - # Restore scroll to current selection. - cur = self.currentItem() - if cur: - self.scrollToItem(cur, QListWidget.ScrollHint.EnsureVisible) + if sb: + sb.setValue(pos) def advance(self) -> None: """Move to next visible item in queue.""" @@ -1565,11 +1565,16 @@ class PlaylistWidget(QListWidget): def _select(self, row: int) -> None: prev = self.currentRow() + # Save scroll position — setCurrentRow triggers Qt internal scroll. + sb = self.verticalScrollBar() + scroll_pos = sb.value() if sb else 0 self.setCurrentRow(row) + if sb: + sb.setValue(scroll_pos) if prev >= 0 and prev != row and self.item(prev): self._refresh_item_text(prev) - if self.item(row): - item = self.item(row) + item = self.item(row) + if item: cur = item.text() # Preserve [N] tag from mark_done. if cur.startswith("[") and "] " in cur: @@ -1579,6 +1584,7 @@ class PlaylistWidget(QListWidget): else: tag = "" item.setText(f"▶ {tag}{os.path.basename(self._paths[row])}") + # If the item is off-screen, scroll just enough to show it. self.scrollToItem(item, QListWidget.ScrollHint.EnsureVisible) self.file_selected.emit(self._paths[row]) @@ -2263,6 +2269,8 @@ class MainWindow(QMainWindow): def _refresh_playlist_checks(self) -> None: """Re-evaluate marks on every playlist item for the current profile.""" profile = self._profile + sb = self._playlist.verticalScrollBar() + pos = sb.value() if sb else 0 self._playlist.setUpdatesEnabled(False) for path in self._playlist._paths: markers = self._db.get_markers(os.path.basename(path), profile) @@ -2271,6 +2279,8 @@ class MainWindow(QMainWindow): else: self._playlist.unmark_done(path) self._playlist.setUpdatesEnabled(True) + if sb: + sb.setValue(pos) def _on_delete_marker(self, output_path: str) -> None: deleted = self._db.delete_group(output_path)