222 lines
6.4 KiB
C++
222 lines
6.4 KiB
C++
#include "params/ParamControls.h"
|
|
|
|
#include "widgets/CompactNumericSpinBox.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
#include <QAbstractSpinBox>
|
|
#include <QApplication>
|
|
#include <QDoubleSpinBox>
|
|
#include <QHBoxLayout>
|
|
#include <QSizePolicy>
|
|
#include <QSlider>
|
|
#include <QSpinBox>
|
|
#include <QWidget>
|
|
|
|
namespace gui {
|
|
|
|
Float01ParamControl::Float01ParamControl(QWidget* parent)
|
|
: QWidget(parent) {
|
|
auto* row = new QHBoxLayout(this);
|
|
row->setContentsMargins(0, 0, 0, 0);
|
|
row->setSpacing(4);
|
|
|
|
m_slider = new QSlider(Qt::Horizontal, this);
|
|
m_slider->setRange(0, 1000);
|
|
m_slider->setSingleStep(1);
|
|
m_slider->setPageStep(10);
|
|
row->addWidget(m_slider, 1);
|
|
|
|
m_spin = new CompactDoubleSpinBox(this, 52);
|
|
m_spin->setRange(0.0, 1.0);
|
|
m_spin->setDecimals(3);
|
|
m_spin->setSingleStep(0.01);
|
|
row->addWidget(m_spin, 0);
|
|
|
|
connect(m_slider, &QSlider::valueChanged, this, [this]() { syncFromSlider(); });
|
|
connect(m_spin, qOverload<double>(&QDoubleSpinBox::valueChanged), this, [this]() { syncFromSpin(); });
|
|
|
|
setValue01(0.5);
|
|
}
|
|
|
|
void Float01ParamControl::setEnabled(bool on) {
|
|
QWidget::setEnabled(on);
|
|
if (m_slider) m_slider->setEnabled(on);
|
|
if (m_spin) m_spin->setEnabled(on);
|
|
}
|
|
|
|
double Float01ParamControl::value01() const {
|
|
return m_spin ? m_spin->value() : 0.5;
|
|
}
|
|
|
|
void Float01ParamControl::setValue01(double v) {
|
|
const double clamped = std::clamp(v, 0.0, 1.0);
|
|
m_block = true;
|
|
if (m_spin) m_spin->setValue(clamped);
|
|
if (m_slider) m_slider->setValue(static_cast<int>(std::lround(clamped * 1000.0)));
|
|
m_block = false;
|
|
}
|
|
|
|
void Float01ParamControl::syncFromSlider() {
|
|
if (m_block || !m_slider || !m_spin) return;
|
|
m_block = true;
|
|
const double v = static_cast<double>(m_slider->value()) / 1000.0;
|
|
m_spin->setValue(v);
|
|
m_block = false;
|
|
emit valueChanged01(v);
|
|
}
|
|
|
|
void Float01ParamControl::syncFromSpin() {
|
|
if (m_block || !m_slider || !m_spin) return;
|
|
m_block = true;
|
|
const double v = m_spin->value();
|
|
m_slider->setValue(static_cast<int>(std::lround(v * 1000.0)));
|
|
m_block = false;
|
|
emit valueChanged01(v);
|
|
}
|
|
|
|
Vec2ParamControl::Vec2ParamControl(QWidget* parent)
|
|
: QWidget(parent) {
|
|
auto* row = new QHBoxLayout(this);
|
|
row->setContentsMargins(0, 0, 0, 0);
|
|
row->setSpacing(3);
|
|
|
|
constexpr int kMaxW = 72;
|
|
m_sx = new CompactIntSpinBox(this, kMaxW);
|
|
m_sx->setRange(-10'000'000, 10'000'000);
|
|
m_sx->setSingleStep(1);
|
|
m_sx->setAccelerated(true);
|
|
row->addWidget(m_sx, 0);
|
|
|
|
m_sy = new CompactIntSpinBox(this, kMaxW);
|
|
m_sy->setRange(-10'000'000, 10'000'000);
|
|
m_sy->setSingleStep(1);
|
|
m_sy->setAccelerated(true);
|
|
row->addWidget(m_sy, 0);
|
|
row->addStretch(1);
|
|
|
|
connect(m_sx, qOverload<int>(&QSpinBox::valueChanged), this, [this]() { emitIfChanged(); });
|
|
connect(m_sy, qOverload<int>(&QSpinBox::valueChanged), this, [this]() { emitIfChanged(); });
|
|
|
|
setValue(0, 0);
|
|
}
|
|
|
|
void Vec2ParamControl::setEnabled(bool on) {
|
|
QWidget::setEnabled(on);
|
|
if (m_sx) m_sx->setEnabled(on);
|
|
if (m_sy) m_sy->setEnabled(on);
|
|
}
|
|
|
|
void Vec2ParamControl::setValue(int x, int y) {
|
|
m_block = true;
|
|
if (m_sx) m_sx->setValue(x);
|
|
if (m_sy) m_sy->setValue(y);
|
|
m_lastX = x;
|
|
m_lastY = y;
|
|
m_block = false;
|
|
}
|
|
|
|
int Vec2ParamControl::x() const { return m_sx ? m_sx->value() : 0; }
|
|
int Vec2ParamControl::y() const { return m_sy ? m_sy->value() : 0; }
|
|
|
|
bool Vec2ParamControl::isActivelyEditing() const {
|
|
QWidget* fw = QApplication::focusWidget();
|
|
for (QWidget* w = fw; w; w = w->parentWidget()) {
|
|
if (w == this) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Vec2ParamControl::emitIfChanged() {
|
|
if (m_block || !m_sx || !m_sy) return;
|
|
const int nx = m_sx->value();
|
|
const int ny = m_sy->value();
|
|
if (nx == m_lastX && ny == m_lastY) return;
|
|
m_lastX = nx;
|
|
m_lastY = ny;
|
|
emit valueChanged(nx, ny);
|
|
}
|
|
|
|
Vec2DoubleParamControl::Vec2DoubleParamControl(QWidget* parent)
|
|
: QWidget(parent) {
|
|
auto* row = new QHBoxLayout(this);
|
|
row->setContentsMargins(0, 0, 0, 0);
|
|
row->setSpacing(4);
|
|
|
|
// 属性栏里的数值输入框不要太宽,否则会挤占面板空间。
|
|
// 坐标/中心等字段通常是整数显示,因此固定更紧凑的宽度即可(仍允许键盘输入)。
|
|
constexpr int kMaxW = 78;
|
|
auto makeSpin = [kMaxW](QDoubleSpinBox* box) {
|
|
box->setObjectName(QStringLiteral("CompactNumericSpin"));
|
|
box->setButtonSymbols(QAbstractSpinBox::UpDownArrows);
|
|
box->setFocusPolicy(Qt::StrongFocus);
|
|
box->setKeyboardTracking(false);
|
|
// 坐标轴/位置统一用整数(仍可直接键盘输入)
|
|
box->setDecimals(0);
|
|
box->setRange(-1.0e7, 1.0e7);
|
|
box->setSingleStep(1.0);
|
|
box->setAccelerated(true);
|
|
box->setMinimumWidth(60);
|
|
box->setMaximumWidth(kMaxW);
|
|
box->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
|
};
|
|
|
|
m_sx = new QDoubleSpinBox(this);
|
|
makeSpin(m_sx);
|
|
row->addWidget(m_sx, 0);
|
|
|
|
m_sy = new QDoubleSpinBox(this);
|
|
makeSpin(m_sy);
|
|
row->addWidget(m_sy, 0);
|
|
|
|
connect(m_sx, qOverload<double>(&QDoubleSpinBox::valueChanged), this, [this]() { emitIfChanged(); });
|
|
connect(m_sy, qOverload<double>(&QDoubleSpinBox::valueChanged), this, [this]() { emitIfChanged(); });
|
|
|
|
setValue(0.0, 0.0);
|
|
}
|
|
|
|
void Vec2DoubleParamControl::setEnabled(bool on) {
|
|
QWidget::setEnabled(on);
|
|
if (m_sx) m_sx->setEnabled(on);
|
|
if (m_sy) m_sy->setEnabled(on);
|
|
}
|
|
|
|
void Vec2DoubleParamControl::setValue(double x, double y) {
|
|
m_block = true;
|
|
const double rx = std::round(x);
|
|
const double ry = std::round(y);
|
|
if (m_sx) m_sx->setValue(rx);
|
|
if (m_sy) m_sy->setValue(ry);
|
|
m_lastX = rx;
|
|
m_lastY = ry;
|
|
m_block = false;
|
|
}
|
|
|
|
double Vec2DoubleParamControl::x() const { return m_sx ? m_sx->value() : 0.0; }
|
|
double Vec2DoubleParamControl::y() const { return m_sy ? m_sy->value() : 0.0; }
|
|
|
|
bool Vec2DoubleParamControl::isActivelyEditing() const {
|
|
QWidget* fw = QApplication::focusWidget();
|
|
for (QWidget* w = fw; w; w = w->parentWidget()) {
|
|
if (w == this) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Vec2DoubleParamControl::emitIfChanged() {
|
|
if (m_block || !m_sx || !m_sy) return;
|
|
const double nx = m_sx->value();
|
|
const double ny = m_sy->value();
|
|
if (qFuzzyCompare(nx + 1.0, m_lastX + 1.0) && qFuzzyCompare(ny + 1.0, m_lastY + 1.0)) return;
|
|
m_lastX = nx;
|
|
m_lastY = ny;
|
|
emit valueChanged(nx, ny);
|
|
}
|
|
|
|
} // namespace gui
|