Scroll tilt navigates one cell/post in grid, preview, and popout
This commit is contained in:
parent
92b7a16ab2
commit
56cb5ce1df
@ -64,6 +64,14 @@
|
|||||||
- Prev/Next buttons hide when at page boundaries instead of just disabling
|
- Prev/Next buttons hide when at page boundaries instead of just disabling
|
||||||
- Source URLs clickable in info panel, truncated at 60 chars for display
|
- Source URLs clickable in info panel, truncated at 60 chars for display
|
||||||
|
|
||||||
|
### Changed: scroll tilt navigation
|
||||||
|
- Scroll tilt left/right now navigates between posts everywhere — grid, embedded preview, and popout — mirroring the L/R keys
|
||||||
|
- Grid: moves selection one cell, falls through to `nav_before_start` / `nav_past_end` at the edges
|
||||||
|
- Preview/popout: emits the existing `navigate` signal (±1)
|
||||||
|
- Vertical scroll still adjusts video volume on the video stack; tilt and vertical can no longer interfere
|
||||||
|
- Fixed: tilting over the image preview no longer zooms the image out (latent bug — `angleDelta().y() == 0` on pure tilt fell into the zoom-out branch)
|
||||||
|
- `page_forward` / `page_back` grid signals removed (only consumer was the old tilt handler)
|
||||||
|
|
||||||
### Improved: video controls
|
### Improved: video controls
|
||||||
- Seek step changed from 5s to ~3s for `,` and `.` keys
|
- Seek step changed from 5s to ~3s for `,` and `.` keys
|
||||||
- `,` and `.` seek keys now work in the main preview panel, not just popout
|
- `,` and `.` seek keys now work in the main preview panel, not just popout
|
||||||
|
|||||||
@ -161,7 +161,7 @@ Categories=Graphics;
|
|||||||
| `Ctrl+A` | Select all |
|
| `Ctrl+A` | Select all |
|
||||||
| `Ctrl+Click` / `Shift+Click` | Multi-select |
|
| `Ctrl+Click` / `Shift+Click` | Multi-select |
|
||||||
| `Home` / `End` | Jump to first / last |
|
| `Home` / `End` | Jump to first / last |
|
||||||
| Scroll tilt left / right | Previous / next page |
|
| Scroll tilt left / right | Previous / next thumbnail (one cell) |
|
||||||
| `Ctrl+C` | Copy file to clipboard |
|
| `Ctrl+C` | Copy file to clipboard |
|
||||||
| Right click | Context menu |
|
| Right click | Context menu |
|
||||||
|
|
||||||
@ -169,7 +169,8 @@ Categories=Graphics;
|
|||||||
|
|
||||||
| Key | Action |
|
| Key | Action |
|
||||||
|-----|--------|
|
|-----|--------|
|
||||||
| Scroll wheel | Zoom |
|
| Scroll wheel | Zoom (image) / volume (video) |
|
||||||
|
| Scroll tilt left / right | Previous / next post |
|
||||||
| Middle click / `0` | Reset view |
|
| Middle click / `0` | Reset view |
|
||||||
| Arrow keys / `h`/`j`/`k`/`l` | Navigate posts |
|
| Arrow keys / `h`/`j`/`k`/`l` | Navigate posts |
|
||||||
| `,` / `.` | Seek 3s back / forward (video) |
|
| `,` / `.` | Seek 3s back / forward (video) |
|
||||||
@ -181,6 +182,7 @@ Categories=Graphics;
|
|||||||
| Key | Action |
|
| Key | Action |
|
||||||
|-----|--------|
|
|-----|--------|
|
||||||
| Arrow keys / `h`/`j`/`k`/`l` | Navigate posts |
|
| Arrow keys / `h`/`j`/`k`/`l` | Navigate posts |
|
||||||
|
| Scroll tilt left / right | Previous / next post |
|
||||||
| `,` / `.` | Seek 3s (video) |
|
| `,` / `.` | Seek 3s (video) |
|
||||||
| `Space` | Play / pause (video) |
|
| `Space` | Play / pause (video) |
|
||||||
| Scroll wheel | Volume up / down (video) |
|
| Scroll wheel | Volume up / down (video) |
|
||||||
|
|||||||
@ -424,8 +424,6 @@ class BooruApp(QMainWindow):
|
|||||||
self._grid.multi_context_requested.connect(self._on_multi_context_menu)
|
self._grid.multi_context_requested.connect(self._on_multi_context_menu)
|
||||||
self._grid.nav_past_end.connect(self._on_nav_past_end)
|
self._grid.nav_past_end.connect(self._on_nav_past_end)
|
||||||
self._grid.nav_before_start.connect(self._on_nav_before_start)
|
self._grid.nav_before_start.connect(self._on_nav_before_start)
|
||||||
self._grid.page_forward.connect(self._next_page)
|
|
||||||
self._grid.page_back.connect(self._prev_page)
|
|
||||||
self._stack.addWidget(self._grid)
|
self._stack.addWidget(self._grid)
|
||||||
|
|
||||||
self._bookmarks_view = BookmarksView(self._db)
|
self._bookmarks_view = BookmarksView(self._db)
|
||||||
|
|||||||
@ -288,10 +288,8 @@ class ThumbnailGrid(QScrollArea):
|
|||||||
multi_context_requested = Signal(list, object) # list[int], QPoint
|
multi_context_requested = Signal(list, object) # list[int], QPoint
|
||||||
reached_bottom = Signal() # emitted when scrolled to the bottom
|
reached_bottom = Signal() # emitted when scrolled to the bottom
|
||||||
reached_top = Signal() # emitted when scrolled to the top
|
reached_top = Signal() # emitted when scrolled to the top
|
||||||
nav_past_end = Signal() # keyboard nav past last post
|
nav_past_end = Signal() # nav past last post (keyboard or scroll tilt)
|
||||||
nav_before_start = Signal() # keyboard nav before first post
|
nav_before_start = Signal() # nav before first post (keyboard or scroll tilt)
|
||||||
page_forward = Signal() # scroll tilt right
|
|
||||||
page_back = Signal() # scroll tilt left
|
|
||||||
|
|
||||||
def __init__(self, parent: QWidget | None = None) -> None:
|
def __init__(self, parent: QWidget | None = None) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
@ -483,15 +481,9 @@ class ThumbnailGrid(QScrollArea):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if key in (Qt.Key.Key_Right, Qt.Key.Key_L):
|
if key in (Qt.Key.Key_Right, Qt.Key.Key_L):
|
||||||
if idx + 1 >= len(self._thumbs):
|
self._nav_horizontal(1)
|
||||||
self.nav_past_end.emit()
|
|
||||||
else:
|
|
||||||
self._select(idx + 1)
|
|
||||||
elif key in (Qt.Key.Key_Left, Qt.Key.Key_H):
|
elif key in (Qt.Key.Key_Left, Qt.Key.Key_H):
|
||||||
if idx - 1 < 0:
|
self._nav_horizontal(-1)
|
||||||
self.nav_before_start.emit()
|
|
||||||
else:
|
|
||||||
self._select(idx - 1)
|
|
||||||
elif key in (Qt.Key.Key_Down, Qt.Key.Key_J):
|
elif key in (Qt.Key.Key_Down, Qt.Key.Key_J):
|
||||||
target = idx + cols
|
target = idx + cols
|
||||||
if target >= len(self._thumbs):
|
if target >= len(self._thumbs):
|
||||||
@ -536,12 +528,23 @@ class ThumbnailGrid(QScrollArea):
|
|||||||
if value <= 0 and sb.maximum() > 0:
|
if value <= 0 and sb.maximum() > 0:
|
||||||
self.reached_top.emit()
|
self.reached_top.emit()
|
||||||
|
|
||||||
|
def _nav_horizontal(self, direction: int) -> None:
|
||||||
|
"""Move selection one cell left (-1) or right (+1); emit edge signals at boundaries."""
|
||||||
|
idx = self._selected_index
|
||||||
|
target = idx + direction
|
||||||
|
if target < 0:
|
||||||
|
self.nav_before_start.emit()
|
||||||
|
elif target >= len(self._thumbs):
|
||||||
|
self.nav_past_end.emit()
|
||||||
|
else:
|
||||||
|
self._select(target)
|
||||||
|
|
||||||
def wheelEvent(self, event: QWheelEvent) -> None:
|
def wheelEvent(self, event: QWheelEvent) -> None:
|
||||||
delta = event.angleDelta().x()
|
delta = event.angleDelta().x()
|
||||||
if delta > 30:
|
if delta > 30:
|
||||||
self.page_back.emit()
|
self._nav_horizontal(-1)
|
||||||
elif delta < -30:
|
elif delta < -30:
|
||||||
self.page_forward.emit()
|
self._nav_horizontal(1)
|
||||||
else:
|
else:
|
||||||
super().wheelEvent(event)
|
super().wheelEvent(event)
|
||||||
|
|
||||||
|
|||||||
@ -361,13 +361,23 @@ class FullscreenPreview(QMainWindow):
|
|||||||
elif key == Qt.Key.Key_Comma and self._stack.currentIndex() == 1:
|
elif key == Qt.Key.Key_Comma and self._stack.currentIndex() == 1:
|
||||||
self._video._seek_relative(-1800)
|
self._video._seek_relative(-1800)
|
||||||
return True
|
return True
|
||||||
if event.type() == QEvent.Type.Wheel and self._stack.currentIndex() == 1 and self.isActiveWindow():
|
if event.type() == QEvent.Type.Wheel and self.isActiveWindow():
|
||||||
delta = event.angleDelta().y()
|
# Horizontal tilt navigates between posts on either stack
|
||||||
if delta:
|
tilt = event.angleDelta().x()
|
||||||
vol = max(0, min(100, self._video.volume + (5 if delta > 0 else -5)))
|
if tilt > 30:
|
||||||
self._video.volume = vol
|
self.navigate.emit(-1)
|
||||||
self._show_overlay()
|
|
||||||
return True
|
return True
|
||||||
|
if tilt < -30:
|
||||||
|
self.navigate.emit(1)
|
||||||
|
return True
|
||||||
|
# Vertical wheel adjusts volume on the video stack only
|
||||||
|
if self._stack.currentIndex() == 1:
|
||||||
|
delta = event.angleDelta().y()
|
||||||
|
if delta:
|
||||||
|
vol = max(0, min(100, self._video.volume + (5 if delta > 0 else -5)))
|
||||||
|
self._video.volume = vol
|
||||||
|
self._show_overlay()
|
||||||
|
return True
|
||||||
if event.type() == QEvent.Type.MouseMove and self.isActiveWindow():
|
if event.type() == QEvent.Type.MouseMove and self.isActiveWindow():
|
||||||
# Map cursor position to window coordinates
|
# Map cursor position to window coordinates
|
||||||
cursor_pos = self.mapFromGlobal(event.globalPosition().toPoint() if hasattr(event, 'globalPosition') else event.globalPos())
|
cursor_pos = self.mapFromGlobal(event.globalPosition().toPoint() if hasattr(event, 'globalPosition') else event.globalPos())
|
||||||
@ -593,9 +603,13 @@ class ImageViewer(QWidget):
|
|||||||
def wheelEvent(self, event: QWheelEvent) -> None:
|
def wheelEvent(self, event: QWheelEvent) -> None:
|
||||||
if not self._pixmap:
|
if not self._pixmap:
|
||||||
return
|
return
|
||||||
|
delta = event.angleDelta().y()
|
||||||
|
if delta == 0:
|
||||||
|
# Pure horizontal tilt — let parent handle (navigation)
|
||||||
|
event.ignore()
|
||||||
|
return
|
||||||
mouse_pos = event.position()
|
mouse_pos = event.position()
|
||||||
old_zoom = self._zoom
|
old_zoom = self._zoom
|
||||||
delta = event.angleDelta().y()
|
|
||||||
factor = 1.15 if delta > 0 else 1 / 1.15
|
factor = 1.15 if delta > 0 else 1 / 1.15
|
||||||
self._zoom = max(0.1, min(self._zoom * factor, 20.0))
|
self._zoom = max(0.1, min(self._zoom * factor, 20.0))
|
||||||
ratio = self._zoom / old_zoom
|
ratio = self._zoom / old_zoom
|
||||||
@ -1367,10 +1381,19 @@ class ImagePreview(QWidget):
|
|||||||
super().mousePressEvent(event)
|
super().mousePressEvent(event)
|
||||||
|
|
||||||
def wheelEvent(self, event) -> None:
|
def wheelEvent(self, event) -> None:
|
||||||
|
# Horizontal tilt navigates between posts on either stack
|
||||||
|
tilt = event.angleDelta().x()
|
||||||
|
if tilt > 30:
|
||||||
|
self.navigate.emit(-1)
|
||||||
|
return
|
||||||
|
if tilt < -30:
|
||||||
|
self.navigate.emit(1)
|
||||||
|
return
|
||||||
if self._stack.currentIndex() == 1:
|
if self._stack.currentIndex() == 1:
|
||||||
delta = event.angleDelta().y()
|
delta = event.angleDelta().y()
|
||||||
vol = max(0, min(100, self._video_player.volume + (5 if delta > 0 else -5)))
|
if delta:
|
||||||
self._video_player.volume = vol
|
vol = max(0, min(100, self._video_player.volume + (5 if delta > 0 else -5)))
|
||||||
|
self._video_player.volume = vol
|
||||||
else:
|
else:
|
||||||
super().wheelEvent(event)
|
super().wheelEvent(event)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user