feat: implement type-safe ReferenceProperty for SmartPointer fields and add UI support for object selection via context-aware dropdowns

This commit is contained in:
AndreaRigoni
2026-04-17 13:20:21 +00:00
parent ec2d437819
commit 506b8f037f
12 changed files with 265 additions and 12 deletions

View File

@@ -13,6 +13,7 @@
#include <QSlider>
#include <QFontDialog>
#include "Settings.h"
#include "Core/ObjectsContext.h"
namespace uLib {
namespace Qt {
@@ -386,7 +387,74 @@ public:
}
};
PropertyEditor::PropertyEditor(QWidget* parent) : QWidget(parent), m_Object(nullptr) {
////////////////////////////////////////////////////////////////////////////////
// ReferencePropertyWidget
ReferencePropertyWidget::ReferencePropertyWidget(ReferencePropertyBase* prop, ::uLib::ObjectsContext* context, QWidget* parent)
: PropertyWidgetBase(prop, parent), m_RefProp(prop), m_Context(context) {
m_Combo = new QComboBox(static_cast<QWidget*>(this));
m_Layout->addWidget(m_Combo, 1);
refreshCombo();
connect(m_Combo, &QComboBox::currentIndexChanged, this, &ReferencePropertyWidget::onComboChanged);
// Listen for property updates to refresh selected item
m_Connection = uLib::Object::connect(prop, &uLib::Object::Updated, [this](){
QSignalBlocker blocker(m_Combo);
refreshCombo();
});
// Listen for context changes to refresh the dropdown list
if (m_Context) {
m_ContextConnection = uLib::Object::connect(m_Context, &uLib::Object::Updated, [this](){
QSignalBlocker blocker(m_Combo);
refreshCombo();
});
}
}
ReferencePropertyWidget::~ReferencePropertyWidget() {
m_Connection.disconnect();
m_ContextConnection.disconnect();
}
void ReferencePropertyWidget::refreshCombo() {
m_Combo->clear();
m_Combo->addItem("(none)", QVariant::fromValue((quintptr)0));
int selectedIdx = 0;
Object* currentRef = m_RefProp->GetReferencedObject();
if (m_Context) {
const auto& objects = m_Context->GetObjects();
for (auto* obj : objects) {
if (m_RefProp->IsCompatible(obj)) {
QString label = QString::fromStdString(obj->GetInstanceName());
if (label.isEmpty()) {
label = QString::fromStdString(std::string(obj->GetClassName()));
}
// Add index suffix if name is empty to disambiguate
m_Combo->addItem(label, QVariant::fromValue((quintptr)obj));
if (obj == currentRef) {
selectedIdx = m_Combo->count() - 1;
}
}
}
}
m_Combo->setCurrentIndex(selectedIdx);
}
void ReferencePropertyWidget::onComboChanged(int index) {
if (index < 0) return;
quintptr ptr = m_Combo->itemData(index).value<quintptr>();
Object* obj = reinterpret_cast<Object*>(ptr);
m_RefProp->SetReferencedObject(obj);
Q_EMIT updated();
}
////////////////////////////////////////////////////////////////////////////////
// PropertyEditor
PropertyEditor::PropertyEditor(QWidget* parent) : QWidget(parent), m_Object(nullptr), m_Context(nullptr) {
m_MainLayout = new QVBoxLayout(this);
m_MainLayout->setContentsMargins(0, 0, 0, 0);
m_ScrollArea = new QScrollArea(this);
@@ -488,18 +556,23 @@ void PropertyEditor::setObject(::uLib::Object* obj, bool displayOnly) {
// widget = new RangePropertyWidget<float>(pflt, m_Container);
}
} else {
// Priority 2: Standard factory lookup
// Priority 2: Check for reference properties (SmartPointer<T>)
if (auto* refProp = dynamic_cast<::uLib::ReferencePropertyBase*>(prop)) {
widget = static_cast<QWidget*>(new ReferencePropertyWidget(refProp, m_Context, m_Container));
} else {
// Priority 3: Standard factory lookup
auto it = m_Factories.find(prop->GetTypeIndex());
if (it != m_Factories.end()) {
widget = it->second(prop, m_Container);
} else {
// Debug info for unknown types
std::cout << "PropertyEditor: No factory for " << prop->GetQualifiedName()
<< " (Type: " << prop->GetTypeName() << ")" << std::endl;
// Debug info for unknown types
std::cout << "PropertyEditor: No factory for " << prop->GetQualifiedName()
<< " (Type: " << prop->GetTypeName() << ")" << std::endl;
widget = new PropertyWidgetBase(prop, m_Container);
widget->layout()->addWidget(new QLabel("(Read-only: " + QString::fromStdString(prop->GetValueAsString()) + ")"));
widget->layout()->addWidget(new QLabel("(Read-only: " + QString::fromStdString(prop->GetValueAsString()) + ")"));
}
}
}
if (widget) {