guiInspector.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "gui/editor/guiInspector.h"
  23. #include "gui/editor/inspector/field.h"
  24. #include "gui/editor/inspector/group.h"
  25. #include "gui/buttons/guiIconButtonCtrl.h"
  26. #include "gui/editor/inspector/dynamicGroup.h"
  27. #include "gui/containers/guiScrollCtrl.h"
  28. #include "gui/editor/inspector/customField.h"
  29. IMPLEMENT_CONOBJECT(GuiInspector);
  30. ConsoleDocClass( GuiInspector,
  31. "@brief A control that allows to edit the properties of one or more SimObjects.\n\n"
  32. "Editor use only.\n\n"
  33. "@internal"
  34. );
  35. //#define DEBUG_SPEW
  36. //-----------------------------------------------------------------------------
  37. GuiInspector::GuiInspector()
  38. : mDividerPos( 0.35f ),
  39. mDividerMargin( 5 ),
  40. mOverDivider( false ),
  41. mMovingDivider( false ),
  42. mHLField( NULL ),
  43. mShowCustomFields( true )
  44. {
  45. mPadding = 1;
  46. }
  47. //-----------------------------------------------------------------------------
  48. GuiInspector::~GuiInspector()
  49. {
  50. clearGroups();
  51. }
  52. //-----------------------------------------------------------------------------
  53. void GuiInspector::initPersistFields()
  54. {
  55. addGroup( "Inspector" );
  56. addField( "dividerMargin", TypeS32, Offset( mDividerMargin, GuiInspector ) );
  57. addField( "groupFilters", TypeRealString, Offset( mGroupFilters, GuiInspector ),
  58. "Specify groups that should be shown or not. Specifying 'shown' implicitly does 'not show' all other groups. Example string: +name -otherName" );
  59. addField( "showCustomFields", TypeBool, Offset( mShowCustomFields, GuiInspector ),
  60. "If false the custom fields Name, Id, and Source Class will not be shown." );
  61. endGroup( "Inspector" );
  62. Parent::initPersistFields();
  63. }
  64. //-----------------------------------------------------------------------------
  65. void GuiInspector::onRemove()
  66. {
  67. clearGroups();
  68. Parent::onRemove();
  69. }
  70. //-----------------------------------------------------------------------------
  71. void GuiInspector::onDeleteNotify( SimObject *object )
  72. {
  73. Parent::onDeleteNotify( object );
  74. if( isInspectingObject( object ) )
  75. removeInspectObject( object );
  76. }
  77. //-----------------------------------------------------------------------------
  78. void GuiInspector::parentResized(const RectI &oldParentRect, const RectI &newParentRect)
  79. {
  80. GuiControl *parent = getParent();
  81. if ( parent && dynamic_cast<GuiScrollCtrl*>(parent) != NULL )
  82. {
  83. GuiScrollCtrl *scroll = dynamic_cast<GuiScrollCtrl*>(parent);
  84. setWidth( ( newParentRect.extent.x - ( scroll->scrollBarThickness() + 4 ) ) );
  85. }
  86. else
  87. Parent::parentResized(oldParentRect,newParentRect);
  88. }
  89. //-----------------------------------------------------------------------------
  90. bool GuiInspector::resize( const Point2I &newPosition, const Point2I &newExtent )
  91. {
  92. //F32 dividerPerc = (F32)getWidth() / (F32)mDividerPos;
  93. bool result = Parent::resize( newPosition, newExtent );
  94. //mDividerPos = (F32)getWidth() * dividerPerc;
  95. updateDivider();
  96. return result;
  97. }
  98. //-----------------------------------------------------------------------------
  99. GuiControl* GuiInspector::findHitControl( const Point2I &pt, S32 initialLayer )
  100. {
  101. if ( mOverDivider || mMovingDivider )
  102. return this;
  103. return Parent::findHitControl( pt, initialLayer );
  104. }
  105. //-----------------------------------------------------------------------------
  106. void GuiInspector::getCursor( GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent )
  107. {
  108. GuiCanvas *pRoot = getRoot();
  109. if( !pRoot )
  110. return;
  111. S32 desiredCursor = mOverDivider ? PlatformCursorController::curResizeVert : PlatformCursorController::curArrow;
  112. // Bail if we're already at the desired cursor
  113. if ( pRoot->mCursorChanged == desiredCursor )
  114. return;
  115. PlatformWindow *pWindow = static_cast<GuiCanvas*>(getRoot())->getPlatformWindow();
  116. AssertFatal(pWindow != NULL,"GuiControl without owning platform window! This should not be possible.");
  117. PlatformCursorController *pController = pWindow->getCursorController();
  118. AssertFatal(pController != NULL,"PlatformWindow without an owned CursorController!");
  119. // Now change the cursor shape
  120. pController->popCursor();
  121. pController->pushCursor(desiredCursor);
  122. pRoot->mCursorChanged = desiredCursor;
  123. }
  124. //-----------------------------------------------------------------------------
  125. void GuiInspector::onMouseMove(const GuiEvent &event)
  126. {
  127. if ( collideDivider( globalToLocalCoord( event.mousePoint ) ) )
  128. mOverDivider = true;
  129. else
  130. mOverDivider = false;
  131. }
  132. //-----------------------------------------------------------------------------
  133. void GuiInspector::onMouseDown(const GuiEvent &event)
  134. {
  135. if ( mOverDivider )
  136. {
  137. mMovingDivider = true;
  138. }
  139. }
  140. //-----------------------------------------------------------------------------
  141. void GuiInspector::onMouseUp(const GuiEvent &event)
  142. {
  143. mMovingDivider = false;
  144. }
  145. //-----------------------------------------------------------------------------
  146. void GuiInspector::onMouseDragged(const GuiEvent &event)
  147. {
  148. if ( !mMovingDivider )
  149. return;
  150. Point2I localPnt = globalToLocalCoord( event.mousePoint );
  151. S32 inspectorWidth = getWidth();
  152. // Distance from mouse/divider position in local space
  153. // to the right edge of the inspector
  154. mDividerPos = inspectorWidth - localPnt.x;
  155. mDividerPos = mClamp( mDividerPos, 0, inspectorWidth );
  156. // Divide that by the inspectorWidth to get a percentage
  157. mDividerPos /= inspectorWidth;
  158. updateDivider();
  159. }
  160. //-----------------------------------------------------------------------------
  161. GuiInspectorGroup* GuiInspector::findExistentGroup( StringTableEntry groupName )
  162. {
  163. // If we have no groups, it couldn't possibly exist
  164. if( mGroups.empty() )
  165. return NULL;
  166. // Attempt to find it in the group list
  167. Vector<GuiInspectorGroup*>::iterator i = mGroups.begin();
  168. for( ; i != mGroups.end(); i++ )
  169. {
  170. if( dStricmp( (*i)->getGroupName(), groupName ) == 0 )
  171. return *i;
  172. }
  173. return NULL;
  174. }
  175. //-----------------------------------------------------------------------------
  176. void GuiInspector::updateFieldValue( StringTableEntry fieldName, StringTableEntry arrayIdx )
  177. {
  178. // We don't know which group contains the field of this name,
  179. // so ask each group in turn, and break when a group returns true
  180. // signifying it contained and updated that field.
  181. Vector<GuiInspectorGroup*>::iterator groupIter = mGroups.begin();
  182. for( ; groupIter != mGroups.end(); groupIter++ )
  183. {
  184. if ( (*groupIter)->updateFieldValue( fieldName, arrayIdx ) )
  185. break;
  186. }
  187. }
  188. //-----------------------------------------------------------------------------
  189. void GuiInspector::clearGroups()
  190. {
  191. #ifdef DEBUG_SPEW
  192. Platform::outputDebugString( "[GuiInspector] Clearing %i (%s)", getId(), getName() );
  193. #endif
  194. // If we have no groups, there's nothing to clear!
  195. if( mGroups.empty() )
  196. return;
  197. mHLField = NULL;
  198. if( isMethod( "onClear" ) )
  199. Con::executef( this, "onClear" );
  200. Vector<GuiInspectorGroup*>::iterator i = mGroups.begin();
  201. freeze(true);
  202. // Delete Groups
  203. for( ; i != mGroups.end(); i++ )
  204. {
  205. if((*i) && (*i)->isProperlyAdded())
  206. (*i)->deleteObject();
  207. }
  208. mGroups.clear();
  209. freeze(false);
  210. updatePanes();
  211. }
  212. //-----------------------------------------------------------------------------
  213. bool GuiInspector::isInspectingObject( SimObject* object )
  214. {
  215. const U32 numTargets = mTargets.size();
  216. for( U32 i = 0; i < numTargets; ++ i )
  217. if( mTargets[ i ] == object )
  218. return true;
  219. return false;
  220. }
  221. //-----------------------------------------------------------------------------
  222. void GuiInspector::inspectObject( SimObject *object )
  223. {
  224. if( mTargets.size() > 1 || !isInspectingObject( object ) )
  225. clearInspectObjects();
  226. addInspectObject( object );
  227. }
  228. //-----------------------------------------------------------------------------
  229. void GuiInspector::clearInspectObjects()
  230. {
  231. const U32 numTargets = mTargets.size();
  232. for( U32 i = 0; i < numTargets; ++ i )
  233. clearNotify( mTargets[ i ] );
  234. clearGroups();
  235. mTargets.clear();
  236. }
  237. //-----------------------------------------------------------------------------
  238. void GuiInspector::addInspectObject( SimObject* object, bool autoSync )
  239. {
  240. // If we are already inspecting the object, just update the groups.
  241. if( isInspectingObject( object ) )
  242. {
  243. #ifdef DEBUG_SPEW
  244. Platform::outputDebugString( "[GuiInspector] Refreshing view of %i:%s (%s)",
  245. object->getId(), object->getClassName(), object->getName() );
  246. #endif
  247. Vector<GuiInspectorGroup*>::iterator i = mGroups.begin();
  248. for ( ; i != mGroups.end(); i++ )
  249. (*i)->updateAllFields();
  250. return;
  251. }
  252. #ifdef DEBUG_SPEW
  253. Platform::outputDebugString( "[GuiInspector] Adding %i:%s (%s) to inspect set",
  254. object->getId(), object->getClassName(), object->getName() );
  255. #endif
  256. // Give users a chance to customize fields on this object
  257. if( object->isMethod("onDefineFieldTypes") )
  258. Con::executef( object, "onDefineFieldTypes" );
  259. // Set Target
  260. mTargets.push_back( object );
  261. deleteNotify( object );
  262. if( autoSync )
  263. refresh();
  264. }
  265. //-----------------------------------------------------------------------------
  266. void GuiInspector::removeInspectObject( SimObject* object )
  267. {
  268. const U32 numTargets = mTargets.size();
  269. for( U32 i = 0; i < numTargets; ++ i )
  270. if( mTargets[ i ] == object )
  271. {
  272. // Delete all inspector data *before* removing the target so that apply calls
  273. // triggered by edit controls losing focus will not find the inspect object
  274. // gone.
  275. clearGroups();
  276. #ifdef DEBUG_SPEW
  277. Platform::outputDebugString( "[GuiInspector] Removing %i:%s (%s) from inspect set",
  278. object->getId(), object->getClassName(), object->getName() );
  279. #endif
  280. mTargets.erase( i );
  281. clearNotify( object );
  282. // Refresh the inspector except if the system is going down.
  283. if( !Sim::isShuttingDown() )
  284. refresh();
  285. return;
  286. }
  287. }
  288. //-----------------------------------------------------------------------------
  289. void GuiInspector::setName( StringTableEntry newName )
  290. {
  291. if( mTargets.size() != 1 )
  292. return;
  293. StringTableEntry name = StringTable->insert(newName);
  294. // Only assign a new name if we provide one
  295. mTargets[ 0 ]->assignName(name);
  296. }
  297. //-----------------------------------------------------------------------------
  298. bool GuiInspector::collideDivider( const Point2I &localPnt )
  299. {
  300. RectI divisorRect( getWidth() - getWidth() * mDividerPos - mDividerMargin, 0, mDividerMargin * 2, getHeight() );
  301. if ( divisorRect.pointInRect( localPnt ) )
  302. return true;
  303. return false;
  304. }
  305. //-----------------------------------------------------------------------------
  306. void GuiInspector::updateDivider()
  307. {
  308. for ( U32 i = 0; i < mGroups.size(); i++ )
  309. for ( U32 j = 0; j < mGroups[i]->mChildren.size(); j++ )
  310. mGroups[i]->mChildren[j]->updateRects();
  311. //setUpdate();
  312. }
  313. //-----------------------------------------------------------------------------
  314. void GuiInspector::getDivider( S32 &pos, S32 &margin )
  315. {
  316. pos = (F32)getWidth() * mDividerPos;
  317. margin = mDividerMargin;
  318. }
  319. //-----------------------------------------------------------------------------
  320. void GuiInspector::setHighlightField( GuiInspectorField *field )
  321. {
  322. if ( mHLField == field )
  323. return;
  324. if ( mHLField.isValid() )
  325. mHLField->setHLEnabled( false );
  326. mHLField = field;
  327. // We could have been passed a null field, meaning, set no field highlighted.
  328. if ( mHLField.isNull() )
  329. return;
  330. mHLField->setHLEnabled( true );
  331. }
  332. //-----------------------------------------------------------------------------
  333. bool GuiInspector::isGroupFiltered( const char *groupName ) const
  334. {
  335. // Internal and Ungrouped always filtered, we never show them.
  336. if ( dStricmp( groupName, "Internal" ) == 0 ||
  337. dStricmp( groupName, "Ungrouped" ) == 0 ||
  338. dStricmp( groupName, "AdvCoordManipulation" ) == 0)
  339. return true;
  340. // Normal case, determine if filtered by looking at the mGroupFilters string.
  341. String searchStr;
  342. // Is this group explicitly show? Does it immediately follow a + char.
  343. searchStr = String::ToString( "+%s", groupName );
  344. if ( mGroupFilters.find( searchStr ) != String::NPos )
  345. return false;
  346. // Were there any other + characters, if so, we are implicitly hidden.
  347. if ( mGroupFilters.find( "+" ) != String::NPos )
  348. return true;
  349. // Is this group explicitly hidden? Does it immediately follow a - char.
  350. searchStr = String::ToString( "-%s", groupName );
  351. if ( mGroupFilters.find( searchStr ) != String::NPos )
  352. return true;
  353. return false;
  354. }
  355. //-----------------------------------------------------------------------------
  356. bool GuiInspector::isGroupExplicitlyFiltered( const char *groupName ) const
  357. {
  358. String searchStr;
  359. searchStr = String::ToString( "-%s", groupName );
  360. if ( mGroupFilters.find( searchStr ) != String::NPos )
  361. return true;
  362. return false;
  363. }
  364. //-----------------------------------------------------------------------------
  365. void GuiInspector::setObjectField( const char *fieldName, const char *data )
  366. {
  367. GuiInspectorField *field;
  368. for ( S32 i = 0; i < mGroups.size(); i++ )
  369. {
  370. field = mGroups[i]->findField( fieldName );
  371. if( field )
  372. {
  373. field->setData( data );
  374. return;
  375. }
  376. }
  377. }
  378. //-----------------------------------------------------------------------------
  379. static SimObject *sgKeyObj = NULL;
  380. bool findInspectors( GuiInspector *obj )
  381. {
  382. if ( obj->isAwake() && obj->isInspectingObject( sgKeyObj ) )
  383. return true;
  384. return false;
  385. }
  386. //-----------------------------------------------------------------------------
  387. GuiInspector* GuiInspector::findByObject( SimObject *obj )
  388. {
  389. sgKeyObj = obj;
  390. Vector< GuiInspector* > found;
  391. Sim::getGuiGroup()->findObjectByCallback( findInspectors, found );
  392. if ( found.empty() )
  393. return NULL;
  394. return found.first();
  395. }
  396. //-----------------------------------------------------------------------------
  397. void GuiInspector::refresh()
  398. {
  399. clearGroups();
  400. // Remove any inspect object that happened to have
  401. // already been killed.
  402. for( U32 i = 0; i < mTargets.size(); ++ i )
  403. if( !mTargets[ i ] )
  404. {
  405. mTargets.erase( i );
  406. -- i;
  407. }
  408. if( !mTargets.size() )
  409. return;
  410. // Special group for fields which should appear at the top of the
  411. // list outside of a rollout control.
  412. GuiInspectorGroup *ungroup = NULL;
  413. if( mTargets.size() == 1 )
  414. {
  415. ungroup = new GuiInspectorGroup( "Ungrouped", this );
  416. ungroup->setHeaderHidden( true );
  417. ungroup->setCanCollapse( false );
  418. if( ungroup != NULL )
  419. {
  420. ungroup->registerObject();
  421. mGroups.push_back( ungroup );
  422. addObject( ungroup );
  423. }
  424. }
  425. // Put the 'transform' group first
  426. GuiInspectorGroup *transform = new GuiInspectorGroup( "Transform", this );
  427. if( transform != NULL )
  428. {
  429. transform->registerObject();
  430. mGroups.push_back( transform );
  431. addObject( transform );
  432. }
  433. // Always create the 'general' group (for fields without a group)
  434. GuiInspectorGroup *general = new GuiInspectorGroup( "General", this );
  435. if( general != NULL )
  436. {
  437. general->registerObject();
  438. mGroups.push_back( general );
  439. addObject( general );
  440. }
  441. // Create the inspector groups for static fields.
  442. for( TargetVector::iterator iter = mTargets.begin(); iter != mTargets.end(); ++ iter )
  443. {
  444. AbstractClassRep::FieldList &fieldList = ( *iter )->getModifiableFieldList();
  445. // Iterate through, identifying the groups and create necessary GuiInspectorGroups
  446. for( AbstractClassRep::FieldList::iterator itr = fieldList.begin(); itr != fieldList.end(); itr++ )
  447. {
  448. if ( itr->type == AbstractClassRep::StartGroupFieldType )
  449. {
  450. GuiInspectorGroup* group = findExistentGroup( itr->pGroupname );
  451. if( !group && !isGroupFiltered( itr->pGroupname ) )
  452. {
  453. GuiInspectorGroup *group = new GuiInspectorGroup( itr->pGroupname, this );
  454. if( group != NULL )
  455. {
  456. group->registerObject();
  457. if( !group->getNumFields() )
  458. {
  459. #ifdef DEBUG_SPEW
  460. Platform::outputDebugString( "[GuiInspector] Removing empty group '%s'",
  461. group->getCaption().c_str() );
  462. #endif
  463. // The group ended up having no fields. Remove it.
  464. group->deleteObject();
  465. }
  466. else
  467. {
  468. mGroups.push_back( group );
  469. addObject( group );
  470. }
  471. }
  472. }
  473. }
  474. }
  475. }
  476. // Deal with dynamic fields
  477. if ( !isGroupFiltered( "Dynamic Fields" ) )
  478. {
  479. GuiInspectorGroup *dynGroup = new GuiInspectorDynamicGroup( "Dynamic Fields", this);
  480. if( dynGroup != NULL )
  481. {
  482. dynGroup->registerObject();
  483. mGroups.push_back( dynGroup );
  484. addObject( dynGroup );
  485. }
  486. }
  487. if( mShowCustomFields && mTargets.size() == 1 )
  488. {
  489. SimObject* object = mTargets.first();
  490. // Add the SimObjectID field to the ungrouped group.
  491. GuiInspectorCustomField* field = new GuiInspectorCustomField();
  492. field->init( this, ungroup );
  493. if( field->registerObject() )
  494. {
  495. ungroup->mChildren.push_back( field );
  496. ungroup->mStack->addObject( field );
  497. static StringTableEntry sId = StringTable->insert( "id" );
  498. field->setCaption( sId );
  499. field->setData( object->getIdString() );
  500. field->setDoc( "SimObjectId of this object. [Read Only]" );
  501. }
  502. else
  503. delete field;
  504. // Add the Source Class field to the ungrouped group.
  505. field = new GuiInspectorCustomField();
  506. field->init( this, ungroup );
  507. if( field->registerObject() )
  508. {
  509. ungroup->mChildren.push_back( field );
  510. ungroup->mStack->addObject( field );
  511. StringTableEntry sSourceClass = StringTable->insert( "Source Class", true );
  512. field->setCaption( sSourceClass );
  513. field->setData( object->getClassName() );
  514. Namespace* ns = object->getClassRep()->getNameSpace();
  515. field->setToolTip( Con::getNamespaceList( ns ) );
  516. field->setDoc( "Native class of this object. [Read Only]" );
  517. }
  518. else
  519. delete field;
  520. }
  521. // If the general group is still empty at this point ( or filtered ), kill it.
  522. if ( isGroupFiltered( "General" ) || general->mStack->size() == 0 )
  523. {
  524. for(S32 i=0; i<mGroups.size(); i++)
  525. {
  526. if ( mGroups[i] == general )
  527. {
  528. mGroups.erase(i);
  529. general->deleteObject();
  530. updatePanes();
  531. break;
  532. }
  533. }
  534. }
  535. // If transform turns out to be empty or filtered, remove it
  536. if( isGroupFiltered( "Transform" ) || transform->mStack->size() == 0 )
  537. {
  538. for(S32 i=0; i<mGroups.size(); i++)
  539. {
  540. if ( mGroups[i] == transform )
  541. {
  542. mGroups.erase(i);
  543. transform->deleteObject();
  544. updatePanes();
  545. break;
  546. }
  547. }
  548. }
  549. // If ungrouped is empty or explicitly filtered, remove it.
  550. if( ungroup && ( isGroupExplicitlyFiltered( "Ungrouped" ) || ungroup->getNumFields() == 0 ) )
  551. {
  552. for(S32 i=0; i<mGroups.size(); i++)
  553. {
  554. if ( mGroups[i] == ungroup )
  555. {
  556. mGroups.erase(i);
  557. ungroup->deleteObject();
  558. updatePanes();
  559. break;
  560. }
  561. }
  562. }
  563. // If the object cannot be renamed, deactivate the name field if we have it.
  564. if( ungroup && getNumInspectObjects() == 1 && !getInspectObject()->isNameChangeAllowed() )
  565. {
  566. GuiInspectorField* nameField = ungroup->findField( "name" );
  567. if( nameField )
  568. nameField->setActive( false );
  569. }
  570. }
  571. //-----------------------------------------------------------------------------
  572. void GuiInspector::sendInspectPreApply()
  573. {
  574. const U32 numObjects = getNumInspectObjects();
  575. for( U32 i = 0; i < numObjects; ++ i )
  576. getInspectObject( i )->inspectPreApply();
  577. }
  578. //-----------------------------------------------------------------------------
  579. void GuiInspector::sendInspectPostApply()
  580. {
  581. const U32 numObjects = getNumInspectObjects();
  582. for( U32 i = 0; i < numObjects; ++ i )
  583. getInspectObject( i )->inspectPostApply();
  584. }
  585. //=============================================================================
  586. // Console Methods.
  587. //=============================================================================
  588. // MARK: ---- Console Methods ----
  589. //-----------------------------------------------------------------------------
  590. ConsoleMethod( GuiInspector, inspect, void, 3, 3, "Inspect(Object)")
  591. {
  592. SimObject * target = Sim::findObject(argv[2]);
  593. if(!target)
  594. {
  595. if(dAtoi(argv[2]) > 0)
  596. Con::warnf("%s::inspect(): invalid object: %s", argv[0], argv[2]);
  597. object->clearInspectObjects();
  598. return;
  599. }
  600. object->inspectObject(target);
  601. }
  602. //-----------------------------------------------------------------------------
  603. ConsoleMethod( GuiInspector, addInspect, void, 3, 4, "( id object, (bool autoSync = true) ) - Add the object to the list of objects being inspected." )
  604. {
  605. SimObject* obj;
  606. if( !Sim::findObject( argv[ 2 ], obj ) )
  607. {
  608. Con::errorf( "%s::addInspect(): invalid object: %s", argv[ 0 ], argv[ 2 ] );
  609. return;
  610. }
  611. if( argc > 3 )
  612. object->addInspectObject( obj, false );
  613. else
  614. object->addInspectObject( obj );
  615. }
  616. //-----------------------------------------------------------------------------
  617. ConsoleMethod( GuiInspector, removeInspect, void, 3, 3, "( id object ) - Remove the object from the list of objects being inspected." )
  618. {
  619. SimObject* obj;
  620. if( !Sim::findObject( argv[ 2 ], obj ) )
  621. {
  622. Con::errorf( "%s::removeInspect(): invalid object: %s", argv[ 0 ], argv[ 2 ] );
  623. return;
  624. }
  625. object->removeInspectObject( obj );
  626. }
  627. //-----------------------------------------------------------------------------
  628. ConsoleMethod( GuiInspector, refresh, void, 2, 2, "Reinspect the currently selected object." )
  629. {
  630. if ( object->getNumInspectObjects() == 0 )
  631. return;
  632. SimObject *target = object->getInspectObject();
  633. if ( target )
  634. object->inspectObject( target );
  635. }
  636. //-----------------------------------------------------------------------------
  637. ConsoleMethod( GuiInspector, getInspectObject, const char*, 2, 3, "getInspectObject( int index=0 ) - Returns currently inspected object" )
  638. {
  639. U32 index = 0;
  640. if( argc > 2 )
  641. index = dAtoi( argv[ 2 ] );
  642. if( index >= object->getNumInspectObjects() )
  643. {
  644. Con::errorf( "GuiInspector::getInspectObject() - index out of range: %i", index );
  645. return "";
  646. }
  647. return object->getInspectObject( index )->getIdString();
  648. }
  649. //-----------------------------------------------------------------------------
  650. ConsoleMethod( GuiInspector, getNumInspectObjects, S32, 2, 2, "() - Return the number of objects currently being inspected." )
  651. {
  652. return object->getNumInspectObjects();
  653. }
  654. //-----------------------------------------------------------------------------
  655. ConsoleMethod( GuiInspector, setName, void, 3, 3, "setName(NewObjectName)")
  656. {
  657. object->setName(argv[2]);
  658. }
  659. //-----------------------------------------------------------------------------
  660. ConsoleMethod( GuiInspector, apply, void, 2, 2, "apply() - Force application of inspected object's attributes" )
  661. {
  662. object->sendInspectPostApply();
  663. }
  664. //-----------------------------------------------------------------------------
  665. ConsoleMethod( GuiInspector, setObjectField, void, 4, 4,
  666. "setObjectField( fieldname, data ) - 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." )
  667. {
  668. object->setObjectField( argv[2], argv[3] );
  669. }
  670. //-----------------------------------------------------------------------------
  671. ConsoleStaticMethod( GuiInspector, findByObject, S32, 2, 2,
  672. "findByObject( SimObject ) - returns the id of an awake inspector that is inspecting the passed object if one exists." )
  673. {
  674. SimObject *obj;
  675. if ( !Sim::findObject( argv[1], obj ) )
  676. return NULL;
  677. obj = GuiInspector::findByObject( obj );
  678. if ( !obj )
  679. return NULL;
  680. return obj->getId();
  681. }