// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include "JFJochAzIntWindow.h" #include #include #include JFJochAzIntWindow::JFJochAzIntWindow( const AzimuthalIntegrationSettings &settings, QWidget *parent) : JFJochHelperWindow(parent), m_settings(settings) { setWindowTitle("Azimuthal integration settings"); QWidget *centralWidget = new QWidget(this); setCentralWidget(centralWidget); auto mainLayout = new QVBoxLayout(centralWidget); // Group box similar to TS Paper + stacked inputs auto group = new QGroupBox("Azimuthal integration", this); auto formLayout = new QFormLayout(group); // Q spacing m_qSpacing = new SliderPlusBox(0.01, 1.0, 0.001, 3, this); m_qSpacing->setValue(m_settings.GetQSpacing_recipA()); formLayout->addRow(tr("Q spacing [Å⁻¹]:"), m_qSpacing); // Low Q m_lowQ = new SliderPlusBox(0.001, 10.0, 0.001, 3, this); m_lowQ->setValue(m_settings.GetLowQ_recipA()); formLayout->addRow(tr("Low Q [Å⁻¹]:"), m_lowQ); // High Q m_highQ = new SliderPlusBox(0.001, 10.0, 0.001, 3, this); m_highQ->setValue(m_settings.GetHighQ_recipA()); formLayout->addRow(tr("High Q [Å⁻¹]:"), m_highQ); // Solid angle / polarization correction checkboxes m_solidAngleCheckBox = new QCheckBox(tr("Solid angle correction"), this); m_solidAngleCheckBox->setChecked(m_settings.IsSolidAngleCorrection()); formLayout->addRow(QString(), m_solidAngleCheckBox); m_polarizationCheckBox = new QCheckBox(tr("Polarization correction"), this); m_polarizationCheckBox->setChecked(m_settings.IsPolarizationCorrection()); formLayout->addRow(QString(), m_polarizationCheckBox); // Azimuthal bins (radio buttons like TS frontend) auto azimGroupBox = new QGroupBox(tr("Azimuthal bins"), this); auto azimLayout = new QHBoxLayout(azimGroupBox); m_azimuthalBinsGroup = new QButtonGroup(this); const QList binOptions = {1, 2, 4, 8, 16, 32, 64, 128}; const int currentBins = m_settings.GetAzimuthalBinCount(); for (int bins : binOptions) { auto *btn = new QRadioButton(QString::number(bins), azimGroupBox); m_azimuthalBinsGroup->addButton(btn, bins); m_azimuthalBinButtons.push_back(btn); azimLayout->addWidget(btn); if (bins == currentBins) { btn->setChecked(true); } } group->setLayout(formLayout); mainLayout->addWidget(group); mainLayout->addWidget(azimGroupBox); // Error label at bottom (no buttons) m_errorLabel = new QLabel(this); m_errorLabel->setStyleSheet("color: rgb(200, 0, 0);"); // red-ish text for errors m_errorLabel->setWordWrap(true); mainLayout->addWidget(m_errorLabel); // Connections – on change, update errors, settings, and emit connect(m_qSpacing, &SliderPlusBox::valueChanged, [this](double val) { m_qSpacingError = (val < 0.01); Update(); }); connect(m_lowQ, &SliderPlusBox::valueChanged, [this](double val) { m_lowQError = (val < 0.001 || val > 10.0); Update(); }); connect(m_highQ, &SliderPlusBox::valueChanged, [this](double val) { m_highQError = (val < 0.001 || val > 10.0); Update(); }); connect(m_solidAngleCheckBox, &QCheckBox::toggled, [this](bool /*checked*/) { Update(); }); connect(m_polarizationCheckBox, &QCheckBox::toggled, [this](bool /*checked*/) { Update(); }); connect(m_azimuthalBinsGroup, QOverload::of(&QButtonGroup::buttonClicked), [this](QAbstractButton * /*btn*/) { Update(); }); Update(); } void JFJochAzIntWindow::UpdateErrorLabel() { const double lowQ = m_lowQ->value(); const double highQ = m_highQ->value(); QStringList messages; if (m_qSpacingError) { messages << tr("Q spacing must be ≥ 0.01 Å⁻¹."); } if (m_lowQError) { messages << tr("Low Q must be between 0.001 and 10 Å⁻¹."); } if (m_highQError) { messages << tr("High Q must be between 0.001 and 10 Å⁻¹."); } if (highQ <= lowQ) { messages << tr("High Q must be greater than Low Q."); } if (messages.isEmpty()) { m_errorLabel->clear(); } else { m_errorLabel->setText(messages.join(' ')); } } void JFJochAzIntWindow::ApplyToSettings() { const float lowQ = static_cast(m_lowQ->value()); const float highQ = static_cast(m_highQ->value()); const float qSpacing = static_cast(m_qSpacing->value()); m_settings.SolidAngleCorrection(m_solidAngleCheckBox->isChecked()); m_settings.PolarizationCorrection(m_polarizationCheckBox->isChecked()); m_settings.QRange_recipA(lowQ, highQ); m_settings.QSpacing_recipA(qSpacing); const int bins = m_azimuthalBinsGroup->checkedId(); if (bins > 0) { m_settings.AzimuthalBinCount(bins); } } void JFJochAzIntWindow::Update() { // Update error label first UpdateErrorLabel(); // If there are validation errors, do not update settings / emit const double lowQ = m_lowQ->value(); const double highQ = m_highQ->value(); const bool rangeError = (highQ <= lowQ); const bool anyError = m_lowQError || m_highQError || m_qSpacingError || rangeError; if (anyError) return; // Update internal settings from widgets ApplyToSettings(); // Emit updated settings when valid emit settingsChanged(m_settings); }