viewer: ROI panel refinements — persist edits, combobox, compact toggles
- Edited ROIs now override the file's for every subsequently loaded image and survive settings changes, until a new file is opened (previously a delete/add was lost on the next image). Tracked via an roi_override_ that is re-applied to curr_experiment and to each loaded image's dataset. - The ROI selector is a compact combobox instead of a list widget. - "Show labels" and "Translucent fill" share one row to save space. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -271,6 +271,7 @@ void JFJochImageReadingWorker::LoadFile_i(const QString &filename, qint64 image_
|
||||
current_file = filename;
|
||||
if (dataset) {
|
||||
curr_experiment = dataset->experiment;
|
||||
roi_override_.reset(); // new file: use its ROIs, forget any earlier edits
|
||||
curr_experiment.ImportIndexingSettings(indexing_settings);
|
||||
curr_experiment.ImportAzimuthalIntegrationSettings(azint_settings);
|
||||
UpdateAzint_i(dataset.get());
|
||||
@@ -378,6 +379,8 @@ void JFJochImageReadingWorker::LoadImage_i(int64_t image_number, int64_t summati
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyROIOverrideToImage_i(); // edited ROIs win over the file's for every image
|
||||
|
||||
current_image = current_image_ptr->ImageData().number;
|
||||
current_summation = summation;
|
||||
|
||||
@@ -466,6 +469,8 @@ void JFJochImageReadingWorker::UpdateDataset_i(const std::optional<DiffractionEx
|
||||
}
|
||||
|
||||
curr_experiment = dataset->experiment;
|
||||
if (roi_override_)
|
||||
curr_experiment.ROI().SetROI(*roi_override_); // keep edited ROIs across settings changes
|
||||
curr_experiment.ImportIndexingSettings(indexing_settings);
|
||||
curr_experiment.ImportAzimuthalIntegrationSettings(azint_settings);
|
||||
UpdateAzint_i(dataset.get());
|
||||
@@ -473,6 +478,7 @@ void JFJochImageReadingWorker::UpdateDataset_i(const std::optional<DiffractionEx
|
||||
emit datasetLoaded(dataset);
|
||||
|
||||
current_image_ptr = std::make_shared<JFJochReaderImage>(current_image_ptr->ImageData(), dataset);
|
||||
ApplyROIOverrideToImage_i();
|
||||
|
||||
if (auto_reanalyze)
|
||||
ReanalyzeImage_i();
|
||||
@@ -596,7 +602,9 @@ void JFJochImageReadingWorker::SetROIDefinition(const ROIDefinition &rois) {
|
||||
|
||||
void JFJochImageReadingWorker::SetROIDefinition_i(const ROIDefinition &rois) {
|
||||
// The worker experiment is the source of truth; the analysis ROI engine is rebuilt
|
||||
// for it so newly loaded images pick up the change automatically.
|
||||
// for it so newly loaded images pick up the change automatically. From now on the
|
||||
// edited ROIs override whatever the file carried.
|
||||
roi_override_ = rois;
|
||||
curr_experiment.ROI().SetROI(rois);
|
||||
if (image_analysis)
|
||||
image_analysis->RebuildROI();
|
||||
@@ -623,6 +631,15 @@ void JFJochImageReadingWorker::SetROIDefinition_i(const ROIDefinition &rois) {
|
||||
emit imageLoaded(current_image_ptr);
|
||||
}
|
||||
|
||||
void JFJochImageReadingWorker::ApplyROIOverrideToImage_i() {
|
||||
if (!roi_override_ || !current_image_ptr)
|
||||
return;
|
||||
auto md = current_image_ptr->CreateMutableDataset();
|
||||
md->experiment.ROI().SetROI(*roi_override_);
|
||||
current_image_ptr = std::make_shared<JFJochReaderImage>(
|
||||
current_image_ptr->ImageData(), std::shared_ptr<const JFJochReaderDataset>(md));
|
||||
}
|
||||
|
||||
void JFJochImageReadingWorker::UpdateUserMask_i(const std::vector<uint32_t> &mask) {
|
||||
std::shared_ptr<const JFJochReaderDataset> dataset;
|
||||
if (http_mode) {
|
||||
|
||||
@@ -53,6 +53,9 @@ private:
|
||||
QString current_file;
|
||||
|
||||
DiffractionExperiment curr_experiment;
|
||||
// Once the user edits ROIs they override whatever the file carried, for this and
|
||||
// every subsequently loaded image, until a new file is opened.
|
||||
std::optional<ROIDefinition> roi_override_;
|
||||
IndexingSettings indexing_settings;
|
||||
AzimuthalIntegrationSettings azint_settings;
|
||||
std::unique_ptr<IndexerThreadPool> indexing;
|
||||
@@ -119,6 +122,7 @@ private:
|
||||
void UpdateAzint_i(const JFJochReaderDataset *dataset);
|
||||
void UpdateUserMask_i(const std::vector<uint32_t> &mask);
|
||||
void SetROIDefinition_i(const ROIDefinition &rois);
|
||||
void ApplyROIOverrideToImage_i(); // rewrite current_image_ptr's dataset with roi_override_
|
||||
void setAutoLoadMode_i(AutoloadMode mode);
|
||||
|
||||
signals:
|
||||
|
||||
@@ -113,15 +113,18 @@ JFJochViewerSidePanel::JFJochViewerSidePanel(QWidget *parent) : QWidget(parent)
|
||||
|
||||
layout->addWidget(new TitleLabel("ROI", this));
|
||||
|
||||
auto roiLabelsCheckBox = new QCheckBox("Show ROI labels", this);
|
||||
auto roiLabelsCheckBox = new QCheckBox("Show labels", this);
|
||||
roiLabelsCheckBox->setCheckState(Qt::CheckState::Unchecked);
|
||||
connect(roiLabelsCheckBox, &QCheckBox::toggled, this, &JFJochViewerSidePanel::showROILabels);
|
||||
layout->addWidget(roiLabelsCheckBox);
|
||||
|
||||
auto roiFillCheckBox = new QCheckBox("Translucent ROI fill", this);
|
||||
auto roiFillCheckBox = new QCheckBox("Translucent fill", this);
|
||||
roiFillCheckBox->setCheckState(Qt::CheckState::Unchecked);
|
||||
connect(roiFillCheckBox, &QCheckBox::toggled, this, &JFJochViewerSidePanel::showROIFill);
|
||||
layout->addWidget(roiFillCheckBox);
|
||||
|
||||
auto roiToggleRow = new QHBoxLayout();
|
||||
roiToggleRow->addWidget(roiLabelsCheckBox);
|
||||
roiToggleRow->addWidget(roiFillCheckBox);
|
||||
layout->addLayout(roiToggleRow);
|
||||
|
||||
roi_list = new JFJochViewerROIList(this);
|
||||
layout->addWidget(roi_list);
|
||||
|
||||
@@ -9,15 +9,13 @@
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QInputDialog>
|
||||
#include <QListWidgetItem>
|
||||
|
||||
JFJochViewerROIList::JFJochViewerROIList(QWidget *parent) : QWidget(parent) {
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
|
||||
list_ = new QListWidget(this);
|
||||
list_->setMaximumHeight(120);
|
||||
layout->addWidget(list_);
|
||||
connect(list_, &QListWidget::itemSelectionChanged, this, &JFJochViewerROIList::OnSelectionChanged);
|
||||
combo_ = new QComboBox(this);
|
||||
layout->addWidget(combo_);
|
||||
connect(combo_, &QComboBox::currentIndexChanged, this, &JFJochViewerROIList::OnSelectionChanged);
|
||||
|
||||
auto *buttons = new QHBoxLayout();
|
||||
type_combo_ = new QComboBox(this);
|
||||
@@ -42,36 +40,33 @@ void JFJochViewerROIList::loadImage(std::shared_ptr<const JFJochReaderImage> ima
|
||||
image_ = image;
|
||||
const QString keep = SelectedName();
|
||||
rois_ = image_ ? image_->Dataset().experiment.ROI().GetROIDefinition() : ROIDefinition{};
|
||||
RebuildList(keep);
|
||||
RebuildCombo(keep);
|
||||
ShowSelectedResult();
|
||||
}
|
||||
|
||||
void JFJochViewerROIList::RebuildList(const QString &keep_selected) {
|
||||
void JFJochViewerROIList::RebuildCombo(const QString &keep_selected) {
|
||||
rebuilding_ = true;
|
||||
list_->clear();
|
||||
combo_->clear();
|
||||
|
||||
auto add_item = [&](const std::string &name, const char *type) {
|
||||
auto *item = new QListWidgetItem(QString("%1 · %2").arg(QString::fromStdString(name), type));
|
||||
item->setData(Qt::UserRole, QString::fromStdString(name)); // name independent of display text
|
||||
list_->addItem(item);
|
||||
// display "name · type", with the bare name kept as item data for lookups
|
||||
combo_->addItem(QString("%1 · %2").arg(QString::fromStdString(name), type),
|
||||
QString::fromStdString(name));
|
||||
};
|
||||
for (const auto &b : rois_.boxes) add_item(b.GetName(), "box");
|
||||
for (const auto &c : rois_.circles) add_item(c.GetName(), "circle");
|
||||
for (const auto &a : rois_.azimuthal) add_item(a.GetName(), "azim");
|
||||
|
||||
if (!keep_selected.isEmpty()) {
|
||||
for (int i = 0; i < list_->count(); i++)
|
||||
if (list_->item(i)->data(Qt::UserRole).toString() == keep_selected) {
|
||||
list_->setCurrentRow(i);
|
||||
break;
|
||||
}
|
||||
const int idx = combo_->findData(keep_selected);
|
||||
if (idx >= 0)
|
||||
combo_->setCurrentIndex(idx);
|
||||
}
|
||||
rebuilding_ = false;
|
||||
}
|
||||
|
||||
QString JFJochViewerROIList::SelectedName() const {
|
||||
auto *item = list_->currentItem();
|
||||
return item ? item->data(Qt::UserRole).toString() : QString();
|
||||
return combo_->currentData().toString();
|
||||
}
|
||||
|
||||
void JFJochViewerROIList::ShowSelectedResult() {
|
||||
@@ -121,7 +116,7 @@ void JFJochViewerROIList::OnAdd() {
|
||||
default: rois_.azimuthal.emplace_back(name, 2.0f, 4.0f); break;
|
||||
}
|
||||
emit roisChanged(rois_);
|
||||
RebuildList(QString::fromStdString(name));
|
||||
RebuildCombo(QString::fromStdString(name));
|
||||
ShowSelectedResult();
|
||||
}
|
||||
|
||||
@@ -137,7 +132,7 @@ void JFJochViewerROIList::OnDelete() {
|
||||
};
|
||||
if (erase_by_name(rois_.boxes) || erase_by_name(rois_.circles) || erase_by_name(rois_.azimuthal)) {
|
||||
emit roisChanged(rois_);
|
||||
RebuildList(QString());
|
||||
RebuildCombo(QString());
|
||||
ShowSelectedResult();
|
||||
}
|
||||
}
|
||||
@@ -168,6 +163,6 @@ void JFJochViewerROIList::OnRename() {
|
||||
}
|
||||
|
||||
emit roisChanged(rois_);
|
||||
RebuildList(new_name);
|
||||
RebuildCombo(new_name);
|
||||
ShowSelectedResult();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <memory>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QListWidget>
|
||||
#include <QComboBox>
|
||||
|
||||
#include "JFJochViewerROIResult.h"
|
||||
@@ -20,7 +19,7 @@
|
||||
class JFJochViewerROIList : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
QListWidget *list_;
|
||||
QComboBox *combo_;
|
||||
QComboBox *type_combo_;
|
||||
JFJochViewerROIResult *result_;
|
||||
|
||||
@@ -28,7 +27,7 @@ class JFJochViewerROIList : public QWidget {
|
||||
std::shared_ptr<const JFJochReaderImage> image_;
|
||||
bool rebuilding_ = false;
|
||||
|
||||
void RebuildList(const QString &keep_selected);
|
||||
void RebuildCombo(const QString &keep_selected);
|
||||
void ShowSelectedResult();
|
||||
[[nodiscard]] QString SelectedName() const;
|
||||
[[nodiscard]] std::string UniqueName() const;
|
||||
|
||||
Reference in New Issue
Block a user