fix some on properties and signal connection
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
#include <QSignalBlocker>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatch>
|
||||
#include <QComboBox>
|
||||
#include <QCheckBox>
|
||||
#include "Vtk/uLibVtkInterface.h"
|
||||
#include "Math/Units.h"
|
||||
#include "Math/Dense.h"
|
||||
@@ -17,10 +19,12 @@ PropertyWidgetBase::PropertyWidgetBase(PropertyBase* prop, QWidget* parent)
|
||||
m_Label->setMinimumWidth(100);
|
||||
m_Layout->addWidget(m_Label);
|
||||
}
|
||||
PropertyWidgetBase::~PropertyWidgetBase() {}
|
||||
PropertyWidgetBase::~PropertyWidgetBase() {
|
||||
m_Connection.disconnect();
|
||||
}
|
||||
|
||||
// Helper for unit parsing
|
||||
static double parseWithUnits(const QString& text, double* factorOut = nullptr, QString* suffixOut = nullptr) {
|
||||
double parseWithUnits(const QString& text, double* factorOut, QString* suffixOut) {
|
||||
static QRegularExpression re("^\\s*([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)\\s*(_?[a-zA-Z]+)?\\s*$");
|
||||
QRegularExpressionMatch match = re.match(text);
|
||||
if (!match.hasMatch()) return 0.0;
|
||||
@@ -57,14 +61,23 @@ static double parseWithUnits(const QString& text, double* factorOut = nullptr, Q
|
||||
}
|
||||
|
||||
// UnitLineEdit implementation
|
||||
UnitLineEdit::UnitLineEdit(QWidget* parent) : QLineEdit(parent), m_Value(0), m_Factor(1.0), m_Suffix("mm"), m_IsInteger(false) {
|
||||
UnitLineEdit::UnitLineEdit(QWidget* parent) : QLineEdit(parent), m_Value(0), m_Factor(1.0), m_Suffix(""), m_IsInteger(false) {
|
||||
connect(this, &QLineEdit::editingFinished, this, &UnitLineEdit::onEditingFinished);
|
||||
}
|
||||
|
||||
void UnitLineEdit::setUnits(const QString& suffix, double factor) {
|
||||
m_Suffix = suffix;
|
||||
m_Factor = factor;
|
||||
updateText();
|
||||
}
|
||||
|
||||
void UnitLineEdit::setValue(double val) {
|
||||
if (m_Value != val) {
|
||||
m_Value = val;
|
||||
// Initial heuristic for unit if it was mm and value becomes large
|
||||
// Suffix heuristic ONLY if it was mm and no explicit unit was given?
|
||||
// Actually, if m_Suffix is empty or we have a specific one, we should respect it.
|
||||
// The original code had a heuristic, but it's better to let property decide.
|
||||
// Let's keep it ONLY if m_Suffix was mm (legacy behavior)
|
||||
if (!m_IsInteger && m_Suffix == "mm" && std::abs(val) >= 1000.0) { m_Suffix = "m"; m_Factor = CLHEP::meter; }
|
||||
updateText();
|
||||
}
|
||||
@@ -91,12 +104,21 @@ void UnitLineEdit::onEditingFinished() {
|
||||
|
||||
void UnitLineEdit::updateText() {
|
||||
QSignalBlocker blocker(this);
|
||||
QString s;
|
||||
if (m_IsInteger) {
|
||||
setText(QString::number((int)m_Value));
|
||||
s = QString::number((int)m_Value);
|
||||
if (s.isEmpty()) s = "0";
|
||||
} else {
|
||||
double displayVal = m_Value / m_Factor;
|
||||
setText(QString::number(displayVal, 'g', 6) + " " + m_Suffix);
|
||||
s = QString::number(displayVal, 'g', 6);
|
||||
if (!s.contains('.') && !s.contains('e')) {
|
||||
s += ".0";
|
||||
}
|
||||
}
|
||||
if (!m_Suffix.isEmpty()) {
|
||||
s += " " + m_Suffix;
|
||||
}
|
||||
setText(s);
|
||||
}
|
||||
|
||||
void UnitLineEdit::setIntegerOnly(bool integerOnly) {
|
||||
@@ -107,10 +129,16 @@ void UnitLineEdit::setIntegerOnly(bool integerOnly) {
|
||||
DoublePropertyWidget::DoublePropertyWidget(Property<double>* prop, QWidget* parent)
|
||||
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
||||
m_Edit = new UnitLineEdit(this);
|
||||
m_Layout->addWidget(m_Edit, 1);
|
||||
QString units = QString::fromStdString(prop->GetUnits());
|
||||
if (!units.isEmpty()) {
|
||||
double factor = 1.0;
|
||||
parseWithUnits("1 " + units, &factor);
|
||||
m_Edit->setUnits(units, factor);
|
||||
}
|
||||
m_Edit->setValue(prop->Get());
|
||||
m_Layout->addWidget(m_Edit, 1);
|
||||
connect(m_Edit, &UnitLineEdit::valueManualChanged, [this](double val){ m_Prop->Set(val); });
|
||||
uLib::Object::connect(m_Prop, &Property<double>::PropertyChanged, [this](){
|
||||
m_Connection = uLib::Object::connect(m_Prop, &Property<double>::PropertyChanged, [this](){
|
||||
m_Edit->setValue(m_Prop->Get());
|
||||
});
|
||||
}
|
||||
@@ -118,10 +146,16 @@ DoublePropertyWidget::DoublePropertyWidget(Property<double>* prop, QWidget* pare
|
||||
FloatPropertyWidget::FloatPropertyWidget(Property<float>* prop, QWidget* parent)
|
||||
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
||||
m_Edit = new UnitLineEdit(this);
|
||||
m_Layout->addWidget(m_Edit, 1);
|
||||
QString units = QString::fromStdString(prop->GetUnits());
|
||||
if (!units.isEmpty()) {
|
||||
double factor = 1.0;
|
||||
parseWithUnits("1 " + units, &factor);
|
||||
m_Edit->setUnits(units, factor);
|
||||
}
|
||||
m_Edit->setValue(prop->Get());
|
||||
m_Layout->addWidget(m_Edit, 1);
|
||||
connect(m_Edit, &UnitLineEdit::valueManualChanged, [this](double val){ m_Prop->Set((float)val); });
|
||||
uLib::Object::connect(m_Prop, &Property<float>::PropertyChanged, [this](){
|
||||
m_Connection = uLib::Object::connect(m_Prop, &Property<float>::PropertyChanged, [this](){
|
||||
m_Edit->setValue((double)m_Prop->Get());
|
||||
});
|
||||
}
|
||||
@@ -130,10 +164,16 @@ IntPropertyWidget::IntPropertyWidget(Property<int>* prop, QWidget* parent)
|
||||
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
||||
m_Edit = new UnitLineEdit(this);
|
||||
m_Edit->setIntegerOnly(true);
|
||||
m_Layout->addWidget(m_Edit, 1);
|
||||
QString units = QString::fromStdString(prop->GetUnits());
|
||||
if (!units.isEmpty()) {
|
||||
double factor = 1.0;
|
||||
parseWithUnits("1 " + units, &factor);
|
||||
m_Edit->setUnits(units, factor);
|
||||
}
|
||||
m_Edit->setValue(prop->Get());
|
||||
m_Layout->addWidget(m_Edit, 1);
|
||||
connect(m_Edit, &UnitLineEdit::valueManualChanged, [this](double val){ m_Prop->Set((int)val); });
|
||||
uLib::Object::connect(m_Prop, &Property<int>::PropertyChanged, [this](){
|
||||
m_Connection = uLib::Object::connect(m_Prop, &Property<int>::PropertyChanged, [this](){
|
||||
m_Edit->setValue((double)m_Prop->Get());
|
||||
});
|
||||
}
|
||||
@@ -144,7 +184,7 @@ BoolPropertyWidget::BoolPropertyWidget(Property<bool>* prop, QWidget* parent)
|
||||
m_CheckBox->setChecked(prop->Get());
|
||||
m_Layout->addWidget(m_CheckBox, 1);
|
||||
connect(m_CheckBox, &QCheckBox::toggled, [this](bool val){ if (m_Prop->Get() != val) m_Prop->Set(val); });
|
||||
uLib::Object::connect(m_Prop, &Property<bool>::PropertyChanged, [this](){
|
||||
m_Connection = uLib::Object::connect(m_Prop, &Property<bool>::PropertyChanged, [this](){
|
||||
if (m_CheckBox->isChecked() != m_Prop->Get()) {
|
||||
QSignalBlocker blocker(m_CheckBox);
|
||||
m_CheckBox->setChecked(m_Prop->Get());
|
||||
@@ -158,11 +198,11 @@ StringPropertyWidget::StringPropertyWidget(Property<std::string>* prop, QWidget*
|
||||
m_LineEdit = new QLineEdit(this);
|
||||
m_LineEdit->setText(QString::fromStdString(prop->Get()));
|
||||
m_Layout->addWidget(m_LineEdit, 1);
|
||||
connect(m_LineEdit, &QLineEdit::editingFinished, [this](){
|
||||
connect(m_LineEdit, &QLineEdit::editingFinished, [this](){
|
||||
std::string val = m_LineEdit->text().toStdString();
|
||||
if (m_Prop->Get() != val) m_Prop->Set(val);
|
||||
if (m_Prop->Get() != val) m_Prop->Set(val);
|
||||
});
|
||||
uLib::Object::connect(m_Prop, &Property<std::string>::PropertyChanged, [this](){
|
||||
m_Connection = uLib::Object::connect(m_Prop, &Property<std::string>::PropertyChanged, [this](){
|
||||
if (m_LineEdit->text().toStdString() != m_Prop->Get()) {
|
||||
QSignalBlocker blocker(m_LineEdit);
|
||||
m_LineEdit->setText(QString::fromStdString(m_Prop->Get()));
|
||||
@@ -171,6 +211,37 @@ StringPropertyWidget::StringPropertyWidget(Property<std::string>* prop, QWidget*
|
||||
}
|
||||
StringPropertyWidget::~StringPropertyWidget() {}
|
||||
|
||||
class EnumPropertyWidget : public PropertyWidgetBase {
|
||||
PropertyBase* m_Prop;
|
||||
QComboBox* m_Combo;
|
||||
public:
|
||||
EnumPropertyWidget(PropertyBase* prop, QWidget* parent)
|
||||
: PropertyWidgetBase(prop, parent), m_Prop(prop) {
|
||||
m_Combo = new QComboBox(this);
|
||||
const auto& labels = prop->GetEnumLabels();
|
||||
for (const auto& label : labels) {
|
||||
m_Combo->addItem(QString::fromStdString(label));
|
||||
}
|
||||
|
||||
// Get initial value
|
||||
if (auto* p = dynamic_cast<Property<int>*>(prop)) {
|
||||
m_Combo->setCurrentIndex(p->Get());
|
||||
connect(m_Combo, &QComboBox::currentIndexChanged, [p](int index){
|
||||
p->Set(index);
|
||||
});
|
||||
// Store connection in base m_Connection so it's auto-disconnected on destruction.
|
||||
m_Connection = uLib::Object::connect(p, &Property<int>::PropertyChanged, [this, p](){
|
||||
if (m_Combo->currentIndex() != p->Get()) {
|
||||
QSignalBlocker blocker(m_Combo);
|
||||
m_Combo->setCurrentIndex(p->Get());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
m_Layout->addWidget(m_Combo, 1);
|
||||
}
|
||||
};
|
||||
|
||||
PropertyEditor::PropertyEditor(QWidget* parent) : QWidget(parent), m_Object(nullptr) {
|
||||
m_MainLayout = new QVBoxLayout(this);
|
||||
m_MainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
@@ -197,6 +268,11 @@ PropertyEditor::PropertyEditor(QWidget* parent) : QWidget(parent), m_Object(null
|
||||
registerFactory<std::string>([](PropertyBase* p, QWidget* parent){
|
||||
return new StringPropertyWidget(static_cast<Property<std::string>*>(p), parent);
|
||||
});
|
||||
|
||||
// Register EnumProperty specifically (needs to check type since it holds Property<int> but is EnumProperty)
|
||||
m_Factories[std::type_index(typeid(EnumProperty))] = [](PropertyBase* p, QWidget* parent) {
|
||||
return new EnumPropertyWidget(p, parent);
|
||||
};
|
||||
|
||||
// Vector Registration
|
||||
registerFactory<Vector2i>([](PropertyBase* p, QWidget* parent){ return new VectorPropertyWidget<Vector2i, 2>(static_cast<Property<Vector2i>*>(p), parent); });
|
||||
@@ -230,11 +306,22 @@ void PropertyEditor::setObject(::uLib::Object* obj, bool displayOnly) {
|
||||
}
|
||||
|
||||
for (auto* prop : *props) {
|
||||
// Priority 1: Check if it provides enum labels
|
||||
if (!prop->GetEnumLabels().empty()) {
|
||||
m_ContainerLayout->addWidget(new EnumPropertyWidget(prop, m_Container));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Priority 2: Standard factory lookup
|
||||
auto it = m_Factories.find(prop->GetTypeIndex());
|
||||
if (it != m_Factories.end()) {
|
||||
QWidget* widget = it->second(prop, m_Container);
|
||||
m_ContainerLayout->addWidget(widget);
|
||||
} else {
|
||||
// Debug info for unknown types
|
||||
std::cout << "PropertyEditor: No factory for " << prop->GetName()
|
||||
<< " (Type: " << prop->GetTypeName() << ")" << std::endl;
|
||||
|
||||
QWidget* fallback = new PropertyWidgetBase(prop, m_Container);
|
||||
fallback->layout()->addWidget(new QLabel("(Read-only: " + QString::fromStdString(prop->GetValueAsString()) + ")"));
|
||||
m_ContainerLayout->addWidget(fallback);
|
||||
|
||||
Reference in New Issue
Block a user