viewer: shift/ctrl-drag creates list ROIs; remove the old scratch panel

The interactive shift-drag (box) / shift+ctrl-drag (circle) now creates a
new persistent ROI in the list instead of feeding the old single-ROI
scratch panel. The base emits a roiScratchDrawn hook on release; the
diffraction image turns the drawn shape into a named ROI committed via
SetROIDefinition.

The old JFJochViewerImageROIStatistics scratch panel and all its wiring
(box/circle configuration, single-ROI result, add/subtract user mask) are
removed from the side panel and window; the ROI list is now the single
source.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 14:31:23 +02:00
co-authored by Claude Opus 4.8
parent 1d015145a4
commit 142cb88aa8
7 changed files with 44 additions and 69 deletions
-26
View File
@@ -132,20 +132,6 @@ JFJochViewerSidePanel::JFJochViewerSidePanel(QWidget *parent) : QWidget(parent)
connect(roi_list, &JFJochViewerROIList::roisChanged, this, &JFJochViewerSidePanel::roisChanged);
connect(roi_list, &JFJochViewerROIList::selectedROIChanged, this, &JFJochViewerSidePanel::selectedROIChanged);
roi = new JFJochViewerImageROIStatistics(this);
layout->addWidget(roi);
connect(roi, &JFJochViewerImageROIStatistics::ROIBoxConfigured, [this] (QRect box) {
emit ROIBoxConfigured(box);
});
connect(roi, &JFJochViewerImageROIStatistics::ROICircleConfigured, [this] (double x, double y, double radius) {
emit ROICircleConfigured(x, y, radius);
});
connect(roi, &JFJochViewerImageROIStatistics::AddROIToUserMask, [this]() { emit AddROIToUserMask(); });
connect(roi, &JFJochViewerImageROIStatistics::SubtractROIFromUserMask, [this]() { emit SubtractROIFromUserMask(); });
layout->addWidget(new TitleLabel("Data analysis", this));
auto analyzeButton = new QPushButton("Full analysis", this);
@@ -193,18 +179,6 @@ void JFJochViewerSidePanel::selectROIInList(QString name) {
roi_list->setSelected(name);
}
void JFJochViewerSidePanel::SetROIBox(QRect box) {
roi->SetROIBox(box);
}
void JFJochViewerSidePanel::SetROICircle(double x, double y, double radius) {
roi->SetROICircle(x, y, radius);
}
void JFJochViewerSidePanel::SetROIResult(ROIMessage msg) {
roi->SetROIResult(msg);
}
void JFJochViewerSidePanel::SetRings(QVector<float> v) {
res_rings->setRings(v);
}
-9
View File
@@ -8,7 +8,6 @@
#include <QLineEdit>
#include <QCheckBox>
#include "widgets/JFJochViewerImageROIStatistics.h"
#include "widgets/JFJochViewerROIList.h"
#include "../reader/JFJochReader.h"
#include "charts/JFJochSimpleChartView.h"
@@ -19,7 +18,6 @@ class JFJochViewerSidePanel : public QWidget {
Q_OBJECT
JFJochViewerSidePanelChart *chart = nullptr;
JFJochViewerImageROIStatistics *roi = nullptr;
JFJochViewerROIList *roi_list = nullptr;
ResolutionRingWidget *res_rings = nullptr;
@@ -40,10 +38,6 @@ signals:
void imageLoaded(std::shared_ptr<const JFJochReaderImage> image);
void ROIBoxConfigured(QRect box);
void ROICircleConfigured(double center_x, double center_y, double radius);
void AddROIToUserMask();
void SubtractROIFromUserMask();
void writeStatusBar(QString string, int timeout_ms = 0);
void ringModeSet(JFJochDiffractionImage::RingMode mode);
@@ -52,9 +46,6 @@ public:
JFJochViewerSidePanel(QWidget *parent);
public slots:
void loadImage(std::shared_ptr<const JFJochReaderImage> image);
void SetROIBox(QRect box);
void SetROICircle(double x, double y, double radius);
void SetROIResult(ROIMessage msg);
void SetRings(QVector<float> v);
void selectROIInList(QString name);
-33
View File
@@ -189,21 +189,6 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString
connect(viewer, &JFJochDiffractionImage::foregroundChanged,
toolBarDisplay, &JFJochViewerToolbarDisplay::updateForeground);
connect(viewer, &JFJochDiffractionImage::roiBoxUpdated,
reading_worker, &JFJochImageReadingWorker::SetROIBox);
connect(viewer, &JFJochDiffractionImage::roiCircleUpdated,
reading_worker, &JFJochImageReadingWorker::SetROICircle);
connect(viewer, &JFJochDiffractionImage::roiBoxUpdated,
side_panel, &JFJochViewerSidePanel::SetROIBox);
connect(viewer, &JFJochDiffractionImage::roiCircleUpdated,
side_panel, &JFJochViewerSidePanel::SetROICircle);
connect(viewer, &JFJochDiffractionImage::roiCalculated,
side_panel, &JFJochViewerSidePanel::SetROIResult);
connect(side_panel, &JFJochViewerSidePanel::roisChanged,
reading_worker, &JFJochImageReadingWorker::SetROIDefinition);
connect(side_panel, &JFJochViewerSidePanel::selectedROIChanged,
@@ -213,24 +198,6 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString
connect(viewer, &JFJochDiffractionImage::roiSelected,
side_panel, &JFJochViewerSidePanel::selectROIInList);
connect(side_panel, &JFJochViewerSidePanel::ROIBoxConfigured,
reading_worker, &JFJochImageReadingWorker::SetROIBox);
connect(side_panel, &JFJochViewerSidePanel::ROICircleConfigured,
reading_worker, &JFJochImageReadingWorker::SetROICircle);
connect(side_panel, &JFJochViewerSidePanel::ROIBoxConfigured,
viewer, &JFJochDiffractionImage::SetROIBox);
connect(side_panel, &JFJochViewerSidePanel::ROICircleConfigured,
viewer, &JFJochDiffractionImage::SetROICircle);
connect(side_panel, &JFJochViewerSidePanel::AddROIToUserMask,
reading_worker, &JFJochImageReadingWorker::AddROIToUserMask);
connect(side_panel, &JFJochViewerSidePanel::SubtractROIFromUserMask,
reading_worker, &JFJochImageReadingWorker::SubtractROIFromUserMask);
connect(menuBar, &JFJochViewerMenu::clearUserMaskSelected,
reading_worker, &JFJochImageReadingWorker::ClearUserMask);
@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include <set>
#include "JFJochDiffractionImage.h"
#include "../../common/DiffractionGeometry.h"
#include "../../common/JFJochMath.h"
@@ -755,6 +757,42 @@ ROIDefinition JFJochDiffractionImage::BuildEditedROIDefinition() const {
return rois;
}
void JFJochDiffractionImage::roiScratchDrawn() {
// The base just drew a scratch box/circle (roiBox/roi_type, in pixel coords);
// turn it into a new persistent ROI in the list.
if (!image || roiBox.isNull() || roiBox.width() <= 0 || roiBox.height() <= 0)
return;
ROIDefinition rois = image->Dataset().experiment.ROI().GetROIDefinition();
if (rois.boxes.size() + rois.circles.size() + rois.azimuthal.size() >= 16)
return;
std::set<std::string> used;
for (const auto &b : rois.boxes) used.insert(b.GetName());
for (const auto &c : rois.circles) used.insert(c.GetName());
for (const auto &a : rois.azimuthal) used.insert(a.GetName());
std::string name;
for (int i = 1; ; i++) {
name = "roi" + std::to_string(i);
if (!used.count(name)) break;
}
if (roi_type == RoiType::RoiBox) {
const QRectF r = roiBox.normalized();
rois.boxes.emplace_back(name, std::lround(r.left()), std::lround(r.right()),
std::lround(r.top()), std::lround(r.bottom()));
} else {
const QPointF c = roiBox.center();
const double rad = 0.5 * std::min(roiBox.width(), roiBox.height());
rois.circles.emplace_back(name, c.x(), c.y(), std::max(0.1, rad));
}
roiBox = QRectF(); // clear the scratch overlay
selected_roi_ = QString::fromStdString(name);
emit roiSelected(selected_roi_);
emit roiGeometryEdited(rois);
}
void JFJochDiffractionImage::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::Key_Delete && image && !selected_roi_.isEmpty()) {
ROIDefinition rois = image->Dataset().experiment.ROI().GetROIDefinition();
@@ -37,6 +37,7 @@ private:
bool roiEditPress(const QPointF &scenePos) override;
void roiEditMove(const QPointF &scenePos) override;
void roiEditRelease() override;
void roiScratchDrawn() override;
void keyPressEvent(QKeyEvent *event) override; // Delete removes the selected ROI
[[nodiscard]] ROIDefinition BuildEditedROIDefinition() const; // current ROIs with the edit applied
[[nodiscard]] ResizeHandle hitTestBoxHandle(const QRectF &r, const QPointF &p, qreal tol) const;
+4 -1
View File
@@ -297,9 +297,12 @@ void JFJochImage::mouseReleaseEvent(QMouseEvent *event) {
if (mouse_event_type == MouseEventType::EditingExternalROI) {
roiEditRelease();
} else {
if (mouse_event_type == MouseEventType::DrawingROI)
const bool drawn = (mouse_event_type == MouseEventType::DrawingROI);
if (drawn)
roiEndPos = RoundPoint(mapToScene(event->pos()));
updateROI();
if (drawn)
roiScratchDrawn(); // turn the drawn scratch box/circle into a persistent ROI
}
}
+1
View File
@@ -84,6 +84,7 @@ protected:
virtual bool roiEditPress(const QPointF &scenePos) { return false; }
virtual void roiEditMove(const QPointF &scenePos) {}
virtual void roiEditRelease() {}
virtual void roiScratchDrawn() {} // a shift/ctrl-drag finished drawing a new box/circle
QPoint lastMousePos; // To track panning movement
// Resizing which edge/corner