This commit is contained in:
2026-05-14 13:30:06 +08:00
parent 974946cee4
commit e43171521d
91 changed files with 10485 additions and 3254 deletions
+125 -35
View File
@@ -1,10 +1,18 @@
#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 {
@@ -12,7 +20,7 @@ Float01ParamControl::Float01ParamControl(QWidget* parent)
: QWidget(parent) {
auto* row = new QHBoxLayout(this);
row->setContentsMargins(0, 0, 0, 0);
row->setSpacing(8);
row->setSpacing(4);
m_slider = new QSlider(Qt::Horizontal, this);
m_slider->setRange(0, 1000);
@@ -20,12 +28,11 @@ Float01ParamControl::Float01ParamControl(QWidget* parent)
m_slider->setPageStep(10);
row->addWidget(m_slider, 1);
m_spin = new QDoubleSpinBox(this);
m_spin = new CompactDoubleSpinBox(this, 52);
m_spin->setRange(0.0, 1.0);
m_spin->setDecimals(3);
m_spin->setSingleStep(0.01);
m_spin->setMinimumWidth(72);
row->addWidget(m_spin);
row->addWidget(m_spin, 0);
connect(m_slider, &QSlider::valueChanged, this, [this]() { syncFromSlider(); });
connect(m_spin, qOverload<double>(&QDoubleSpinBox::valueChanged), this, [this]() { syncFromSpin(); });
@@ -73,59 +80,142 @@ Vec2ParamControl::Vec2ParamControl(QWidget* parent)
: QWidget(parent) {
auto* row = new QHBoxLayout(this);
row->setContentsMargins(0, 0, 0, 0);
row->setSpacing(8);
row->setSpacing(3);
m_x = new QDoubleSpinBox(this);
m_x->setRange(-1e9, 1e9);
m_x->setDecimals(2);
m_x->setSingleStep(1.0);
m_x->setMinimumWidth(72);
row->addWidget(m_x, 1);
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_y = new QDoubleSpinBox(this);
m_y->setRange(-1e9, 1e9);
m_y->setDecimals(2);
m_y->setSingleStep(1.0);
m_y->setMinimumWidth(72);
row->addWidget(m_y, 1);
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_x, qOverload<double>(&QDoubleSpinBox::valueChanged), this, [this]() { emitIfChanged(); });
connect(m_y, qOverload<double>(&QDoubleSpinBox::valueChanged), this, [this]() { emitIfChanged(); });
connect(m_sx, qOverload<int>(&QSpinBox::valueChanged), this, [this]() { emitIfChanged(); });
connect(m_sy, qOverload<int>(&QSpinBox::valueChanged), this, [this]() { emitIfChanged(); });
setValue(0.0, 0.0);
setValue(0, 0);
}
void Vec2ParamControl::setEnabled(bool on) {
QWidget::setEnabled(on);
if (m_x) m_x->setEnabled(on);
if (m_y) m_y->setEnabled(on);
if (m_sx) m_sx->setEnabled(on);
if (m_sy) m_sy->setEnabled(on);
}
void Vec2ParamControl::setValue(double x, double y) {
void Vec2ParamControl::setValue(int x, int y) {
m_block = true;
if (m_x) m_x->setValue(x);
if (m_y) m_y->setValue(y);
if (m_sx) m_sx->setValue(x);
if (m_sy) m_sy->setValue(y);
m_lastX = x;
m_lastY = y;
m_block = false;
}
double Vec2ParamControl::x() const { return m_x ? m_x->value() : 0.0; }
double Vec2ParamControl::y() const { return m_y ? m_y->value() : 0.0; }
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_x || !m_y) return;
const double nx = m_x->value();
const double ny = m_y->value();
auto nearEq = [](double a, double b) {
const double scale = std::max({1.0, std::abs(a), std::abs(b)});
return std::abs(a - b) <= 1e-4 * scale;
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);
};
if (nearEq(nx, m_lastX) && nearEq(ny, m_lastY)) return;
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
+34 -8
View File
@@ -4,11 +4,10 @@
class QDoubleSpinBox;
class QSlider;
class QLabel;
class QSpinBox;
namespace gui {
// 0..1 浮点参数:Slider + DoubleSpinBox(可复用)
class Float01ParamControl final : public QWidget {
Q_OBJECT
public:
@@ -31,15 +30,43 @@ private:
bool m_block = false;
};
// Vec2 参数:两个 DoubleSpinBox(可复用)
class Vec2ParamControl final : public QWidget {
Q_OBJECT
public:
explicit Vec2ParamControl(QWidget* parent = nullptr);
void setValue(int x, int y);
[[nodiscard]] int x() const;
[[nodiscard]] int y() const;
[[nodiscard]] bool isActivelyEditing() const;
void setEnabled(bool on);
signals:
void valueChanged(int x, int y);
private:
void emitIfChanged();
QSpinBox* m_sx = nullptr;
QSpinBox* m_sy = nullptr;
bool m_block = false;
int m_lastX = 0;
int m_lastY = 0;
};
/// 世界坐标等:可直接键盘输入小数,带宽幅
class Vec2DoubleParamControl final : public QWidget {
Q_OBJECT
public:
explicit Vec2DoubleParamControl(QWidget* parent = nullptr);
void setValue(double x, double y);
double x() const;
double y() const;
[[nodiscard]] double x() const;
[[nodiscard]] double y() const;
[[nodiscard]] bool isActivelyEditing() const;
void setEnabled(bool on);
@@ -49,12 +76,11 @@ signals:
private:
void emitIfChanged();
QDoubleSpinBox* m_x = nullptr;
QDoubleSpinBox* m_y = nullptr;
QDoubleSpinBox* m_sx = nullptr;
QDoubleSpinBox* m_sy = nullptr;
bool m_block = false;
double m_lastX = 0.0;
double m_lastY = 0.0;
};
} // namespace gui