Files
Jungfraujoch/viewer/JFJochViewerSidePanel.cpp
T
leonarski_f 03ac43da69 viewer: panel polish — accordions, shared geometry, detector tilt, SG name
Declutter the side and settings panels (review items a–f):

- New CollapsibleSection widget (slim navy header + coral rule + chevron).
- Inspector: Image features / Resolution rings / ROI are now collapsible and
  start folded (ROI auto-expands when ROIs change); drop the Data-analysis and
  Powder-calibration sections (they live in the hero buttons and settings dock).
- Settings dock: move Geometry to a shared section above the MX/AzInt toggle
  (both communities need it); add Detector tilt (PONI rot1/rot2, deg) and
  rename "Beam center" -> "Beam origin" with PONI/XDS tooltips; show the
  space-group number and resolved Hermann–Mauguin symbol on one line; wrap
  sections in accordions, anchored top with a bottom stretch so expanding one
  does not shift the others.
- Toolbar: drop the redundant "Image number" label.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 16:26:15 +02:00

174 lines
7.1 KiB
C++

// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include <QHBoxLayout>
#include <QPushButton>
#include <QColorDialog>
#include "JFJochViewerSidePanel.h"
#include "widgets/TitleLabel.h"
#include "widgets/CollapsibleSection.h"
#include "widgets/JFJochViewerImageStatistics.h"
JFJochViewerSidePanel::JFJochViewerSidePanel(QWidget *parent) : QWidget(parent) {
auto layout = new QVBoxLayout(this);
layout->addWidget(new TitleLabel("Image statistics", this));
auto stats = new JFJochViewerImageStatistics(this);
layout->addWidget(stats);
connect(this, &JFJochViewerSidePanel::imageLoaded, stats, &JFJochViewerImageStatistics::loadImage);
auto *featuresSection = new CollapsibleSection("Image features", this);
auto spotToggleCheckBox = new QCheckBox("Show spots", this);
spotToggleCheckBox->setCheckState(Qt::CheckState::Unchecked);
connect(spotToggleCheckBox, &QCheckBox::toggled, this, &JFJochViewerSidePanel::spotsToggled);
auto highlightIceRingToggleCheckBox = new QCheckBox("Highlight spots on ice rings", this);
highlightIceRingToggleCheckBox->setCheckState(Qt::CheckState::Checked);
connect(highlightIceRingToggleCheckBox, &QCheckBox::toggled, this,&JFJochViewerSidePanel::highlightIceRingsToggled);
auto predictionsToggleCheckBox = new QCheckBox("Show predictions", this);
predictionsToggleCheckBox->setCheckState(Qt::CheckState::Unchecked);
connect(predictionsToggleCheckBox, &QCheckBox::toggled, this,
&JFJochViewerSidePanel::predictionsToggled);
auto highestPixelsComboBox = new QComboBox(this);
highestPixelsComboBox->addItem("Show 0 highest pixels", 0);
highestPixelsComboBox->addItem("Show 1 highest pixel", 1);
highestPixelsComboBox->addItem("Show 2 highest pixels", 2);
highestPixelsComboBox->addItem("Show 3 highest pixels", 3);
highestPixelsComboBox->addItem("Show 5 highest pixels", 5);
highestPixelsComboBox->addItem("Show 10 highest pixels", 10);
highestPixelsComboBox->setCurrentIndex(0);
connect(highestPixelsComboBox, &QComboBox::currentIndexChanged, this, [this, highestPixelsComboBox](int index) {
int value = highestPixelsComboBox->itemData(index).toInt();
emit showHighestPixels(value);
});
auto saturatedPixelsCheckBox = new QCheckBox("Show saturated pixels", this);
connect(saturatedPixelsCheckBox, &QCheckBox::toggled, this, &JFJochViewerSidePanel::saturatedPixelsToggled);
auto colorSelectButton = new QPushButton("Select feature color", this);
connect(colorSelectButton, &QPushButton::clicked, this, [this]() {
QColor color = QColorDialog::getColor(Qt::magenta, this, "Select Feature Color");
if (color.isValid()) {
emit setFeatureColor(color);
}
});
auto spotColorSelectButton = new QPushButton("Select spot color", this);
connect(spotColorSelectButton, &QPushButton::clicked, this, [this]() {
QColor color = QColorDialog::getColor(Qt::green, this, "Select Spot Color");
if (color.isValid()) {
emit setSpotColor(color);
}
});
auto image_feature_grid = new QGridLayout();
image_feature_grid->addWidget(spotToggleCheckBox, 0, 0);
image_feature_grid->addWidget(highlightIceRingToggleCheckBox, 0, 1);
image_feature_grid->addWidget(predictionsToggleCheckBox, 1, 0);
image_feature_grid->addWidget(saturatedPixelsCheckBox, 2, 0);
image_feature_grid->addWidget(highestPixelsComboBox, 2, 1);
image_feature_grid->addWidget(colorSelectButton, 3, 0);
image_feature_grid->addWidget(spotColorSelectButton, 3, 1);
featuresSection->setContentLayout(image_feature_grid);
featuresSection->setExpanded(false);
layout->addWidget(featuresSection);
auto *ringsSection = new CollapsibleSection("Resolution rings", this);
auto *ringsLayout = new QVBoxLayout();
ringsLayout->setContentsMargins(0, 0, 0, 0);
res_rings = new ResolutionRingWidget(this);
connect(res_rings, &ResolutionRingWidget::resRingsSet, [this] (const QVector<float> &v) {
emit resRingsSet(v);
});
connect(res_rings, &ResolutionRingWidget::ringModeSet, [this] (JFJochDiffractionImage::RingMode mode) {
emit ringModeSet(mode);
});
ringsLayout->addWidget(res_rings);
ringsSection->setContentLayout(ringsLayout);
ringsSection->setExpanded(false);
layout->addWidget(ringsSection);
// The per-image statistics plot now lives in the dataset-info dock (its "Per-image" toggle),
// and powder calibration / full analysis live in the settings dock and the hero buttons,
// so they are no longer duplicated here.
roiSection = new CollapsibleSection("ROI", this);
auto *roiLayout = new QVBoxLayout();
roiLayout->setContentsMargins(0, 0, 0, 0);
auto roiLabelsCheckBox = new QCheckBox("Show labels", this);
roiLabelsCheckBox->setCheckState(Qt::CheckState::Unchecked);
connect(roiLabelsCheckBox, &QCheckBox::toggled, this, &JFJochViewerSidePanel::showROILabels);
auto roiFillCheckBox = new QCheckBox("Translucent fill", this);
roiFillCheckBox->setCheckState(Qt::CheckState::Unchecked);
connect(roiFillCheckBox, &QCheckBox::toggled, this, &JFJochViewerSidePanel::showROIFill);
auto roiToggleRow = new QHBoxLayout();
roiToggleRow->addWidget(roiLabelsCheckBox);
roiToggleRow->addWidget(roiFillCheckBox);
roiLayout->addLayout(roiToggleRow);
roi_list = new JFJochViewerROIList(this);
roiLayout->addWidget(roi_list);
connect(this, &JFJochViewerSidePanel::imageLoaded, roi_list, &JFJochViewerROIList::loadImage);
connect(roi_list, &JFJochViewerROIList::roisChanged, this, &JFJochViewerSidePanel::roisChanged);
connect(roi_list, &JFJochViewerROIList::selectedROIChanged, this, &JFJochViewerSidePanel::selectedROIChanged);
connect(roi_list, &JFJochViewerROIList::downloadROIs, this, &JFJochViewerSidePanel::downloadROIs);
connect(roi_list, &JFJochViewerROIList::uploadROIs, this, &JFJochViewerSidePanel::uploadROIs);
connect(roi_list, &JFJochViewerROIList::maskFromROI, this, &JFJochViewerSidePanel::maskFromROI);
connect(roi_list, &JFJochViewerROIList::roisChanged, this, [this] { roiSection->setExpanded(true); });
roiSection->setContentLayout(roiLayout);
roiSection->setExpanded(false);
layout->addWidget(roiSection);
layout->addStretch();
setLayout(layout); // Set the layout to the widget
}
void JFJochViewerSidePanel::spotsToggled(bool input) {
emit showSpots(input);
}
void JFJochViewerSidePanel::predictionsToggled(bool input) {
emit showPredictions(input);
}
void JFJochViewerSidePanel::loadImage(std::shared_ptr<const JFJochReaderImage> image) {
emit imageLoaded(image);
}
void JFJochViewerSidePanel::saturatedPixelsToggled(bool input) {
emit showSaturatedPixels(input);
}
void JFJochViewerSidePanel::highlightIceRingsToggled(bool input) {
emit highlightIceRings(input);
}
void JFJochViewerSidePanel::selectROIInList(QString name) {
roi_list->setSelected(name);
}
void JFJochViewerSidePanel::SetRings(QVector<float> v) {
res_rings->setRings(v);
}