From a6fbd1d195aeeda2206f653cf6eaf55017a88d24 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 28 Aug 2026 10:18:19 +0200 Subject: [PATCH] Viewer: Alt and the wheel step through the images The wheel already zooms, and with Ctrl or Shift it moves the foreground; Alt now moves through the dataset, one image per notch, wheel up forward - the direction QAbstractSlider's own wheel handling uses, which is what the toolbar's scrub slider follows. The view does not know which image it is showing, so it emits the step and the navigation toolbar applies it: the same loadImage() every other control ends in, with the same clamp and the same Sum setting, so nothing about loading is duplicated. An empty dataset is left alone, because loadImage(-1) does not mean "before the first image" but "the latest one" when the viewer is following a running collection over HTTP. The signal is on JFJochImage, so the other views emit it too; only the diffraction view is connected, which leaves them as they were. Note for a desktop where Alt+wheel does nothing: many window managers grab Alt-modified mouse events before the application sees them, and that is a window-manager setting, not something the viewer can take back. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01FBumeJVx4oeXxiBRpkrE5H --- docs/CHANGELOG.md | 3 +++ viewer/JFJochViewerWindow.cpp | 2 ++ viewer/image_viewer/JFJochImage.cpp | 10 ++++++++++ viewer/image_viewer/JFJochImage.h | 2 ++ viewer/toolbar/JFJochViewerToolbarImage.cpp | 10 ++++++++++ viewer/toolbar/JFJochViewerToolbarImage.h | 1 + 6 files changed, 28 insertions(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index a568fc030..14505b792 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog ## 1.0.0 +### 1.0.0-rc.166 +* In `jfjoch_viewer`, Alt and the mouse wheel step through the dataset one image at a time. + ### 1.0.0-rc.165 This is an UNSTABLE release. It includes many experimental features, as well as many AI generated fixes. We recommend using rc.152 for production use. diff --git a/viewer/JFJochViewerWindow.cpp b/viewer/JFJochViewerWindow.cpp index 3c8cfabb5..215557691 100644 --- a/viewer/JFJochViewerWindow.cpp +++ b/viewer/JFJochViewerWindow.cpp @@ -224,6 +224,8 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString connect(toolBarImage, &JFJochViewerToolbarImage::loadImage, reading_worker, &JFJochImageReadingWorker::LoadImage); + connect(viewer, &JFJochDiffractionImage::stepImage, toolBarImage, &JFJochViewerToolbarImage::stepImage); + connect(toolBarDisplay, &JFJochViewerToolbarDisplay::setForeground, viewer, &JFJochDiffractionImage::changeForeground); diff --git a/viewer/image_viewer/JFJochImage.cpp b/viewer/image_viewer/JFJochImage.cpp index e06eb3133..39e4c21ad 100644 --- a/viewer/image_viewer/JFJochImage.cpp +++ b/viewer/image_viewer/JFJochImage.cpp @@ -143,6 +143,16 @@ void JFJochImage::setFeatureColor(QColor input) { void JFJochImage::wheelEvent(QWheelEvent *event) { if (!scene()) return; + // Alt+wheel steps through the dataset instead of zooming. The view does not know which image + // it shows, so the step is emitted and the navigation toolbar applies it. + if (event->modifiers() & Qt::AltModifier) { + const int delta = event->angleDelta().y(); + if (delta != 0) + emit stepImage(delta > 0 ? 1 : -1); + event->accept(); + return; + } + const double zoomFactor = 1.15; // Zoom factor // Get the position of the mouse in scene coordinates diff --git a/viewer/image_viewer/JFJochImage.h b/viewer/image_viewer/JFJochImage.h index 8b43034ca..b8cb6ea67 100644 --- a/viewer/image_viewer/JFJochImage.h +++ b/viewer/image_viewer/JFJochImage.h @@ -230,6 +230,8 @@ signals: void hoverScenePos(QPointF scenePos); // A new frame has been rendered into Frame(). Follower views repaint on this. void frameRendered(); + // Alt+wheel asks for a move through the dataset: +1 one image forward, -1 one back. + void stepImage(int steps); private slots: void onScroll(int value); public slots: diff --git a/viewer/toolbar/JFJochViewerToolbarImage.cpp b/viewer/toolbar/JFJochViewerToolbarImage.cpp index 1fbddc77e..8ab28efd2 100644 --- a/viewer/toolbar/JFJochViewerToolbarImage.cpp +++ b/viewer/toolbar/JFJochViewerToolbarImage.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-only #include "JFJochViewerToolbarImage.h" +#include #include #include "../widgets/ToolbarIcons.h" @@ -176,6 +177,15 @@ void JFJochViewerToolbarImage::leftmostButtonPressed() { emit loadImage(0, sum); } +void JFJochViewerToolbarImage::stepImage(int steps) { + if (image_count_in_dataset == 0) + return; + const auto target = std::clamp(curr_image + steps, 0, + static_cast(image_count_in_dataset) - 1); + if (target != curr_image) + emit loadImage(target, sum); +} + void JFJochViewerToolbarImage::imageNumberSliderPressed() { image_number_slider_manual = true; } diff --git a/viewer/toolbar/JFJochViewerToolbarImage.h b/viewer/toolbar/JFJochViewerToolbarImage.h index 93792ef2b..88b9b9eb8 100644 --- a/viewer/toolbar/JFJochViewerToolbarImage.h +++ b/viewer/toolbar/JFJochViewerToolbarImage.h @@ -57,6 +57,7 @@ public: explicit JFJochViewerToolbarImage(QWidget *parent = nullptr); public slots: void setImageNumber(int64_t total_images, int64_t current_image); + void stepImage(int steps); void setAutoloadMode(JFJochImageReadingWorker::AutoloadMode input); void setHttpConnection(bool connected, QString addr); private slots: