viewer: numeric editing of the selected ROI's bounds

The ROI panel now shows editable numeric fields for the selected ROI,
labelled by type: box min/max X/Y, circle centre/radius, or azimuthal
Q-range and phi sector. Editing a field rebuilds that ROI and commits it
through the same SetROIDefinition path, so all three types can be created
(via +) and dialled in by typing, not only by dragging.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 14:24:57 +02:00
co-authored by Claude Opus 4.8
parent d413af0e92
commit 1d015145a4
2 changed files with 88 additions and 0 deletions
+82
View File
@@ -4,9 +4,13 @@
#include "JFJochViewerROIList.h"
#include <set>
#include <cmath>
#include "../../common/JFJochMath.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QPushButton>
#include <QInputDialog>
@@ -32,16 +36,93 @@ JFJochViewerROIList::JFJochViewerROIList(QWidget *parent) : QWidget(parent) {
connect(ren, &QPushButton::clicked, this, &JFJochViewerROIList::OnRename);
connect(del, &QPushButton::clicked, this, &JFJochViewerROIList::OnDelete);
auto *grid = new QGridLayout();
for (int i = 0; i < 4; i++) {
flabel_[i] = new QLabel("", this);
fedit_[i] = new QLineEdit(this);
grid->addWidget(flabel_[i], i, 0);
grid->addWidget(fedit_[i], i, 1);
connect(fedit_[i], &QLineEdit::editingFinished, this, &JFJochViewerROIList::ApplyEditor);
}
layout->addLayout(grid);
result_ = new JFJochViewerROIResult(this);
layout->addWidget(result_);
}
void JFJochViewerROIList::UpdateEditor() {
const std::string sel = SelectedName().toStdString();
auto set = [&](int i, const QString &label, double val, bool integer) {
flabel_[i]->setText(label);
flabel_[i]->setVisible(!label.isEmpty());
fedit_[i]->setVisible(!label.isEmpty());
if (!label.isEmpty())
fedit_[i]->setText(integer ? QString::number(std::lround(val)) : QString::number(val, 'g', 6));
};
for (int i = 0; i < 4; i++)
set(i, "", 0, false);
for (const auto &b : rois_.boxes)
if (b.GetName() == sel) {
set(0, "Min X", b.GetXMin(), true); set(1, "Max X", b.GetXMax(), true);
set(2, "Min Y", b.GetYMin(), true); set(3, "Max Y", b.GetYMax(), true);
return;
}
for (const auto &c : rois_.circles)
if (c.GetName() == sel) {
set(0, "Center X", c.GetX(), false); set(1, "Center Y", c.GetY(), false);
set(2, "Radius", c.GetRadius_pxl(), false); set(3, "", 0, false);
return;
}
for (const auto &a : rois_.azimuthal)
if (a.GetName() == sel) {
set(0, "Q min [1/A]", a.GetQMin_recipA(), false); set(1, "Q max [1/A]", a.GetQMax_recipA(), false);
set(2, "phi min [deg]", a.GetPhiMin_deg(), false); set(3, "phi max [deg]", a.GetPhiMax_deg(), false);
return;
}
}
void JFJochViewerROIList::ApplyEditor() {
if (rebuilding_)
return;
const std::string sel = SelectedName().toStdString();
bool changed = false;
for (auto &b : rois_.boxes)
if (b.GetName() == sel) {
b = ROIBox(sel, fedit_[0]->text().toLongLong(), fedit_[1]->text().toLongLong(),
fedit_[2]->text().toLongLong(), fedit_[3]->text().toLongLong());
changed = true; break;
}
for (auto &c : rois_.circles)
if (c.GetName() == sel) {
c = ROICircle(sel, fedit_[0]->text().toDouble(), fedit_[1]->text().toDouble(),
std::max(0.1, fedit_[2]->text().toDouble()));
changed = true; break;
}
for (auto &a : rois_.azimuthal)
if (a.GetName() == sel) {
const float qmin = fedit_[0]->text().toFloat();
const float qmax = fedit_[1]->text().toFloat();
const float phimin = fedit_[2]->text().toFloat();
const float phimax = fedit_[3]->text().toFloat();
const float d_min = (qmax > 0) ? 2.0f * static_cast<float>(PI) / qmax : a.GetDMin_A();
const float d_max = (qmin > 0) ? 2.0f * static_cast<float>(PI) / qmin : a.GetDMax_A();
a = ROIAzimuthal(sel, d_min, d_max, phimin, phimax);
changed = true; break;
}
if (changed)
emit roisChanged(rois_);
}
void JFJochViewerROIList::loadImage(std::shared_ptr<const JFJochReaderImage> image) {
image_ = image;
const QString keep = SelectedName();
rois_ = image_ ? image_->Dataset().experiment.ROI().GetROIDefinition() : ROIDefinition{};
RebuildCombo(keep);
ShowSelectedResult();
UpdateEditor();
}
void JFJochViewerROIList::RebuildCombo(const QString &keep_selected) {
@@ -103,6 +184,7 @@ void JFJochViewerROIList::OnSelectionChanged() {
if (rebuilding_)
return;
ShowSelectedResult();
UpdateEditor();
emit selectedROIChanged(SelectedName());
}
+6
View File
@@ -7,6 +7,8 @@
#include <QWidget>
#include <QComboBox>
#include <QLineEdit>
#include <QLabel>
#include "JFJochViewerROIResult.h"
#include "../../common/ROIDefinition.h"
@@ -21,6 +23,8 @@ class JFJochViewerROIList : public QWidget {
QComboBox *combo_;
QComboBox *type_combo_;
QLabel *flabel_[4];
QLineEdit *fedit_[4];
JFJochViewerROIResult *result_;
ROIDefinition rois_;
@@ -28,6 +32,8 @@ class JFJochViewerROIList : public QWidget {
bool rebuilding_ = false;
void RebuildCombo(const QString &keep_selected);
void UpdateEditor(); // populate the numeric fields for the selected ROI
void ApplyEditor(); // rebuild the selected ROI from the numeric fields
void ShowSelectedResult();
[[nodiscard]] QString SelectedName() const;
[[nodiscard]] std::string UniqueName() const;