Files
Jungfraujoch/viewer/windows/JFJochCalibrationWindow.cpp
T
leonarski_fandClaude Opus 5 4ea5e6d01b viewer: stop rebuilding closed windows on every dataset tick
The queue-level fix for the live-follow OOM bounded how many datasets are
in flight, but not what each tick costs. Three handlers did full-dataset or
full-detector work per tick regardless of whether their window was open:

- the calibration window copied the whole pixel mask (GetMask returns a
  reference; it was taken by value), memcpy'd it and ran a full-resolution
  recolour on the GUI thread;
- the image-list window rebuilt one row of eight QStandardItems per image,
  and then repainted every cell of the model on every frame to move a
  one-row highlight;
- the dataset-info plot was rebuilt twice per tick, because setCurrentIndex
  fires currentIndexChanged -> comboBoxSelected -> UpdatePlot and the
  caller then called UpdatePlot again.

The first two now defer to showEvent while hidden, following the pattern
JFJochViewerReciprocalSpaceWindow::rebuildGL already uses; the highlight
repaints only the two rows that change; and the combo is blocked around
setCurrentIndex so the plot is built once.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 14:58:35 +02:00

129 lines
4.7 KiB
C++

// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include "JFJochCalibrationWindow.h"
#include <QCloseEvent>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
JFJochCalibrationWindow::JFJochCalibrationWindow(QWidget *parent) : JFJochHelperWindow(parent) {
QWidget *centralWidget = new QWidget(this);
setWindowTitle("Calibration image viewer");
setCentralWidget(centralWidget);
auto grid_layout = new QGridLayout();
viewer = new JFJochSimpleImage(this);
calibration_option = new QComboBox(this);
color_map_select = new QComboBox(this);
color_map_select->addItem("Viridis", static_cast<int>(ColorScaleEnum::Viridis));
color_map_select->addItem("Heat", static_cast<int>(ColorScaleEnum::Heat));
color_map_select->addItem("Indigo", static_cast<int>(ColorScaleEnum::Indigo));
color_map_select->addItem("B/W", static_cast<int>(ColorScaleEnum::BW));
color_map_select->setCurrentIndex(static_cast<int>(ColorScaleEnum::Indigo));
background_slider = new SliderPlusBox(1, 32768, 1.0, 0, this, SliderPlusBox::ScaleType::Linear);
foreground_slider = new SliderPlusBox(1, 32768, 1.0, 0, this, SliderPlusBox::ScaleType::Linear);
auto background_row = new QHBoxLayout();
auto foreground_row = new QHBoxLayout();
background_row->addWidget(new QLabel("Background:"));
background_row->addWidget(background_slider);
foreground_row->addWidget(new QLabel("Foreground:"));
foreground_row->addWidget(foreground_slider);
grid_layout->addWidget(calibration_option, 0, 0);
grid_layout->addWidget(color_map_select, 0, 1);
grid_layout->addLayout(background_row, 1, 0, 1, 2);
grid_layout->addLayout(foreground_row, 2, 0, 1, 2);
grid_layout->addWidget(viewer, 3, 0, 1, 2);
connect(viewer, &JFJochSimpleImage::backgroundChanged,
[this] (float val) {
QSignalBlocker blocker(background_slider);
background_slider->setValue(val);
});
connect(viewer, &JFJochSimpleImage::foregroundChanged,
[this] (float val) {
QSignalBlocker blocker(foreground_slider);
foreground_slider->setValue(val);
});
connect(background_slider, &SliderPlusBox::valueChanged, viewer, &JFJochSimpleImage::changeBackground);
connect(foreground_slider, &SliderPlusBox::valueChanged, viewer, &JFJochSimpleImage::changeForeground);
connect(color_map_select, &QComboBox::currentIndexChanged, this, [this](int index) {
viewer->setColorMap(index);
});
connect(calibration_option, &QComboBox::currentIndexChanged, this, &JFJochCalibrationWindow::CalibrationSelected);
centralWidget->setLayout(grid_layout);
statusBar = new QStatusBar(this);
setStatusBar(statusBar);
connect(viewer, &JFJochSimpleImage::writeStatusBar,
statusBar, &QStatusBar::showMessage);
}
void JFJochCalibrationWindow::datasetLoaded(std::shared_ptr<const JFJochReaderDataset> in_dataset) {
dataset = std::move(in_dataset);
QSignalBlocker b(calibration_option);
calibration_option->clear();
if (dataset) {
calibration_option->addItem("Pixel mask");
for (auto &calibration : dataset->calibration_data)
calibration_option->addItem(calibration.c_str());
}
// Rebuilding the mask is a full-detector copy plus a full-resolution recolour on the GUI
// thread, and this arrives on every dataset tick when following a live acquisition. Do not pay
// it for a window nobody has open.
if (!isVisible()) {
pending_mask_reload = true;
return;
}
LoadMask();
}
void JFJochCalibrationWindow::showEvent(QShowEvent *event) {
JFJochHelperWindow::showEvent(event);
if (pending_mask_reload) {
pending_mask_reload = false;
LoadMask();
}
}
void JFJochCalibrationWindow::calibrationLoaded(std::shared_ptr<const SimpleImage> image) {
viewer->setImage(image);
}
void JFJochCalibrationWindow::LoadMask() {
if (dataset) {
auto mask = std::make_shared<SimpleImage>();
const auto &tmp = dataset->pixel_mask->GetMask();
mask->buffer.resize(tmp.size() * sizeof(uint32_t));
memcpy(mask->buffer.data(), tmp.data(), tmp.size() * sizeof(uint32_t));
mask->image = CompressedImage(mask->buffer.data(), mask->buffer.size(),
dataset->experiment.GetXPixelsNum(), dataset->experiment.GetYPixelsNum(), CompressedImageMode::Uint32);
viewer->setImage(mask);
}
}
void JFJochCalibrationWindow::CalibrationSelected(int val) {
if (val == 0)
LoadMask();
else
emit loadCalibration(calibration_option->itemText(val));
}
void JFJochCalibrationWindow::setFeatureColor(QColor input) {
viewer->setFeatureColor(input);
}