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" )
DefineConsoleMethod(GuiInspectorDynamicGroup , addDynamicField , void , () , "obj.addDynamicField();" )
DefineConsoleMethod(GuiInspectorDynamicGroup , inspectGroup , bool , () , "Refreshes the dynamic fields in the inspector." )
DefineConsoleMethod(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" )

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

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

DefineConsoleMethod(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
 30#ifdef TORQUE_EXPERIMENTAL_EC
 31#include "T3D/components/component.h"
 32#endif
 33
 34IMPLEMENT_CONOBJECT(GuiInspectorDynamicGroup);
 35
 36ConsoleDocClass( GuiInspectorDynamicGroup,
 37   "@brief Used to inspect an object's FieldDictionary (dynamic fields) instead "
 38   "of regular persistent fields.\n\n"
 39   "Editor use only.\n\n"
 40   "@internal"
 41);
 42
 43//-----------------------------------------------------------------------------
 44// GuiInspectorDynamicGroup - add custom controls
 45//-----------------------------------------------------------------------------
 46bool GuiInspectorDynamicGroup::createContent()
 47{
 48   if(!Parent::createContent())
 49      return false;
 50
 51   // encapsulate the button in a dummy control.
 52   GuiControl* shell = new GuiControl();
 53   shell->setDataField( StringTable->insert("profile"), NULL, "GuiTransparentProfile" );
 54   if( !shell->registerObject() )
 55   {
 56      delete shell;
 57      return false;
 58   }
 59
 60   // add a button that lets us add new dynamic fields.
 61   GuiBitmapButtonCtrl* addFieldBtn = new GuiBitmapButtonCtrl();
 62   {
 63      SimObject* profilePtr = Sim::findObject("InspectorDynamicFieldButton");
 64      if( profilePtr != NULL )
 65         addFieldBtn->setControlProfile( dynamic_cast<GuiControlProfile*>(profilePtr) );
 66      
 67      // FIXME Hardcoded image
 68      addFieldBtn->setBitmap("tools/gui/images/iconAdd.png");
 69
 70      char commandBuf[64];
 71      dSprintf(commandBuf, 64, "%d.addDynamicField();", this->getId());
 72      addFieldBtn->setField("command", commandBuf);
 73      addFieldBtn->setSizing(horizResizeLeft,vertResizeCenter);
 74      //addFieldBtn->setField("buttonMargin", "2 2");
 75      addFieldBtn->resize(Point2I(getWidth() - 20,2), Point2I(16, 16));
 76      addFieldBtn->registerObject("zAddButton");
 77   }
 78
 79   shell->resize(Point2I(0,0), Point2I(getWidth(), 28));
 80   shell->addObject(addFieldBtn);
 81
 82   // save off the shell control, so we can push it to the bottom of the stack in inspectGroup()
 83   mAddCtrl = shell;
 84   mStack->addObject(shell);
 85
 86   return true;
 87}
 88
 89struct FieldEntry
 90{
 91   SimFieldDictionary::Entry* mEntry;
 92   U32 mNumTargets;
 93};
 94
 95static S32 QSORT_CALLBACK compareEntries(const void* a,const void* b)
 96{
 97   FieldEntry& fa = *((FieldEntry *)a);
 98   FieldEntry& fb = *((FieldEntry *)b);
 99   return dStrnatcmp(fa.mEntry->slotName, fb.mEntry->slotName);
100}
101
102//-----------------------------------------------------------------------------
103// GuiInspectorDynamicGroup - inspectGroup override
104//-----------------------------------------------------------------------------
105bool GuiInspectorDynamicGroup::inspectGroup()
106{
107   if( !mParent )
108      return false;
109
110   // clear the first responder if it's set
111   mStack->clearFirstResponder();
112
113   // Clearing the fields and recreating them will more than likely be more
114   // efficient than looking up existent fields, updating them, and then iterating
115   // over existent fields and making sure they still exist, if not, deleting them.
116   clearFields();
117
118   // Create a vector of the fields
119   Vector< FieldEntry> flist;
120   
121   const U32 numTargets = mParent->getNumInspectObjects();
122   for( U32 i = 0; i < numTargets; ++ i )
123   {
124      SimObject* target = mParent->getInspectObject( i );
125      
126      // Then populate with fields
127      SimFieldDictionary * fieldDictionary = target->getFieldDictionary();
128      for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr)
129      {
130#ifdef TORQUE_EXPERIMENTAL_EC
131         if (target->getClassRep()->isSubclassOf("Component"))
132         {
133            Component* compTarget = dynamic_cast<Component*>(target);
134
135            ComponentField* compField = compTarget->getComponentField((*ditr)->slotName);
136            if (compField)
137               continue;
138         }
139#endif
140         if( i == 0 )
141         {
142            flist.increment();
143            flist.last().mEntry = *ditr;
144            flist.last().mNumTargets = 1;
145         }
146         else
147         {
148            const U32 numFields = flist.size();
149            for( U32 n = 0; n < numFields; ++ n )
150               if( flist[ n ].mEntry->slotName == ( *ditr )->slotName )
151               {
152                  flist[ n ].mNumTargets ++;
153                  break;
154               }
155         }
156      }
157   }
158
159   dQsort( flist.address(), flist.size(), sizeof( FieldEntry ), compareEntries );
160
161   for(U32 i = 0; i < flist.size(); i++)
162   {
163      if( flist[ i ].mNumTargets != numTargets )
164         continue;
165
166      SimFieldDictionary::Entry* entry = flist[i].mEntry;
167
168      // Create a dynamic field inspector.  Can't reuse typed GuiInspectorFields as
169      // these rely on AbstractClassRep::Fields.
170      GuiInspectorDynamicField *field = new GuiInspectorDynamicField( mParent, this, entry );
171
172      // Register the inspector field and add it to our lists
173      if( field->registerObject() )
174      {
175         mChildren.push_back( field );
176         mStack->addObject( field );
177      }
178      else
179         delete field;
180   }
181
182   mStack->pushObjectToBack(mAddCtrl);
183
184   setUpdate();
185
186   return true;
187}
188
189void GuiInspectorDynamicGroup::updateAllFields()
190{
191   // We overload this to just reinspect the group.
192   inspectGroup();
193}
194
195DefineConsoleMethod(GuiInspectorDynamicGroup, inspectGroup, bool, (), , "Refreshes the dynamic fields in the inspector.")
196{
197   return object->inspectGroup();
198}
199
200void GuiInspectorDynamicGroup::clearFields()
201{
202   // save mAddCtrl
203   Sim::getGuiGroup()->addObject(mAddCtrl);
204   // delete everything else
205   mStack->clear();
206   // clear the mChildren list.
207   mChildren.clear();
208   // and restore.
209   mStack->addObject(mAddCtrl);
210}
211
212SimFieldDictionary::Entry* GuiInspectorDynamicGroup::findDynamicFieldInDictionary( StringTableEntry fieldName )
213{
214   SimFieldDictionary * fieldDictionary = mParent->getInspectObject()->getFieldDictionary();
215
216   for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr)
217   {
218      SimFieldDictionary::Entry * entry = (*ditr);
219
220      if( entry->slotName == fieldName )
221         return entry;
222   }
223
224   return NULL;
225}
226
227void GuiInspectorDynamicGroup::addDynamicField()
228{
229   // We can't add a field without a target
230   if( !mStack )
231   {
232      Con::warnf("GuiInspectorDynamicGroup::addDynamicField - no target SimObject to add a dynamic field to.");
233      return;
234   }
235
236   // find a field name that is not in use. 
237   // But we wont try more than 100 times to find an available field.
238   U32 uid = 1;
239   char buf[64] = "dynamicField";
240   SimFieldDictionary::Entry* entry = findDynamicFieldInDictionary(buf);
241   while(entry != NULL && uid < 100)
242   {
243      dSprintf(buf, sizeof(buf), "dynamicField%03d", uid++);
244      entry = findDynamicFieldInDictionary(buf);
245   }
246   
247   const U32 numTargets = mParent->getNumInspectObjects();
248   if( numTargets > 1 )
249      Con::executef( mParent, "onBeginCompoundEdit" );
250
251   for( U32 i = 0; i < numTargets; ++ i )
252   {
253      SimObject* target = mParent->getInspectObject( i );
254      
255      Con::evaluatef( "%d.dynamicField = \"defaultValue\";", target->getId(), buf );
256 
257      // Notify script.
258   
259      Con::executef( mParent, "onFieldAdded", target->getIdString(), buf );
260   }
261   
262   if( numTargets > 1 )
263      Con::executef( mParent, "onEndCompoundEdit" );
264
265   // now we simply re-inspect the object, to see the new field.
266   inspectGroup();
267   instantExpand();
268}
269
270DefineConsoleMethod( GuiInspectorDynamicGroup, addDynamicField, void, (), , "obj.addDynamicField();" )
271{
272   object->addDynamicField();
273}
274
275DefineConsoleMethod( GuiInspectorDynamicGroup, removeDynamicField, void, (), , "" )
276{
277}
278