guiInspector.cpp 27 KB

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