guiTreeViewCtrl.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  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/guiTreeViewCtrl.h"
  23. #include "graphics/dgl.h"
  24. #include "gui/guiDefaultControlRender.h"
  25. #include "gui/guiCanvas.h"
  26. #include "gui/editor/guiEditCtrl.h"
  27. #include "guiTreeViewCtrl_ScriptBinding.h"
  28. IMPLEMENT_CONOBJECT(GuiTreeViewCtrl);
  29. GuiTreeViewCtrl::GuiTreeViewCtrl()
  30. {
  31. mActive = true;
  32. mIndentSize = 10;
  33. mMultipleSelections = true;
  34. mTouchPoint = Point2I::Zero;
  35. mDragActive = false;
  36. mDragIndex = 0;
  37. mIsDragLegal = false;
  38. mIsBoundToGuiEditor = false;
  39. mFocusControl = nullptr;
  40. }
  41. GuiTreeViewCtrl::~GuiTreeViewCtrl()
  42. {
  43. }
  44. GuiTreeViewCtrl::TreeItem* GuiTreeViewCtrl::grabItemPtr(S32 index)
  45. {
  46. // Range Check
  47. if (index >= mItems.size() || index < 0)
  48. {
  49. Con::warnf("GuiTreeViewCtrl::grabItemPtr - index out of range!");
  50. return nullptr;
  51. }
  52. // Grab our item
  53. TreeItem* treeItem = dynamic_cast<GuiTreeViewCtrl::TreeItem*>(mItems[index]);
  54. return treeItem;
  55. }
  56. void GuiTreeViewCtrl::initPersistFields()
  57. {
  58. Parent::initPersistFields();
  59. addField("BindToGuiEditor", TypeBool, Offset(mIsBoundToGuiEditor, GuiTreeViewCtrl));
  60. }
  61. void GuiTreeViewCtrl::onTouchDown(const GuiEvent& event)
  62. {
  63. mTouchPoint == event.mousePoint;
  64. S32 hitIndex = getHitIndex(event);
  65. if (mIsBoundToGuiEditor && smDesignTime && hitIndex == 0)
  66. {
  67. if (!(event.modifier & SI_CTRL) && !(event.modifier & SI_SHIFT))
  68. {
  69. clearSelection();
  70. GuiEditCtrl* edit = GuiControl::smEditorHandle;
  71. if (edit)
  72. {
  73. GuiControl* root = static_cast<GuiControl*>(mItems[0]->itemData);
  74. edit->setCurrentAddSet(root, true);
  75. }
  76. }
  77. }
  78. else
  79. {
  80. Parent::onTouchDown(event);
  81. }
  82. }
  83. void GuiTreeViewCtrl::onTouchDragged(const GuiEvent& event)
  84. {
  85. mDragActive = false;
  86. if (!mActive || !mVisible)
  87. return;
  88. S32 hitIndex = getHitIndex(event);
  89. if (hitIndex >= mItems.size() || hitIndex == -1)
  90. return;
  91. LBItem* hitItem = mItems[hitIndex];
  92. if (hitItem == NULL || !hitItem->isActive)
  93. return;
  94. if (mAbs(mTouchPoint.x - event.mousePoint.x) > 2 || mAbs(mTouchPoint.y - event.mousePoint.y) > 2)
  95. {
  96. mDragActive = true;
  97. }
  98. }
  99. void GuiTreeViewCtrl::onTouchUp(const GuiEvent& event)
  100. {
  101. if (mDragActive && mIsDragLegal)
  102. {
  103. TreeItem* dragItem = grabItemPtr(mDragIndex);
  104. if (mReorderMethod == ReorderMethod::Below && dragItem->isOpen)
  105. {
  106. mReorderMethod = ReorderMethod::Insert;
  107. }
  108. SimGroup* target = static_cast<SimGroup*>(mReorderMethod == ReorderMethod::Insert ? dragItem->itemData : dragItem->trunk->itemData);
  109. if (!target)
  110. {
  111. Con::warnf("GuiTreeViewCtrl::onTouchUp - attempted to drag selection into an object that is not a SimGroup");
  112. return;
  113. }
  114. vector<SimObject*> objectAboveTargetList = vector<SimObject*>();
  115. if (mReorderMethod != ReorderMethod::Insert)
  116. {
  117. S32 index = mReorderMethod == ReorderMethod::Below ? mDragIndex : mDragIndex - 1;
  118. TreeItem* checkItem = grabItemPtr(index);
  119. while (checkItem->level == dragItem->level)
  120. {
  121. if(!checkItem->isSelected)
  122. {
  123. SimObject* obj = static_cast<SimObject*>(checkItem->itemData);
  124. objectAboveTargetList.push_back(obj);
  125. }
  126. index = index - 1;
  127. checkItem = grabItemPtr(index);
  128. }
  129. }
  130. else
  131. {
  132. dragItem->isOpen = true;
  133. }
  134. for (S32 i = mItems.size() - 1; i >= 0; i--)
  135. {
  136. TreeItem* treeItem = dynamic_cast<TreeItem*>(mItems[i]);
  137. if(treeItem && treeItem->isSelected)
  138. {
  139. SimObject* obj = static_cast<SimObject*>(treeItem->itemData);
  140. if(obj)
  141. {
  142. target->addObject(obj);
  143. target->bringObjectToFront(obj);
  144. }
  145. }
  146. }
  147. for (auto obj : objectAboveTargetList)
  148. {
  149. SimGroup* group = obj->getGroup();
  150. group->bringObjectToFront(obj);
  151. }
  152. GuiControl* control = static_cast<GuiControl*>(mReorderMethod != ReorderMethod::Insert ? dragItem->trunk->itemData : dragItem->itemData);
  153. if (control)
  154. {
  155. control->childrenReordered();
  156. }
  157. refreshTree();
  158. }
  159. mDragActive = false;
  160. Parent::onTouchUp(event);
  161. }
  162. void GuiTreeViewCtrl::onPreRender()
  163. {
  164. if (mIsBoundToGuiEditor && smDesignTime && smEditorHandle)
  165. {
  166. GuiEditCtrl* edit = GuiControl::smEditorHandle;
  167. if (edit)
  168. {
  169. const GuiControl* oldFocus = mFocusControl;
  170. mFocusControl = edit->getCurrentAddSet();
  171. if(oldFocus != mFocusControl)
  172. {
  173. for (S32 i = 0; i < mItems.size(); i++)
  174. {
  175. LBItem* item = mItems[i];
  176. TreeItem* treeItem = dynamic_cast<TreeItem*>(item);
  177. SimObject* obj = static_cast<SimObject*>(item->itemData);
  178. if (obj && obj->getId() == mFocusControl->getId())
  179. {
  180. treeItem->isSelected = false;
  181. if(!treeItem->isOpen)
  182. {
  183. treeItem->isOpen = true;
  184. refreshTree();
  185. }
  186. }
  187. }
  188. }
  189. }
  190. }
  191. }
  192. void GuiTreeViewCtrl::onRender(Point2I offset, const RectI& updateRect)
  193. {
  194. mFocusLevel = -1;
  195. RectI clip = dglGetClipRect();
  196. if (mFitParentWidth && (mBounds.extent.x != clip.extent.x || mItemSize.x != clip.extent.x))
  197. {
  198. mBounds.extent.x = clip.extent.x;
  199. mItemSize.x = clip.extent.x;
  200. }
  201. RectI dragRect;
  202. for (S32 i = 0, j = 0; i < mItems.size(); i++)
  203. {
  204. // Only render visible items
  205. if ((j + 1) * mItemSize.y + offset.y < updateRect.point.y)
  206. continue;
  207. // Break out once we're no longer in visible item range
  208. if (j * mItemSize.y + offset.y >= updateRect.point.y + updateRect.extent.y)
  209. break;
  210. RectI itemRect = RectI(offset.x, offset.y + (j * mItemSize.y), mItemSize.x, mItemSize.y);
  211. TreeItem* treeItem = dynamic_cast<TreeItem*>(mItems[i]);
  212. if(!treeItem || treeItem->isVisible)
  213. {
  214. if (mFocusLevel >= 0 && mFocusLevel >= treeItem->level)
  215. {
  216. mFocusLevel = -1;
  217. }
  218. // Render our item
  219. onRenderItem(itemRect, mItems[i]);
  220. if (mItems[i]->ID == mFocusControl->getId())
  221. {
  222. mFocusLevel = treeItem->level;
  223. }
  224. if (mDragActive && j == mDragIndex)
  225. {
  226. dragRect = RectI(itemRect);
  227. }
  228. j++;
  229. }
  230. }
  231. if(mDragActive && mIsDragLegal)
  232. {
  233. onRenderDragLine(dragRect);
  234. }
  235. }
  236. void GuiTreeViewCtrl::onRenderItem(RectI& itemRect, LBItem* item)
  237. {
  238. TreeItem* treeItem = dynamic_cast<TreeItem*>(item);
  239. SimObject* obj = static_cast<SimObject*>(item->itemData);
  240. if (!treeItem)
  241. {
  242. Parent::onRenderItem(itemRect, item);
  243. return;
  244. }
  245. Point2I cursorPt = Point2I(0, 0);
  246. GuiCanvas* root = getRoot();
  247. if (root)
  248. {
  249. cursorPt = root->getCursorPos();
  250. }
  251. bool isFocus = obj == mFocusControl;
  252. GuiControlState currentState = GuiControlState::NormalState;
  253. if (!mActive || !item->isActive)
  254. currentState = GuiControlState::DisabledState;
  255. else if (item->isSelected)
  256. currentState = GuiControlState::SelectedState;
  257. else if (itemRect.pointInRect(cursorPt))
  258. currentState = GuiControlState::HighlightState;
  259. RectI ctrlRect = applyMargins(itemRect.point, itemRect.extent, currentState, mProfile);
  260. if (!ctrlRect.isValidRect())
  261. {
  262. return;
  263. }
  264. renderUniversalRect(ctrlRect, mProfile, currentState);
  265. //Render Text
  266. dglSetBitmapModulation(getFontColor(mProfile, currentState));
  267. RectI fillRect = applyBorders(ctrlRect.point, ctrlRect.extent, currentState, mProfile);
  268. RectI contentRect = applyPadding(fillRect.point, fillRect.extent, currentState, mProfile);
  269. //indent to the focus level
  270. if(mFocusLevel >= 0)
  271. {
  272. contentRect.point.x += (mFocusLevel * contentRect.extent.y);
  273. contentRect.extent.x -= (mFocusLevel * contentRect.extent.y);
  274. //convert this space to a line by crushing down the sides
  275. S32 crush = mRound((contentRect.extent.y - 2) / 2);
  276. RectI line = RectI(contentRect.point.x + crush, contentRect.point.y, 2, contentRect.extent.y);
  277. ColorI lineColor = currentState == SelectedState ? mProfile->getFillColor(NormalState) : mProfile->getFillColor(SelectedState);
  278. dglDrawRectFill(line, lineColor);
  279. //Remove indent
  280. contentRect.point.x -= (mFocusLevel * contentRect.extent.y);
  281. contentRect.extent.x += (mFocusLevel * contentRect.extent.y);
  282. }
  283. // Indent by level
  284. contentRect.point.x += (treeItem->level * contentRect.extent.y);
  285. contentRect.extent.x -= (treeItem->level * contentRect.extent.y);
  286. // Render open/close triangle
  287. if(obj)
  288. {
  289. SimGroup* setObj = dynamic_cast<SimGroup*>(obj);
  290. GuiControl* guiCtrl = dynamic_cast<GuiControl*>(obj);
  291. bool showTriangle = (guiCtrl && guiCtrl->mIsContainer) || (!guiCtrl && setObj && setObj->size() > 0);
  292. if (showTriangle)
  293. {
  294. RectI drawArea = RectI(contentRect.point.x, contentRect.point.y, contentRect.extent.y, contentRect.extent.y);
  295. treeItem->triangleArea.set(drawArea.point, drawArea.extent);
  296. ColorI color = mProfile->getFontColor(currentState);
  297. if (isFocus)
  298. {
  299. color = mProfile->getFillColor(SelectedState);
  300. }
  301. renderTriangleIcon(drawArea, color, treeItem->isOpen ? GuiDirection::Down : GuiDirection::Right, 8);
  302. }
  303. }
  304. contentRect.point.x += contentRect.extent.y;
  305. contentRect.extent.x -= contentRect.extent.y;
  306. renderText(contentRect.point, contentRect.extent, item->itemText, mProfile);
  307. }
  308. void GuiTreeViewCtrl::onRenderDragLine(RectI& itemRect)
  309. {
  310. ColorI colorW = ColorI(255,255,255,150);
  311. ColorI colorB = ColorI(0, 0, 0, 150);
  312. RectI rect = RectI(itemRect);
  313. rect.inset(4, 2);
  314. if (mReorderMethod == ReorderMethod::Insert)
  315. {
  316. dglDrawRect(itemRect, colorW);
  317. itemRect.inset(-1, -1);
  318. dglDrawRect(itemRect, colorB);
  319. }
  320. else if (mReorderMethod == ReorderMethod::Above)
  321. {
  322. itemRect.extent.y = 4;
  323. dglDrawRect(itemRect, colorW);
  324. itemRect.inset(-1, -1);
  325. dglDrawRect(itemRect, colorB);
  326. }
  327. else if(mReorderMethod == ReorderMethod::Below)
  328. {
  329. itemRect.point.y += mItemSize.y;
  330. itemRect.extent.y = 4;
  331. dglDrawRect(itemRect, colorW);
  332. itemRect.inset(-1, -1);
  333. dglDrawRect(itemRect, colorB);
  334. }
  335. }
  336. S32 GuiTreeViewCtrl::getHitIndex(const GuiEvent& event)
  337. {
  338. Point2I localPoint = globalToLocalCoord(event.mousePoint);
  339. if (localPoint.y < 0)
  340. {
  341. return -1;
  342. }
  343. S32 slot = (S32)mFloor((F32)localPoint.y / (F32)mItemSize.y);
  344. for (S32 i = 0, j = 0; i < mItems.size(); i++)
  345. {
  346. TreeItem* treeItem = dynamic_cast<TreeItem*>(mItems[i]);
  347. if (treeItem && treeItem->isVisible)
  348. {
  349. if (j == slot)
  350. {
  351. S32 roundSlot = (S32)mRound((F32)localPoint.y / (F32)mItemSize.y);
  352. mReorderMethod = roundSlot == slot ? ReorderMethod::Above : ReorderMethod::Below;
  353. SimObject* obj = static_cast<SimObject*>(treeItem->itemData);
  354. bool showTriangle = false;
  355. if(obj)
  356. {
  357. SimGroup* setObj = dynamic_cast<SimGroup*>(obj);
  358. GuiControl* guiCtrl = dynamic_cast<GuiControl*>(obj);
  359. showTriangle = (guiCtrl && guiCtrl->mIsContainer) || (!guiCtrl && setObj && setObj->size() > 0);
  360. if (((slot * mItemSize.y) + 5) < localPoint.y && mReorderMethod == ReorderMethod::Above && showTriangle)
  361. {
  362. mReorderMethod = ReorderMethod::Insert;
  363. }
  364. }
  365. if (j == 0)
  366. {
  367. mReorderMethod = ReorderMethod::Insert;
  368. }
  369. mIsDragLegal = true;
  370. for(TreeItem* trunk = treeItem; trunk != nullptr; trunk = trunk->trunk)
  371. {
  372. if (trunk->isSelected)
  373. {
  374. mIsDragLegal = false;
  375. break;
  376. }
  377. }
  378. mDragIndex = j;
  379. return i;
  380. }
  381. j++;
  382. }
  383. }
  384. return -1;
  385. }
  386. void GuiTreeViewCtrl::handleItemClick(LBItem* hitItem, S32 hitIndex, const GuiEvent& event)
  387. {
  388. TreeItem* treeItem = dynamic_cast<TreeItem*>(hitItem);
  389. if (treeItem)
  390. {
  391. if (treeItem->triangleArea.pointInRect(event.mousePoint))
  392. {
  393. treeItem->isOpen = !treeItem->isOpen;
  394. setBranchesVisible(treeItem, treeItem->isOpen);
  395. return;
  396. }
  397. }
  398. Parent::handleItemClick(hitItem, hitIndex, event);
  399. }
  400. void GuiTreeViewCtrl::handleItemClick_ClickCallbacks(LBItem* hitItem, S32 hitIndex, const GuiEvent& event)
  401. {
  402. TreeItem* treeItem = dynamic_cast<TreeItem*>(hitItem);
  403. if (!treeItem)
  404. {
  405. Parent::handleItemClick_ClickCallbacks(hitItem, hitIndex, event);
  406. return;
  407. }
  408. SimObject* obj = static_cast<SimObject*>(treeItem->itemData);
  409. if (hitItem == mLastClickItem && event.mouseClickCount == 2)
  410. {
  411. if (caller->isMethod("onDoubleClick"))
  412. Con::executef(caller, 2, "onDoubleClick", Con::getIntArg(obj->getId()));
  413. }
  414. else if (caller->isMethod("onClick"))
  415. {
  416. Con::executef(caller, 2, "onClick", Con::getIntArg(obj->getId()));
  417. }
  418. }
  419. void GuiTreeViewCtrl::inspectObject(SimObject* obj)
  420. {
  421. clearItems();
  422. mRootObject = obj;
  423. StringTableEntry text = getObjectText(obj);
  424. S32 id = addItemWithID(text, obj->getId(), obj);
  425. TreeItem* treeItem = grabItemPtr(id);
  426. treeItem->level = 0;
  427. addBranches(treeItem, obj, 1);
  428. }
  429. void GuiTreeViewCtrl::uninspectObject()
  430. {
  431. clearItems();
  432. mRootObject = NULL;
  433. }
  434. void GuiTreeViewCtrl::addBranches(TreeItem* treeItem, SimObject* obj, U16 level)
  435. {
  436. SimGroup* setObj = dynamic_cast<SimGroup*>(obj);
  437. if(setObj)
  438. {
  439. for(auto sub : *setObj)
  440. {
  441. StringTableEntry text = getObjectText(sub);
  442. S32 index = addItemWithID(text, sub->getId(), sub);
  443. TreeItem* branch = grabItemPtr(index);
  444. branch->level = level;
  445. branch->trunk = treeItem;
  446. treeItem->branchList.push_back(branch);
  447. addBranches(branch, sub, level + 1);
  448. }
  449. }
  450. }
  451. GuiListBoxCtrl::LBItem* GuiTreeViewCtrl::createItem()
  452. {
  453. LBItem* newItem = new TreeItem;
  454. if (!newItem)
  455. {
  456. return nullptr;
  457. }
  458. return newItem;
  459. }
  460. void GuiTreeViewCtrl::refreshTree()
  461. {
  462. if (mRootObject)
  463. {
  464. Vector<U32> selectedList;
  465. Vector<U32> openList;
  466. for (auto item : mItems)
  467. {
  468. TreeItem* treeItem = dynamic_cast<TreeItem*>(item);
  469. if (item->isSelected)
  470. {
  471. selectedList.push_back(treeItem->ID);
  472. }
  473. if (treeItem && treeItem->isOpen)
  474. {
  475. openList.push_back(treeItem->ID);
  476. }
  477. }
  478. Point2I pos = Point2I::Zero;
  479. auto scroller = dynamic_cast<GuiScrollCtrl*>(getParent());
  480. if (scroller)
  481. {
  482. pos = scroller->mScrollOffset;
  483. }
  484. inspectObject(mRootObject);
  485. for (auto item : mItems)
  486. {
  487. TreeItem* treeItem = dynamic_cast<TreeItem*>(item);
  488. if (selectedList.contains(treeItem->ID))
  489. {
  490. item->isSelected = true;
  491. mSelectedItems.push_front(item);
  492. }
  493. if (treeItem && openList.contains(treeItem->ID))
  494. {
  495. treeItem->isOpen = true;
  496. }
  497. else if(treeItem)
  498. {
  499. treeItem->isOpen = false;
  500. setBranchesVisible(treeItem, treeItem->isOpen);
  501. }
  502. }
  503. if (scroller)
  504. {
  505. scroller->scrollTo(pos.x, pos.y);
  506. }
  507. }
  508. }
  509. StringTableEntry GuiTreeViewCtrl::getObjectText(SimObject* obj)
  510. {
  511. char buffer[1024];
  512. if (obj)
  513. {
  514. if (isMethod("onGetObjectText"))
  515. {
  516. const char* text = Con::executef(this, 2, "onGetObjectText", Con::getIntArg(obj->getId()));
  517. StringTableEntry name = StringTable->insert(text, true);
  518. if (name != StringTable->EmptyString)
  519. {
  520. return name;
  521. }
  522. }
  523. const char* pObjName = obj->getName();
  524. const char* pInternalName = obj->getInternalName();
  525. GuiControl* ctrl = dynamic_cast<GuiControl*>(obj);
  526. const char* theText = ctrl ? ctrl->getText() : "";
  527. StringTableEntry textEntry = StringTable->insert(theText, true);
  528. if(textEntry == StringTable->EmptyString)
  529. {
  530. if (pObjName != NULL)
  531. dSprintf(buffer, sizeof(buffer), "%d: %s - %s", obj->getId(), obj->getClassName(), pObjName);
  532. else if (pInternalName != NULL)
  533. dSprintf(buffer, sizeof(buffer), "%d: %s [%s]", obj->getId(), obj->getClassName(), pInternalName);
  534. else
  535. dSprintf(buffer, sizeof(buffer), "%d: %s", obj->getId(), obj->getClassName());
  536. }
  537. else
  538. {
  539. if (pObjName != NULL)
  540. dSprintf(buffer, sizeof(buffer), "%d: %s \"%s\" - %s", obj->getId(), obj->getClassName(), textEntry, pObjName);
  541. else if (pInternalName != NULL)
  542. dSprintf(buffer, sizeof(buffer), "%d: %s \"%s\" [%s]", obj->getId(), obj->getClassName(), textEntry, pInternalName);
  543. else
  544. dSprintf(buffer, sizeof(buffer), "%d: %s \"%s\"", obj->getId(), obj->getClassName(), textEntry);
  545. }
  546. }
  547. return StringTable->insert(buffer, true);
  548. }
  549. void GuiTreeViewCtrl::calculateHeaderExtent()
  550. {
  551. if(mProfile)
  552. {
  553. GuiBorderProfile* topProfile = mProfile->getTopBorder();
  554. GuiBorderProfile* bottomProfile = mProfile->getBottomBorder();
  555. S32 topSize = (topProfile) ? topProfile->getMargin(NormalState) + topProfile->getBorder(NormalState) + topProfile->getPadding(NormalState) : 0;
  556. S32 bottomSize = (bottomProfile) ? bottomProfile->getMargin(NormalState) + bottomProfile->getBorder(NormalState) + bottomProfile->getPadding(NormalState) : 0;
  557. GFont* font = mProfile->getFont();
  558. S32 fontSize = (font) ? font->getHeight() : 0;
  559. S32 height = topSize + bottomSize + fontSize;
  560. S32 width = mBounds.extent.x;
  561. }
  562. }
  563. void GuiTreeViewCtrl::setBranchesVisible(TreeItem* treeItem, bool isVisible)
  564. {
  565. for (auto branch : treeItem->branchList)
  566. {
  567. if(!isVisible || branch->isOpen)
  568. {
  569. setBranchesVisible(branch, isVisible);
  570. }
  571. branch->isVisible = isVisible;
  572. }
  573. }
  574. void GuiTreeViewCtrl::setItemOpen(S32 index, bool isOpen)
  575. {
  576. if ((index >= mItems.size()) || index < 0)
  577. {
  578. Con::warnf("GuiTreeViewCtrl::setItemOpen - invalid index");
  579. return;
  580. }
  581. TreeItem* item = dynamic_cast<TreeItem*>(mItems[index]);
  582. item->isOpen = isOpen;
  583. }
  584. bool GuiTreeViewCtrl::getItemOpen(S32 index)
  585. {
  586. if ((index >= mItems.size()) || index < 0)
  587. {
  588. Con::warnf("GuiTreeViewCtrl::getItemOpen - invalid index");
  589. return true;
  590. }
  591. TreeItem* item = dynamic_cast<TreeItem*>(mItems[index]);
  592. return item->isOpen;
  593. }
  594. S32 GuiTreeViewCtrl::getItemTrunk(S32 index)
  595. {
  596. if ((index >= mItems.size()) || index < 0)
  597. {
  598. Con::warnf(" GuiTreeViewCtrl::getItemTrunk - invalid index");
  599. return -1;
  600. }
  601. TreeItem* item = dynamic_cast<TreeItem*>(mItems[index]);
  602. return item->level == 0 ? -1 : getItemIndex(item->trunk);
  603. }