Torque3D Documentation / _generateds / guiInspector.cpp

guiInspector.cpp

Engine/source/gui/editor/guiInspector.cpp

More...

Public Variables

Public Functions

ConsoleDocClass(GuiInspector , "@brief A <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> that allows <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> edit the properties of one or more <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">SimObjects.\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineEngineMethod(GuiInspector , addInspect , void , (const char *simObject, bool autoSync) , (true) , "Add the object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the list of objects being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">inspected.\n</a>" "@param simObject <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> add <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the inspection." "@param autoSync Auto sync the values when they change." )
DefineEngineMethod(GuiInspector , apply , void , () , "Force application of inspected object's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">attributes.\n</a>" )
DefineEngineMethod(GuiInspector , findByObject , S32 , (SimObject *obj) , "Returns the <a href="/coding/file/win32cursorcontroller_8cpp/#win32cursorcontroller_8cpp_1ab38592509822a5f4674447022cc62efe">id</a> of an awake inspector that is inspecting the passed object <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> one <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">exists\n</a>" "@param object <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> find away inspector for." "@return <a href="/coding/file/win32cursorcontroller_8cpp/#win32cursorcontroller_8cpp_1ab38592509822a5f4674447022cc62efe">id</a> of an awake inspector that is inspecting the passed object <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> one exists, else <a href="/coding/file/typesx86unix_8h/#typesx86unix_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a> or 0." )
DefineEngineMethod(GuiInspector , getInspectObject , const char * , (S32 index) , (0) , "Returns currently inspected <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param index Index of object in inspection list you want <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> get." "@return object being inspected." )
DefineEngineMethod(GuiInspector , getNumInspectObjects , S32 , () , "Return the number of objects currently being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">inspected.\n</a>" "@return number of objects currently being inspected." )
DefineEngineMethod(GuiInspector , inspect , void , (const char *simObject) , ("") , "Inspect the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param simObject <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> inspect." )
DefineEngineMethod(GuiInspector , refresh , void , () , "Re-inspect the currently selected <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" )
DefineEngineMethod(GuiInspector , removeInspect , void , (const char *simObject) , "Remove the object from the list of objects being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">inspected.\n</a>" "@param simObject <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> remove from the inspection." )
DefineEngineMethod(GuiInspector , setName , void , (const char *newObjectName) , "Rename the object being inspected (first object in inspect list).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param newObjectName <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> name <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> object being inspected." )
DefineEngineMethod(GuiInspector , setObjectField , void , (const char *fieldname, const char *data) , "Set <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> named fields <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> on the inspected object <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it exists. This triggers all the usual callbacks that would occur <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the field had been changed through the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gui..\n</a>" "@param fieldname Field name on object we are inspecting we want <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> change." "@param data New <a href="/coding/file/document_8h/#document_8h_1a071cf97155ba72ac9a1fc4ad7e63d481">Value</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the given field." )

Detailed Description

Public Variables

SimObject * sgKeyObj 

Public Functions

ConsoleDocClass(GuiInspector , "@brief A <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> that allows <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> edit the properties of one or more <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">SimObjects.\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )

DefineEngineMethod(GuiInspector , addInspect , void , (const char *simObject, bool autoSync) , (true) , "Add the object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the list of objects being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">inspected.\n</a>" "@param simObject <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> add <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the inspection." "@param autoSync Auto sync the values when they change." )

DefineEngineMethod(GuiInspector , apply , void , () , "Force application of inspected object's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">attributes.\n</a>" )

DefineEngineMethod(GuiInspector , findByObject , S32 , (SimObject *obj) , "Returns the <a href="/coding/file/win32cursorcontroller_8cpp/#win32cursorcontroller_8cpp_1ab38592509822a5f4674447022cc62efe">id</a> of an awake inspector that is inspecting the passed object <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> one <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">exists\n</a>" "@param object <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> find away inspector for." "@return <a href="/coding/file/win32cursorcontroller_8cpp/#win32cursorcontroller_8cpp_1ab38592509822a5f4674447022cc62efe">id</a> of an awake inspector that is inspecting the passed object <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> one exists, else <a href="/coding/file/typesx86unix_8h/#typesx86unix_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a> or 0." )

DefineEngineMethod(GuiInspector , getInspectObject , const char * , (S32 index) , (0) , "Returns currently inspected <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param index Index of object in inspection list you want <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> get." "@return object being inspected." )

DefineEngineMethod(GuiInspector , getNumInspectObjects , S32 , () , "Return the number of objects currently being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">inspected.\n</a>" "@return number of objects currently being inspected." )

DefineEngineMethod(GuiInspector , inspect , void , (const char *simObject) , ("") , "Inspect the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param simObject <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> inspect." )

DefineEngineMethod(GuiInspector , refresh , void , () , "Re-inspect the currently selected <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" )

DefineEngineMethod(GuiInspector , removeInspect , void , (const char *simObject) , "Remove the object from the list of objects being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">inspected.\n</a>" "@param simObject <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> remove from the inspection." )

DefineEngineMethod(GuiInspector , setName , void , (const char *newObjectName) , "Rename the object being inspected (first object in inspect list).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param newObjectName <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> name <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> object being inspected." )

DefineEngineMethod(GuiInspector , setObjectField , void , (const char *fieldname, const char *data) , "Set <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> named fields <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> on the inspected object <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it exists. This triggers all the usual callbacks that would occur <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the field had been changed through the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gui..\n</a>" "@param fieldname Field name on object we are inspecting we want <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> change." "@param data New <a href="/coding/file/document_8h/#document_8h_1a071cf97155ba72ac9a1fc4ad7e63d481">Value</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the given field." )

findInspectors(GuiInspector * obj)

IMPLEMENT_CONOBJECT(GuiInspector )

  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 "console/engineAPI.h"
 25#include "gui/editor/guiInspector.h"
 26#include "gui/editor/inspector/field.h"
 27#include "gui/editor/inspector/group.h"
 28#include "gui/buttons/guiIconButtonCtrl.h"
 29#include "gui/editor/inspector/dynamicGroup.h"
 30#include "gui/containers/guiScrollCtrl.h"
 31#include "gui/editor/inspector/customField.h"
 32
 33IMPLEMENT_CONOBJECT(GuiInspector);
 34
 35ConsoleDocClass( GuiInspector,
 36   "@brief A control that allows to edit the properties of one or more SimObjects.\n\n"
 37   "Editor use only.\n\n"
 38   "@internal"
 39);
 40
 41
 42//#define DEBUG_SPEW
 43
 44
 45//-----------------------------------------------------------------------------
 46
 47GuiInspector::GuiInspector()
 48 : mDividerPos( 0.35f ),
 49   mDividerMargin( 5 ),
 50   mOverDivider( false ),
 51   mMovingDivider( false ),
 52   mHLField( NULL ),
 53   mShowCustomFields( true ),
 54   mComponentGroupTargetId(-1)
 55{
 56   mPadding = 1;
 57}
 58
 59//-----------------------------------------------------------------------------
 60
 61GuiInspector::~GuiInspector()
 62{
 63   clearGroups();
 64}
 65
 66//-----------------------------------------------------------------------------
 67
 68void GuiInspector::initPersistFields()
 69{
 70   addGroup( "Inspector" );
 71   
 72      addField( "dividerMargin", TypeS32, Offset( mDividerMargin, GuiInspector ) );
 73
 74      addField( "groupFilters", TypeRealString, Offset( mGroupFilters, GuiInspector ), 
 75         "Specify groups that should be shown or not. Specifying 'shown' implicitly does 'not show' all other groups. Example string: +name -otherName" );
 76
 77      addField( "showCustomFields", TypeBool, Offset( mShowCustomFields, GuiInspector ),
 78         "If false the custom fields Name, Id, and Source Class will not be shown." );
 79         
 80   endGroup( "Inspector" );
 81
 82   Parent::initPersistFields();
 83}
 84
 85//-----------------------------------------------------------------------------
 86
 87void GuiInspector::onRemove()
 88{
 89   clearGroups();
 90   Parent::onRemove();
 91}
 92
 93//-----------------------------------------------------------------------------
 94
 95void GuiInspector::onDeleteNotify( SimObject *object )
 96{
 97   Parent::onDeleteNotify( object );
 98   
 99   if( isInspectingObject( object ) )
100      removeInspectObject( object );
101}
102
103//-----------------------------------------------------------------------------
104
105void GuiInspector::parentResized(const RectI &oldParentRect, const RectI &newParentRect)
106{
107   GuiControl *parent = getParent();
108   if ( parent && dynamic_cast<GuiScrollCtrl*>(parent) != NULL )
109   {
110      GuiScrollCtrl *scroll = dynamic_cast<GuiScrollCtrl*>(parent);
111      setWidth( ( newParentRect.extent.x - ( scroll->scrollBarThickness() + 4  ) ) );
112   }
113   else
114      Parent::parentResized(oldParentRect,newParentRect);
115}
116
117//-----------------------------------------------------------------------------
118
119bool GuiInspector::resize( const Point2I &newPosition, const Point2I &newExtent )
120{
121   //F32 dividerPerc = (F32)getWidth() / (F32)mDividerPos;
122
123   bool result = Parent::resize( newPosition, newExtent );
124
125   //mDividerPos = (F32)getWidth() * dividerPerc;
126
127   updateDivider();
128
129   return result;
130}
131
132//-----------------------------------------------------------------------------
133
134GuiControl* GuiInspector::findHitControl( const Point2I &pt, S32 initialLayer )
135{
136   if ( mOverDivider || mMovingDivider )
137      return this;
138
139   return Parent::findHitControl( pt, initialLayer );
140}
141
142//-----------------------------------------------------------------------------
143
144void GuiInspector::getCursor( GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent )
145{
146   GuiCanvas *pRoot = getRoot();
147   if( !pRoot )
148      return;
149
150   S32 desiredCursor = mOverDivider ? PlatformCursorController::curResizeVert : PlatformCursorController::curArrow;
151
152   // Bail if we're already at the desired cursor
153   if ( pRoot->mCursorChanged == desiredCursor )
154      return;
155
156   PlatformWindow *pWindow = static_cast<GuiCanvas*>(getRoot())->getPlatformWindow();
157   AssertFatal(pWindow != NULL,"GuiControl without owning platform window!  This should not be possible.");
158   PlatformCursorController *pController = pWindow->getCursorController();
159   AssertFatal(pController != NULL,"PlatformWindow without an owned CursorController!");
160
161   // Now change the cursor shape
162   pController->popCursor();
163   pController->pushCursor(desiredCursor);
164   pRoot->mCursorChanged = desiredCursor;
165}
166
167//-----------------------------------------------------------------------------
168
169void GuiInspector::onMouseMove(const GuiEvent &event)
170{
171   if ( collideDivider( globalToLocalCoord( event.mousePoint ) ) )
172      mOverDivider = true;
173   else
174      mOverDivider = false;
175}
176
177//-----------------------------------------------------------------------------
178
179void GuiInspector::onMouseDown(const GuiEvent &event)
180{
181   if ( mOverDivider )
182   {
183      mMovingDivider = true;
184   }
185}
186
187//-----------------------------------------------------------------------------
188
189void GuiInspector::onMouseUp(const GuiEvent &event)
190{
191   mMovingDivider = false;   
192}
193
194//-----------------------------------------------------------------------------
195
196void GuiInspector::onMouseDragged(const GuiEvent &event)
197{
198   if ( !mMovingDivider )   
199      return;
200
201   Point2I localPnt = globalToLocalCoord( event.mousePoint );
202
203   S32 inspectorWidth = getWidth();
204
205   // Distance from mouse/divider position in local space
206   // to the right edge of the inspector
207   mDividerPos = inspectorWidth - localPnt.x;
208   mDividerPos = mClamp( mDividerPos, 0, inspectorWidth );
209
210   // Divide that by the inspectorWidth to get a percentage
211   mDividerPos /= inspectorWidth;
212
213   updateDivider();
214}
215
216//-----------------------------------------------------------------------------
217
218GuiInspectorGroup* GuiInspector::findExistentGroup( StringTableEntry groupName )
219{
220   // If we have no groups, it couldn't possibly exist
221   if( mGroups.empty() )
222      return NULL;
223
224   // Attempt to find it in the group list
225   Vector<GuiInspectorGroup*>::iterator i = mGroups.begin();
226
227   for( ; i != mGroups.end(); i++ )
228   {
229      if( dStricmp( (*i)->getGroupName(), groupName ) == 0 )
230         return *i;
231   }
232
233   return NULL;
234}
235
236S32 GuiInspector::findExistentGroupIndex(StringTableEntry groupName)
237{
238   // If we have no groups, it couldn't possibly exist
239   if (mGroups.empty())
240      return -1;
241
242   // Attempt to find it in the group list
243   Vector<GuiInspectorGroup*>::iterator i = mGroups.begin();
244
245   S32 index = 0;
246   for (; i != mGroups.end(); i++)
247   {
248      if (dStricmp((*i)->getGroupName(), groupName) == 0)
249         return index;
250
251      index++;
252   }
253
254   return -1;
255}
256
257//-----------------------------------------------------------------------------
258
259void GuiInspector::updateFieldValue( StringTableEntry fieldName, StringTableEntry arrayIdx )
260{
261   // We don't know which group contains the field of this name,
262   // so ask each group in turn, and break when a group returns true
263   // signifying it contained and updated that field.
264
265   Vector<GuiInspectorGroup*>::iterator groupIter = mGroups.begin();
266
267   for( ; groupIter != mGroups.end(); groupIter++ )
268   {   
269      if ( (*groupIter)->updateFieldValue( fieldName, arrayIdx ) )
270         break;
271   }
272}
273
274//-----------------------------------------------------------------------------
275
276void GuiInspector::clearGroups()
277{
278   #ifdef DEBUG_SPEW
279   Platform::outputDebugString( "[GuiInspector] Clearing %i (%s)", getId(), getName() );
280   #endif
281   
282   // If we have no groups, there's nothing to clear!
283   if( mGroups.empty() )
284      return;
285
286   mHLField = NULL;
287   
288   if( isMethod( "onClear" ) )
289      Con::executef( this, "onClear" );
290
291   Vector<GuiInspectorGroup*>::iterator i = mGroups.begin();
292
293   freeze(true);
294
295   // Delete Groups
296   for( ; i != mGroups.end(); i++ )
297   {
298      if((*i) && (*i)->isProperlyAdded())
299         (*i)->deleteObject();
300   }   
301
302   mGroups.clear();
303
304   freeze(false);
305   updatePanes();
306}
307
308//-----------------------------------------------------------------------------
309
310bool GuiInspector::isInspectingObject( SimObject* object )
311{
312   const U32 numTargets = mTargets.size();
313   for( U32 i = 0; i < numTargets; ++ i )
314      if( mTargets[ i ] == object )
315         return true;
316         
317   return false;
318}
319
320//-----------------------------------------------------------------------------
321
322void GuiInspector::inspectObject( SimObject *object )
323{  
324   if( mTargets.size() > 1 || !isInspectingObject( object ) )
325      clearInspectObjects();
326         
327   addInspectObject( object );
328}
329
330//-----------------------------------------------------------------------------
331
332void GuiInspector::clearInspectObjects()
333{
334   const U32 numTargets = mTargets.size();
335   for( U32 i = 0; i < numTargets; ++ i )
336      clearNotify( mTargets[ i ] );
337      
338   clearGroups();
339   mTargets.clear();
340}
341
342//-----------------------------------------------------------------------------
343
344void GuiInspector::addInspectObject( SimObject* object, bool autoSync )
345{   
346   // If we are already inspecting the object, just update the groups.
347   
348   if( isInspectingObject( object ) )
349   {
350      #ifdef DEBUG_SPEW
351      Platform::outputDebugString( "[GuiInspector] Refreshing view of %i:%s (%s)",
352         object->getId(), object->getClassName(), object->getName() );
353      #endif
354
355      Vector<GuiInspectorGroup*>::iterator i = mGroups.begin();
356      for ( ; i != mGroups.end(); i++ )
357         (*i)->updateAllFields();
358
359      return;
360   }
361
362   #ifdef DEBUG_SPEW
363   Platform::outputDebugString( "[GuiInspector] Adding %i:%s (%s) to inspect set",
364      object->getId(), object->getClassName(), object->getName() );
365   #endif
366
367   // Give users a chance to customize fields on this object
368   if( object->isMethod("onDefineFieldTypes") )
369      Con::executef( object, "onDefineFieldTypes" );
370
371   // Set Target
372   mTargets.push_back( object );
373   deleteNotify( object );
374   
375   if( autoSync )
376      refresh();
377}
378
379//-----------------------------------------------------------------------------
380
381void GuiInspector::removeInspectObject( SimObject* object )
382{
383   const U32 numTargets = mTargets.size();
384   for( U32 i = 0; i < numTargets; ++ i )
385      if( mTargets[ i ] == object )
386      {      
387         // Delete all inspector data *before* removing the target so that apply calls
388         // triggered by edit controls losing focus will not find the inspect object
389         // gone.
390
391         clearGroups();
392         
393         #ifdef DEBUG_SPEW
394         Platform::outputDebugString( "[GuiInspector] Removing %i:%s (%s) from inspect set",
395            object->getId(), object->getClassName(), object->getName() );
396         #endif
397
398         mTargets.erase( i );
399         clearNotify( object );
400         
401         // Refresh the inspector except if the system is going down.
402
403         if( !Sim::isShuttingDown() )
404            refresh();
405         
406         return;
407      }   
408}
409
410//-----------------------------------------------------------------------------
411
412void GuiInspector::setName( StringTableEntry newName )
413{
414   if( mTargets.size() != 1 )
415      return;
416
417   StringTableEntry name = StringTable->insert(newName);
418
419   // Only assign a new name if we provide one
420   mTargets[ 0 ]->assignName(name);
421}
422
423//-----------------------------------------------------------------------------
424
425bool GuiInspector::collideDivider( const Point2I &localPnt )
426{   
427   RectI divisorRect( getWidth() - getWidth() * mDividerPos - mDividerMargin, 0, mDividerMargin * 2, getHeight() ); 
428
429   if ( divisorRect.pointInRect( localPnt ) )
430      return true;
431
432   return false;
433}
434
435//-----------------------------------------------------------------------------
436
437void GuiInspector::updateDivider()
438{
439   for ( U32 i = 0; i < mGroups.size(); i++ )
440      for ( U32 j = 0; j < mGroups[i]->mChildren.size(); j++ )
441         mGroups[i]->mChildren[j]->updateRects(); 
442
443   //setUpdate();
444}
445
446//-----------------------------------------------------------------------------
447
448void GuiInspector::getDivider( S32 &pos, S32 &margin )
449{   
450   pos = (F32)getWidth() * mDividerPos;
451   margin = mDividerMargin;   
452}
453
454//-----------------------------------------------------------------------------
455
456void GuiInspector::setHighlightField( GuiInspectorField *field )
457{
458   if ( mHLField == field )
459      return;
460
461   if ( mHLField.isValid() )
462      mHLField->setHLEnabled( false );
463   mHLField = field;
464
465   // We could have been passed a null field, meaning, set no field highlighted.
466   if ( mHLField.isNull() )
467      return;
468
469   mHLField->setHLEnabled( true );
470}
471
472//-----------------------------------------------------------------------------
473
474bool GuiInspector::isGroupFiltered( const char *groupName ) const
475{
476   // Internal and Ungrouped always filtered, we never show them.   
477   if ( dStricmp( groupName, "Internal" ) == 0 ||
478        dStricmp( groupName, "Ungrouped" ) == 0 ||
479        dStricmp( groupName, "AdvCoordManipulation" ) == 0)
480      return true;
481
482   // Normal case, determine if filtered by looking at the mGroupFilters string.
483   String searchStr;
484
485   // Is this group explicitly show? Does it immediately follow a + char.
486   searchStr = String::ToString( "+%s", groupName );
487   if ( mGroupFilters.find( searchStr ) != String::NPos )
488      return false;   
489
490   // Were there any other + characters, if so, we are implicitly hidden.   
491   if ( mGroupFilters.find( "+" ) != String::NPos )
492      return true;
493
494   // Is this group explicitly hidden? Does it immediately follow a - char.
495   searchStr = String::ToString( "-%s", groupName );
496   if ( mGroupFilters.find( searchStr ) != String::NPos )
497      return true;   
498
499   return false;
500}
501
502//-----------------------------------------------------------------------------
503
504bool GuiInspector::isGroupExplicitlyFiltered( const char *groupName ) const
505{  
506   String searchStr;
507
508   searchStr = String::ToString( "-%s", groupName );
509
510   if ( mGroupFilters.find( searchStr ) != String::NPos )
511      return true;   
512
513   return false;
514}
515
516//-----------------------------------------------------------------------------
517
518void GuiInspector::setObjectField( const char *fieldName, const char *data )
519{
520   GuiInspectorField *field;
521
522   for ( S32 i = 0; i < mGroups.size(); i++ )
523   {
524      field = mGroups[i]->findField( fieldName );
525
526      if( field )
527      {
528         field->setData( data );
529         return;
530      }
531   }
532}
533
534//-----------------------------------------------------------------------------
535
536static SimObject *sgKeyObj = NULL;
537
538bool findInspectors( GuiInspector *obj )
539{   
540   if ( obj->isAwake() && obj->isInspectingObject( sgKeyObj ) )
541      return true;
542
543   return false;
544}
545
546//-----------------------------------------------------------------------------
547
548GuiInspector* GuiInspector::findByObject( SimObject *obj )
549{
550   sgKeyObj = obj;
551
552   Vector< GuiInspector*> found;
553   Sim::getGuiGroup()->findObjectByCallback( findInspectors, found );
554
555   if ( found.empty() )
556      return NULL;
557
558   return found.first();
559}
560
561//-----------------------------------------------------------------------------
562
563void GuiInspector::refresh()
564{
565   clearGroups();
566   
567   // Remove any inspect object that happened to have
568   // already been killed.
569   
570   for( U32 i = 0; i < mTargets.size(); ++ i )
571      if( !mTargets[ i ] )
572      {
573         mTargets.erase( i );
574         -- i;
575      }
576      
577   if( !mTargets.size() )
578      return;
579   
580   // Special group for fields which should appear at the top of the
581   // list outside of a rollout control.
582   
583   GuiInspectorGroup *ungroup = NULL;
584   if( mTargets.size() == 1 )
585   {
586      ungroup = new GuiInspectorGroup( "Ungrouped", this );
587      ungroup->setHeaderHidden( true );
588      ungroup->setCanCollapse( false );
589
590      ungroup->registerObject();
591      mGroups.push_back( ungroup );
592      addObject( ungroup );
593   }
594
595   // Put the 'transform' group first
596   GuiInspectorGroup *transform = new GuiInspectorGroup( "Transform", this );
597
598   transform->registerObject();
599   mGroups.push_back(transform);
600   addObject(transform);
601
602   // Always create the 'general' group (for fields without a group)      
603   GuiInspectorGroup *general = new GuiInspectorGroup( "General", this );
604
605   general->registerObject();
606   mGroups.push_back(general);
607   addObject(general);
608
609   // Create the inspector groups for static fields.
610
611   for( TargetVector::iterator iter = mTargets.begin(); iter != mTargets.end(); ++ iter )
612   {
613      AbstractClassRep::FieldList &fieldList = ( *iter )->getModifiableFieldList();
614
615      // Iterate through, identifying the groups and create necessary GuiInspectorGroups
616      for( AbstractClassRep::FieldList::iterator itr = fieldList.begin(); itr != fieldList.end(); itr++ )
617      {      
618         if ( itr->type == AbstractClassRep::StartGroupFieldType )
619         {
620            GuiInspectorGroup* group = findExistentGroup( itr->pGroupname );
621            
622            if( !group && !isGroupFiltered( itr->pGroupname ) )
623            {
624               GuiInspectorGroup *newGroup = new GuiInspectorGroup( itr->pGroupname, this );
625
626            newGroup->registerObject();
627               if( !newGroup->getNumFields() )
628               {
629                  #ifdef DEBUG_SPEW
630                  Platform::outputDebugString( "[GuiInspector] Removing empty group '%s'",
631                 newGroup->getCaption().c_str() );
632                  #endif
633                     
634                  // The group ended up having no fields.  Remove it.
635                  newGroup->deleteObject();
636               }
637               else
638               {
639                  mGroups.push_back(newGroup);
640                  addObject(newGroup);
641               }
642            }
643         }
644      }
645   }
646
647   mTargets.first()->onInspect(this);
648
649   // Deal with dynamic fields
650   if ( !isGroupFiltered( "Dynamic Fields" ) )
651   {
652      GuiInspectorGroup *dynGroup = new GuiInspectorDynamicGroup( "Dynamic Fields", this);
653
654      dynGroup->registerObject();
655      mGroups.push_back( dynGroup );
656      addObject( dynGroup );
657   }
658
659   if( mShowCustomFields && mTargets.size() == 1 )
660   {
661      SimObject* object = mTargets.first();
662      
663      // Add the SimObjectID field to the ungrouped group.
664      
665      GuiInspectorCustomField* field = new GuiInspectorCustomField();
666      field->init( this, ungroup );
667
668      if( field->registerObject() )
669      {
670         ungroup->mChildren.push_back( field );
671         ungroup->mStack->addObject( field );
672         
673         static StringTableEntry sId = StringTable->insert( "id" );
674         
675         field->setCaption( sId );
676         field->setData( object->getIdString() );
677         field->setDoc( "SimObjectId of this object. [Read Only]" );
678      }
679      else
680         delete field;
681
682      // Add the Source Class field to the ungrouped group.
683      
684      field = new GuiInspectorCustomField();
685      field->init( this, ungroup );
686
687      if( field->registerObject() )
688      {
689         ungroup->mChildren.push_back( field );
690         ungroup->mStack->addObject( field );
691         
692         StringTableEntry sSourceClass = StringTable->insert( "Source Class", true );
693         field->setCaption( sSourceClass );
694         field->setData( object->getClassName() );
695
696         Namespace* ns = object->getClassRep()->getNameSpace();
697         field->setToolTip( Con::getNamespaceList( ns ) );
698
699         field->setDoc( "Native class of this object. [Read Only]" );
700      }
701      else
702         delete field;
703   }
704
705
706   // If the general group is still empty at this point ( or filtered ), kill it.
707   if ( isGroupFiltered( "General" ) || general->mStack->size() == 0 )
708   {
709      for(S32 i=0; i<mGroups.size(); i++)
710      {
711         if ( mGroups[i] == general )
712         {
713            mGroups.erase(i);
714            general->deleteObject();
715            updatePanes();
716
717            break;
718         }
719      }
720   }
721
722   // If transform turns out to be empty or filtered, remove it
723   if( isGroupFiltered( "Transform" ) || transform->mStack->size() == 0 )
724   {
725      for(S32 i=0; i<mGroups.size(); i++)
726      {
727         if ( mGroups[i] == transform )
728         {
729            mGroups.erase(i);
730            transform->deleteObject();
731            updatePanes();
732
733            break;
734         }
735      }
736   }
737
738   // If ungrouped is empty or explicitly filtered, remove it.   
739   if( ungroup && ( isGroupExplicitlyFiltered( "Ungrouped" ) || ungroup->getNumFields() == 0 ) )
740   {
741      for(S32 i=0; i<mGroups.size(); i++)
742      {
743         if ( mGroups[i] == ungroup )
744         {
745            mGroups.erase(i);
746            ungroup->deleteObject();
747            updatePanes();
748
749            break;
750         }
751      }
752   }
753   
754   // If the object cannot be renamed, deactivate the name field if we have it.
755   
756   if( ungroup && getNumInspectObjects() == 1 && !getInspectObject()->isNameChangeAllowed() )
757   {
758      GuiInspectorField* nameField = ungroup->findField( "name" );
759      if( nameField )
760         nameField->setActive( false );
761   }
762}
763
764//-----------------------------------------------------------------------------
765
766void GuiInspector::sendInspectPreApply()
767{
768   const U32 numObjects = getNumInspectObjects();
769   for( U32 i = 0; i < numObjects; ++ i )
770      getInspectObject( i )->inspectPreApply();
771}
772
773//-----------------------------------------------------------------------------
774
775void GuiInspector::sendInspectPostApply()
776{
777   const U32 numObjects = getNumInspectObjects();
778   for( U32 i = 0; i < numObjects; ++ i )
779      getInspectObject( i )->inspectPostApply();
780}
781
782//=============================================================================
783//    Console Methods.
784//=============================================================================
785// MARK: ---- Console Methods ----
786
787//-----------------------------------------------------------------------------
788DefineEngineMethod( GuiInspector, inspect, void, (const char* simObject), (""),
789   "Inspect the given object.\n"
790   "@param simObject Object to inspect.")
791{
792   SimObject * target = Sim::findObject(simObject);
793   if(!target)
794   {
795      if(dAtoi(simObject) > 0)
796         Con::warnf("%s::inspect(): invalid object: %s", object->getClassName(), simObject);
797
798      object->clearInspectObjects();
799      return;
800   }
801
802   object->inspectObject(target);
803}
804
805//-----------------------------------------------------------------------------
806
807DefineEngineMethod( GuiInspector, addInspect, void, (const char* simObject, bool autoSync), (true),
808   "Add the object to the list of objects being inspected.\n"
809   "@param simObject Object to add to the inspection."
810   "@param autoSync Auto sync the values when they change.")
811{
812   SimObject* obj;
813   if( !Sim::findObject( simObject, obj ) )
814   {
815      Con::errorf( "%s::addInspect(): invalid object: %s", object->getClassName(), simObject );
816      return;
817   }
818
819   object->addInspectObject( obj, autoSync );
820}
821
822//-----------------------------------------------------------------------------
823
824DefineEngineMethod( GuiInspector, removeInspect, void, (const char* simObject), ,
825   "Remove the object from the list of objects being inspected.\n"
826   "@param simObject Object to remove from the inspection.")
827{
828   SimObject* obj;
829   if( !Sim::findObject( simObject, obj ) )
830   {
831      Con::errorf( "%s::removeInspect(): invalid object: %s", object->getClassName(), simObject );
832      return;
833   }
834
835   object->removeInspectObject( obj );
836}
837
838//-----------------------------------------------------------------------------
839
840DefineEngineMethod( GuiInspector, refresh, void, (), ,
841   "Re-inspect the currently selected object.\n")
842{
843   if ( object->getNumInspectObjects() == 0 )
844      return;
845
846   SimObject *target = object->getInspectObject();
847   if ( target )
848      object->inspectObject( target );
849}
850
851//-----------------------------------------------------------------------------
852
853DefineEngineMethod( GuiInspector, getInspectObject, const char*, (S32 index), (0),
854   "Returns currently inspected object.\n"
855   "@param index Index of object in inspection list you want to get."
856   "@return object being inspected.")
857{
858      
859   if( index < 0 || index >= object->getNumInspectObjects() )
860   {
861      Con::errorf( "GuiInspector::getInspectObject() - index out of range: %i", index );
862      return "";
863   }
864   
865   return object->getInspectObject( index )->getIdString();
866}
867
868//-----------------------------------------------------------------------------
869
870DefineEngineMethod( GuiInspector, getNumInspectObjects, S32, (), ,
871   "Return the number of objects currently being inspected.\n"
872   "@return number of objects currently being inspected.")
873{
874   return object->getNumInspectObjects();
875}
876
877//-----------------------------------------------------------------------------
878
879DefineEngineMethod( GuiInspector, setName, void, (const char* newObjectName), ,
880   "Rename the object being inspected (first object in inspect list).\n"
881   "@param newObjectName new name for object being inspected.")
882{
883   object->setName(newObjectName);
884}
885
886//-----------------------------------------------------------------------------
887
888DefineEngineMethod( GuiInspector, apply, void, (), ,
889   "Force application of inspected object's attributes.\n")
890{
891   object->sendInspectPostApply();
892}
893
894//-----------------------------------------------------------------------------
895
896DefineEngineMethod( GuiInspector, setObjectField, void, (const char* fieldname, const char* data ), ,
897   "Set a named fields value on the inspected object if it exists. This triggers all the usual callbacks that would occur if the field had been changed through the gui..\n"
898   "@param fieldname Field name on object we are inspecting we want to change."
899   "@param data New Value for the given field.")
900{
901   object->setObjectField( fieldname, data );
902}
903
904//-----------------------------------------------------------------------------
905
906DefineEngineMethod( GuiInspector, findByObject, S32, (SimObject* obj), ,
907   "Returns the id of an awake inspector that is inspecting the passed object if one exists\n"
908   "@param object Object to find away inspector for."
909   "@return id of an awake inspector that is inspecting the passed object if one exists, else NULL or 0.")
910{
911   if ( !obj)
912      return NULL;
913
914   SimObject *inspector = GuiInspector::findByObject(obj);
915
916   if ( !inspector )
917      return NULL;
918
919   return inspector->getId();
920}
921