Ver Fonte

Merge pull request #2089 from Areloch/VariableInspectorRefactor

Updates the VariableInspector, VariableGroup and VariableField objects
Areloch há 8 anos atrás
pai
commit
f9b7f66571

+ 1 - 0
Engine/source/console/consoleObject.h

@@ -475,6 +475,7 @@ public:
       FIELD_HideInInspectors     = BIT( 0 ),    ///< Do not show the field in inspectors.
       FIELD_ComponentInspectors = BIT(1),       ///< Custom fields used by components. They are likely to be non-standard size/configuration, so 
                                                 ///< They are handled specially
+      FIELD_CustomInspectors = BIT(2),          ///< Display as a button in inspectors.
    };
 
    struct Field

+ 7 - 1
Engine/source/gui/editor/guiInspector.h

@@ -82,7 +82,13 @@ public:
    virtual void clearInspectObjects();
 
    /// Get the currently inspected object
-   SimObject* getInspectObject( U32 index = 0 ) { return mTargets[ index ]; }
+   SimObject* getInspectObject(U32 index = 0)
+   {
+      if (!mTargets.empty())
+         return mTargets[index];
+      else
+         return nullptr;
+   }
    
    /// Return the number of objects being inspected by this GuiInspector.
    U32 getNumInspectObjects() const { return mTargets.size(); }

+ 43 - 15
Engine/source/gui/editor/guiInspectorTypes.cpp

