From 89672ea0ab4e4632bd01b612e11cf430195199b8 Mon Sep 17 00:00:00 2001 From: Areloch Date: Thu, 2 Jun 2016 22:40:29 -0500 Subject: [PATCH] Hooks the component fields back into the inspector so they are registered as proper fields of their types, as opposed to the regular string-only dynamic fields. --- Engine/source/T3D/components/component.cpp | 16 +- .../T3D/components/render/meshComponent.cpp | 2 + Engine/source/T3D/entity.cpp | 2 +- .../source/gui/controls/guiTreeViewCtrl.cpp | 2 +- Engine/source/gui/editor/guiInspector.cpp | 12 + .../gui/editor/inspector/componentGroup.cpp | 260 ++++++++++++++++++ .../gui/editor/inspector/componentGroup.h | 70 +++++ .../gui/editor/inspector/dynamicGroup.cpp | 14 + 8 files changed, 369 insertions(+), 9 deletions(-) create mode 100644 Engine/source/gui/editor/inspector/componentGroup.cpp create mode 100644 Engine/source/gui/editor/inspector/componentGroup.h diff --git a/Engine/source/T3D/components/component.cpp b/Engine/source/T3D/components/component.cpp index 607df5e30..47784d4b2 100644 --- a/Engine/source/T3D/components/component.cpp +++ b/Engine/source/T3D/components/component.cpp @@ -410,20 +410,22 @@ void Component::addComponentField(const char *fieldName, const char *desc, const S32 fieldTypeMask = -1; StringTableEntry fieldType = StringTable->insert(type); - if (fieldType == StringTable->insert("TypeS32")) + if (fieldType == StringTable->insert("int")) fieldTypeMask = TypeS32; - else if (fieldType == StringTable->insert("TypeF32")) + else if (fieldType == StringTable->insert("float")) fieldTypeMask = TypeF32; - else if (fieldType == StringTable->insert("TypePoint3F")) + else if (fieldType == StringTable->insert("vector")) fieldTypeMask = TypePoint3F; - else if (fieldType == StringTable->insert("TypeMaterialName")) + else if (fieldType == StringTable->insert("material")) fieldTypeMask = TypeMaterialName; - else if (fieldType == StringTable->insert("TypeImageFilename")) + else if (fieldType == StringTable->insert("image")) fieldTypeMask = TypeImageFilename; - else if (fieldType == StringTable->insert("TypeShapeFilename")) + else if (fieldType == StringTable->insert("shape")) fieldTypeMask = TypeShapeFilename; - else if (fieldType == StringTable->insert("TypeBool")) + else if (fieldType == StringTable->insert("bool")) fieldTypeMask = TypeBool; + else if (fieldType == StringTable->insert("object")) + fieldTypeMask = TypeSimObjectPtr; else fieldTypeMask = TypeString; diff --git a/Engine/source/T3D/components/render/meshComponent.cpp b/Engine/source/T3D/components/render/meshComponent.cpp index 50c8f7506..6f4835666 100644 --- a/Engine/source/T3D/components/render/meshComponent.cpp +++ b/Engine/source/T3D/components/render/meshComponent.cpp @@ -115,6 +115,8 @@ void MeshComponent::onRemove() { Parent::onRemove(); + mMeshAsset.clear(); + SAFE_DELETE(mShapeInstance); } diff --git a/Engine/source/T3D/entity.cpp b/Engine/source/T3D/entity.cpp index f5ca1adb1..00ecedad0 100644 --- a/Engine/source/T3D/entity.cpp +++ b/Engine/source/T3D/entity.cpp @@ -230,7 +230,7 @@ bool Entity::onAdd() void Entity::onRemove() { - clearComponents(false); + clearComponents(true); removeFromScene(); diff --git a/Engine/source/gui/controls/guiTreeViewCtrl.cpp b/Engine/source/gui/controls/guiTreeViewCtrl.cpp index f8bc41c2e..a5e833a19 100644 --- a/Engine/source/gui/controls/guiTreeViewCtrl.cpp +++ b/Engine/source/gui/controls/guiTreeViewCtrl.cpp @@ -3798,7 +3798,7 @@ void GuiTreeViewCtrl::onMouseDown(const GuiEvent & event) if (item->isInspectorData()) { Entity* e = dynamic_cast(item->getObject()); - if (item->mScriptInfo.mText != StringTable->insert("Components")) + //if (item->mScriptInfo.mText != StringTable->insert("Components")) { Entity* e = dynamic_cast(item->getObject()); if (e) diff --git a/Engine/source/gui/editor/guiInspector.cpp b/Engine/source/gui/editor/guiInspector.cpp index 811441e2d..565597571 100644 --- a/Engine/source/gui/editor/guiInspector.cpp +++ b/Engine/source/gui/editor/guiInspector.cpp @@ -32,6 +32,7 @@ #ifdef TORQUE_EXPERIMENTAL_EC #include "gui/editor/inspector/entityGroup.h" #include "gui/editor/inspector/mountingGroup.h" +#include "gui/editor/inspector/componentGroup.h" #endif IMPLEMENT_CONOBJECT(GuiInspector); @@ -609,6 +610,17 @@ void GuiInspector::refresh() addObject(mounting); } } + + if (mTargets.first()->getClassRep()->isSubclassOf("Component")) + { + //Build the component field groups as the component describes it + Component* comp = dynamic_cast(mTargets.first().getPointer()); + + GuiInspectorComponentGroup *compGroup = new GuiInspectorComponentGroup("Component Fields", this); + compGroup->registerObject(); + mGroups.push_back(compGroup); + addObject(compGroup); + } #endif // Create the inspector groups for static fields. diff --git a/Engine/source/gui/editor/inspector/componentGroup.cpp b/Engine/source/gui/editor/inspector/componentGroup.cpp new file mode 100644 index 000000000..6dd6f379c --- /dev/null +++ b/Engine/source/gui/editor/inspector/componentGroup.cpp @@ -0,0 +1,260 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "gui/buttons/guiIconButtonCtrl.h" +#include "gui/editor/guiInspector.h" +#include "gui/editor/inspector/componentGroup.h" +#include "core/strings/stringUnit.h" +#include "T3D/components/component.h" +#include "gui/editor/inspector/field.h" + +#include "console/engineAPI.h" + +IMPLEMENT_CONOBJECT(GuiInspectorComponentGroup); + +ConsoleDocClass(GuiInspectorComponentGroup, + "@brief Used to inspect an object's FieldDictionary (dynamic fields) instead " + "of regular persistent fields.\n\n" + "Editor use only.\n\n" + "@internal" + ); + +GuiInspectorComponentGroup::GuiInspectorComponentGroup(StringTableEntry groupName, SimObjectPtr parent) +: GuiInspectorGroup(groupName, parent) +{ + /*mNeedScroll=false;*/ +}; + +bool GuiInspectorComponentGroup::onAdd() +{ + if (!Parent::onAdd()) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// GuiInspectorComponentGroup - add custom controls +//----------------------------------------------------------------------------- +bool GuiInspectorComponentGroup::createContent() +{ + if(!Parent::createContent()) + return false; + + Con::evaluatef("%d.stack = %d;", this->getId(), mStack->getId()); + + Con::executef(this, "createContent"); + + return true; +} + +//----------------------------------------------------------------------------- +// GuiInspectorComponentGroup - inspectGroup override +//----------------------------------------------------------------------------- +bool GuiInspectorComponentGroup::inspectGroup() +{ + // We can't inspect a group without a target! + if (!mParent || !mParent->getNumInspectObjects()) + return false; + + // to prevent crazy resizing, we'll just freeze our stack for a sec.. + mStack->freeze(true); + + mStack->clear(); + + bool bNoGroup = false; + + // Un-grouped fields are all sorted into the 'general' group + if (dStricmp(mCaption, "General") == 0) + bNoGroup = true; + + // Just delete all fields and recreate them (like the dynamicGroup) + // because that makes creating controls for array fields a lot easier + clearFields(); + + bool bNewItems = false; + bool bMakingArray = false; + GuiStackControl *pArrayStack = NULL; + GuiRolloutCtrl *pArrayRollout = NULL; + bool bGrabItems = false; + + Component* comp = dynamic_cast(getInspector()->getInspectObject(0)); + + //if this isn't a component, what are we even doing here? + if (!comp) + return false; + + for (U32 i = 0; i < comp->getComponentFieldCount(); i++) + { + ComponentField* field = comp->getComponentField(i); + + bNewItems = true; + + GuiInspectorField *fieldGui = constructField(field->mFieldType); + if (fieldGui == NULL) + fieldGui = new GuiInspectorField(); + + fieldGui->init(mParent, this); + + AbstractClassRep::Field *refField; + //check statics + refField = const_cast(comp->findField(field->mFieldName)); + if (!refField) + { + //check dynamics + SimFieldDictionary* fieldDictionary = comp->getFieldDictionary(); + SimFieldDictionaryIterator itr(fieldDictionary); + + while (*itr) + { + SimFieldDictionary::Entry* entry = *itr; + if (entry->slotName == field->mFieldName) + { + AbstractClassRep::Field f; + f.pFieldname = StringTable->insert(field->mFieldName); + + if (field->mFieldDescription) + f.pFieldDocs = field->mFieldDescription; + + f.type = field->mFieldType; + f.offset = -1; + f.elementCount = 1; + f.validator = NULL; + f.flag = 0; //change to be the component type + + f.setDataFn = &defaultProtectedSetFn; + f.getDataFn = &defaultProtectedGetFn; + f.writeDataFn = &defaultProtectedWriteFn; + + if (!dStrcmp(field->mGroup, "")) + f.pGroupname = "Component"; + else + f.pGroupname = field->mGroup; + + ConsoleBaseType* conType = ConsoleBaseType::getType(field->mFieldType); + AssertFatal(conType, "ConsoleObject::addField - invalid console type"); + f.table = conType->getEnumTable(); + + tempFields.push_back(f); + + refField = &f; + + break; + } + ++itr; + } + } + + if (!refField) + continue; + + fieldGui->setInspectorField(&tempFields[tempFields.size() - 1]); + + if (fieldGui->registerObject()) + { +#ifdef DEBUG_SPEW + Platform::outputDebugString("[GuiInspectorGroup] Adding field '%s'", + field->pFieldname); +#endif + + mChildren.push_back(fieldGui); + mStack->addObject(fieldGui); + } + else + { + SAFE_DELETE(fieldGui); + } + } + + mStack->freeze(false); + mStack->updatePanes(); + + // If we've no new items, there's no need to resize anything! + if (bNewItems == false && !mChildren.empty()) + return true; + + sizeToContents(); + + setUpdate(); + + return true; +} + +void GuiInspectorComponentGroup::updateAllFields() +{ + // We overload this to just reinspect the group. + inspectGroup(); +} + +void GuiInspectorComponentGroup::onMouseMove(const GuiEvent &event) +{ + //mParent->mOverDivider = false; +} +ConsoleMethod(GuiInspectorComponentGroup, inspectGroup, bool, 2, 2, "Refreshes the dynamic fields in the inspector.") +{ + return object->inspectGroup(); +} + +void GuiInspectorComponentGroup::clearFields() +{ +} + +SimFieldDictionary::Entry* GuiInspectorComponentGroup::findDynamicFieldInDictionary(StringTableEntry fieldName) +{ + SimFieldDictionary * fieldDictionary = mParent->getInspectObject()->getFieldDictionary(); + + for (SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr) + { + SimFieldDictionary::Entry * entry = (*ditr); + + if (entry->slotName == fieldName) + return entry; + } + + return NULL; +} + +void GuiInspectorComponentGroup::addDynamicField() +{ +} + +AbstractClassRep::Field* GuiInspectorComponentGroup::findObjectBehaviorField(Component* target, String fieldName) +{ + AbstractClassRep::FieldList& fieldList = target->getClassRep()->mFieldList; + for (AbstractClassRep::FieldList::iterator itr = fieldList.begin(); + itr != fieldList.end(); ++itr) + { + AbstractClassRep::Field* field = &(*itr); + String fldNm(field->pFieldname); + if (fldNm == fieldName) + return field; + } + return NULL; +} +ConsoleMethod(GuiInspectorComponentGroup, addDynamicField, void, 2, 2, "obj.addDynamicField();") +{ + object->addDynamicField(); +} + +ConsoleMethod(GuiInspectorComponentGroup, removeDynamicField, void, 3, 3, "") +{ +} diff --git a/Engine/source/gui/editor/inspector/componentGroup.h b/Engine/source/gui/editor/inspector/componentGroup.h new file mode 100644 index 000000000..34b748c98 --- /dev/null +++ b/Engine/source/gui/editor/inspector/componentGroup.h @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef GUI_INSPECTOR_COMPONENT_GROUP_H +#define GUI_INSPECTOR_COMPONENT_GROUP_H + +#include "gui/editor/inspector/group.h" +#include "console/simFieldDictionary.h" +#include "T3D/components/component.h" +#include "gui/controls/guiPopUpCtrlEx.h" + +class GuiInspectorComponentGroup : public GuiInspectorGroup +{ +private: + typedef GuiInspectorGroup Parent; + GuiControl* mAddCtrl; + + Vector tempFields; + +public: + DECLARE_CONOBJECT(GuiInspectorComponentGroup); + GuiInspectorComponentGroup() { /*mNeedScroll=false;*/ }; + GuiInspectorComponentGroup(StringTableEntry groupName, SimObjectPtr parent); + + //----------------------------------------------------------------------------- + // inspectGroup is overridden in GuiInspectorComponentGroup to inspect an + // objects FieldDictionary (dynamic fields) instead of regular persistent + // fields. + virtual bool onAdd(); + bool inspectGroup(); + virtual void updateAllFields(); + + void onMouseMove(const GuiEvent &event); + + // For scriptable dynamic field additions + void addDynamicField(); + + // Clear our fields (delete them) + void clearFields(); + + // Find an already existent field by name in the dictionary + virtual SimFieldDictionary::Entry* findDynamicFieldInDictionary(StringTableEntry fieldName); + + AbstractClassRep::Field* findObjectBehaviorField(Component* target, String fieldName); +protected: + // create our inner controls when we add + virtual bool createContent(); + +}; + +#endif diff --git a/Engine/source/gui/editor/inspector/dynamicGroup.cpp b/Engine/source/gui/editor/inspector/dynamicGroup.cpp index ef5d98b3a..78d8c4bd8 100644 --- a/Engine/source/gui/editor/inspector/dynamicGroup.cpp +++ b/Engine/source/gui/editor/inspector/dynamicGroup.cpp @@ -26,6 +26,10 @@ #include "gui/editor/inspector/dynamicField.h" #include "console/engineAPI.h" +#ifdef TORQUE_EXPERIMENTAL_EC +#include "T3D/components/component.h" +#endif + IMPLEMENT_CONOBJECT(GuiInspectorDynamicGroup); ConsoleDocClass( GuiInspectorDynamicGroup, @@ -122,6 +126,16 @@ bool GuiInspectorDynamicGroup::inspectGroup() SimFieldDictionary * fieldDictionary = target->getFieldDictionary(); for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr) { +#ifdef TORQUE_EXPERIMENTAL_EC + if (target->getClassRep()->isSubclassOf("Component")) + { + Component* compTarget = dynamic_cast(target); + + ComponentField* compField = compTarget->getComponentField((*ditr)->slotName); + if (compField) + continue; + } +#endif if( i == 0 ) { flist.increment();