guiInspector.cc 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 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/buttons/guiButtonCtrl.h"
  24. #include "memory/frameAllocator.h"
  25. #pragma region GuiInspector
  26. //////////////////////////////////////////////////////////////////////////
  27. // GuiInspector
  28. //////////////////////////////////////////////////////////////////////////
  29. IMPLEMENT_CONOBJECT(GuiInspector);
  30. GuiInspector::GuiInspector()
  31. {
  32. mGroups.clear();
  33. mTarget = NULL;
  34. mOpenGroupList.clear();
  35. mGroupPanelProfile = NULL;
  36. setField("GroupPanelProfile", "GuiPanelProfile");
  37. mGroupGridProfile = NULL;
  38. setField("GroupGridProfile", "GuiDefaultProfile");
  39. mLabelProfile = NULL;
  40. setField("LabelProfile", "GuiDefaultProfile");
  41. mTextEditProfile = NULL;
  42. setField("TextEditProfile", "GuiTextEditProfile");
  43. mDropDownProfile = NULL;
  44. setField("DropDownProfile", "GuiDropDownProfile");
  45. mDropDownItemProfile = NULL;
  46. setField("DropDownItemProfile", "GuiListBoxProfile");
  47. mScrollProfile = NULL;
  48. setField("ScrollProfile", "GuiScrollProfile");
  49. mBackgroundProfile = NULL;
  50. setField("BackgroundProfile", "GuiDefaultProfile");
  51. mThumbProfile = NULL;
  52. setField("ThumbProfile", "GuiScrollThumbProfile");
  53. mArrowProfile = NULL;
  54. setField("ArrowProfile", "GuiScrollArrowProfile");
  55. mTrackProfile = NULL;
  56. setField("TrackProfile", "GuiScrollTrackProfile");
  57. mCheckboxProfile = NULL;
  58. setField("CheckboxProfile", "GuiCheckboxProfile");
  59. mButtonProfile = NULL;
  60. setField("ButtonProfile", "GuiButtonProfile");
  61. mUseConstantHeightThumb = false;
  62. mScrollBarThickness = 12;
  63. mShowArrowButtons = true;
  64. mFieldCellSize.set(300, 30);
  65. mControlOffset.set(10, 16);
  66. }
  67. GuiInspector::~GuiInspector()
  68. {
  69. clearGroups();
  70. }
  71. void GuiInspector::initPersistFields()
  72. {
  73. Parent::initPersistFields();
  74. addField("GroupPanelProfile", TypeGuiProfile, Offset(mGroupPanelProfile, GuiInspector));
  75. addField("GroupGridProfile", TypeGuiProfile, Offset(mGroupGridProfile, GuiInspector));
  76. addField("LabelProfile", TypeGuiProfile, Offset(mLabelProfile, GuiInspector));
  77. addField("TextEditProfile", TypeGuiProfile, Offset(mTextEditProfile, GuiInspector));
  78. addField("DropDownProfile", TypeGuiProfile, Offset(mDropDownProfile, GuiInspector));
  79. addField("DropDownItemProfile", TypeGuiProfile, Offset(mDropDownItemProfile, GuiInspector));
  80. addField("ScrollProfile", TypeGuiProfile, Offset(mScrollProfile, GuiInspector));
  81. addField("backgroundProfile", TypeGuiProfile, Offset(mBackgroundProfile, GuiInspector));
  82. addField("thumbProfile", TypeGuiProfile, Offset(mThumbProfile, GuiInspector));
  83. addField("trackProfile", TypeGuiProfile, Offset(mTrackProfile, GuiInspector));
  84. addField("arrowProfile", TypeGuiProfile, Offset(mArrowProfile, GuiInspector));
  85. addField("CheckboxProfile", TypeGuiProfile, Offset(mCheckboxProfile, GuiInspector));
  86. addField("ButtonProfile", TypeGuiProfile, Offset(mButtonProfile, GuiInspector));
  87. addField("ColorPopupProfile", TypeGuiProfile, Offset(mColorPopupProfile, GuiInspector));
  88. addField("ColorPopupPanelProfile", TypeGuiProfile, Offset(mColorPopupPanelProfile, GuiInspector));
  89. addField("ColorPopupPickerProfile", TypeGuiProfile, Offset(mColorPopupPickerProfile, GuiInspector));
  90. addField("ColorPopupSelectorProfile", TypeGuiProfile, Offset(mColorPopupSelectorProfile, GuiInspector));
  91. addField("constantThumbHeight", TypeBool, Offset(mUseConstantHeightThumb, GuiInspector));
  92. addField("scrollBarThickness", TypeS32, Offset(mScrollBarThickness, GuiInspector));
  93. addField("showArrowButtons", TypeBool, Offset(mShowArrowButtons, GuiInspector));
  94. addField("FieldCellSize", TypePoint2I, Offset(mFieldCellSize, GuiInspector));
  95. addField("ControlOffset", TypePoint2I, Offset(mControlOffset, GuiInspector));
  96. }
  97. bool GuiInspector::onWake()
  98. {
  99. if (!Parent::onWake())
  100. return false;
  101. if (mGroupPanelProfile != NULL)
  102. mGroupPanelProfile->incRefCount();
  103. if (mGroupGridProfile != NULL)
  104. mGroupGridProfile->incRefCount();
  105. if (mLabelProfile != NULL)
  106. mLabelProfile->incRefCount();
  107. if (mTextEditProfile != NULL)
  108. mTextEditProfile->incRefCount();
  109. if (mDropDownProfile != NULL)
  110. mDropDownProfile->incRefCount();
  111. if (mDropDownItemProfile != NULL)
  112. mDropDownItemProfile->incRefCount();
  113. if (mScrollProfile != NULL)
  114. mScrollProfile->incRefCount();
  115. if (mBackgroundProfile != NULL)
  116. mBackgroundProfile->incRefCount();
  117. if (mThumbProfile != NULL)
  118. mThumbProfile->incRefCount();
  119. if (mTrackProfile != NULL)
  120. mTrackProfile->incRefCount();
  121. if (mArrowProfile != NULL)
  122. mArrowProfile->incRefCount();
  123. if (mCheckboxProfile != NULL)
  124. mCheckboxProfile->incRefCount();
  125. if (mButtonProfile != NULL)
  126. mButtonProfile->incRefCount();
  127. if (mColorPopupProfile != NULL)
  128. mColorPopupProfile->incRefCount();
  129. if (mColorPopupPanelProfile != NULL)
  130. mColorPopupPanelProfile->incRefCount();
  131. if (mColorPopupPickerProfile != NULL)
  132. mColorPopupPickerProfile->incRefCount();
  133. if (mColorPopupSelectorProfile != NULL)
  134. mColorPopupSelectorProfile->incRefCount();
  135. return true;
  136. }
  137. void GuiInspector::onSleep()
  138. {
  139. Parent::onSleep();
  140. if (mGroupPanelProfile != NULL)
  141. mGroupPanelProfile->decRefCount();
  142. if (mGroupGridProfile != NULL)
  143. mGroupGridProfile->decRefCount();
  144. if (mLabelProfile != NULL)
  145. mLabelProfile->decRefCount();
  146. if (mTextEditProfile != NULL)
  147. mTextEditProfile->decRefCount();
  148. if (mDropDownProfile != NULL)
  149. mDropDownProfile->decRefCount();
  150. if (mDropDownItemProfile != NULL)
  151. mDropDownItemProfile->decRefCount();
  152. if (mScrollProfile != NULL)
  153. mScrollProfile->decRefCount();
  154. if (mBackgroundProfile != NULL)
  155. mBackgroundProfile->decRefCount();
  156. if (mThumbProfile != NULL)
  157. mThumbProfile->decRefCount();
  158. if (mTrackProfile != NULL)
  159. mTrackProfile->decRefCount();
  160. if (mArrowProfile != NULL)
  161. mArrowProfile->decRefCount();
  162. if (mCheckboxProfile != NULL)
  163. mCheckboxProfile->decRefCount();
  164. if (mButtonProfile != NULL)
  165. mButtonProfile->decRefCount();
  166. if (mColorPopupProfile != NULL)
  167. mColorPopupProfile->decRefCount();
  168. if (mColorPopupPanelProfile != NULL)
  169. mColorPopupPanelProfile->decRefCount();
  170. if (mColorPopupPickerProfile != NULL)
  171. mColorPopupPickerProfile->decRefCount();
  172. if (mColorPopupSelectorProfile != NULL)
  173. mColorPopupSelectorProfile->decRefCount();
  174. }
  175. void GuiInspector::inspectPostApply()
  176. {
  177. Parent::inspectPostApply();
  178. if (mTarget)
  179. {
  180. inspectObject(mTarget);
  181. }
  182. }
  183. void GuiInspector::resize(const Point2I &newPosition, const Point2I &newExtent)
  184. {
  185. Parent::resize(Point2I(0, 0), newExtent);
  186. }
  187. void GuiInspector::parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent)
  188. {
  189. Parent::parentResized(oldParentExtent,newParentExtent);
  190. }
  191. bool GuiInspector::findExistentGroup( StringTableEntry groupName )
  192. {
  193. // If we have no groups, it couldn't possibly exist
  194. if( mGroups.empty() )
  195. return false;
  196. // Attempt to find it in the group list
  197. Vector<GuiInspectorGroup*>::iterator i = mGroups.begin();
  198. for( ; i != mGroups.end(); i++ )
  199. {
  200. if( dStricmp( (*i)->getGroupName(), groupName ) == 0 )
  201. return true;
  202. }
  203. return false;
  204. }
  205. void GuiInspector::clearGroups()
  206. {
  207. // If we're clearing the groups, we want to clear our target too.
  208. mTarget = NULL;
  209. // If we have no groups, there's nothing to clear!
  210. if( mGroups.empty() )
  211. return;
  212. mOpenGroupList.clear();
  213. for(Vector<GuiInspectorGroup*>::iterator i = mGroups.begin(); i != mGroups.end(); i++ )
  214. {
  215. if ((*i)->isProperlyAdded())
  216. {
  217. GuiInspectorGroup* group = static_cast<GuiInspectorGroup*>(*i);
  218. //First, save which groups are open by name
  219. if (group->getExpanded())
  220. {
  221. mOpenGroupList.push_back(group->getGroupName());
  222. }
  223. group->deleteObject();
  224. }
  225. }
  226. mGroups.clear();
  227. GuiControl* firstRes = getFirstResponder();
  228. clearFirstResponder(firstRes);
  229. }
  230. void GuiInspector::inspectObject( SimObject *object )
  231. {
  232. GuiCanvas *guiCanvas = getRoot();
  233. if( !guiCanvas )
  234. return;
  235. SimObjectPtr<GuiControl> currResponder = guiCanvas->getFirstResponder();
  236. // If our target is the same as our current target, just update the groups.
  237. if( mTarget == object )
  238. {
  239. Vector<GuiInspectorGroup*>::iterator i = mGroups.begin();
  240. for ( ; i != mGroups.end(); i++ )
  241. (*i)->inspectGroup();
  242. // Don't steal first responder
  243. if( !currResponder.isNull() )
  244. guiCanvas->setFirstResponder( currResponder );
  245. return;
  246. }
  247. // Clear our current groups
  248. clearGroups();
  249. // Set Target
  250. mTarget = object;
  251. // Always create the 'general' group (for un-grouped fields)
  252. GuiInspectorGroup* general = new GuiInspectorGroup( mTarget, "General", this );
  253. if( general != NULL )
  254. {
  255. general->registerObject();
  256. mGroups.push_back( general );
  257. addObject( general );
  258. checkOpenGroupList(general);
  259. }
  260. // Grab this objects field list
  261. AbstractClassRep::FieldList &fieldList = mTarget->getModifiableFieldList();
  262. AbstractClassRep::FieldList::iterator itr;
  263. // Iterate through, identifying the groups and create necessary GuiInspectorGroups
  264. for(itr = fieldList.begin(); itr != fieldList.end(); itr++)
  265. {
  266. if(itr->type == AbstractClassRep::StartGroupFieldType && !findExistentGroup( itr->pGroupname ) )
  267. {
  268. GuiInspectorGroup *group = new GuiInspectorGroup( mTarget, itr->pGroupname, this );
  269. if( group != NULL )
  270. {
  271. group->registerObject();
  272. mGroups.push_back( group );
  273. addObject( group );
  274. checkOpenGroupList(group);
  275. }
  276. }
  277. }
  278. // Deal with dynamic fields
  279. GuiInspectorGroup *dynGroup = new GuiInspectorDynamicGroup( mTarget, "Dynamic Fields", this);
  280. if( dynGroup != NULL )
  281. {
  282. dynGroup->registerObject();
  283. mGroups.push_back( dynGroup );
  284. addObject( dynGroup );
  285. }
  286. // If any group is still empty at this point, kill it.
  287. for(S32 i=0; i<mGroups.size(); i++)
  288. {
  289. if(mGroups[i]->mGrid->size() == 0)
  290. {
  291. mGroups[i]->deleteObject();
  292. mGroups.erase(i);
  293. i--;
  294. }
  295. }
  296. resize(getPosition(), getExtent());
  297. // Don't steal first responder
  298. if( !currResponder.isNull() )
  299. guiCanvas->setFirstResponder( currResponder );
  300. }
  301. void GuiInspector::checkOpenGroupList(GuiInspectorGroup* group)
  302. {
  303. for (Vector<StringTableEntry>::iterator i = mOpenGroupList.begin(); i != mOpenGroupList.end(); i++)
  304. {
  305. StringTableEntry text = static_cast<StringTableEntry>(*i);
  306. if (dStrcmp(text, group->getGroupName()) == 0)
  307. {
  308. group->setExpandedInstant(true);
  309. }
  310. }
  311. }
  312. ConsoleMethod( GuiInspector, inspect, void, 3, 3, "(obj) Goes through the object's fields and autogenerates editor boxes\n"
  313. "@return No return value.")
  314. {
  315. SimObject * target = Sim::findObject(argv[2]);
  316. if(!target)
  317. {
  318. if(dAtoi(argv[2]) > 0)
  319. Con::warnf("%s::inspect(): invalid object: %s", argv[0], argv[2]);
  320. object->clearGroups();
  321. return;
  322. }
  323. object->inspectObject(target);
  324. }
  325. ConsoleMethod( GuiInspector, getInspectObject, const char*, 2, 2, "() - Returns currently inspected object\n"
  326. "@return The Object's ID as a string.")
  327. {
  328. SimObject *pSimObject = object->getInspectObject();
  329. if( pSimObject != NULL )
  330. return pSimObject->getIdString();
  331. return "";
  332. }
  333. ConsoleMethod(GuiInspector, clear, const char*, 2, 2, "() - Uninspects\n"
  334. "@return Not used.")
  335. {
  336. object->clearGroups();
  337. return "";
  338. }
  339. void GuiInspector::setName( const char* newName )
  340. {
  341. if( mTarget == NULL )
  342. return;
  343. // Only assign a new name if we provide one
  344. mTarget->assignName(newName);
  345. }
  346. ConsoleMethod( GuiInspector, setName, void, 3, 3, "(NewObjectName) Set object name.\n"
  347. "@return No return value.")
  348. {
  349. object->setName(argv[2]);
  350. }
  351. ConsoleMethod(GuiInspector, clearHiddenFields, void, 2, 2, "() Clears the list of hidden fields\n"
  352. "@return No return value.")
  353. {
  354. object->clearHiddenField();
  355. }
  356. ConsoleMethod(GuiInspector, addHiddenField, void, 3, 3, "() Adds a new field to the list of hidden fields\n"
  357. "@return No return value.")
  358. {
  359. object->addHiddenField(argv[2]);
  360. }
  361. ConsoleMethod(GuiInspector, openGroupByIndex, void, 3, 3, "(Index) Opens the group that matches the given zero-based index\n"
  362. "@return No return value.")
  363. {
  364. if (argc < 1)
  365. {
  366. return;
  367. }
  368. S32 index = dAtoi(argv[2]);
  369. if (index >= object->mGroups.size())
  370. {
  371. return;
  372. }
  373. object->mGroups[index]->setExpanded(true);
  374. }
  375. #pragma endregion
  376. #pragma region GuiInspectorField
  377. //////////////////////////////////////////////////////////////////////////
  378. // GuiInspectorField
  379. //////////////////////////////////////////////////////////////////////////
  380. // The GuiInspectorField control is a representation of a single abstract
  381. // field for a given ConsoleObject derived object. It handles creation
  382. // getting and setting of it's fields data and editing control.
  383. //
  384. // Creation of custom edit controls is done through this class and is
  385. // dependent upon the dynamic console type, which may be defined to be
  386. // custom for different types.
  387. //
  388. // Note : GuiInspectorField controls must have a GuiInspectorGroup as their
  389. // parent.
  390. IMPLEMENT_CONOBJECT(GuiInspectorField);
  391. GuiInspectorField::GuiInspectorField( GuiInspectorGroup* parent, SimObjectPtr<SimObject> target, AbstractClassRep::Field* field )
  392. {
  393. if( field != NULL )
  394. mText = StringTable->insert( field->pFieldname );
  395. else
  396. mText = StringTable->EmptyString;
  397. mGroup = parent;
  398. mTarget = target;
  399. mField = field;
  400. mCanSave = false;
  401. mFieldArrayIndex = NULL;
  402. }
  403. GuiInspectorField::GuiInspectorField()
  404. {
  405. mText = StringTable->EmptyString;
  406. mGroup = NULL;
  407. mTarget = NULL;
  408. mField = NULL;
  409. mFieldArrayIndex = NULL;
  410. mCanSave = false;
  411. }
  412. GuiInspectorField::~GuiInspectorField()
  413. {
  414. }
  415. //////////////////////////////////////////////////////////////////////////
  416. // Get/Set Data Functions
  417. //////////////////////////////////////////////////////////////////////////
  418. void GuiInspectorField::setData( const char* data )
  419. {
  420. if( mField == NULL || mTarget == NULL )
  421. return;
  422. mTarget->inspectPreApply();
  423. if (mGroup->mInspector->isMethod("onPreApply"))
  424. {
  425. Con::executef(mGroup->mInspector, 3, "onPreApply", Con::getIntArg(mTarget->getId()));
  426. }
  427. mTarget->setDataField( mField->pFieldname, mFieldArrayIndex, data );
  428. // Force our edit to update
  429. updateValue( data );
  430. mTarget->inspectPostApply();
  431. if (mGroup->mInspector->isMethod("onPostApply"))
  432. {
  433. Con::executef(mGroup->mInspector, 3, "onPostApply", Con::getIntArg(mTarget->getId()));
  434. }
  435. }
  436. const char* GuiInspectorField::getData()
  437. {
  438. if( mField == NULL || mTarget == NULL )
  439. return "";
  440. return mTarget->getDataField( mField->pFieldname, mFieldArrayIndex );
  441. }
  442. void GuiInspectorField::setInspectorField( AbstractClassRep::Field *field, const char*arrayIndex )
  443. {
  444. mField = field;
  445. if( arrayIndex != NULL )
  446. {
  447. mFieldArrayIndex = StringTable->insert( arrayIndex );
  448. S32 frameTempSize = dStrlen( field->pFieldname ) + 32;
  449. FrameTemp<char> valCopy( frameTempSize );
  450. dSprintf( (char *)valCopy, frameTempSize, "%s%s", field->pFieldname, arrayIndex );
  451. mText = StringTable->insert( valCopy );
  452. }
  453. else
  454. mText = StringTable->insert( field->pFieldname );
  455. }
  456. StringTableEntry GuiInspectorField::getFieldName()
  457. {
  458. // Sanity
  459. if ( mField == NULL )
  460. return StringTable->EmptyString;
  461. // Array element?
  462. if( mFieldArrayIndex != NULL )
  463. {
  464. S32 frameTempSize = dStrlen( mField->pFieldname ) + 32;
  465. FrameTemp<char> valCopy( frameTempSize );
  466. dSprintf( (char *)valCopy, frameTempSize, "%s%s:", mField->pFieldname, mFieldArrayIndex );
  467. // Return formatted element
  468. return StringTable->insert( valCopy );
  469. }
  470. // Plain ole field name.
  471. return mField->pFieldname;
  472. };
  473. //////////////////////////////////////////////////////////////////////////
  474. // Overrideables for custom edit fields
  475. //////////////////////////////////////////////////////////////////////////
  476. GuiControl* GuiInspectorField::constructEditControl(S32 width)
  477. {
  478. GuiControl* retCtrl = new GuiTextEditCtrl();
  479. // If we couldn't construct the control, bail!
  480. if( retCtrl == NULL )
  481. return retCtrl;
  482. // Let's make it look pretty.
  483. retCtrl->setControlProfile(mGroup->mInspector->mTextEditProfile);
  484. // Don't forget to register ourselves
  485. registerEditControl( retCtrl );
  486. char szBuffer[512];
  487. dSprintf( szBuffer, 512, "%d.apply(%d.getText());",getId(), retCtrl->getId() );
  488. retCtrl->setField("AltCommand", szBuffer );
  489. retCtrl->mBounds.set(mGroup->mInspector->mControlOffset, Point2I(width - mGroup->mInspector->mControlOffset.x, 30));
  490. return retCtrl;
  491. }
  492. void GuiInspectorField::registerEditControl( GuiControl *ctrl )
  493. {
  494. if(!mTarget)
  495. return;
  496. char szName[512];
  497. dSprintf( szName, 512, "IE_%s_%d_%s_Field", ctrl->getClassName(), mTarget->getId(),mText);
  498. // Register the object
  499. ctrl->registerObject( szName );
  500. }
  501. bool GuiInspectorField::onAdd()
  502. {
  503. if( !Parent::onAdd() )
  504. return false;
  505. if( !mTarget )
  506. return false;
  507. setControlProfile(mGroup->mInspector->mLabelProfile);
  508. //Find the target width
  509. Point2I origin = Point2I(0,0);
  510. RectI innerRect = getInnerRect(origin, mGroup->mInspector->mFieldCellSize, NormalState, mProfile);
  511. mEdit = constructEditControl(innerRect.extent.x);
  512. if( mEdit == NULL )
  513. return false;
  514. innerRect.extent.y = mGroup->mInspector->mControlOffset.y + mEdit->getExtent().y;
  515. Point2I outerExt = getOuterExtent(innerRect.extent, NormalState, mProfile);
  516. mBounds.extent.y = outerExt.y;
  517. //Set the tool tip if possible
  518. if (mField != NULL && mField->pFieldDocs != NULL)
  519. {
  520. mEdit->setField("tooltip", mField->pFieldDocs);
  521. if (mGroup->mInspector->mTooltipProfile != NULL)
  522. {
  523. char buffer[256];
  524. dSprintf(buffer, sizeof(buffer), "%d", mGroup->mInspector->mTooltipProfile->getId());
  525. mEdit->setField("tooltipProfile", buffer);
  526. }
  527. }
  528. addObject( mEdit );
  529. // Force our editField to set it's value
  530. updateValue( getData() );
  531. return true;
  532. }
  533. void GuiInspectorField::updateValue( const char* newValue )
  534. {
  535. GuiTextEditCtrl *ctrl = dynamic_cast<GuiTextEditCtrl*>( mEdit );
  536. if( ctrl != NULL )
  537. ctrl->setText( newValue );
  538. }
  539. ConsoleMethod( GuiInspectorField, apply, void, 3,3, "(newValue) Applies the given value to the field\n"
  540. "@return No return value." )
  541. {
  542. object->setData( argv[2] );
  543. }
  544. #pragma endregion
  545. #pragma region GuiInspectorGroup
  546. //////////////////////////////////////////////////////////////////////////
  547. // GuiInspectorGroup
  548. //////////////////////////////////////////////////////////////////////////
  549. //
  550. // The GuiInspectorGroup control is a helper control that the inspector
  551. // makes use of which houses a collapsible panel type control for separating
  552. // inspected objects fields into groups. The content of the inspector is
  553. // made up of zero or more GuiInspectorGroup controls inside of a GuiChainControl
  554. //
  555. //
  556. //
  557. IMPLEMENT_CONOBJECT(GuiInspectorGroup);
  558. GuiInspectorGroup::GuiInspectorGroup()
  559. {
  560. mChildren.clear();
  561. mTarget = NULL;
  562. mInspector = NULL;
  563. mCanSave = false;
  564. mHorizSizing = horizSizingOptions::horizResizeWidth;
  565. mVertSizing = vertSizingOptions::vertResizeTop;
  566. mBounds.set(10, 0, (mInspector->getExtent().x - 20), 24);
  567. }
  568. GuiInspectorGroup::GuiInspectorGroup( SimObjectPtr<SimObject> target, StringTableEntry groupName, SimObjectPtr<GuiInspector> inspector )
  569. {
  570. mChildren.clear();
  571. mText = StringTable->insert(groupName);
  572. mTarget = target;
  573. mInspector = inspector;
  574. mCanSave = false;
  575. mHorizSizing = horizSizingOptions::horizResizeWidth;
  576. mVertSizing = vertSizingOptions::vertResizeTop;
  577. mBounds.set(10, 0, (mInspector->getExtent().x - 20), 24);
  578. }
  579. bool GuiInspectorGroup::onAdd()
  580. {
  581. if( !Parent::onAdd() )
  582. return false;
  583. setControlProfile(mInspector->mGroupPanelProfile);
  584. // Create our inner controls. Allow subclasses to provide other content.
  585. if(!createContent())
  586. return false;
  587. inspectGroup();
  588. return true;
  589. }
  590. bool GuiInspectorGroup::createContent()
  591. {
  592. // Create our field stack control
  593. mGrid = new GuiGridCtrl();
  594. if( !mGrid)
  595. return false;
  596. mGrid->setControlProfile(mInspector->mGroupGridProfile);
  597. mGrid->setCellSize(mInspector->mFieldCellSize.x, mInspector->mFieldCellSize.y);
  598. mGrid->setCellSpacing(0,0);
  599. mGrid->setCellModeX(GuiGridCtrl::CellMode::Variable);
  600. mGrid->setCellModeY(GuiGridCtrl::CellMode::Variable);
  601. mGrid->setMaxColCount(0);
  602. mGrid->mIsExtentDynamic = true;
  603. mGrid->mOrderMode = GuiGridCtrl::OrderMode::LRTB;
  604. mGrid->setWidth(getExtent().x - 20);
  605. mGrid->setPosition(Point2I(10, getExtent().y));
  606. mGrid->setField("horizSizing", "width");
  607. mGrid->setField("vertSizing", "bottom");
  608. mGrid->registerObject();
  609. addObject( mGrid );
  610. return true;
  611. }
  612. GuiInspectorField* GuiInspectorGroup::constructField( S32 fieldType )
  613. {
  614. ConsoleBaseType *cbt = ConsoleBaseType::getType(fieldType);
  615. AssertFatal(cbt, "GuiInspectorGroup::constructField - could not resolve field type!");
  616. // Alright, is it a datablock?
  617. if(cbt->isDatablock())
  618. {
  619. // This is fairly straightforward to deal with.
  620. GuiInspectorDatablockField *dbFieldClass = new GuiInspectorDatablockField( cbt->getTypeClassName() );
  621. if( dbFieldClass != NULL )
  622. {
  623. // return our new datablock field with correct datablock type enumeration info
  624. return dbFieldClass;
  625. }
  626. }
  627. // Nope, not a datablock. So maybe it has a valid inspector field override we can use?
  628. if(!cbt->getInspectorFieldType())
  629. // Nothing, so bail.
  630. return NULL;
  631. // Otherwise try to make it!
  632. ConsoleObject *co = create(cbt->getInspectorFieldType());
  633. GuiInspectorField *gif = dynamic_cast<GuiInspectorField*>(co);
  634. if(!gif)
  635. {
  636. // Wasn't appropriate type, bail.
  637. delete co;
  638. return NULL;
  639. }
  640. return gif;
  641. }
  642. GuiInspectorField *GuiInspectorGroup::findField( StringTableEntry fieldName )
  643. {
  644. // If we don't have any field children we can't very well find one then can we?
  645. if( mChildren.empty() )
  646. return NULL;
  647. Vector<GuiInspectorField*>::iterator i = mChildren.begin();
  648. for( ; i != mChildren.end(); i++ )
  649. {
  650. if( (*i)->getFieldName() != NULL && dStricmp( (*i)->getFieldName(), fieldName ) == 0 )
  651. return (*i);
  652. }
  653. return NULL;
  654. }
  655. bool GuiInspectorGroup::inspectGroup()
  656. {
  657. // We can't inspect a group without a target!
  658. if( !mTarget )
  659. return false;
  660. // to prevent crazy resizing, we'll just freeze our stack for a sec..
  661. //mStack->freeze(true);
  662. bool bNoGroup = false;
  663. // Un-grouped fields are all sorted into the 'general' group
  664. if ( dStricmp( mText, "General" ) == 0 )
  665. bNoGroup = true;
  666. AbstractClassRep::FieldList &fieldList = mTarget->getModifiableFieldList();
  667. AbstractClassRep::FieldList::iterator itr;
  668. bool bGrabItems = false;
  669. bool bNewItems = false;
  670. for(itr = fieldList.begin(); itr != fieldList.end(); itr++)
  671. {
  672. if( itr->type == AbstractClassRep::StartGroupFieldType )
  673. {
  674. // If we're dealing with general fields, always set grabItems to true (to skip them)
  675. if( bNoGroup == true || ( itr->pGroupname != NULL && dStricmp( itr->pGroupname, mText ) == 0 ))
  676. bGrabItems = true;
  677. continue;
  678. }
  679. else if ( itr->type == AbstractClassRep::EndGroupFieldType )
  680. {
  681. // If we're dealing with general fields, always set grabItems to false (to grab them)
  682. if( bNoGroup == true || ( itr->pGroupname != NULL && dStricmp( itr->pGroupname, mText ) == 0 ))
  683. bGrabItems = false;
  684. continue;
  685. }
  686. if((bGrabItems == true || (bNoGroup == true && bGrabItems == false)) && itr->type != AbstractClassRep::DepricatedFieldType )
  687. {
  688. //We are inside a group and looking for items that don't have a group. Move on.
  689. if( bNoGroup == true && bGrabItems == true )
  690. continue;
  691. // We are going to check to see if this item is an array
  692. // if so, we're going to construct a field for each array element
  693. if( itr->elementCount > 1 )
  694. {
  695. for(S32 nI = 0; nI < itr->elementCount; nI++)
  696. {
  697. FrameTemp<char> intToStr( 64 );
  698. dSprintf( intToStr, 64, "%d", nI );
  699. const char *val = mTarget->getDataField( itr->pFieldname, intToStr );
  700. if (!val)
  701. val = StringTable->EmptyString;
  702. // Copy Val and construct proper ValueName[nI] format
  703. // which is "ValueName0" for index 0, etc.
  704. S32 frameTempSize = dStrlen( val ) + 32;
  705. FrameTemp<char> valCopy( frameTempSize );
  706. dSprintf( (char *)valCopy, frameTempSize, "%s%d", itr->pFieldname, nI );
  707. // If the field already exists, just update it
  708. GuiInspectorField *field = findField( valCopy );
  709. if( field != NULL )
  710. {
  711. field->updateValue( field->getData() );
  712. continue;
  713. }
  714. bNewItems = true;
  715. field = constructField( itr->type );
  716. if( field == NULL )
  717. {
  718. field = new GuiInspectorField( this, mTarget, itr );
  719. field->setExtent(Point2I(this->getExtent().x,30));
  720. field->setInspectorField( itr, intToStr );
  721. }
  722. else
  723. {
  724. field->setExtent(Point2I(this->getExtent().x, 30));
  725. field->setTarget( mTarget );
  726. field->setInspectorGroup( this );
  727. field->setInspectorField( itr, intToStr );
  728. }
  729. field->registerObject();
  730. mChildren.push_back( field );
  731. mGrid->addObject( field );
  732. }
  733. }
  734. else
  735. {
  736. // If the field already exists, just update it
  737. GuiInspectorField *field = findField( itr->pFieldname );
  738. if( field != NULL )
  739. {
  740. field->updateValue( field->getData() );
  741. continue;
  742. }
  743. bNewItems = true;
  744. //check the hidden field list
  745. if (mInspector->hideField(itr->pFieldname))
  746. {
  747. continue;
  748. }
  749. //Time to create a new field
  750. field = constructField( itr->type );
  751. if( field == NULL )
  752. field = new GuiInspectorField( this, mTarget, itr );
  753. else
  754. {
  755. field->setTarget( mTarget );
  756. field->setInspectorGroup( this );
  757. field->setInspectorField( itr );
  758. }
  759. field->setExtent(Point2I(this->getExtent().x, 30));
  760. field->registerObject();
  761. mChildren.push_back( field );
  762. mGrid->addObject( field );
  763. }
  764. }
  765. }
  766. // If we've no new items, there's no need to resize anything!
  767. if( bNewItems == false && !mChildren.empty() )
  768. return true;
  769. //sizeToContents();
  770. setUpdate();
  771. return true;
  772. }
  773. #pragma endregion
  774. #pragma region GuiInspectorDynamicGroup
  775. IMPLEMENT_CONOBJECT(GuiInspectorDynamicGroup);
  776. //////////////////////////////////////////////////////////////////////////
  777. // GuiInspectorDynamicGroup - add custom controls
  778. //////////////////////////////////////////////////////////////////////////
  779. bool GuiInspectorDynamicGroup::createContent()
  780. {
  781. if(!Parent::createContent())
  782. return false;
  783. // add a button that lets us add new dynamic fields.
  784. GuiButtonCtrl* addFieldBtn = new GuiButtonCtrl();
  785. {
  786. SimObject* profilePtr = Sim::findObject("EditorButton");
  787. if( profilePtr != NULL )
  788. addFieldBtn->setControlProfile( dynamic_cast<GuiControlProfile*>(profilePtr) );
  789. char commandBuf[64];
  790. dSprintf(commandBuf, 64, "%d.addDynamicField();", this->getId());
  791. addFieldBtn->setField("profile", "GuiButtonProfile");
  792. addFieldBtn->setField("command", commandBuf);
  793. addFieldBtn->setField("text", "+");
  794. addFieldBtn->setExtent(Point2I(30, 30));
  795. addFieldBtn->registerObject("zAddButton");
  796. }
  797. // encapsulate the button in a dummy control.
  798. GuiControl* shell = new GuiControl();
  799. shell->setField( "profile", "GuiTextProfile" );
  800. shell->registerObject();
  801. shell->setField("text", "Add Field");
  802. shell->setExtent(Point2I(getExtent().x - 30,30 + 10));
  803. addFieldBtn->setPosition(Point2I((shell->getExtent().x) - 30, 0));
  804. shell->addObject(addFieldBtn);
  805. // save off the shell control, so we can push it to the bottom of the stack in inspectGroup()
  806. mAddCtrl = shell;
  807. mGrid->addObject(shell);
  808. return true;
  809. }
  810. static S32 QSORT_CALLBACK compareEntries(const void* a,const void* b)
  811. {
  812. SimFieldDictionary::Entry *fa = *((SimFieldDictionary::Entry **)a);
  813. SimFieldDictionary::Entry *fb = *((SimFieldDictionary::Entry **)b);
  814. return dStricmp(fa->slotName, fb->slotName);
  815. }
  816. //////////////////////////////////////////////////////////////////////////
  817. // GuiInspectorDynamicGroup - inspectGroup override
  818. //////////////////////////////////////////////////////////////////////////
  819. bool GuiInspectorDynamicGroup::inspectGroup()
  820. {
  821. // We can't inspect a group without a target!
  822. if( !mTarget )
  823. return false;
  824. // Clearing the fields and recreating them will more than likely be more
  825. // efficient than looking up existent fields, updating them, and then iterating
  826. // over existent fields and making sure they still exist, if not, deleting them.
  827. clearFields();
  828. // Create a vector of the fields
  829. Vector<SimFieldDictionary::Entry *> flist;
  830. // Then populate with fields
  831. SimFieldDictionary * fieldDictionary = mTarget->getFieldDictionary();
  832. for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr)
  833. {
  834. flist.push_back(*ditr);
  835. }
  836. dQsort(flist.address(),flist.size(),sizeof(SimFieldDictionary::Entry *),compareEntries);
  837. for(U32 i = 0; i < (U32)flist.size(); i++)
  838. {
  839. SimFieldDictionary::Entry * entry = flist[i];
  840. GuiInspectorField *field = new GuiInspectorDynamicField( this, mTarget, entry );
  841. if( field != NULL )
  842. {
  843. field->setExtent(Point2I(this->getExtent().x, 30));
  844. field->registerObject();
  845. mChildren.push_back( field );
  846. mGrid->addObject( field );
  847. }
  848. }
  849. mGrid->pushObjectToBack(mAddCtrl);
  850. setUpdate();
  851. return true;
  852. }
  853. ConsoleMethod(GuiInspectorDynamicGroup, inspectGroup, bool, 2, 2, "() Refreshes the dynamic fields in the inspector.\n"
  854. "@return Returns true on success.")
  855. {
  856. return object->inspectGroup();
  857. }
  858. void GuiInspectorDynamicGroup::clearFields()
  859. {
  860. // save mAddCtrl
  861. Sim::getGuiGroup()->addObject(mAddCtrl);
  862. // delete everything else
  863. mGrid->clear();
  864. // clear the mChildren list.
  865. mChildren.clear();
  866. // and restore.
  867. mGrid->addObject(mAddCtrl);
  868. }
  869. SimFieldDictionary::Entry* GuiInspectorDynamicGroup::findDynamicFieldInDictionary( StringTableEntry fieldName )
  870. {
  871. if( !mTarget )
  872. return NULL;
  873. SimFieldDictionary * fieldDictionary = mTarget->getFieldDictionary();
  874. for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr)
  875. {
  876. SimFieldDictionary::Entry * entry = (*ditr);
  877. if( dStricmp( entry->slotName, fieldName ) == 0 )
  878. return entry;
  879. }
  880. return NULL;
  881. }
  882. void GuiInspectorDynamicGroup::addDynamicField()
  883. {
  884. // We can't add a field without a target
  885. if( !mTarget || !mGrid)
  886. {
  887. Con::warnf("GuiInspectorDynamicGroup::addDynamicField - no target SimObject to add a dynamic field to.");
  888. return;
  889. }
  890. // find a field name that is not in use.
  891. // But we wont try more than 100 times to find an available field.
  892. U32 uid = 1;
  893. char buf[64] = "dynamicField";
  894. SimFieldDictionary::Entry* entry = findDynamicFieldInDictionary(buf);
  895. while(entry != NULL && uid < 100)
  896. {
  897. dSprintf(buf, sizeof(buf), "dynamicField%03d", uid++);
  898. entry = findDynamicFieldInDictionary(buf);
  899. }
  900. //Con::evaluatef( "%d.%s = \"defaultValue\";", mTarget->getId(), buf );
  901. mTarget->setDataField(StringTable->insert(buf), NULL, "defaultValue");
  902. // now we simply re-inspect the object, to see the new field.
  903. this->inspectGroup();
  904. //animateToContents();
  905. }
  906. ConsoleMethod( GuiInspectorDynamicGroup, addDynamicField, void, 2, 2, "obj.addDynamicField();" )
  907. {
  908. object->addDynamicField();
  909. }
  910. #pragma endregion
  911. #pragma region GuiInspectorDynamicField
  912. //////////////////////////////////////////////////////////////////////////
  913. // GuiInspectorDynamicField - Child class of GuiInspectorField
  914. //////////////////////////////////////////////////////////////////////////
  915. IMPLEMENT_CONOBJECT(GuiInspectorDynamicField);
  916. GuiInspectorDynamicField::GuiInspectorDynamicField( GuiInspectorGroup* parent, SimObjectPtr<SimObject> target, SimFieldDictionary::Entry* field )
  917. {
  918. mGroup = parent;
  919. mTarget = target;
  920. mDynField = field;
  921. mRenameCtrl = NULL;
  922. }
  923. void GuiInspectorDynamicField::setData( const char* data )
  924. {
  925. if( mTarget == NULL || mDynField == NULL )
  926. return;
  927. char buf[1024];
  928. const char * newValue = mEdit->getScriptValue();
  929. dStrcpy( buf, newValue ? newValue : "" );
  930. collapseEscape(buf);
  931. mTarget->getFieldDictionary()->setFieldValue(mDynField->slotName, buf);
  932. // Force our edit to update
  933. updateValue( data );
  934. }
  935. const char* GuiInspectorDynamicField::getData()
  936. {
  937. if( mTarget == NULL || mDynField == NULL )
  938. return "";
  939. return mTarget->getFieldDictionary()->getFieldValue( mDynField->slotName );
  940. }
  941. void GuiInspectorDynamicField::renameField( StringTableEntry newFieldName )
  942. {
  943. if( mTarget == NULL || mDynField == NULL || mGroup == NULL || mEdit == NULL )
  944. {
  945. Con::warnf("GuiInspectorDynamicField::renameField - No target object or dynamic field data found!" );
  946. return;
  947. }
  948. if( !newFieldName )
  949. {
  950. Con::warnf("GuiInspectorDynamicField::renameField - Invalid field name specified!" );
  951. return;
  952. }
  953. // Only proceed if the name has changed
  954. if( dStricmp( newFieldName, getFieldName() ) == 0 )
  955. return;
  956. // Grab a pointer to our parent and cast it to GuiInspectorDynamicGroup
  957. GuiInspectorDynamicGroup *group = dynamic_cast<GuiInspectorDynamicGroup*>(mGroup);
  958. if( group == NULL )
  959. {
  960. Con::warnf("GuiInspectorDynamicField::renameField - Unable to locate GuiInspectorDynamicGroup parent!" );
  961. return;
  962. }
  963. // Grab our current dynamic field value
  964. const char* currentValue = getData();
  965. // Create our new field with the value of our old field and the new fields name!
  966. mTarget->setDataField( newFieldName, NULL, currentValue );
  967. // Configure our field to grab data from the new dynamic field
  968. SimFieldDictionary::Entry *newEntry = group->findDynamicFieldInDictionary( newFieldName );
  969. if( newEntry == NULL )
  970. {
  971. Con::warnf("GuiInspectorDynamicField::renameField - Unable to find new field!" );
  972. return;
  973. }
  974. // Set our old fields data to "" (which will effectively erase the field)
  975. mTarget->setDataField( getFieldName(), NULL, "" );
  976. // Assign our dynamic field pointer (where we retrieve field information from) to our new field pointer
  977. mDynField = newEntry;
  978. // Lastly we need to reassign our AltCommand fields for our value edit control
  979. char szBuffer[512];
  980. dSprintf( szBuffer, 512, "%d.%s = %d.getText();",mTarget->getId(), getFieldName(), mEdit->getId() );
  981. mEdit->setExtent(Point2I((getExtent().x / 2) - 20, 30));
  982. mEdit->setField("AltCommand", szBuffer );
  983. }
  984. ConsoleMethod( GuiInspectorDynamicField, renameField, void, 3,3, "field.renameField(newDynamicFieldName);" )
  985. {
  986. object->renameField( StringTable->insert(argv[2]) );
  987. }
  988. bool GuiInspectorDynamicField::onAdd()
  989. {
  990. if( !Parent::onAdd() )
  991. return false;
  992. mRenameCtrl = constructRenameControl();
  993. pushObjectToBack(mEdit);
  994. return true;
  995. }
  996. GuiControl* GuiInspectorDynamicField::constructRenameControl()
  997. {
  998. // Create our renaming field
  999. GuiControl* retCtrl = new GuiTextEditCtrl();
  1000. // If we couldn't construct the control, bail!
  1001. if( retCtrl == NULL )
  1002. return retCtrl;
  1003. // Let's make it look pretty.
  1004. retCtrl->setField( "profile", "GuiTextEditProfile" );
  1005. // Don't forget to register ourselves
  1006. char szName[512];
  1007. dSprintf( szName, 512, "IE_%s_%d_%s_Rename", retCtrl->getClassName(), mTarget->getId(), getFieldName() );
  1008. retCtrl->registerObject( szName );
  1009. // Our command will evaluate to :
  1010. //
  1011. // if( (editCtrl).getText() !$= "" )
  1012. // (field).renameField((editCtrl).getText());
  1013. //
  1014. char szBuffer[512];
  1015. dSprintf( szBuffer, 512, "if( %d.getText() !$= \"\" ) %d.renameField(%d.getText());",retCtrl->getId(), getId(), retCtrl->getId() );
  1016. dynamic_cast<GuiTextEditCtrl*>(retCtrl)->setText( getFieldName() );
  1017. retCtrl->setExtent(Point2I((getExtent().x / 2) - 20, 30));
  1018. retCtrl->setField("AltCommand", szBuffer );
  1019. addObject( retCtrl );
  1020. // Finally, add a delete button for this field
  1021. GuiButtonCtrl * delButt = new GuiButtonCtrl();
  1022. if( delButt != NULL )
  1023. {
  1024. dSprintf(szBuffer, 512, "%d.%s = \"\";%d.inspectGroup();", mTarget->getId(), getFieldName(), mGroup->getId());
  1025. delButt->setField("profile", "GuiButtonProfile");
  1026. delButt->setField("Text", "X");
  1027. delButt->setPosition(Point2I((getExtent().x - 40), 0));
  1028. delButt->setField("extent", "30 30");
  1029. delButt->setField("Command", szBuffer);
  1030. delButt->registerObject();
  1031. addObject(delButt);
  1032. }
  1033. return retCtrl;
  1034. }
  1035. void GuiInspectorDynamicField::resize( const Point2I &newPosition, const Point2I &newExtent )
  1036. {
  1037. Parent::resize( newPosition, newExtent );
  1038. }
  1039. #pragma endregion
  1040. #pragma region GuiInspectorDatablockField
  1041. //////////////////////////////////////////////////////////////////////////
  1042. // GuiInspectorDatablockField
  1043. // Field construction for datablock types
  1044. //////////////////////////////////////////////////////////////////////////
  1045. IMPLEMENT_CONOBJECT(GuiInspectorDatablockField);
  1046. static S32 QSORT_CALLBACK stringCompare(const void *a,const void *b)
  1047. {
  1048. StringTableEntry sa = *(StringTableEntry*)a;
  1049. StringTableEntry sb = *(StringTableEntry*)b;
  1050. return(dStricmp(sb, sa));
  1051. }
  1052. GuiInspectorDatablockField::GuiInspectorDatablockField( StringTableEntry className )
  1053. {
  1054. setClassName(className);
  1055. };
  1056. void GuiInspectorDatablockField::setClassName( StringTableEntry className )
  1057. {
  1058. // Walk the ACR list and find a matching class if any.
  1059. AbstractClassRep *walk = AbstractClassRep::getClassList();
  1060. while(walk)
  1061. {
  1062. if(!dStricmp(walk->getClassName(), className))
  1063. {
  1064. // Match!
  1065. mDesiredClass = walk;
  1066. return;
  1067. }
  1068. walk = walk->getNextClass();
  1069. }
  1070. // No dice.
  1071. Con::warnf("GuiInspectorDatablockField::setClassName - no class '%s' found!", className);
  1072. return;
  1073. }
  1074. GuiControl* GuiInspectorDatablockField::constructEditControl()
  1075. {
  1076. GuiControl* retCtrl = new GuiDropDownCtrl();
  1077. // If we couldn't construct the control, bail!
  1078. if( retCtrl == NULL )
  1079. return retCtrl;
  1080. GuiDropDownCtrl *menu = dynamic_cast<GuiDropDownCtrl*>(retCtrl);
  1081. menu->setField("text", getData());
  1082. registerEditControl( retCtrl );
  1083. // Configure it to update our value when the dropdown is closed
  1084. char szBuffer[512];
  1085. dSprintf( szBuffer, 512, "%d.%s = %d.getText();%d.inspect(%d);",mTarget->getId(), mField->pFieldname, menu->getId(), mGroup->mInspector->getId(), mTarget->getId() );
  1086. menu->setField("Command", szBuffer );
  1087. Vector<StringTableEntry> entries;
  1088. SimDataBlockGroup * grp = Sim::getDataBlockGroup();
  1089. for(SimDataBlockGroup::iterator i = grp->begin(); i != grp->end(); i++)
  1090. {
  1091. SimDataBlock * datablock = dynamic_cast<SimDataBlock*>(*i);
  1092. // Skip non-datablocks if we somehow encounter them.
  1093. if(!datablock)
  1094. continue;
  1095. // Ok, now we have to figure inheritance info.
  1096. if( datablock && datablock->getClassRep()->isClass(mDesiredClass) )
  1097. entries.push_back(datablock->getName());
  1098. }
  1099. // sort the entries
  1100. dQsort(entries.address(), entries.size(), sizeof(StringTableEntry), stringCompare);
  1101. // add them to our enum
  1102. for(U32 j = 0; j < (U32)entries.size(); j++)
  1103. menu->getList()->addItem(entries[j]);
  1104. return retCtrl;
  1105. }
  1106. #pragma endregion