@@ -400,7 +400,7 @@ ConsoleDocClass( GuiInspectorTypeCheckBox,
 
 GuiControl* GuiInspectorTypeCheckBox::constructEditControl()
 {
-   if ( mField->flag.test(AbstractClassRep::FieldFlags::FIELD_ComponentInspectors) )
+   if (mField && mField->flag.test(AbstractClassRep::FIELD_CustomInspectors))
    {
       // This checkbox (bool field) is meant to be treated as a button.
       GuiControl* retCtrl = new GuiButtonCtrl();
@@ -425,27 +425,55 @@ GuiControl* GuiInspectorTypeCheckBox::constructEditControl()
       button->setField("Command", szBuffer );
 
       return retCtrl;
-   } else {
-   GuiControl* retCtrl = new GuiCheckBoxCtrl();
+   }
+   else if (mField && mField->flag.test(AbstractClassRep::FieldFlags::FIELD_ComponentInspectors))
+   {
+      // This checkbox (bool field) is meant to be treated as a button.
+      GuiControl* retCtrl = new GuiButtonCtrl();
 
-   GuiCheckBoxCtrl *check = dynamic_cast<GuiCheckBoxCtrl*>(retCtrl);
+      // If we couldn't construct the control, bail!
+      if (retCtrl == NULL)
+         return retCtrl;
 
-   // Let's make it look pretty.
-   retCtrl->setDataField( StringTable->insert("profile"), NULL, "InspectorTypeCheckboxProfile" );
-   retCtrl->setField( "text", "" );
+      GuiButtonCtrl *button = dynamic_cast<GuiButtonCtrl*>(retCtrl);
 
-   check->setIndent( 4 );
+      // Let's make it look pretty.
+      retCtrl->setDataField(StringTable->insert("profile"), NULL, "InspectorTypeButtonProfile");
+      retCtrl->setField("text", "Click Here");
 
-   retCtrl->setScriptValue( getData() );
+      retCtrl->setScriptValue(getData());
 
-   _registerEditControl( retCtrl );
+      _registerEditControl(retCtrl);
 
-   // Configure it to update our value when the popup is closed
-   char szBuffer[512];
-   dSprintf( szBuffer, 512, "%d.apply(%d.getValue());",getId(),check->getId() );
-   check->setField("Command", szBuffer );
+      // Configure it to update our value when the popup is closed
+      char szBuffer[512];
+      dSprintf(szBuffer, 512, "%d.apply(%d.getValue());", getId(), button->getId());
+      button->setField("Command", szBuffer);
 
-   return retCtrl;
+      return retCtrl;
+   }
+   else 
+   {
+      GuiControl* retCtrl = new GuiCheckBoxCtrl();
+
+      GuiCheckBoxCtrl *check = dynamic_cast<GuiCheckBoxCtrl*>(retCtrl);
+
+      // Let's make it look pretty.
+      retCtrl->setDataField(StringTable->insert("profile"), NULL, "InspectorTypeCheckboxProfile");
+      retCtrl->setField("text", "");
+
+      check->setIndent(4);
+
+      retCtrl->setScriptValue(getData());
+
+      _registerEditControl(retCtrl);
+
+      // Configure it to update our value when the popup is closed
+      char szBuffer[512];
+      dSprintf(szBuffer, 512, "%d.apply(%d.getValue());", getId(), check->getId());
+      check->setField("Command", szBuffer);
+
+      return retCtrl;
    }
 }
 

+ 88 - 7
Engine/source/gui/editor/inspector/field.cpp

@@ -49,7 +49,8 @@ GuiInspectorField::GuiInspectorField( GuiInspector* inspector,
    mInspector( inspector ),
    mField( field ), 
    mFieldArrayIndex( NULL ), 
-   mEdit( NULL )
+   mEdit( NULL ),
+   mTargetObject(NULL)
 {
    if( field != NULL )
       mCaption    = field->pFieldname;
@@ -72,7 +73,11 @@ GuiInspectorField::GuiInspectorField()
    mEdit( NULL ),
    mCaption( StringTable->EmptyString() ),
    mFieldArrayIndex( NULL ),
-   mHighlighted( false )
+   mHighlighted( false ),
+   mTargetObject(NULL),
+   mVariableName(StringTable->EmptyString()),
+   mCallbackName(StringTable->EmptyString()),
+   mSpecialEditField(false)
 {
    setCanSave( false );
 }
@@ -118,6 +123,7 @@ bool GuiInspectorField::onAdd()
    // Force our editField to set it's value
    updateValue();
 
+   Con::evaluatef("%d.edit = %d;", this->getId(), mEdit->getId());
    return true;
 }
 
@@ -244,6 +250,24 @@ void GuiInspectorField::onRightMouseUp( const GuiEvent &event )
 
 void GuiInspectorField::setData( const char* data, bool callbacks )
 {
+   if (mSpecialEditField)
+   {
+      if (mTargetObject != nullptr && mVariableName != StringTable->EmptyString())
+      {
+         mTargetObject->setDataField(mVariableName, NULL, data);
+
+         if (mCallbackName != StringTable->EmptyString())
+            Con::executef(mInspector, mCallbackName, mVariableName, data, mTargetObject);
+      }
+      else if (mVariableName != StringTable->EmptyString())
+      {
+         Con::setVariable(mVariableName, data);
+
+         if (mCallbackName != StringTable->EmptyString())
+            Con::executef(mInspector, mCallbackName, mVariableName, data);
+      }
+   }
+
    if( mField == NULL )
       return;
 
@@ -257,7 +281,19 @@ void GuiInspectorField::setData( const char* data, bool callbacks )
             
       for( U32 i = 0; i < numTargets; ++ i )
       {
-         SimObject* target = mInspector->getInspectObject( i );
+         //For now, for simplicity's sake, you can only edit the components in a simple edit
+         SimObject* target = NULL;
+         if (numTargets == 1)
+         {
+            target = mTargetObject;
+
+            if (!target)
+               target = mInspector->getInspectObject(i);
+         }
+         else
+         {
+            target = mInspector->getInspectObject(i);
+         }
          
          String oldValue = target->getDataField( mField->pFieldname, mFieldArrayIndex);
          
@@ -347,10 +383,31 @@ void GuiInspectorField::setData( const char* data, bool callbacks )
 
 const char* GuiInspectorField::getData( U32 inspectObjectIndex )
 {
-   if( mField == NULL )
-      return "";
+   if (!mSpecialEditField)
+   {
+      if (mField == NULL)
+         return "";
+
+      if (mTargetObject)
+         return mTargetObject->getDataField(mField->pFieldname, mFieldArrayIndex);
 
-   return mInspector->getInspectObject( inspectObjectIndex )->getDataField( mField->pFieldname, mFieldArrayIndex );
+      return mInspector->getInspectObject(inspectObjectIndex)->getDataField(mField->pFieldname, mFieldArrayIndex);
+   }
+   else
+   {
+      if (mTargetObject != nullptr && mVariableName != StringTable->EmptyString())
+      {
+         return mTargetObject->getDataField(mVariableName, NULL);
+      }
+      else if (mVariableName != StringTable->EmptyString())
+      {
+         return Con::getVariable(mVariableName);
+      }
+      else
+      {
+         return "";
+      }
+   }
 }
 
 //-----------------------------------------------------------------------------
@@ -483,6 +540,17 @@ void GuiInspectorField::setValue( StringTableEntry newValue )
 
 //-----------------------------------------------------------------------------
 
+void GuiInspectorField::setEditControl(GuiControl* editCtrl) 
+{ 
+   if (mEdit)
+      mEdit->deleteObject();
+
+   mEdit = editCtrl; 
+   addObject(mEdit);
+}
+
+//-----------------------------------------------------------------------------
+
 bool GuiInspectorField::updateRects()
 {
    S32 dividerPos, dividerMargin;
@@ -587,7 +655,10 @@ void GuiInspectorField::_executeSelectedCallback()
 void GuiInspectorField::_registerEditControl( GuiControl *ctrl )
 {
    char szName[512];
-   dSprintf( szName, 512, "IE_%s_%d_%s_Field", ctrl->getClassName(), mInspector->getInspectObject()->getId(), mCaption);
+   if(mInspector->getInspectObject() != nullptr)
+      dSprintf( szName, 512, "IE_%s_%d_%s_Field", ctrl->getClassName(), mInspector->getInspectObject()->getId(), mCaption);
+   else
+      dSprintf(szName, 512, "IE_%s_%s_Field", ctrl->getClassName(), mCaption);
 
    // Register the object
    ctrl->registerObject( szName );
@@ -663,3 +734,13 @@ DefineConsoleMethod( GuiInspectorField, reset, void, (), , "() - Reset to defaul
 {
    object->resetData();
 }
+
+DefineConsoleMethod(GuiInspectorField, setCaption, void, (String newCaption),, "() - Reset to default value.")
+{
+   object->setCaption(StringTable->insert(newCaption.c_str()));
+}
+
+DefineConsoleMethod(GuiInspectorField, setEditControl, void, (GuiControl* editCtrl), (nullAsType<GuiControl*>()), "() - Reset to default value.")
+{
+   object->setEditControl(editCtrl);
+}

+ 20 - 0
Engine/source/gui/editor/inspector/field.h

@@ -84,6 +84,16 @@ class GuiInspectorField : public GuiControl
       ///
       bool mHighlighted;
 
+      //An override that lets us bypass inspector-dependent logic for setting/getting variables/fields
+      bool mSpecialEditField;
+      //An override to make sure this field is associated to an object that isn't expressly
+      //the one the inspector is inspecting. Such as an entity's component.
+      SimObject* mTargetObject;
+      //Special edit field, variable name - the variable or field name targeted
+      StringTableEntry mVariableName;
+      //Special edit field, callback name - if defined, we'll do a callback to the function listed here when editing the field
+      StringTableEntry mCallbackName;
+
       virtual void _registerEditControl( GuiControl *ctrl );
       virtual void _executeSelectedCallback();
       
@@ -116,6 +126,10 @@ class GuiInspectorField : public GuiControl
       /// this is exposed in case someone wants to override the normal caption.
       virtual void setCaption( StringTableEntry caption ) { mCaption = caption; }
 
+      void setEditControl(GuiControl* editCtrl);
+
+      virtual void setDocs(String docs) { mFieldDocs = docs; }
+
       /// Returns pointer to this InspectorField's edit ctrl.
       virtual GuiControl* getEditCtrl() { return mEdit; }
 
@@ -187,6 +201,12 @@ class GuiInspectorField : public GuiControl
       virtual void onMouseDown( const GuiEvent &event );
       virtual void onRightMouseUp( const GuiEvent &event );
 
+      void setTargetObject(SimObject* obj) { mTargetObject = obj; }
+      SimObject* getTargetObject() { return mTargetObject; }
+      void setSpecialEditField(bool isSpecialEditField) { mSpecialEditField = isSpecialEditField; }
+      void setSpecialEditVariableName(String varName) { mVariableName = StringTable->insert(varName); }
+      void setSpecialEditCallbackName(String callName) { mCallbackName = StringTable->insert(callName); }
+
       DECLARE_CONOBJECT( GuiInspectorField );
       DECLARE_CATEGORY( "Gui Editor" );
 };

+ 18 - 3
Engine/source/gui/editor/inspector/variableField.cpp

@@ -93,10 +93,25 @@ bool GuiInspectorVariableField::onAdd()
 
 void GuiInspectorVariableField::setData( const char* data, bool callbacks )
 {   
-   if ( !mCaption || mCaption[0] == 0 )
-      return;
+   if (mOwnerObject == nullptr && mVariableName == StringTable->EmptyString())
+   {
+      if (!mCaption || mCaption[0] == 0)
+         return;
 
-   Con::setVariable( mCaption, data );   
+      Con::setVariable(mCaption, data);
+   }
+   else
+   {
+      if (mOwnerObject != nullptr)
+      {
+         mOwnerObject->setDataField(mVariableName, NULL, data);
+      }
+      else
+      {
+         //probably a global var if we have no object attached, so just let it set
+         Con::setVariable(mVariableName, data);
+      }
+   }
 
    // Force our edit to update
    updateValue();

+ 2 - 1
Engine/source/gui/editor/inspector/variableField.h

@@ -56,7 +56,8 @@ public:
    virtual void updateData() {};
 
 protected:
-
+   StringTableEntry mVariableName;
+   SimObject* mOwnerObject;
 };
 
 #endif // _GUI_INSPECTOR_VARIABLEFIELD_H_

+ 168 - 19
Engine/source/gui/editor/inspector/variableGroup.cpp

@@ -51,7 +51,7 @@ GuiInspectorVariableGroup::~GuiInspectorVariableGroup()
 
 GuiInspectorField* GuiInspectorVariableGroup::constructField( S32 fieldType )
 {
-   return NULL;
+   return Parent::constructField(fieldType);
 }
 
 bool GuiInspectorVariableGroup::inspectGroup()
@@ -59,39 +59,133 @@ bool GuiInspectorVariableGroup::inspectGroup()
    // to prevent crazy resizing, we'll just freeze our stack for a sec..
    mStack->freeze(true);
 
-   clearFields();
+   bool bNewItems = false;
 
-   Vector<String> names;
+   if (!mSearchString.equal(""))
+   {
+      Vector<String> names;
 
-   gEvalState.globalVars.exportVariables( mSearchString, &names, NULL );
+      gEvalState.globalVars.exportVariables(mSearchString, &names, NULL);
 
-   bool bNewItems = false;
+      for (U32 i = 0; i < names.size(); i++)
+      {
+         const String &varName = names[i];
+
+         // If the field already exists, just update it
+         GuiInspectorVariableField *field = dynamic_cast<GuiInspectorVariableField*>(findField(varName));
+         if (field != NULL)
+         {
+            field->updateValue();
+            continue;
+         }
+
+         bNewItems = true;
+
+         field = new GuiInspectorVariableField();
+         field->init(mParent, this);
+         field->setInspectorField(NULL, StringTable->insert(varName));
+
+         if (field->registerObject())
+         {
+            mChildren.push_back(field);
+            mStack->addObject(field);
+         }
+         else
+            delete field;
+      }
+   }
+
+   for (U32 i = 0; i < mFields.size(); i++)
+   {
+      bNewItems = true;
 
-   for ( U32 i = 0; i < names.size(); i++ )
-   {      
-      const String &varName = names[i];
+      GuiInspectorField *fieldGui = findField(mFields[i]->mFieldName);
+      if (fieldGui != NULL)
+      {
+         fieldGui->updateValue();
+         continue;
+      }
 
-      // If the field already exists, just update it
-      GuiInspectorVariableField *field = dynamic_cast<GuiInspectorVariableField*>( findField( varName ) );
-      if ( field != NULL )
+      //first and foremost, nab the field type and check if it's a custom field or not.
+      //If it's not a custom field, proceed below, if it is, hand it off to script to be handled by the component
+      if (mFields[i]->mFieldType == -1)
       {
-         field->updateValue();
+         if (isMethod("onConstructField"))
+         {
+            //ensure our stack variable is bound if we need it
+            Con::evaluatef("%d.stack = %d;", this->getId(), mStack->getId());
+
+            Con::executef(this, "onConstructField", mFields[i]->mFieldName,
+               mFields[i]->mFieldLabel, mFields[i]->mFieldTypeName, mFields[i]->mFieldDescription,
+               mFields[i]->mDefaultValue, mFields[i]->mDataValues, mFields[i]->mOwnerObject);
+         }
          continue;
       }
 
       bNewItems = true;
 
-      field = new GuiInspectorVariableField();
-      field->init( mParent, this );            
-      field->setInspectorField( NULL, StringTable->insert( varName ) );
+      fieldGui = constructField(mFields[i]->mFieldType);
+      if (fieldGui == NULL)
+         fieldGui = new GuiInspectorField();
 
-      if ( field->registerObject() )
+      fieldGui->init(mParent, this);
+
+      fieldGui->setSpecialEditField(true);
+
+      if (mFields[i]->mOwnerObject)
+      {
+         fieldGui->setTargetObject(mFields[i]->mOwnerObject);
+      }
+      else
       {
-         mChildren.push_back( field );
-         mStack->addObject( field );
+         //check if we're binding to a global var first, if we have no owner
+         if (mFields[i]->mFieldName[0] != '$')
+         {
+            fieldGui->setTargetObject(mParent);
+         }
+      }
+
+      fieldGui->setSpecialEditVariableName(mFields[i]->mFieldName);
+      fieldGui->setSpecialEditCallbackName(mFields[i]->mSetCallbackName);
+
+      fieldGui->setInspectorField(NULL, mFields[i]->mFieldLabel);
+      fieldGui->setDocs(mFields[i]->mFieldDescription);
+
+      /*if (mFields[i]->mSetCallbackName != StringTable->EmptyString())
+      {
+         fieldGui->on.notify()
+      }*/
+         
+      if (fieldGui->registerObject())
+      {
+#ifdef DEBUG_SPEW
+         Platform::outputDebugString("[GuiInspectorVariableGroup] Adding field '%s'",
+            field->pFieldname);
+#endif
+
+         if (mFields[i]->mOwnerObject)
+         {
+            String val = mFields[i]->mOwnerObject->getDataField(mFields[i]->mFieldName, NULL);
+
+            if(val.isEmpty())
+               fieldGui->setValue(mFields[i]->mDefaultValue);
+            else
+               fieldGui->setValue(val);
+         }
+         else
+         {
+            fieldGui->setValue(mFields[i]->mDefaultValue);
+         }
+
+         fieldGui->setActive(mFields[i]->mEnabled);
+
+         mChildren.push_back(fieldGui);
+         mStack->addObject(fieldGui);
       }
       else
-         delete field;         
+      {
+         SAFE_DELETE(fieldGui);
+      }
    }
    
    mStack->freeze(false);
@@ -107,3 +201,58 @@ bool GuiInspectorVariableGroup::inspectGroup()
 
    return true;
 }
+
+void GuiInspectorVariableGroup::clearFields()
+{
+   mFields.clear();
+}
+
+void GuiInspectorVariableGroup::addField(VariableField* field)
+{
+   bool found = false;
+
+   for (U32 i = 0; i < mFields.size(); i++)
+   {
+      if (mFields[i]->mFieldName == field->mFieldName)
+      {
+         found = true;
+         break;
+      }
+   }
+
+   if(!found)
+      mFields.push_back(field);
+}
+
+void GuiInspectorVariableGroup::addInspectorField(GuiInspectorField* field)
+{
+   mStack->addObject(field);
+   mChildren.push_back(field);
+   mStack->updatePanes();
+}
+
+GuiInspectorField* GuiInspectorVariableGroup::createInspectorField()
+{
+   GuiInspectorField* newField = new GuiInspectorField();
+
+   newField->init(mParent, this);
+
+   newField->setSpecialEditField(true);
+
+   if (newField->registerObject())
+   {
+      return newField;
+   }
+
+   return NULL;
+}
+
+DefineConsoleMethod(GuiInspectorVariableGroup, createInspectorField, GuiInspectorField*, (),, "createInspectorField()")
+{
+   return object->createInspectorField();
+}
+
+DefineConsoleMethod(GuiInspectorVariableGroup, addInspectorField, void, (GuiInspectorField* field), (nullAsType<GuiInspectorField*>()), "addInspectorField( GuiInspectorFieldObject )")
+{
+   object->addInspectorField(field);
+}

+ 29 - 0
Engine/source/gui/editor/inspector/variableGroup.h

@@ -31,6 +31,28 @@
 class GuiInspector;
 class GuiInspectorField;
 
+struct VariableField
+{
+   StringTableEntry mFieldName;
+   StringTableEntry mFieldLabel;
+   StringTableEntry mFieldDescription;
+
+   StringTableEntry mFieldTypeName;
+   S32 mFieldType;
+
+   SimObject* mOwnerObject;
+
+   StringTableEntry mDefaultValue;
+   String mDataValues;
+
+   String mGroup;
+
+   StringTableEntry mSetCallbackName;
+
+   bool mHidden;
+   bool mEnabled;
+};
+
 class GuiInspectorVariableGroup : public GuiInspectorGroup
 {
 public:
@@ -49,7 +71,14 @@ public:
 
    virtual bool inspectGroup();
 
+   void clearFields();
+   void addField(VariableField* field);
+
+   void addInspectorField(GuiInspectorField* field);
+   GuiInspectorField* createInspectorField();
+
 protected:
+   Vector<VariableField*> mFields;
 };
 
 #endif // _GUI_INSPECTOR_VARIABLEGROUP_H_

+ 197 - 2
Engine/source/gui/editor/inspector/variableInspector.cpp

@@ -21,7 +21,6 @@
 //-----------------------------------------------------------------------------
 
 #include "gui/editor/inspector/variableInspector.h"
-#include "gui/editor/inspector/variableGroup.h"
 #include "console/engineAPI.h"
 
 GuiVariableInspector::GuiVariableInspector()
@@ -56,7 +55,203 @@ void GuiVariableInspector::loadVars( String searchStr )
    mGroups.push_back( group );
    addObject( group );
  
-   //group->inspectGroup();
+   group->inspectGroup();
+}
+
+void GuiVariableInspector::update()
+{
+   clearGroups();
+
+   for (U32 i = 0; i < mFields.size(); i++)
+   {
+      //first, get the var's group name. if the group exists, we'll add to it's list
+      GuiInspectorVariableGroup *group = nullptr;
+
+      for (U32 g = 0; g < mGroups.size(); g++)
+      {
+         if (mGroups[g]->getCaption().equal(mFields[i].mGroup))
+         {
+            group = static_cast<GuiInspectorVariableGroup*>(mGroups[g]);
+            break;
+         }
+      }
+
+      if (group == nullptr)
+      {
+         group = new GuiInspectorVariableGroup();
+
+         group->setHeaderHidden(false);
+         group->setCanCollapse(true);
+         group->mParent = this;
+         group->setCaption(mFields[i].mGroup);
+
+         group->registerObject();
+         mGroups.push_back(group);
+         addObject(group);
+      }
+      
+      group->addField(&mFields[i]);
+   }
+
+   //And now, cue our update for the groups themselves
+   for (U32 g = 0; g < mGroups.size(); g++)
+   {
+      mGroups[g]->inspectGroup();
+   }
+}
+
+void GuiVariableInspector::startGroup(const char* name)
+{
+   if (!mCurrentGroup.isEmpty())
+      return;
+
+   mCurrentGroup = name;
+}
+
+void GuiVariableInspector::endGroup()
+{
+   mCurrentGroup = "";
+}
+
+void GuiVariableInspector::addField(const char* name, const char* label, const char* typeName, const char* description, 
+   const char* defaultValue, const char* dataValues, SimObject* ownerObj)
+{
+   VariableField newField;
+   newField.mFieldName = StringTable->insert(name);
+   newField.mFieldLabel = StringTable->insert(label);
+   newField.mFieldTypeName = StringTable->insert(typeName);
+   newField.mFieldDescription = StringTable->insert(description);
+   newField.mDefaultValue = StringTable->insert(defaultValue);
+   newField.mDataValues = String(dataValues);
+   newField.mGroup = mCurrentGroup;
+   newField.mSetCallbackName = StringTable->EmptyString();
+   newField.mEnabled = true;
+
+   newField.mOwnerObject = ownerObj;
+
+   //establish the field on the ownerObject(if we have one)
+   //This way, we can let the field hook into the object's field and modify it when changed
+   if (newField.mOwnerObject != nullptr)
+   {
+      if (!newField.mOwnerObject->isField(newField.mFieldName))
+      {
+         newField.mOwnerObject->setDataField(newField.mFieldName, NULL, newField.mDefaultValue);
+      }
+   }
+
+   //
+   //find the field type
+   S32 fieldTypeMask = -1;
+
+   if (newField.mFieldTypeName == StringTable->insert("int"))
+      fieldTypeMask = TypeS32;
+   else if (newField.mFieldTypeName == StringTable->insert("float"))
+      fieldTypeMask = TypeF32;
+   else if (newField.mFieldTypeName == StringTable->insert("vector"))
+      fieldTypeMask = TypePoint3F;
+   //else if (fieldType == StringTable->insert("material"))
+   //   fieldTypeMask = TypeMaterialName;
+   else if (newField.mFieldTypeName == StringTable->insert("image"))
+      fieldTypeMask = TypeImageFilename;
+   else if (newField.mFieldTypeName == StringTable->insert("shape"))
+      fieldTypeMask = TypeShapeFilename;
+   else if (newField.mFieldTypeName == StringTable->insert("bool"))
+      fieldTypeMask = TypeBool;
+   else if (newField.mFieldTypeName == StringTable->insert("object"))
+      fieldTypeMask = TypeSimObjectPtr;
+   else if (newField.mFieldTypeName == StringTable->insert("string"))
+      fieldTypeMask = TypeString;
+   else if (newField.mFieldTypeName == StringTable->insert("colorI"))
+      fieldTypeMask = TypeColorI;
+   else if (newField.mFieldTypeName == StringTable->insert("colorF"))
+      fieldTypeMask = TypeColorF;
+   else if (newField.mFieldTypeName == StringTable->insert("ease"))
+      fieldTypeMask = TypeEaseF;
+   else
+      fieldTypeMask = -1;
+
+   newField.mFieldType = fieldTypeMask;
+   //
+
+   mFields.push_back(newField);
+
+   update();
+}
+
+void GuiVariableInspector::addCallbackField(const char* name, const char* label, const char* typeName, const char* description,
+   const char* defaultValue, const char* dataValues, const char* callbackName, SimObject* ownerObj)
+{
+   addField(name, label, typeName, description, defaultValue, dataValues, ownerObj);
+
+   //Add the callback name
+   mFields.last().mSetCallbackName = StringTable->insert(callbackName);
+
+   update();
+}
+
+void GuiVariableInspector::clearFields()
+{
+   mFields.clear();
+   update();
+}
+
+void GuiVariableInspector::setFieldEnabled(const char* name, bool enabled)
+{
+   String fieldName = name;
+   for (U32 i = 0; i < mFields.size(); i++)
+   {
+      if (fieldName.equal(mFields[i].mFieldName, String::NoCase))
+      {
+         mFields[i].mEnabled = enabled;
+         update();
+         return;
+      }
+   }
+}
+
+DefineConsoleMethod(GuiVariableInspector, startGroup, void, (const char* name),, "startGroup( groupName )")
+{
+   object->startGroup(name);
+}
+
+DefineConsoleMethod(GuiVariableInspector, endGroup, void, (),, "endGroup()")
+{
+   object->endGroup();
+}
+
+DefineConsoleMethod(GuiVariableInspector, addField, void, (const char* name, const char* label, const char* typeName, 
+   const char* description, const char* defaultValue, const char* dataValues, SimObject* ownerObj),
+   ("","","","","", "", nullAsType<SimObject*>()), "addField( fieldName/varName, fieldLabel, fieldTypeName, description, defaultValue, defaultValues, ownerObject )")
+{
+   if (name == "" || typeName == "")
+      return;
+
+   object->addField(name, label, typeName, description, defaultValue, dataValues, ownerObj);
+}
+
+DefineConsoleMethod(GuiVariableInspector, addCallbackField, void, (const char* name, const char* label, const char* typeName,
+   const char* description, const char* defaultValue, const char* dataValues, const char* callbackName, SimObject* ownerObj),
+   ("", "", "", "", "", "", nullAsType<SimObject*>()), "addField( fieldName/varName, fieldLabel, fieldTypeName, description, defaultValue, defaultValues, callbackName, ownerObject )")
+{
+   if (name == "" || typeName == "")
+      return;
+
+   object->addCallbackField(name, label, typeName, description, defaultValue, dataValues, callbackName, ownerObj);
+}
+
+DefineConsoleMethod(GuiVariableInspector, update, void, (), , "update()")
+{
+   object->update();
+}
+
+DefineConsoleMethod(GuiVariableInspector, clearFields, void, (), , "clearFields()")
+{
+   object->clearFields();
+}
+
+DefineConsoleMethod(GuiVariableInspector, setFieldEnabled, void, (const char* fieldName, bool isEnabled), (true), "setFieldEnabled( fieldName, isEnabled )")
+{
+   object->setFieldEnabled(fieldName, isEnabled);
 }
 
 DefineConsoleMethod( GuiVariableInspector, loadVars, void, ( const char * searchString ), , "loadVars( searchString )" )

+ 18 - 0
Engine/source/gui/editor/inspector/variableInspector.h

@@ -26,6 +26,9 @@
 #ifndef _GUI_INSPECTOR_H_
 #include "gui/editor/guiInspector.h"
 #endif
+#ifndef _GUI_INSPECTOR_VARIABLEGROUP_H_
+#include "gui/editor/inspector/variableGroup.h"
+#endif
 
 
 class GuiVariableInspector : public GuiInspector
@@ -44,8 +47,23 @@ public:
 
    virtual void loadVars( String searchString );
 
+   void update();
+
+   void startGroup(const char* name);
+   void endGroup();
+
+   void addField(const char* name, const char* label, const char* typeName, const char* description, 
+      const char* defaultValue, const char* dataValues, SimObject* ownerObj);
+   void addCallbackField(const char* name, const char* label, const char* typeName, const char* description,
+      const char* defaultValue, const char* dataValues, const char* callbackName, SimObject* ownerObj);
+   void setFieldEnabled(const char* name, bool enabled);
+   void clearFields();
 
 protected:
+   
+   Vector<VariableField> mFields;
+
+   String mCurrentGroup;
 
 };