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:
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user