diff --git a/engine/src/components/component.cpp b/engine/src/components/component.cpp index fae941a05..b803794bb 100644 --- a/engine/src/components/component.cpp +++ b/engine/src/components/component.cpp @@ -180,15 +180,19 @@ inline void trimmType(TString &type, bool &isArray) { } } -Object *loadObjectHelper(const Variant &value, const MetaObject *meta) { +Object *loadObjectHelper(const Variant &value) { Object *object = nullptr; - if(meta->canCastTo(gResource)) { - object = Engine::loadResource(value.toString()); - } else { - uint32_t uuid = value.toInt(); - if(uuid != 0) { - object = Engine::findObject(uuid); - } + switch(value.type()) { + case MetaType::STRING: { + object = Engine::loadResource(value.toString()); + } break; + case MetaType::INTEGER: { + uint32_t uuid = value.toInt(); + if(uuid != 0) { + object = Engine::findObject(uuid); + } + } break; + default: break; } return object; @@ -229,18 +233,20 @@ void Component::loadUserData(const VariantMap &data) { if(isArray) { VariantList list; for(auto it : field->second.toList()) { - Object *object = loadObjectHelper(it, factory->first); + Object *object = loadObjectHelper(it); if(object) { list.push_back(Variant(type, &object)); } } setProperty(it.first.data(), list); } else { - Object *object = loadObjectHelper(field->second, factory->first); + Object *object = loadObjectHelper(field->second); if(object) { setProperty(it.first.data(), Variant(type, &object)); } } + } else { + setProperty(it.first.data(), field->second); } } } @@ -299,6 +305,8 @@ VariantMap Component::saveUserData() const { Object *object = (value.data() == nullptr) ? nullptr : *(reinterpret_cast(value.data())); result[it.first] = saveObjectHelper(object, factory->first); } + } else if(isArray) { + result[it.first] = value; } } return result; diff --git a/modules/vms/angel/includes/angelsystem.h b/modules/vms/angel/includes/angelsystem.h index 625ca29ad..da6e27c51 100644 --- a/modules/vms/angel/includes/angelsystem.h +++ b/modules/vms/angel/includes/angelsystem.h @@ -52,10 +52,13 @@ class AngelSystem : public System { void bindMetaType(asIScriptEngine *engine, const MetaType::Table &table); void bindMetaObject(asIScriptEngine *engine, const TString &name, const MetaObject *meta); + MetaType::Table *metaType(const TString &typeName); + static void messageCallback(const asSMessageInfo *msg, void *param); private: std::unordered_map m_metaObjects; + std::unordered_map m_metaTypes; asIScriptEngine *m_scriptEngine; diff --git a/modules/vms/angel/includes/components/angelbehaviour.h b/modules/vms/angel/includes/components/angelbehaviour.h index 1aba06cd1..7af244d7f 100644 --- a/modules/vms/angel/includes/components/angelbehaviour.h +++ b/modules/vms/angel/includes/components/angelbehaviour.h @@ -52,7 +52,7 @@ class AngelBehaviour : public NativeBehaviour { void onReferenceDestroyed() override; Variant readProperty(const MetaProperty &property) const; - void writeProperty(const MetaProperty &property, const Variant value); + void writeProperty(const MetaProperty &property, const Variant &value); void methodCallEvent(MethodCallEvent *event) override; @@ -78,10 +78,11 @@ class AngelBehaviour : public NativeBehaviour { TString m_script; struct PropertyFields { - Object *object; - void *address; - bool isObject; - bool isScript; + Object *object = nullptr; + void *address = nullptr; + bool isObject = false; + bool isScript = false; + bool isArray = false; }; std::unordered_map m_propertyFields; diff --git a/modules/vms/angel/src/angelsystem.cpp b/modules/vms/angel/src/angelsystem.cpp index 1f9aee09a..f040aa123 100644 --- a/modules/vms/angel/src/angelsystem.cpp +++ b/modules/vms/angel/src/angelsystem.cpp @@ -95,13 +95,7 @@ AngelSystem::~AngelSystem() { deleteAllObjects(); - if(m_context) { - m_context->Release(); - } - - if(m_scriptModule) { - m_scriptModule->Discard(); - } + unload(); if(m_scriptEngine) { m_scriptEngine->ShutDownAndRelease(); @@ -117,8 +111,6 @@ bool AngelSystem::init() { int32_t r = m_scriptEngine->SetMessageCallback(asFUNCTION(messageCallback), nullptr, asCALL_CDECL); if(r >= 0) { - m_context = m_scriptEngine->CreateContext(); - registerClasses(m_scriptEngine); reload(); @@ -181,6 +173,8 @@ void AngelSystem::reload() { return; } + m_context = m_scriptEngine->CreateContext(); + if(m_script) { AngelStream stream(m_script->m_array); m_scriptModule->LoadByteCode(&stream); @@ -248,7 +242,7 @@ void AngelSystem::reload() { behaviour->loadUserData(data); } } else { - Log(Log::ERR) << __FUNCTION__ << "Filed to load a script"; + aError() << __FUNCTION__ << "Filed to load a script"; } } @@ -263,7 +257,7 @@ void *AngelSystem::execute(asIScriptObject *object, asIScriptFunction *func) { if(m_context->Execute() == asEXECUTION_EXCEPTION) { int column; m_context->GetExceptionLineNumber(&column); - Log(Log::ERR) << __FUNCTION__ << "Unhandled Exception:" << m_context->GetExceptionString() << m_context->GetExceptionFunction()->GetName() << "Line:" << column; + aError() << __FUNCTION__ << "Unhandled Exception:" << m_context->GetExceptionString() << m_context->GetExceptionFunction()->GetName() << "Line:" << column; } } else { return nullptr; @@ -305,13 +299,39 @@ MetaObject *AngelSystem::getMetaObject(asIScriptObject *object) { bool isProtected; info->GetProperty(i, &name, &typeId, &isPrivate, &isProtected); if(!isPrivate && !isProtected) { + TString typeName; uint32_t metaType = 0; if(typeId > asTYPEID_DOUBLE) { asITypeInfo *type = m_scriptEngine->GetTypeInfoById(typeId); if(type) { - metaType = MetaType::type(type->GetName()); - if(type->GetFlags() & asOBJ_REF) { - metaType++; + typeName = type->GetName(); + if(typeName == "array") { + typeId = type->GetSubTypeId(); + if(typeId > asTYPEID_DOUBLE) { + asITypeInfo *subType = type->GetSubType(); + typeName = TString(subType->GetName()) + "[]"; + } else { + // Implement array with base type + switch(typeId) { + case asTYPEID_VOID: metaType = MetaType::INVALID; break; + case asTYPEID_BOOL: typeName = "bool[]"; break; + case asTYPEID_INT8: + case asTYPEID_INT16: + case asTYPEID_INT32: + case asTYPEID_INT64: + case asTYPEID_UINT8: + case asTYPEID_UINT16: + case asTYPEID_UINT32: + case asTYPEID_UINT64: typeName = "int[]"; break; + case asTYPEID_FLOAT: + case asTYPEID_DOUBLE: typeName = "float[]"; break; + default: break; + } + } + } else { + if(type->GetFlags() & asOBJ_REF) { + typeName += '*'; + } } } } else { @@ -331,12 +351,18 @@ MetaObject *AngelSystem::getMetaObject(asIScriptObject *object) { default: break; } } - MetaType::Table *table = MetaType::table(metaType); - if(table) { - propertyTable.push_back({name, table, nullptr, nullptr, nullptr, nullptr, nullptr, - &Reader::read, - &Writer::write}); + const MetaType::Table *table = nullptr; + if(!typeName.isEmpty()) { + typeName.replace("string", "TString"); + + table = AngelSystem::metaType(typeName); + } else { + table = MetaType::table(metaType); } + + propertyTable.push_back({name, table, nullptr, nullptr, nullptr, nullptr, nullptr, + &Reader::read, + &Writer::write}); } } } @@ -388,11 +414,32 @@ void AngelSystem::unload() { for(uint32_t i = 0; i < m_scriptModule->GetObjectTypeCount(); i++) { asITypeInfo *info = m_scriptModule->GetObjectTypeByIndex(i); if(info && isBehaviour(info)) { - factoryRemove(info->GetName(), std::string(gUri) + info->GetName()); + factoryRemove(info->GetName(), TString(gUri) + info->GetName()); } } m_scriptModule->Discard(); + m_scriptModule = nullptr; } + + if(m_context) { + if(m_context->GetState() == asEXECUTION_ACTIVE) { + m_context->Abort(); + } + m_context->Release(); + m_context = nullptr; + } + + for(auto it : m_metaObjects) { + // need to delete props and methods as well + delete it.second; + } + m_metaObjects.clear(); + + for(auto it : m_metaTypes) { + delete []it.second->dynamicName; + delete it.second; + } + m_metaTypes.clear(); } Object *castTo(Object *ptr) { @@ -766,6 +813,24 @@ void AngelSystem::bindMetaObject(asIScriptEngine *engine, const TString &name, c } } +MetaType::Table *AngelSystem::metaType(const TString &typeName) { + MetaType::Table *table = MetaType::table(MetaType::type(typeName.data())); + if(table == nullptr) { + auto it = m_metaTypes.find(typeName); + if(it != m_metaTypes.end()) { + return it->second; + } else { + table = new MetaType::Table(); + table->dynamicName = new char[typeName.size() + 1]; + memcpy(table->dynamicName, typeName.data(), typeName.size() + 1); + + m_metaTypes[typeName] = table; + } + } + + return table; +} + void AngelSystem::messageCallback(const asSMessageInfo *msg, void *param) { PROFILE_FUNCTION(); diff --git a/modules/vms/angel/src/components/angelbehaviour.cpp b/modules/vms/angel/src/components/angelbehaviour.cpp index b927b3e96..39ec5c5e9 100644 --- a/modules/vms/angel/src/components/angelbehaviour.cpp +++ b/modules/vms/angel/src/components/angelbehaviour.cpp @@ -8,11 +8,11 @@ #include #include +#include #include "angelsystem.h" namespace { - const char *gResource("Resource"); const char *gGeneral("General"); }; @@ -58,29 +58,15 @@ void AngelBehaviour::createObject() { if(module) { asITypeInfo *type = module->GetTypeInfoByDecl(m_script.data()); if(type) { - int result = ptr->context()->PushState(); - TString stream = m_script + " @+" + m_script + "()"; - asIScriptFunction *func = type->GetFactoryByDecl(stream.data()); - asIScriptObject **obj = static_cast(ptr->execute(nullptr, func)); - if(obj != nullptr) { - asIScriptObject *object = *obj; - if(object) { - setScriptObject(object); - } else { - Log(Log::ERR) << __FUNCTION__ << "Can't create an object" << m_script; - } - if(result == 0) { - ptr->context()->PopState(); - if(object) { - object->AddRef(); - } - } + asIScriptObject *object = static_cast(ptr->module()->GetEngine()->CreateScriptObject(type)); + if(object) { + setScriptObject(object); } else { - Log(Log::ERR) << __FUNCTION__ << "Systen returned NULL during execution" << m_script; + aError() << __FUNCTION__ << "Systen returned NULL during execution" << m_script; } } } else { - Log(Log::ERR) << __FUNCTION__ << "The Script Module is NULL" << m_script; + aError() << __FUNCTION__ << "The Script Module is NULL" << m_script; } } @@ -123,19 +109,26 @@ void AngelBehaviour::setScriptObject(asIScriptObject *object) { info->GetProperty(i, &name, &typeId, &isPrivate, &isProtected); if(!isPrivate && !isProtected) { PropertyFields propertyFields; - propertyFields.isScript = false; - propertyFields.isObject = false; - propertyFields.object = nullptr; propertyFields.address = object->GetAddressOfProperty(i); if(typeId > asTYPEID_DOUBLE) { asITypeInfo *type = engine->GetTypeInfoById(typeId); if(type) { - auto factory = System::metaFactory(type->GetName()); + TString typeName(type->GetName()); + + if(typeName == "array") { + type = type->GetSubType(); + if(type) { + typeName = type->GetName(); + } + propertyFields.isArray = true; + } + + auto factory = System::metaFactory(typeName); if(factory) { propertyFields.isObject = true; } - if(type->GetFlags() & asOBJ_SCRIPT_OBJECT) { + if(type && type->GetFlags() & asOBJ_SCRIPT_OBJECT) { propertyFields.isScript = true; } } @@ -180,7 +173,7 @@ void AngelBehaviour::unregisterClassFactory(ObjectSystem *system) { VariantList AngelBehaviour::saveData() const { PROFILE_FUNCTION(); - return serializeData(AngelBehaviour::metaClass()); + return serializeData(metaObject()); } void AngelBehaviour::loadData(const VariantList &data) { @@ -188,24 +181,6 @@ void AngelBehaviour::loadData(const VariantList &data) { Object::loadData(data); } -inline void trimmType(std::string &type, bool &isArray) { - if(type.back() == '*') { - type.pop_back(); - while(type.back() == ' ') { - type.pop_back(); - } - } else if(type.back() == ']') { - type.pop_back(); - while(type.back() == ' ') { - type.pop_back(); - } - if(type.back() == '[') { - type.pop_back(); - isArray = true; - } - } -} - void AngelBehaviour::setType(const TString &type) { PROFILE_FUNCTION(); setScript(type); @@ -216,7 +191,7 @@ void AngelBehaviour::setSystem(ObjectSystem *system) { } void AngelBehaviour::scriptSlot() { - // Method placeholder for the all incoming signals + // Placeholder method for the all incoming signals } void AngelBehaviour::onReferenceDestroyed() { @@ -236,6 +211,64 @@ Variant AngelBehaviour::readProperty(const MetaProperty &property) const { auto it = m_propertyFields.find(property.name()); if(it != m_propertyFields.end()) { const PropertyFields &fields = it->second; + if(fields.isArray) { + CScriptArray *array = reinterpret_cast(fields.address); + + int typeId = array->GetElementTypeId(); + asITypeInfo *type = nullptr; + if(typeId > asTYPEID_DOUBLE) { + type = m_object->GetEngine()->GetTypeInfoById(typeId); + + if(type) { + if(TString(type->GetName()) == "string") { + typeId = MetaType::STRING; + } else { + typeId = MetaType::type(type->GetName()); + if(type->GetFlags() & asOBJ_REF) { + typeId++; + } + } + } + } else { + switch(typeId) { + case asTYPEID_VOID: typeId = MetaType::INVALID; break; + case asTYPEID_BOOL: typeId = MetaType::BOOLEAN; break; + case asTYPEID_INT8: + case asTYPEID_INT16: + case asTYPEID_INT32: + case asTYPEID_INT64: + case asTYPEID_UINT8: + case asTYPEID_UINT16: + case asTYPEID_UINT32: + case asTYPEID_UINT64: typeId = MetaType::INTEGER; break; + case asTYPEID_FLOAT: + case asTYPEID_DOUBLE: typeId = MetaType::FLOAT; break; + default: break; + } + } + + VariantList list; + for(int i = 0; i < array->GetSize(); i++) { + switch(typeId) { + case MetaType::BOOLEAN: list.push_back(Variant(*reinterpret_cast(array->At(i)))); break; + case MetaType::INTEGER: list.push_back(Variant(*reinterpret_cast(array->At(i)))); break; + case MetaType::FLOAT: list.push_back(Variant(*reinterpret_cast(array->At(i)))); break; + case MetaType::STRING: { + std::string *str = reinterpret_cast(array->At(i)); + if(str) { + list.push_back(TString(*str)); + } + } break; + default: { + if(type) { + void *ptr = *reinterpret_cast(array->At(i)); + list.push_back(Variant(typeId, &ptr)); + } + } break; + } + } + return list; + } if(fields.isScript) { if(fields.address) { AngelBehaviour *behaviour = nullptr; @@ -252,7 +285,7 @@ Variant AngelBehaviour::readProperty(const MetaProperty &property) const { return Variant(); } -void AngelBehaviour::writeProperty(const MetaProperty &property, const Variant value) { +void AngelBehaviour::writeProperty(const MetaProperty &property, const Variant &value) { PROFILE_FUNCTION(); auto it = m_propertyFields.find(property.name()); @@ -273,20 +306,56 @@ void AngelBehaviour::writeProperty(const MetaProperty &property, const Variant v } } if(fields.isObject) { - Object *object = nullptr; - if(value.type() == MetaType::INTEGER) { - uint32_t uuid = static_cast(value.toInt()); - if(uuid) { - object = Engine::findObject(uuid); + if(fields.isArray) { + CScriptArray *array = reinterpret_cast(fields.address); + array->Resize(0); + + for(auto &element : *(reinterpret_cast(value.data()))) { + Object *object = nullptr; + if(element.type() == MetaType::INTEGER) { + uint32_t uuid = static_cast(element.toInt()); + if(uuid) { + object = Engine::findObject(uuid); + } + } else { + object = (element.data() == nullptr) ? nullptr : *(reinterpret_cast(element.data())); + } + if(object) { + connect(object, _SIGNAL(destroyed()), this, _SLOT(onReferenceDestroyed())); + } + + array->InsertLast(element.data()); } + return; } else { - object = (value.data() == nullptr) ? nullptr : *(reinterpret_cast(value.data())); + Object *object = nullptr; + if(value.type() == MetaType::INTEGER) { + uint32_t uuid = static_cast(value.toInt()); + if(uuid) { + object = Engine::findObject(uuid); + } + } else { + object = (value.data() == nullptr) ? nullptr : *(reinterpret_cast(value.data())); + } + if(fields.object != object) { + disconnect(fields.object, _SIGNAL(destroyed()), this, _SLOT(onReferenceDestroyed())); + fields.object = object; + connect(fields.object, _SIGNAL(destroyed()), this, _SLOT(onReferenceDestroyed())); + } } - if(fields.object != object) { - disconnect(fields.object, _SIGNAL(destroyed()), this, _SLOT(onReferenceDestroyed())); - fields.object = object; - connect(fields.object, _SIGNAL(destroyed()), this, _SLOT(onReferenceDestroyed())); + } else if(fields.isArray) { + CScriptArray *array = reinterpret_cast(fields.address); + array->Resize(0); + + for(auto &element : *(reinterpret_cast(value.data()))) { + if(element.userType() == MetaType::STRING) { + std::string str = element.toString().toStdString(); + array->InsertLast(&str); + } else { + array->InsertLast(element.data()); + } } + return; } memcpy(fields.address, value.data(), MetaType(property.table()->type).size()); diff --git a/thirdparty/angelscript/modules/scriptarray/scriptarray.cpp b/thirdparty/angelscript/modules/scriptarray/scriptarray.cpp index ca3ec4771..aa916eced 100644 --- a/thirdparty/angelscript/modules/scriptarray/scriptarray.cpp +++ b/thirdparty/angelscript/modules/scriptarray/scriptarray.cpp @@ -560,7 +560,7 @@ void CScriptArray::SetValue(asUINT index, void *value) // At() will take care of the out-of-bounds checking, though // if called from the application then nothing will be done void *ptr = At(index); - if( ptr == 0 ) return; + if( ptr == 0 || value == nullptr) return; if ((subTypeId & ~asTYPEID_MASK_SEQNBR) && !(subTypeId & asTYPEID_OBJHANDLE)) { diff --git a/thirdparty/next/inc/core/metatype.h b/thirdparty/next/inc/core/metatype.h index 7e09d009c..4e5905cbd 100644 --- a/thirdparty/next/inc/core/metatype.h +++ b/thirdparty/next/inc/core/metatype.h @@ -76,6 +76,7 @@ class NEXT_LIBRARY_EXPORT MetaType { std::type_index const(*index)(); const char *name; int flags; + char *dynamicName; }; typedef bool (*converterCallback)(void *to, const void *from, const uint32_t fromType); diff --git a/thirdparty/next/src/core/astring.cpp b/thirdparty/next/src/core/astring.cpp index 617a2195f..90103436a 100644 --- a/thirdparty/next/src/core/astring.cpp +++ b/thirdparty/next/src/core/astring.cpp @@ -224,7 +224,7 @@ TString &TString::removeFirst() { } TString &TString::removeLast() { - m_data.erase(m_data.end() - 1); + m_data.pop_back(); return *this; } diff --git a/thirdparty/next/src/core/metatype.cpp b/thirdparty/next/src/core/metatype.cpp index 463c5aea5..b3c78873b 100644 --- a/thirdparty/next/src/core/metatype.cpp +++ b/thirdparty/next/src/core/metatype.cpp @@ -447,7 +447,10 @@ MetaType::MetaType(const Table *table) : */ const char *MetaType::name() const { PROFILE_FUNCTION(); - return m_table->name; + if(m_table->name) { + return m_table->name; + } + return m_table->dynamicName; } /*! Returns the size of type. diff --git a/worldeditor/src/screens/objecthierarchy/objecthierarchymodel.h b/worldeditor/src/screens/objecthierarchy/objecthierarchymodel.h index 8f8a36500..874940dac 100644 --- a/worldeditor/src/screens/objecthierarchy/objecthierarchymodel.h +++ b/worldeditor/src/screens/objecthierarchy/objecthierarchymodel.h @@ -123,7 +123,7 @@ class ObjectsFilter : public QSortFilterProxyModel { }; struct ObjectData { - std::string type; + TString type; Scene *scene = nullptr; Actor *actor = nullptr; Component *component = nullptr; diff --git a/worldeditor/src/screens/propertyedit/custom/array/arrayedit.cpp b/worldeditor/src/screens/propertyedit/custom/array/arrayedit.cpp index 28d9ee850..a3f9bbd3e 100644 --- a/worldeditor/src/screens/propertyedit/custom/array/arrayedit.cpp +++ b/worldeditor/src/screens/propertyedit/custom/array/arrayedit.cpp @@ -2,16 +2,16 @@ #include "ui_arrayedit.h" #include -#include -#include #include "arrayelement.h" +#include "../../property.h" ArrayEdit::ArrayEdit(QWidget *parent) : PropertyEdit(parent), ui(new Ui::ArrayEdit), - m_dynamic(false), - m_height(0) { + m_height(0), + metaType(0), + m_dynamic(false) { ui->setupUi(this); ui->lineEdit->setValidator(new QIntValidator(0, INT32_MAX, this)); @@ -80,14 +80,42 @@ void ArrayEdit::setObject(Object *object, const TString &name) { m_dynamic = true; } } + } else { + MetaProperty property = meta->property(index); + m_typeName = TString(property.type().name()); + + bool isArray = false; + Property::trimmType(m_typeName, isArray); + + metaType = MetaType::type(m_typeName.data()); + auto factory = Engine::metaFactory(m_typeName); + if(factory) { + metaType++; + } } } void ArrayEdit::addOne() { if(m_list.isEmpty()) { if(m_object) { - m_list.push_back(QVariant()); - m_object->setProperty(m_propertyName.data(), { Variant() }); + Variant value; + switch(metaType) { + case MetaType::BOOLEAN: value = Variant(false); break; + case MetaType::INTEGER: value = Variant(0); break; + case MetaType::FLOAT: value = Variant(0.0f); break; + case MetaType::STRING: value = Variant(TString()); break; + case MetaType::VECTOR2: value = Variant(Vector2()); break; + case MetaType::VECTOR3: value = Variant(Vector3()); break; + case MetaType::VECTOR4: value = Variant(Vector4()); break; + default: { + void *ptr = nullptr; + value = Variant(metaType, &ptr); + } break; + } + + m_list.push_back(Property::qVariant(value, TString(), m_typeName, m_object)); + VariantList list = { value }; + m_object->setProperty(m_propertyName.data(), list); } } else { m_list.push_back(m_list.back()); diff --git a/worldeditor/src/screens/propertyedit/custom/array/arrayedit.h b/worldeditor/src/screens/propertyedit/custom/array/arrayedit.h index a2ebe329d..d9c6f9839 100644 --- a/worldeditor/src/screens/propertyedit/custom/array/arrayedit.h +++ b/worldeditor/src/screens/propertyedit/custom/array/arrayedit.h @@ -40,8 +40,12 @@ private slots: QList m_editors; + TString m_typeName; + int m_height; + int metaType; + bool m_dynamic; }; diff --git a/worldeditor/src/screens/propertyedit/custom/objectselect/objectselect.cpp b/worldeditor/src/screens/propertyedit/custom/objectselect/objectselect.cpp index a0e67e4a7..1afb93f11 100644 --- a/worldeditor/src/screens/propertyedit/custom/objectselect/objectselect.cpp +++ b/worldeditor/src/screens/propertyedit/custom/objectselect/objectselect.cpp @@ -76,7 +76,7 @@ void ObjectSelect::setTemplateData(const Template &data) { QString name("None"); TString path = AssetManager::instance()->guidToPath(m_templateData.path); if(!path.isEmpty()) { - name = QString("%1 (%2)").arg(QFileInfo(path.data()).baseName(), m_templateData.type.data()); + name = QFileInfo(path.data()).baseName(); m_icon->setIcon(QPixmap::fromImage(AssetManager::instance()->icon(path.data()))); } else { m_icon->setIcon(QIcon()); @@ -84,7 +84,8 @@ void ObjectSelect::setTemplateData(const Template &data) { name = "Ivalid"; } } - ui->lineEdit->setText(name); + + ui->lineEdit->setText(QString("%1 (%2)").arg(name, m_templateData.type.data())); } void ObjectSelect::onDialog() { @@ -93,7 +94,7 @@ void ObjectSelect::onDialog() { if(!m_asset) { sBrowser->onSetRootObject(m_objectData.scene); - sBrowser->setTypeFilter(m_objectData.type.c_str()); + sBrowser->setTypeFilter(m_objectData.type.data()); Object *object = m_objectData.actor; if(m_objectData.component != nullptr) { object = m_objectData.component->actor(); @@ -118,7 +119,7 @@ void ObjectSelect::onComponentSelected(Object *object) { Actor *actor = dynamic_cast(object); if(actor) { const MetaObject *meta = actor->metaObject(); - if(meta->canCastTo(m_objectData.type.c_str())) { + if(meta->canCastTo(m_objectData.type.data())) { m_objectData.actor = actor; } else { m_objectData.component = actor->component(m_objectData.type); diff --git a/worldeditor/src/screens/propertyedit/property.cpp b/worldeditor/src/screens/propertyedit/property.cpp index 119696a5c..28ea94de2 100644 --- a/worldeditor/src/screens/propertyedit/property.cpp +++ b/worldeditor/src/screens/propertyedit/property.cpp @@ -30,24 +30,6 @@ namespace { const char *gEnabled("enabled"); } -inline void trimmType(std::string &type, bool &isArray) { - if(type.back() == '*') { - type.pop_back(); - while(type.back() == ' ') { - type.pop_back(); - } - } else if(type.back() == ']') { - type.pop_back(); - while(type.back() == ' ') { - type.pop_back(); - } - if(type.back() == '[') { - type.pop_back(); - isArray = true; - } - } -} - Property::Property(const TString &name, Property *parent, bool root) : QObject(parent), m_nextObject(nullptr), @@ -71,7 +53,7 @@ void Property::setPropertyObject(Object *propertyObject) { m_name += " (Invalid)"; } - m_readOnly = hasTag(gReadOnlyTag); + m_readOnly = hasTag(m_hints, gReadOnlyTag); if(m_root) { const MetaObject *meta = m_nextObject->metaObject(); @@ -103,7 +85,7 @@ QVariant Property::value(int role) const { if(index > -1) { const MetaProperty property(meta->property(index)); - return qVariant(property.read(m_nextObject), property.type().name(), m_nextObject); + return qVariant(property.read(m_nextObject), m_hints, property.type().name(), m_nextObject); } else { // Dynamic property Variant value = m_nextObject->property(qPrintable(objectName())); TString typeName; @@ -111,7 +93,7 @@ QVariant Property::value(int role) const { typeName = MetaType::name(value.userType()); } - return qVariant(value, typeName, m_nextObject); + return qVariant(value, m_hints, typeName, m_nextObject); } } } @@ -128,10 +110,15 @@ void Property::setValue(const QVariant &value) { Variant target; if(index > -1) { MetaProperty property(meta->property(index)); - target = aVariant(value, current, property); + + TString typeName = MetaType::name(current.userType()); + if(property.isValid()) { + typeName = property.type().name(); + } + + target = aVariant(value, current.userType(), typeName); } else { - MetaProperty property({}); - target = aVariant(value, current, property); + target = aVariant(value, current.userType(), TString()); } if(target != current) { @@ -270,19 +257,19 @@ void Property::onEditorDestoyed() { m_editor = nullptr; } -QVariant Property::qVariant(const Variant &value, const TString &typeName, Object *object) const { +QVariant Property::qVariant(const Variant &value, const TString &hints, const TString &typeName, Object *object) { if(!value.isValid()) { return QVariant(); } - TString editor(propertyTag(gEditorTag)); + TString editor(propertyTag(hints, gEditorTag)); switch(value.userType()) { case MetaType::BOOLEAN: { return QVariant(value.toBool()); } case MetaType::INTEGER: { - TString enumProperty = propertyTag(gEnumTag); + TString enumProperty = propertyTag(hints, gEnumTag); int32_t intValue = value.toInt(); if(editor == gAxises) { @@ -309,7 +296,7 @@ QVariant Property::qVariant(const Variant &value, const TString &typeName, Objec } else if(editor == gLocale) { return QVariant::fromValue(QLocale(str.data())); } else if(editor == gAsset) { - return QVariant::fromValue(Template(str, propertyTag(gTypeTag))); + return QVariant::fromValue(Template(str, propertyTag(hints, gTypeTag))); } return QVariant(str.data()); } @@ -337,31 +324,31 @@ QVariant Property::qVariant(const Variant &value, const TString &typeName, Objec } bool isArray = false; - std::string typeNameTrimmed = typeName.toStdString(); + TString typeNameTrimmed = typeName; trimmType(typeNameTrimmed, isArray); if(isArray) { QVariantList result; for(auto &it : *(reinterpret_cast(value.data()))) { - result << qObjectVariant(it, typeNameTrimmed, editor); + result << qVariant(it, hints, typeNameTrimmed, object); } return result; } - return qObjectVariant(value, typeNameTrimmed, editor); + return qObjectVariant(value, typeNameTrimmed, editor, object); } -QVariant Property::qObjectVariant(const Variant &value, const std::string &typeName, const TString &editor) const { +QVariant Property::qObjectVariant(const Variant &value, const TString &typeName, const TString &editor, Object *object) { auto factory = System::metaFactory(typeName); if(factory) { - Object *object = (value.data() == nullptr) ? nullptr : *(reinterpret_cast(value.data())); + Object *objectValue = (value.data() == nullptr) ? nullptr : *(reinterpret_cast(value.data())); if(factory->first->canCastTo(gResource) || (editor == gAsset)) { - return QVariant::fromValue(Template(Engine::reference(object), MetaType::name(value.userType()))); + return QVariant::fromValue(Template(Engine::reference(objectValue), MetaType::name(value.userType()))); } else { Scene *scene = nullptr; - Actor *actor = dynamic_cast(object); - Component *component = dynamic_cast(object); + Actor *actor = dynamic_cast(objectValue); + Component *component = dynamic_cast(objectValue); if(actor) { scene = actor->scene(); @@ -370,11 +357,11 @@ QVariant Property::qObjectVariant(const Variant &value, const std::string &typeN } if(scene == nullptr) { - Actor *nextActor = dynamic_cast(m_nextObject); + Actor *nextActor = dynamic_cast(object); if(nextActor) { scene = nextActor->scene(); } else { - Component *nextActorComp = dynamic_cast(m_nextObject); + Component *nextActorComp = dynamic_cast(object); if(nextActorComp) { scene = nextActorComp->scene(); } @@ -394,18 +381,18 @@ QVariant Property::qObjectVariant(const Variant &value, const std::string &typeN return QVariant(); } -Variant Property::aVariant(const QVariant &value, const Variant ¤t, const MetaProperty &property) { - if(!current.isValid()) { - return current; +Variant Property::aVariant(const QVariant &value, const uint32_t type, const TString &typeName) { + if(type == 0) { + return Variant(); } - TString editor(propertyTag(gEditorTag)); + TString editor(propertyTag(m_hints, gEditorTag)); - switch(current.userType()) { + switch(type) { case MetaType::BOOLEAN: { return Variant(value.toBool()); } case MetaType::INTEGER: { - TString enumProperty = propertyTag(gEnumTag); + TString enumProperty = propertyTag(m_hints, gEnumTag); if(!enumProperty.isEmpty()) { Enum enumValue = value.value(); return Variant(enumValue.m_value); @@ -444,32 +431,25 @@ Variant Property::aVariant(const QVariant &value, const Variant ¤t, const } bool isArray = false; - std::string typeName = MetaType::name(current.userType()); - if(property.isValid()) { - typeName = property.type().name(); - } - trimmType(typeName, isArray); + TString trimmedTypeName = typeName; + trimmType(trimmedTypeName, isArray); if(isArray) { VariantList result; + uint32_t userType = MetaType::type(trimmedTypeName.data()); + if(userType > MetaType::USERTYPE) { + userType++; + } + for(auto &it : value.toList()) { - uint32_t usertType = current.userType(); - if(usertType == MetaType::VARIANTLIST) { - VariantList &list = *(reinterpret_cast(current.data())); - if(!list.empty()) { - usertType = list.front().userType(); - } else { - usertType = MetaType::type(typeName.c_str()) + 1; - } - } - result.push_back(aObjectVariant(it, usertType, typeName)); + result.push_back(aVariant(it, userType, trimmedTypeName)); } return result; } - return aObjectVariant(value, current.userType(), typeName); + return aObjectVariant(value, type, typeName); } Variant Property::aObjectVariant(const QVariant &value, uint32_t type, const TString &typeName) { @@ -501,8 +481,8 @@ Variant Property::aObjectVariant(const QVariant &value, uint32_t type, const TSt return Variant(); } -TString Property::propertyTag(const TString &tag) const { - StringList list(m_hints.split(',')); +TString Property::propertyTag(const TString &hints, const TString &tag) { + StringList list(hints.split(',')); for(TString it : list) { int index = it.indexOf(tag); if(index > -1) { @@ -512,8 +492,8 @@ TString Property::propertyTag(const TString &tag) const { return TString(); } -bool Property::hasTag(const TString &tag) const { - StringList list(m_hints.split(',')); +bool Property::hasTag(const TString &hints, const TString &tag) { + StringList list(hints.split(',')); for(TString it : list) { int index = it.indexOf(tag); if(index > -1) { @@ -522,3 +502,21 @@ bool Property::hasTag(const TString &tag) const { } return false; } + +void Property::trimmType(TString &type, bool &isArray) { + if(type.back() == '*') { + type.removeLast(); + while(type.back() == ' ') { + type.removeLast(); + } + } else if(type.back() == ']') { + type.removeLast(); + while(type.back() == ' ') { + type.removeLast(); + } + if(type.back() == '[') { + type.removeLast(); + isArray = true; + } + } +} diff --git a/worldeditor/src/screens/propertyedit/property.h b/worldeditor/src/screens/propertyedit/property.h index 5ab951f95..fe3432877 100644 --- a/worldeditor/src/screens/propertyedit/property.h +++ b/worldeditor/src/screens/propertyedit/property.h @@ -59,8 +59,13 @@ class Property : public QObject { virtual bool isChecked() const; virtual void setChecked(bool value); - TString propertyTag(const TString &tag) const; - bool hasTag(const TString &tag) const; + static TString propertyTag(const TString &hints, const TString &tag); + static bool hasTag(const TString &hints, const TString &tag); + + static void trimmType(TString &type, bool &isArray); + + static QVariant qVariant(const Variant &value, const TString &typeName, const TString &hints, Object *object); + static QVariant qObjectVariant(const Variant &value, const TString &typeName, const TString &editor, Object *object); signals: void propertyChanged(const Object::ObjectList &objects, const TString &property, Variant value); @@ -72,10 +77,7 @@ protected slots: protected: virtual QWidget *createEditor(QWidget *parent) const; - QVariant qVariant(const Variant &value, const TString &typeName, Object *object) const; - QVariant qObjectVariant(const Variant &value, const std::string &typeName, const TString &editor) const; - - Variant aVariant(const QVariant &value, const Variant ¤t, const MetaProperty &property); + Variant aVariant(const QVariant &value, uint32_t type, const TString &typeName); Variant aObjectVariant(const QVariant &value, uint32_t type, const TString &typeName); protected: @@ -83,6 +85,7 @@ protected slots: TString m_hints; TString m_name; + mutable TString m_typeNameTrimmed; mutable QWidget *m_editor;