refactor(datatypes): changed how typeinfo works

This commit is contained in:
maelstrom 2025-06-02 00:36:26 +02:00
parent bb67a246e2
commit 0f44012e33
17 changed files with 103 additions and 77 deletions

View file

@ -26,7 +26,7 @@
#define AUTOGEN_PREAMBLE_DATA \ #define AUTOGEN_PREAMBLE_DATA \
public: \ public: \
static const TypeInfo TYPE; \ static const TypeDescriptor TYPE; \
virtual void PushLuaValue(lua_State*) const; \ virtual void PushLuaValue(lua_State*) const; \
static result<Variant, LuaCastError> FromLuaValue(lua_State*, int idx); \ static result<Variant, LuaCastError> FromLuaValue(lua_State*, int idx); \
private: private:

View file

@ -3,6 +3,7 @@
#include <string> #include <string>
#include <functional> #include <functional>
#include <optional> #include <optional>
#include "datatypes/enum.h"
#include "error/result.h" #include "error/result.h"
#include "error/data.h" #include "error/data.h"
@ -18,7 +19,7 @@ typedef std::function<std::optional<Variant>(std::string)> FromString;
typedef std::function<result<Variant, LuaCastError>(lua_State*, int idx)> FromLuaValue; typedef std::function<result<Variant, LuaCastError>(lua_State*, int idx)> FromLuaValue;
typedef std::function<void(Variant self, lua_State*)> PushLuaValue; typedef std::function<void(Variant self, lua_State*)> PushLuaValue;
struct TypeInfo { struct TypeDescriptor {
std::string name; std::string name;
Serializer serializer; Serializer serializer;
Deserializer deserializer; Deserializer deserializer;
@ -27,3 +28,23 @@ struct TypeInfo {
PushLuaValue pushLuaValue; PushLuaValue pushLuaValue;
FromLuaValue fromLuaValue; FromLuaValue fromLuaValue;
}; };
enum DataType {
// This distinction is not currently useful, so to
// minimize complexity, there will only be two categories
// (for now)
//DATA_PRIMITIVE,
//DATA_COMPOUND,
DATA_VALUE,
DATA_ENUM,
};
struct TypeInfo {
DataType type;
union {
const TypeDescriptor* descriptor;
_EnumData* enumData;
};
inline TypeInfo(const TypeDescriptor* descriptor) : type(DATA_VALUE), descriptor(descriptor) {}
};

View file

@ -1,6 +1,5 @@
#include "enum.h" #include "enum.h"
Enum::Enum(_EnumData* data) : data(data) {} Enum::Enum(_EnumData* data) : data(data) {}
std::vector<EnumItem> Enum::GetEnumItems() { std::vector<EnumItem> Enum::GetEnumItems() {

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "base.h"
#include <optional> #include <optional>
#include <string>
#include <vector> #include <vector>
struct _EnumData { struct _EnumData {

View file

@ -30,7 +30,7 @@ result<Variant, LuaCastError> Null_FromLuaValue(lua_State* L, int idx) {
return Variant(std::monostate()); return Variant(std::monostate());
} }
const TypeInfo NULL_TYPE { const TypeDescriptor NULL_TYPE {
"null", "null",
Null_Serialize, Null_Serialize,
Null_Deserialize, Null_Deserialize,
@ -70,7 +70,7 @@ result<Variant, LuaCastError> Bool_FromLuaValue(lua_State* L, int idx) {
return Variant(lua_toboolean(L, idx)); return Variant(lua_toboolean(L, idx));
} }
const TypeInfo BOOL_TYPE { const TypeDescriptor BOOL_TYPE {
"bool", "bool",
Bool_Serialize, Bool_Serialize,
Bool_Deserialize, Bool_Deserialize,
@ -113,7 +113,7 @@ result<Variant, LuaCastError> Int_FromLuaValue(lua_State* L, int idx) {
return Variant((int)lua_tonumber(L, idx)); return Variant((int)lua_tonumber(L, idx));
} }
const TypeInfo INT_TYPE { const TypeDescriptor INT_TYPE {
"int", "int",
Int_Serialize, Int_Serialize,
Int_Deserialize, Int_Deserialize,
@ -158,7 +158,7 @@ result<Variant, LuaCastError> Float_FromLuaValue(lua_State* L, int idx) {
return Variant((float)lua_tonumber(L, idx)); return Variant((float)lua_tonumber(L, idx));
} }
const TypeInfo FLOAT_TYPE { const TypeDescriptor FLOAT_TYPE {
"float", "float",
Float_Serialize, Float_Serialize,
Float_Deserialize, Float_Deserialize,
@ -198,7 +198,7 @@ result<Variant, LuaCastError> String_FromLuaValue(lua_State* L, int idx) {
return Variant(lua_tostring(L, idx)); return Variant(lua_tostring(L, idx));
} }
const TypeInfo STRING_TYPE { const TypeDescriptor STRING_TYPE {
"string", "string",
String_Serialize, String_Serialize,
String_Deserialize, String_Deserialize,

View file

@ -2,8 +2,8 @@
#include "base.h" #include "base.h"
extern const TypeInfo NULL_TYPE; extern const TypeDescriptor NULL_TYPE;
extern const TypeInfo BOOL_TYPE; extern const TypeDescriptor BOOL_TYPE;
extern const TypeInfo INT_TYPE; extern const TypeDescriptor INT_TYPE;
extern const TypeInfo FLOAT_TYPE; extern const TypeDescriptor FLOAT_TYPE;
extern const TypeInfo STRING_TYPE; extern const TypeDescriptor STRING_TYPE;

View file

@ -14,7 +14,7 @@ InstanceRef::InstanceRef() {};
InstanceRef::InstanceRef(std::weak_ptr<Instance> instance) : ref(instance) {}; InstanceRef::InstanceRef(std::weak_ptr<Instance> instance) : ref(instance) {};
InstanceRef::~InstanceRef() = default; InstanceRef::~InstanceRef() = default;
const TypeInfo InstanceRef::TYPE = { const TypeDescriptor InstanceRef::TYPE = {
.name = "Ref", .name = "Ref",
.serializer = toVariantFunction(&InstanceRef::Serialize), .serializer = toVariantFunction(&InstanceRef::Serialize),
.deserializer = &InstanceRef::Deserialize, .deserializer = &InstanceRef::Deserialize,
@ -131,7 +131,8 @@ static int inst_newindex(lua_State* L) {
if (key == "Parent" && inst->IsParentLocked()) if (key == "Parent" && inst->IsParentLocked())
return luaL_error(L, "Cannot set property Parent (%s) of %s, parent is locked", inst->GetParent() ? inst->GetParent().value()->name.c_str() : "NULL", inst->GetClass()->className.c_str()); return luaL_error(L, "Cannot set property Parent (%s) of %s, parent is locked", inst->GetParent() ? inst->GetParent().value()->name.c_str() : "NULL", inst->GetClass()->className.c_str());
result<Variant, LuaCastError> value = meta->type->fromLuaValue(L, -1); // TODO: Make this work for enums, this is not a solution!!
result<Variant, LuaCastError> value = meta->type.descriptor->fromLuaValue(L, -1);
lua_pop(L, 3); lua_pop(L, 3);
if (value.isError()) if (value.isError())

View file

@ -13,7 +13,7 @@ public:
InstanceRef(std::weak_ptr<Instance>); InstanceRef(std::weak_ptr<Instance>);
~InstanceRef(); ~InstanceRef();
static const TypeInfo TYPE; static const TypeDescriptor TYPE;
operator std::weak_ptr<Instance>(); operator std::weak_ptr<Instance>();

View file

@ -225,7 +225,7 @@ static const struct luaL_Reg signal_metatable [] = {
SignalRef::SignalRef(std::weak_ptr<Signal> ref) : signal(ref) {} SignalRef::SignalRef(std::weak_ptr<Signal> ref) : signal(ref) {}
SignalRef::~SignalRef() = default; SignalRef::~SignalRef() = default;
const TypeInfo SignalRef::TYPE = { const TypeDescriptor SignalRef::TYPE = {
.name = "Signal", .name = "Signal",
.toString = toVariantFunction(&SignalRef::ToString), .toString = toVariantFunction(&SignalRef::ToString),
.pushLuaValue = toVariantFunction(&SignalRef::PushLuaValue), .pushLuaValue = toVariantFunction(&SignalRef::PushLuaValue),
@ -346,7 +346,7 @@ static const struct luaL_Reg signalconnection_metatable [] = {
SignalConnectionRef::SignalConnectionRef(std::weak_ptr<SignalConnection> ref) : signalConnection(ref) {} SignalConnectionRef::SignalConnectionRef(std::weak_ptr<SignalConnection> ref) : signalConnection(ref) {}
SignalConnectionRef::~SignalConnectionRef() = default; SignalConnectionRef::~SignalConnectionRef() = default;
const TypeInfo SignalConnectionRef::TYPE = { const TypeDescriptor SignalConnectionRef::TYPE = {
.name = "Signal", .name = "Signal",
.toString = toVariantFunction(&SignalConnectionRef::ToString), .toString = toVariantFunction(&SignalConnectionRef::ToString),
.pushLuaValue = toVariantFunction(&SignalConnectionRef::PushLuaValue), .pushLuaValue = toVariantFunction(&SignalConnectionRef::PushLuaValue),

View file

@ -112,7 +112,7 @@ public:
SignalRef(std::weak_ptr<Signal>); SignalRef(std::weak_ptr<Signal>);
~SignalRef(); ~SignalRef();
static const TypeInfo TYPE; static const TypeDescriptor TYPE;
operator std::weak_ptr<Signal>(); operator std::weak_ptr<Signal>();
@ -129,7 +129,7 @@ public:
SignalConnectionRef(std::weak_ptr<SignalConnection>); SignalConnectionRef(std::weak_ptr<SignalConnection>);
~SignalConnectionRef(); ~SignalConnectionRef();
static const TypeInfo TYPE; static const TypeDescriptor TYPE;
operator std::weak_ptr<SignalConnection>(); operator std::weak_ptr<SignalConnection>();

View file

@ -19,7 +19,7 @@
#endif #endif
} }
const TypeInfo* VARIANT_TYPES[] { const TypeDescriptor* VARIANT_TYPES[] {
&NULL_TYPE, &NULL_TYPE,
&BOOL_TYPE, &BOOL_TYPE,
&INT_TYPE, &INT_TYPE,
@ -42,20 +42,18 @@ void Variant::Serialize(pugi::xml_node node) const {
} }
void Variant::PushLuaValue(lua_State* state) const { void Variant::PushLuaValue(lua_State* state) const {
printf("What %zu\n", wrapped.index());
VARIANT_TYPES[wrapped.index()]->pushLuaValue(*this, state); VARIANT_TYPES[wrapped.index()]->pushLuaValue(*this, state);
} }
Variant Variant::Deserialize(pugi::xml_node node) { Variant Variant::Deserialize(pugi::xml_node node, const TypeInfo type) {
if (TYPE_MAP.count(node.name()) == 0) { if (type.type == DATA_VALUE)
Logger::fatalErrorf("Unknown type for property: '%s'", node.name()); return type.descriptor->deserializer(node);
panic(); else
panic(); //TODO: NYI
} }
const TypeInfo* type = TYPE_MAP[node.name()]; std::map<std::string, const TypeDescriptor*> TYPE_MAP = {
return type->deserializer(node);
}
std::map<std::string, const TypeInfo*> TYPE_MAP = {
{ "null", &NULL_TYPE }, { "null", &NULL_TYPE },
{ "bool", &BOOL_TYPE }, { "bool", &BOOL_TYPE },
{ "int", &INT_TYPE }, { "int", &INT_TYPE },

View file

@ -40,7 +40,7 @@ public:
void Serialize(pugi::xml_node node) const; void Serialize(pugi::xml_node node) const;
void PushLuaValue(lua_State* state) const; void PushLuaValue(lua_State* state) const;
static Variant Deserialize(pugi::xml_node node); static Variant Deserialize(pugi::xml_node node, const TypeInfo);
}; };
template <typename T, typename R, typename ...Args> template <typename T, typename R, typename ...Args>
@ -58,4 +58,4 @@ std::function<R(Variant, Args...)> toVariantFunction(R(T::*f)(Args...) const) {
} }
// Map of all data types to their type names // Map of all data types to their type names
extern std::map<std::string, const TypeInfo*> TYPE_MAP; extern std::map<std::string, const TypeDescriptor*> TYPE_MAP;

View file

@ -270,11 +270,11 @@ void Instance::Serialize(pugi::xml_node parent, RefStateSerialize state) {
PropertyMeta meta = GetPropertyMeta(name).expect("Meta of declared property is missing"); PropertyMeta meta = GetPropertyMeta(name).expect("Meta of declared property is missing");
if (meta.flags & (PROP_NOSAVE | PROP_READONLY)) continue; // This property should not be serialized. Skip... if (meta.flags & (PROP_NOSAVE | PROP_READONLY)) continue; // This property should not be serialized. Skip...
pugi::xml_node propertyNode = propertiesNode.append_child(meta.type->name); pugi::xml_node propertyNode = propertiesNode.append_child(meta.type.type == DATA_ENUM ? "token" : meta.type.descriptor->name);
propertyNode.append_attribute("name").set_value(name); propertyNode.append_attribute("name").set_value(name);
// Update std::shared_ptr<Instance> properties using map above // Update std::shared_ptr<Instance> properties using map above
if (meta.type == &InstanceRef::TYPE) { if (meta.type.type == DATA_VALUE && meta.type.descriptor == &InstanceRef::TYPE) {
std::weak_ptr<Instance> refWeak = GetPropertyValue(name).expect("Declared property is missing").get<InstanceRef>(); std::weak_ptr<Instance> refWeak = GetPropertyValue(name).expect("Declared property is missing").get<InstanceRef>();
if (refWeak.expired()) continue; if (refWeak.expired()) continue;
@ -332,9 +332,10 @@ result<std::shared_ptr<Instance>, NoSuchInstance> Instance::Deserialize(pugi::xm
Logger::fatalErrorf("Attempt to set unknown property '%s' of %s", propertyName.c_str(), object->GetClass()->className.c_str()); Logger::fatalErrorf("Attempt to set unknown property '%s' of %s", propertyName.c_str(), object->GetClass()->className.c_str());
continue; continue;
} }
auto meta = meta_.expect();
// Update std::shared_ptr<Instance> properties using map above // Update std::shared_ptr<Instance> properties using map above
if (meta_.expect().type == &InstanceRef::TYPE) { if (meta.type.type == DATA_VALUE && meta.type.descriptor == &InstanceRef::TYPE) {
if (propertyNode.text().empty()) if (propertyNode.text().empty())
continue; continue;
@ -353,7 +354,7 @@ result<std::shared_ptr<Instance>, NoSuchInstance> Instance::Deserialize(pugi::xm
object->SetPropertyValue(propertyName, InstanceRef()).expect(); object->SetPropertyValue(propertyName, InstanceRef()).expect();
} }
} else { } else {
Variant value = Variant::Deserialize(propertyNode); Variant value = Variant::Deserialize(propertyNode, meta.type);
object->SetPropertyValue(propertyName, value).expect("Declared property was missing"); object->SetPropertyValue(propertyName, value).expect("Declared property was missing");
} }
} }
@ -436,7 +437,7 @@ std::optional<std::shared_ptr<Instance>> Instance::Clone(RefStateClone state) {
if (meta.flags & (PROP_READONLY | PROP_NOSAVE)) continue; if (meta.flags & (PROP_READONLY | PROP_NOSAVE)) continue;
// Update std::shared_ptr<Instance> properties using map above // Update std::shared_ptr<Instance> properties using map above
if (meta.type == &InstanceRef::TYPE) { if (meta.type.type == DATA_VALUE && meta.type.descriptor == &InstanceRef::TYPE) {
std::weak_ptr<Instance> refWeak = GetPropertyValue(property).expect().get<InstanceRef>(); std::weak_ptr<Instance> refWeak = GetPropertyValue(property).expect().get<InstanceRef>();
if (refWeak.expired()) continue; if (refWeak.expired()) continue;
@ -486,7 +487,7 @@ std::vector<std::pair<std::string, std::shared_ptr<Instance>>> Instance::GetRefe
for (std::string property : propertyNames) { for (std::string property : propertyNames) {
PropertyMeta meta = GetPropertyMeta(property).expect(); PropertyMeta meta = GetPropertyMeta(property).expect();
if (meta.type != &InstanceRef::TYPE) continue; if (meta.type.type != DATA_VALUE || meta.type.descriptor != &InstanceRef::TYPE) continue;
std::weak_ptr<Instance> ref = GetPropertyValue(property).expect().get<InstanceRef>(); std::weak_ptr<Instance> ref = GetPropertyValue(property).expect().get<InstanceRef>();
if (ref.expired()) continue; if (ref.expired()) continue;

View file

@ -24,7 +24,7 @@ enum PropertyCategory {
const int PROPERTY_CATEGORY_MAX = PROP_CATEGORY_SURFACE_INPUT; const int PROPERTY_CATEGORY_MAX = PROP_CATEGORY_SURFACE_INPUT;
struct PropertyMeta { struct PropertyMeta {
const TypeInfo* type; const TypeInfo type;
PropertyFlags flags; PropertyFlags flags;
PropertyCategory category = PROP_CATEGORY_DATA; PropertyCategory category = PROP_CATEGORY_DATA;
}; };

View file

@ -131,7 +131,7 @@ std::shared_ptr<DataModel> DataModel::CloneModel() {
if (meta.flags & (PROP_READONLY | PROP_NOSAVE)) continue; if (meta.flags & (PROP_READONLY | PROP_NOSAVE)) continue;
// Update std::shared_ptr<Instance> properties using map above // Update std::shared_ptr<Instance> properties using map above
if (meta.type == &InstanceRef::TYPE) { if (meta.type.type == DATA_VALUE && meta.type.descriptor == &InstanceRef::TYPE) {
std::weak_ptr<Instance> refWeak = GetPropertyValue(property).expect().get<InstanceRef>(); std::weak_ptr<Instance> refWeak = GetPropertyValue(property).expect().get<InstanceRef>();
if (refWeak.expired()) continue; if (refWeak.expired()) continue;

View file

@ -53,7 +53,7 @@ public:
Variant currentValue = inst->GetPropertyValue(propertyName).expect(); Variant currentValue = inst->GetPropertyValue(propertyName).expect();
if (isComposite) { if (isComposite) {
if (meta.type == &Vector3::TYPE) { if (meta.type.descriptor == &Vector3::TYPE) {
Vector3 vector = currentValue.get<Vector3>(); Vector3 vector = currentValue.get<Vector3>();
float value = componentName == "X" ? vector.X() : componentName == "Y" ? vector.Y() : componentName == "Z" ? vector.Z() : 0; float value = componentName == "X" ? vector.X() : componentName == "Y" ? vector.Y() : componentName == "Z" ? vector.Z() : 0;
@ -66,7 +66,9 @@ public:
return nullptr; return nullptr;
} }
if (meta.type == &FLOAT_TYPE) { if (meta.type.type == DATA_ENUM) {
} else if (meta.type.descriptor == &FLOAT_TYPE) {
QDoubleSpinBox* spinBox = new QDoubleSpinBox(parent); QDoubleSpinBox* spinBox = new QDoubleSpinBox(parent);
spinBox->setValue(currentValue.get<float>()); spinBox->setValue(currentValue.get<float>());
@ -77,24 +79,24 @@ public:
} }
return spinBox; return spinBox;
} else if (meta.type == &INT_TYPE) { } else if (meta.type.descriptor == &INT_TYPE) {
QSpinBox* spinBox = new QSpinBox(parent); QSpinBox* spinBox = new QSpinBox(parent);
spinBox->setValue(currentValue.get<int>()); spinBox->setValue(currentValue.get<int>());
return spinBox; return spinBox;
} else if (meta.type == &STRING_TYPE) { } else if (meta.type.descriptor == &STRING_TYPE) {
QLineEdit* lineEdit = new QLineEdit(parent); QLineEdit* lineEdit = new QLineEdit(parent);
lineEdit->setText(QString::fromStdString(currentValue.get<std::string>())); lineEdit->setText(QString::fromStdString(currentValue.get<std::string>()));
return lineEdit; return lineEdit;
} else if (meta.type == &Color3::TYPE) { } else if (meta.type.descriptor == &Color3::TYPE) {
QColorDialog* colorDialog = new QColorDialog(parent->window()); QColorDialog* colorDialog = new QColorDialog(parent->window());
Color3 color = currentValue.get<Color3>(); Color3 color = currentValue.get<Color3>();
colorDialog->setCurrentColor(QColor::fromRgbF(color.R(), color.G(), color.B())); colorDialog->setCurrentColor(QColor::fromRgbF(color.R(), color.G(), color.B()));
return colorDialog; return colorDialog;
} else if (meta.type->fromString) { } else if (meta.type.descriptor->fromString) {
QLineEdit* lineEdit = new QLineEdit(parent); QLineEdit* lineEdit = new QLineEdit(parent);
lineEdit->setText(QString::fromStdString(currentValue.ToString())); lineEdit->setText(QString::fromStdString(currentValue.ToString()));
@ -119,7 +121,7 @@ public:
Variant currentValue = inst->GetPropertyValue(propertyName).expect(); Variant currentValue = inst->GetPropertyValue(propertyName).expect();
if (isComposite) { if (isComposite) {
if (meta.type == &Vector3::TYPE) { if (meta.type.descriptor == &Vector3::TYPE) {
Vector3 vector = currentValue.get<Vector3>(); Vector3 vector = currentValue.get<Vector3>();
float value = componentName == "X" ? vector.X() : componentName == "Y" ? vector.Y() : componentName == "Z" ? vector.Z() : 0; float value = componentName == "X" ? vector.X() : componentName == "Y" ? vector.Y() : componentName == "Z" ? vector.Z() : 0;
@ -132,24 +134,26 @@ public:
return; return;
} }
if (meta.type == &FLOAT_TYPE) { if (meta.type.type == DATA_ENUM) {
} else if (meta.type.descriptor == &FLOAT_TYPE) {
QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor); QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor);
spinBox->setValue(currentValue.get<float>()); spinBox->setValue(currentValue.get<float>());
} else if (meta.type == &INT_TYPE) { } else if (meta.type.descriptor == &INT_TYPE) {
QSpinBox* spinBox = dynamic_cast<QSpinBox*>(editor); QSpinBox* spinBox = dynamic_cast<QSpinBox*>(editor);
spinBox->setValue(currentValue.get<int>()); spinBox->setValue(currentValue.get<int>());
} else if (meta.type == &STRING_TYPE) { } else if (meta.type.descriptor == &STRING_TYPE) {
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor); QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
lineEdit->setText(QString::fromStdString((std::string)currentValue.get<std::string>())); lineEdit->setText(QString::fromStdString((std::string)currentValue.get<std::string>()));
} else if (meta.type == &Color3::TYPE) { } else if (meta.type.descriptor == &Color3::TYPE) {
QColorDialog* colorDialog = dynamic_cast<QColorDialog*>(editor); QColorDialog* colorDialog = dynamic_cast<QColorDialog*>(editor);
Color3 color = currentValue.get<Color3>(); Color3 color = currentValue.get<Color3>();
colorDialog->setCurrentColor(QColor::fromRgbF(color.R(), color.G(), color.B())); colorDialog->setCurrentColor(QColor::fromRgbF(color.R(), color.G(), color.B()));
} else if (meta.type->fromString) { } else if (meta.type.descriptor->fromString) {
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor); QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
lineEdit->setText(QString::fromStdString((std::string)currentValue.ToString())); lineEdit->setText(QString::fromStdString((std::string)currentValue.ToString()));
@ -170,7 +174,7 @@ public:
PropertyMeta meta = inst->GetPropertyMeta(propertyName).expect(); PropertyMeta meta = inst->GetPropertyMeta(propertyName).expect();
if (isComposite) { if (isComposite) {
if (meta.type == &Vector3::TYPE) { if (meta.type.descriptor == &Vector3::TYPE) {
QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor); QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor);
float value = spinBox->value(); float value = spinBox->value();
@ -187,22 +191,24 @@ public:
return; return;
} }
if (meta.type == &FLOAT_TYPE) { if (meta.type.type == DATA_ENUM) {
} else if (meta.type.descriptor == &FLOAT_TYPE) {
QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor); QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor);
inst->SetPropertyValue(propertyName, (float)spinBox->value()).expect(); inst->SetPropertyValue(propertyName, (float)spinBox->value()).expect();
model->setData(index, spinBox->value()); model->setData(index, spinBox->value());
} else if (meta.type == &INT_TYPE) { } else if (meta.type.descriptor == &INT_TYPE) {
QSpinBox* spinBox = dynamic_cast<QSpinBox*>(editor); QSpinBox* spinBox = dynamic_cast<QSpinBox*>(editor);
inst->SetPropertyValue(propertyName, (int)spinBox->value()).expect(); inst->SetPropertyValue(propertyName, (int)spinBox->value()).expect();
model->setData(index, spinBox->value()); model->setData(index, spinBox->value());
} else if (meta.type == &STRING_TYPE) { } else if (meta.type.descriptor == &STRING_TYPE) {
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor); QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
inst->SetPropertyValue(propertyName, lineEdit->text().toStdString()).expect(); inst->SetPropertyValue(propertyName, lineEdit->text().toStdString()).expect();
model->setData(index, lineEdit->text()); model->setData(index, lineEdit->text());
} else if (meta.type == &Color3::TYPE) { } else if (meta.type.descriptor == &Color3::TYPE) {
QColorDialog* colorDialog = dynamic_cast<QColorDialog*>(editor); QColorDialog* colorDialog = dynamic_cast<QColorDialog*>(editor);
QColor color = colorDialog->currentColor(); QColor color = colorDialog->currentColor();
@ -210,14 +216,14 @@ public:
inst->SetPropertyValue(propertyName, color3).expect(); inst->SetPropertyValue(propertyName, color3).expect();
model->setData(index, QString::fromStdString(color3.ToString()), Qt::DisplayRole); model->setData(index, QString::fromStdString(color3.ToString()), Qt::DisplayRole);
model->setData(index, color, Qt::DecorationRole); model->setData(index, color, Qt::DecorationRole);
} else if (meta.type->fromString) { } else if (meta.type.descriptor->fromString) {
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor); QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
std::optional<Variant> parsedResult = meta.type->fromString(lineEdit->text().toStdString()); std::optional<Variant> parsedResult = meta.type.descriptor->fromString(lineEdit->text().toStdString());
if (!parsedResult) return; if (!parsedResult) return;
inst->SetPropertyValue(propertyName, parsedResult.value()).expect(); inst->SetPropertyValue(propertyName, parsedResult.value()).expect();
model->setData(index, QString::fromStdString(parsedResult.value().ToString())); model->setData(index, QString::fromStdString(parsedResult.value().ToString()));
view->rebuildCompositeProperty(view->itemFromIndex(index), meta.type, parsedResult.value()); view->rebuildCompositeProperty(view->itemFromIndex(index), meta.type.descriptor, parsedResult.value());
} }
} }
}; };
@ -299,33 +305,33 @@ void PropertiesView::setSelected(std::optional<std::shared_ptr<Instance>> instan
PropertyMeta meta = inst->GetPropertyMeta(property).expect(); PropertyMeta meta = inst->GetPropertyMeta(property).expect();
Variant currentValue = inst->GetPropertyValue(property).expect(); Variant currentValue = inst->GetPropertyValue(property).expect();
if (meta.type == &CFrame::TYPE || meta.flags & PROP_HIDDEN) continue; if (meta.type.descriptor == &CFrame::TYPE || meta.flags & PROP_HIDDEN) continue;
QTreeWidgetItem* item = new QTreeWidgetItem; QTreeWidgetItem* item = new QTreeWidgetItem;
item->setFlags(item->flags() | Qt::ItemIsEditable | Qt::ItemIsSelectable); item->setFlags(item->flags() | Qt::ItemIsEditable | Qt::ItemIsSelectable);
item->setData(0, Qt::DisplayRole, QString::fromStdString(property)); item->setData(0, Qt::DisplayRole, QString::fromStdString(property));
if (meta.type == &BOOL_TYPE) { if (meta.type.descriptor == &BOOL_TYPE) {
item->setCheckState(1, (bool)currentValue.get<bool>() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); item->setCheckState(1, (bool)currentValue.get<bool>() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
} else if (meta.type == &Color3::TYPE) { } else if (meta.type.descriptor == &Color3::TYPE) {
Color3 color = currentValue.get<Color3>(); Color3 color = currentValue.get<Color3>();
item->setData(1, Qt::DecorationRole, QColor::fromRgbF(color.R(), color.G(), color.B())); item->setData(1, Qt::DecorationRole, QColor::fromRgbF(color.R(), color.G(), color.B()));
item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString())); item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString()));
} else if (meta.type == &Vector3::TYPE) { } else if (meta.type.descriptor == &Vector3::TYPE) {
Vector3 vector = currentValue.get<Vector3>(); Vector3 vector = currentValue.get<Vector3>();
item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString())); item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString()));
// } else if (meta.type == &CFrame::TYPE) { // } else if (meta.type.descriptor == &CFrame::TYPE) {
// Vector3 vector = currentValue.get<CFrame>().Position(); // Vector3 vector = currentValue.get<CFrame>().Position();
// item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString())); // item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString()));
} else { } else {
item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString())); item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString()));
} }
if (meta.type != &Color3::TYPE && (!meta.type->fromString || meta.flags & PROP_READONLY)) { if (meta.type.type == DATA_VALUE && meta.type.descriptor != &Color3::TYPE && (!meta.type.descriptor->fromString || meta.flags & PROP_READONLY)) {
item->setDisabled(true); item->setDisabled(true);
} }
rebuildCompositeProperty(item, meta.type, currentValue); rebuildCompositeProperty(item, meta.type.descriptor, currentValue);
propertyCategories[meta.category]->addChild(item); propertyCategories[meta.category]->addChild(item);
propertyCategories[meta.category]->setExpanded(true); propertyCategories[meta.category]->setExpanded(true);
@ -353,12 +359,12 @@ void PropertiesView::propertyChanged(QTreeWidgetItem *item, int column) {
std::string propertyName = item->data(0, Qt::DisplayRole).toString().toStdString(); std::string propertyName = item->data(0, Qt::DisplayRole).toString().toStdString();
PropertyMeta meta = inst->GetPropertyMeta(propertyName).expect(); PropertyMeta meta = inst->GetPropertyMeta(propertyName).expect();
if (meta.type == &BOOL_TYPE) { if (meta.type.descriptor == &BOOL_TYPE) {
inst->SetPropertyValue(propertyName, item->checkState(1) == Qt::Checked).expect(); inst->SetPropertyValue(propertyName, item->checkState(1) == Qt::Checked).expect();
} }
} }
void PropertiesView::rebuildCompositeProperty(QTreeWidgetItem *item, const TypeInfo* type, Variant value) { void PropertiesView::rebuildCompositeProperty(QTreeWidgetItem *item, const TypeDescriptor* type, Variant value) {
if (type == &Vector3::TYPE) { if (type == &Vector3::TYPE) {
// https://forum.qt.io/post/266837 // https://forum.qt.io/post/266837
foreach(auto i, item->takeChildren()) delete i; foreach(auto i, item->takeChildren()) delete i;
@ -393,7 +399,7 @@ void PropertiesView::onPropertyUpdated(std::shared_ptr<Instance> inst, std::stri
PropertyMeta meta = inst->GetPropertyMeta(property).expect(); PropertyMeta meta = inst->GetPropertyMeta(property).expect();
Variant currentValue = inst->GetPropertyValue(property).expect(); Variant currentValue = inst->GetPropertyValue(property).expect();
if (meta.type == &CFrame::TYPE) return; if (meta.type.descriptor == &CFrame::TYPE) return;
for (int categoryItemIdx = 0; categoryItemIdx < topLevelItemCount(); categoryItemIdx++) { for (int categoryItemIdx = 0; categoryItemIdx < topLevelItemCount(); categoryItemIdx++) {
QTreeWidgetItem* categoryItem = topLevelItem(categoryItemIdx); QTreeWidgetItem* categoryItem = topLevelItem(categoryItemIdx);
@ -402,27 +408,27 @@ void PropertiesView::onPropertyUpdated(std::shared_ptr<Instance> inst, std::stri
if (item->data(0, Qt::DisplayRole).toString().toStdString() != property) continue; if (item->data(0, Qt::DisplayRole).toString().toStdString() != property) continue;
if (meta.type == &BOOL_TYPE) { if (meta.type.descriptor == &BOOL_TYPE) {
// This is done because otherwise propertyChanged will catch this change erroneously // This is done because otherwise propertyChanged will catch this change erroneously
ignorePropertyUpdates = true; ignorePropertyUpdates = true;
item->setCheckState(1, (bool)currentValue.get<bool>() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); item->setCheckState(1, (bool)currentValue.get<bool>() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
ignorePropertyUpdates = false; ignorePropertyUpdates = false;
} else if (meta.type == &Color3::TYPE) { } else if (meta.type.descriptor == &Color3::TYPE) {
Color3 color = currentValue.get<Color3>(); Color3 color = currentValue.get<Color3>();
item->setData(1, Qt::DecorationRole, QColor::fromRgbF(color.R(), color.G(), color.B())); item->setData(1, Qt::DecorationRole, QColor::fromRgbF(color.R(), color.G(), color.B()));
item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString())); item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString()));
} else if (meta.type == &Vector3::TYPE) { } else if (meta.type.descriptor == &Vector3::TYPE) {
Vector3 vector = currentValue.get<Vector3>(); Vector3 vector = currentValue.get<Vector3>();
item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString())); item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString()));
} else { } else {
item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString())); item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString()));
} }
if (meta.type != &Color3::TYPE && (!meta.type->fromString || meta.flags & PROP_READONLY)) { if (meta.type.type == DATA_VALUE && meta.type.descriptor != &Color3::TYPE && (!meta.type.descriptor->fromString || meta.flags & PROP_READONLY)) {
item->setDisabled(true); item->setDisabled(true);
} }
rebuildCompositeProperty(item, meta.type, currentValue); rebuildCompositeProperty(item, meta.type.descriptor, currentValue);
return; return;
} }

View file

@ -15,7 +15,7 @@ class PropertiesView : public QTreeWidget {
std::weak_ptr<Instance> currentInstance; std::weak_ptr<Instance> currentInstance;
void propertyChanged(QTreeWidgetItem *item, int column); void propertyChanged(QTreeWidgetItem *item, int column);
void activateProperty(QTreeWidgetItem *item, int column); void activateProperty(QTreeWidgetItem *item, int column);
void rebuildCompositeProperty(QTreeWidgetItem *item, const TypeInfo*, Variant); void rebuildCompositeProperty(QTreeWidgetItem *item, const TypeDescriptor*, Variant);
void onPropertyUpdated(std::shared_ptr<Instance> instance, std::string property, Variant newValue); void onPropertyUpdated(std::shared_ptr<Instance> instance, std::string property, Variant newValue);
friend PropertiesItemDelegate; friend PropertiesItemDelegate;