Torque3D Documentation / _generateds / dynamicGroup.cpp

dynamicGroup.cpp

Engine/source/gui/editor/inspector/dynamicGroup.cpp

More...

Classes:

Public Functions

ConsoleDocClass(GuiInspectorDynamicGroup , "@brief Used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> inspect an object's FieldDictionary (dynamic fields) instead " "of regular persistent <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">fields.\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineEngineMethod(GuiInspectorDynamicGroup , addDynamicField , void , () , "obj.addDynamicField();" )
DefineEngineMethod(GuiInspectorDynamicGroup , inspectGroup , bool , () , "Refreshes the dynamic fields in the inspector." )
DefineEngineMethod(GuiInspectorDynamicGroup , removeDynamicField , void , () , "" )

Detailed Description

Public Functions

compareEntries(const void * a, const void * b)

ConsoleDocClass(GuiInspectorDynamicGroup , "@brief Used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> inspect an object's FieldDictionary (dynamic fields) instead " "of regular persistent <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">fields.\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )

DefineEngineMethod(GuiInspectorDynamicGroup , addDynamicField , void , () , "obj.addDynamicField();" )

DefineEngineMethod(GuiInspectorDynamicGroup , inspectGroup , bool , () , "Refreshes the dynamic fields in the inspector." )

DefineEngineMethod(GuiInspectorDynamicGroup , removeDynamicField , void , () , "" )

IMPLEMENT_CONOBJECT(GuiInspectorDynamicGroup )

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "gui/buttons/guiIconButtonCtrl.h"
 25#include "gui/editor/guiInspector.h"
 26#include "gui/editor/inspector/dynamicGroup.h"
 27#include "gui/editor/inspector/dynamicField.h"
 28#include "console/engineAPI.h"
 29
 30IMPLEMENT_CONOBJECT(GuiInspectorDynamicGroup);
 31
 32ConsoleDocClass( GuiInspectorDynamicGroup,
 33   "@brief Used to inspect an object's FieldDictionary (dynamic fields) instead "
 34   "of regular persistent fields.\n\n"
 35   "Editor use only.\n\n"
 36   "@internal"
 37);
 38
 39//-----------------------------------------------------------------------------
 40// GuiInspectorDynamicGroup - add custom controls
 41//-----------------------------------------------------------------------------
 42bool GuiInspectorDynamicGroup::createContent()
 43{
 44   if(!Parent::createContent())
 45      return false;
 46
 47   // encapsulate the button in a dummy control.
 48   GuiControl* shell = new GuiControl();
 49   shell->setDataField( StringTable->insert("profile"), NULL, "GuiTransparentProfile" );
 50   if( !shell->registerObject() )
 51   {
 52      delete shell;
 53      return false;
 54   }
 55
 56   // add a button that lets us add new dynamic fields.
 57   GuiBitmapButtonCtrl* addFieldBtn = new GuiBitmapButtonCtrl();
 58   {
 59      SimObject* profilePtr = Sim::findObject("InspectorDynamicFieldButton");
 60      if( profilePtr != NULL )
 61         addFieldBtn->setControlProfile( dynamic_cast<GuiControlProfile*>(profilePtr) );
 62      
 63      // FIXME Hardcoded image
 64      addFieldBtn->setBitmap("tools/gui/images/iconAdd.png");
 65
 66      char commandBuf[64];
 67      dSprintf(commandBuf, 64, "%d.addDynamicField();", this->getId());
 68      addFieldBtn->setField("command", commandBuf);
 69      addFieldBtn->setSizing(horizResizeLeft,vertResizeCenter);
 70      //addFieldBtn->setField("buttonMargin", "2 2");
 71      addFieldBtn->resize(Point2I(getWidth() - 20,2), Point2I(16, 16));
 72      addFieldBtn->registerObject("zAddButton");
 73   }
 74
 75   shell->resize(Point2I(0,0), Point2I(getWidth(), 28));
 76   shell->addObject(addFieldBtn);
 77
 78   // save off the shell control, so we can push it to the bottom of the stack in inspectGroup()
 79   mAddCtrl = shell;
 80   mStack->addObject(shell);
 81
 82   return true;
 83}
 84
 85struct FieldEntry
 86{
 87   SimFieldDictionary::Entry* mEntry;
 88   U32 mNumTargets;
 89};
 90
 91static S32 QSORT_CALLBACK compareEntries(const void* a,const void* b)
 92{
 93   FieldEntry& fa = *((FieldEntry *)a);
 94   FieldEntry& fb = *((FieldEntry *)b);
 95   return dStrnatcmp(fa.mEntry->slotName, fb.mEntry->slotName);
 96}
 97
 98//-----------------------------------------------------------------------------
 99// GuiInspectorDynamicGroup - inspectGroup override
100//-----------------------------------------------------------------------------
101bool GuiInspectorDynamicGroup::inspectGroup()
102{
103   if( !mParent )
104      return false;
105
106   // clear the first responder if it's set
107   mStack->clearFirstResponder();
108
109   // Clearing the fields and recreating them will more than likely be more
110   // efficient than looking up existent fields, updating them, and then iterating
111   // over existent fields and making sure they still exist, if not, deleting them.
112   clearFields();
113
114   // Create a vector of the fields
115   Vector< FieldEntry> flist;
116   
117   const U32 numTargets = mParent->getNumInspectObjects();
118   for( U32 i = 0; i < numTargets; ++ i )
119   {
120      SimObject* target = mParent->getInspectObject( i );
121      
122      // Then populate with fields
123      SimFieldDictionary * fieldDictionary = target->getFieldDictionary();
124      for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr)
125      {
126         if( i == 0 )
127         {
128            flist.increment();
129            flist.last().mEntry = *ditr;
130            flist.last().mNumTargets = 1;
131         }
132         else
133         {
134            const U32 numFields = flist.size();
135            for( U32 n = 0; n < numFields; ++ n )
136               if( flist[ n ].mEntry->slotName == ( *ditr )->slotName )
137               {
138                  flist[ n ].mNumTargets ++;
139                  break;
140               }
141         }
142      }
143   }
144
145   dQsort( flist.address(), flist.size(), sizeof( FieldEntry ), compareEntries );
146
147   for(U32 i = 0; i < flist.size(); i++)
148   {
149      if( flist[ i ].mNumTargets != numTargets )
150         continue;
151
152      SimFieldDictionary::Entry* entry = flist[i].mEntry;
153
154      // Create a dynamic field inspector.  Can't reuse typed GuiInspectorFields as
155      // these rely on AbstractClassRep::Fields.
156      GuiInspectorDynamicField *field = new GuiInspectorDynamicField( mParent, this, entry );
157
158      // Register the inspector field and add it to our lists
159      if( field->registerObject() )
160      {
161         mChildren.push_back( field );
162         mStack->addObject( field );
163      }
164      else
165         delete field;
166   }
167
168   mStack->pushObjectToBack(mAddCtrl);
169
170   setUpdate();
171
172   return true;
173}
174
175void GuiInspectorDynamicGroup::updateAllFields()
176{
177   // We overload this to just reinspect the group.
178   inspectGroup();
179}
180
181DefineEngineMethod(GuiInspectorDynamicGroup, inspectGroup, bool, (), , "Refreshes the dynamic fields in the inspector.")
182{
183   return object->inspectGroup();
184}
185
186void GuiInspectorDynamicGroup::clearFields()
187{
188   // save mAddCtrl
189   Sim::getGuiGroup()->addObject(mAddCtrl);
190   // delete everything else
191   mStack->clear();
192   // clear the mChildren list.
193   mChildren.clear();
194   // and restore.
195   mStack->addObject(mAddCtrl);
196}
197
198SimFieldDictionary::Entry* GuiInspectorDynamicGroup::findDynamicFieldInDictionary( StringTableEntry fieldName )
199{
200   SimFieldDictionary * fieldDictionary = mParent->getInspectObject()->getFieldDictionary();
201
202   for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr)
203   {
204      SimFieldDictionary::Entry * entry = (*ditr);
205
206      if( entry->slotName == fieldName )
207         return entry;
208   }
209
210   return NULL;
211}
212
213void GuiInspectorDynamicGroup::addDynamicField()
214{
215   // We can't add a field without a target
216   if( !mStack )
217   {
218      Con::warnf("GuiInspectorDynamicGroup::addDynamicField - no target SimObject to add a dynamic field to.");
219      return;
220   }
221
222   // find a field name that is not in use. 
223   // But we wont try more than 100 times to find an available field.
224   U32 uid = 1;
225   char buf[64] = "dynamicField";
226   SimFieldDictionary::Entry* entry = findDynamicFieldInDictionary(buf);
227   while(entry != NULL && uid < 100)
228   {
229      dSprintf(buf, sizeof(buf), "dynamicField%03d", uid++);
230      entry = findDynamicFieldInDictionary(buf);
231   }
232   
233   const U32 numTargets = mParent->getNumInspectObjects();
234   if( numTargets > 1 )
235      Con::executef( mParent, "onBeginCompoundEdit" );
236
237   for( U32 i = 0; i < numTargets; ++ i )
238   {
239      SimObject* target = mParent->getInspectObject( i );
240      
241      Con::evaluatef( "%d.dynamicField = \"defaultValue\";", target->getId(), buf );
242 
243      // Notify script.
244   
245      Con::executef( mParent, "onFieldAdded", target->getIdString(), buf );
246   }
247   
248   if( numTargets > 1 )
249      Con::executef( mParent, "onEndCompoundEdit" );
250
251   // now we simply re-inspect the object, to see the new field.
252   inspectGroup();
253   instantExpand();
254}
255
256DefineEngineMethod( GuiInspectorDynamicGroup, addDynamicField, void, (), , "obj.addDynamicField();" )
257{
258   object->addDynamicField();
259}
260
261DefineEngineMethod( GuiInspectorDynamicGroup, removeDynamicField, void, (), , "" )
262{
263}
264