guiInspector.cpp 26 KB

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