v1.0.0-rc.41
This commit is contained in:
139
viewer/widgets/SliderPlusBox.cpp
Normal file
139
viewer/widgets/SliderPlusBox.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
#include "SliderPlusBox.h"
|
||||
#include "../common/JFJochException.h"
|
||||
SliderPlusBox::SliderPlusBox(double min, double max, double step, int decimals, QWidget *parent, ScaleType scaleType)
|
||||
: QWidget(parent), v(min), m_step(step), m_min(min), m_max(max), m_decimals(decimals),
|
||||
m_pendingSliderValue(0), m_sliderDragging(false), m_scaleType(scaleType) {
|
||||
if (step <= 0)
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
"Scale factor for SliderPlusBox must be positive");
|
||||
|
||||
if (m_scaleType == Logarithmic && m_min <= 0)
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
"Minimum value must be greater than zero for logarithmic scale");
|
||||
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
m_slider = new QSlider(Qt::Horizontal, this);
|
||||
updateSliderRange();
|
||||
|
||||
m_doubleSpinBox = new QDoubleSpinBox(this);
|
||||
m_doubleSpinBox->setRange(min, max);
|
||||
m_doubleSpinBox->setDecimals(decimals);
|
||||
m_doubleSpinBox->setSingleStep(step);
|
||||
m_doubleSpinBox->setValue(v);
|
||||
m_doubleSpinBox->setStyleSheet("background-color: rgb(255, 255, 255);");
|
||||
|
||||
m_updateTimer = new QTimer(this);
|
||||
m_updateTimer->setInterval(500); // 500ms throttle
|
||||
m_updateTimer->setSingleShot(false);
|
||||
|
||||
layout->addWidget(m_slider);
|
||||
layout->addWidget(m_doubleSpinBox);
|
||||
|
||||
connect(m_slider, &QSlider::valueChanged, [this](int value) {
|
||||
const QSignalBlocker blocker(m_doubleSpinBox);
|
||||
m_pendingSliderValue = value;
|
||||
double realValue = sliderToValue(value);
|
||||
m_doubleSpinBox->setValue(realValue);
|
||||
if (!m_updateTimer->isActive() && m_sliderDragging)
|
||||
m_updateTimer->start();
|
||||
}
|
||||
);
|
||||
|
||||
connect(m_updateTimer, &QTimer::timeout, [this]() {
|
||||
updateFromSlider(m_pendingSliderValue);
|
||||
});
|
||||
|
||||
connect(m_slider, &QSlider::sliderPressed, [this]() {
|
||||
m_sliderDragging = true;
|
||||
});
|
||||
|
||||
connect(m_slider, &QSlider::sliderReleased, [this]() {
|
||||
m_sliderDragging = false;
|
||||
m_updateTimer->stop();
|
||||
updateFromSlider(m_slider->value());
|
||||
});
|
||||
|
||||
connect(m_doubleSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
||||
[this](double value) {
|
||||
const QSignalBlocker blocker(m_slider);
|
||||
int sliderValue = valueToSlider(value);
|
||||
m_slider->setValue(sliderValue);
|
||||
v = value;
|
||||
emit valueChanged(v);
|
||||
});
|
||||
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void SliderPlusBox::updateSliderRange() {
|
||||
if (m_scaleType == Linear) {
|
||||
m_slider->setRange(static_cast<int>(m_min / m_step), static_cast<int>(m_max / m_step));
|
||||
m_slider->setValue(valueToSlider(v));
|
||||
} else { // Logarithmic
|
||||
// Use a higher resolution for logarithmic scale (1000 steps)
|
||||
m_slider->setRange(0, 1000);
|
||||
m_slider->setValue(valueToSlider(v));
|
||||
}
|
||||
}
|
||||
|
||||
double SliderPlusBox::sliderToValue(int sliderValue) const {
|
||||
if (m_scaleType == Linear) {
|
||||
return sliderValue * m_step;
|
||||
} else { // Logarithmic
|
||||
// Map from slider position (0-1000) to logarithmic value range
|
||||
double logMin = std::log10(m_min);
|
||||
double logMax = std::log10(m_max);
|
||||
double normalizedPos = static_cast<double>(sliderValue) / 1000.0;
|
||||
double logValue = logMin + normalizedPos * (logMax - logMin);
|
||||
return std::pow(10.0, logValue);
|
||||
}
|
||||
}
|
||||
|
||||
int SliderPlusBox::valueToSlider(double value) const {
|
||||
if (m_scaleType == Linear) {
|
||||
return static_cast<int>(value / m_step);
|
||||
} else { // Logarithmic
|
||||
// Map from value to slider position (0-1000)
|
||||
double logMin = std::log10(m_min);
|
||||
double logMax = std::log10(m_max);
|
||||
double logValue = std::log10(std::max(value, m_min)); // Ensure we don't go below min
|
||||
double normalizedPos = (logValue - logMin) / (logMax - logMin);
|
||||
return static_cast<int>(normalizedPos * 1000.0);
|
||||
}
|
||||
}
|
||||
|
||||
void SliderPlusBox::updateFromSlider(int sliderValue) {
|
||||
// Update our internal value and emit the signal
|
||||
v = sliderToValue(sliderValue);
|
||||
emit valueChanged(v);
|
||||
}
|
||||
|
||||
void SliderPlusBox::setValue(double value) {
|
||||
m_doubleSpinBox->setValue(value);
|
||||
}
|
||||
|
||||
void SliderPlusBox::setScaleType(ScaleType type) {
|
||||
if (m_scaleType == type)
|
||||
return;
|
||||
|
||||
if (type == Logarithmic && m_min <= 0) {
|
||||
qWarning() << "Cannot switch to logarithmic scale with min <= 0";
|
||||
return;
|
||||
}
|
||||
|
||||
m_scaleType = type;
|
||||
|
||||
// Preserve the current value during scale type change
|
||||
double currentValue = v;
|
||||
|
||||
// Update the slider range for the new scale type
|
||||
updateSliderRange();
|
||||
|
||||
// Reset the value
|
||||
setValue(currentValue);
|
||||
}
|
||||
Reference in New Issue
Block a user