guiFrameSetCtrl.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  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 "console/consoleTypes.h"
  23. #include "console/console.h"
  24. #include "gui/containers/guiFrameSetCtrl.h"
  25. #include "gui/guiDefaultControlRender.h"
  26. #include "gui/guiCanvas.h"
  27. #include "gui/containers/guiWindowCtrl.h"
  28. #include "graphics/dgl.h"
  29. #include "gui/containers/guiTabBookCtrl.h"
  30. #include "gui/containers/guiTabPageCtrl.h"
  31. #include "guiFrameSetCtrl_ScriptBinding.h"
  32. void GuiFrameSetCtrl::Frame::deleteChildren()
  33. {
  34. if (child1)
  35. {
  36. child1->deleteChildren();
  37. delete child1;
  38. }
  39. if (child2)
  40. {
  41. child2->deleteChildren();
  42. delete child2;
  43. }
  44. }
  45. void GuiFrameSetCtrl::Frame::resize(const Point2I& newPosition, const Point2I& newExtent)
  46. {
  47. const S32 minSize = owner->minSize;
  48. extent.set(newExtent.x, newExtent.y);
  49. localPosition.set(newPosition.x, newPosition.y);
  50. sizeInsertButtons(newPosition, newExtent);
  51. if (control)
  52. {
  53. if (control->mMinExtent.x > minSize || control->mMinExtent.y > minSize)
  54. {
  55. control->mMinExtent.set(minSize, minSize);
  56. }
  57. control->resize(newPosition, newExtent);
  58. }
  59. else if (child1 && child2)
  60. {
  61. S32 spaceX = isVertical ? newExtent.x : newExtent.x - owner->mDividerThickness;
  62. S32 spaceY = !isVertical ? newExtent.y : newExtent.y - owner->mDividerThickness;
  63. S32 x1 = newExtent.x;
  64. S32 x2 = newExtent.x;
  65. if(!isVertical)
  66. {
  67. if (child1->isAnchored)
  68. {
  69. x1 = getMin(child1->extent.x, spaceX - minSize);
  70. x2 = spaceX - x1;
  71. }
  72. else
  73. {
  74. x2 = getMin(child2->extent.x, spaceX - minSize);
  75. x1 = spaceX - x2;
  76. }
  77. }
  78. S32 y1 = newExtent.y;
  79. S32 y2 = newExtent.y;
  80. if (isVertical)
  81. {
  82. if (child1->isAnchored)
  83. {
  84. y1 = getMin(child1->extent.y, spaceY - minSize);
  85. y2 = spaceY - y1;
  86. }
  87. else
  88. {
  89. y2 = getMin(child2->extent.y, spaceY - minSize);
  90. y1 = spaceY - y2;
  91. }
  92. }
  93. Point2I ext1 = Point2I(x1, y1);
  94. Point2I ext2 = Point2I(x2, y2);
  95. Point2I pos2 = isVertical ? Point2I(newPosition.x, newPosition.y + y1 + owner->mDividerThickness) : Point2I(newPosition.x + x1 + owner->mDividerThickness, newPosition.y);
  96. if(isVertical)
  97. {
  98. dividerRect.set(newPosition.x, newPosition.y + y1, x1, owner->mDividerThickness);
  99. }
  100. else
  101. {
  102. dividerRect.set(newPosition.x + x1, newPosition.y, owner->mDividerThickness, y1);
  103. }
  104. child1->resize(newPosition, ext1);
  105. child2->resize(pos2, ext2);
  106. }
  107. }
  108. void GuiFrameSetCtrl::Frame::sizeInsertButtons(const Point2I& newPosition, const Point2I& newExtent)
  109. {
  110. const U32 size = 40;
  111. const U32 gutter = 10;
  112. hasLeftRightButtons = false;
  113. hasTopBottomButtons = false;
  114. if (newExtent.x > (4 * (size + gutter)))
  115. {
  116. hasLeftRightButtons = true;
  117. mLeftButtonRect = RectI(newPosition.x + gutter, newPosition.y + ((newExtent.y - size) / 2), size, size);
  118. mRightButtonRect = RectI(newPosition.x + newExtent.x - (gutter + size), newPosition.y + ((newExtent.y - size) / 2), size, size);
  119. }
  120. if (newExtent.y > (4 * (size + gutter)))
  121. {
  122. hasTopBottomButtons = true;
  123. mTopButtonRect = RectI(newPosition.x + ((newExtent.x - size) / 2), newPosition.y + gutter, size, size);
  124. mBottomButtonRect = RectI(newPosition.x + ((newExtent.x - size) / 2), newPosition.y + newExtent.y - (gutter + size), size, size);
  125. }
  126. mCenterButtonRect = RectI(newPosition.x + ((newExtent.x - size) / 2), newPosition.y + ((newExtent.y - size) / 2), size, size);
  127. }
  128. GuiFrameSetCtrl::Frame* GuiFrameSetCtrl::Frame::findFrame(const S32 frameID)
  129. {
  130. if (id == frameID)
  131. {
  132. return this;
  133. }
  134. if (child1 && child2)
  135. {
  136. Frame* attempt = child1->findFrame(frameID);
  137. return attempt ? attempt : child2->findFrame(frameID);
  138. }
  139. return nullptr;
  140. }
  141. GuiFrameSetCtrl::Frame* GuiFrameSetCtrl::Frame::findEmptyFrame()
  142. {
  143. if (!control && !child1 && !child2)
  144. {
  145. return this;
  146. }
  147. else if (child1 && child2)
  148. {
  149. Frame* attempt = child1->findEmptyFrame();
  150. return attempt ? attempt : child2->findEmptyFrame();
  151. }
  152. return nullptr;
  153. }
  154. GuiFrameSetCtrl::Frame* GuiFrameSetCtrl::Frame::twin()
  155. {
  156. if (parent)
  157. {
  158. if (parent->child1 == this)
  159. {
  160. return parent->child2;
  161. }
  162. else
  163. {
  164. return parent->child1;
  165. }
  166. }
  167. return this;
  168. }
  169. GuiFrameSetCtrl::Frame* GuiFrameSetCtrl::Frame::findHitDivider(const Point2I& position)
  170. {
  171. S32 x = position.x;
  172. S32 y = position.y;
  173. if (child1 && child2)
  174. {
  175. if (x >= dividerRect.point.x && x <= (dividerRect.point.x + dividerRect.extent.x) &&
  176. y >= dividerRect.point.y && y <= (dividerRect.point.y + dividerRect.extent.y))
  177. {
  178. return this;
  179. }
  180. Frame* attempt = child1->findHitDivider(position);
  181. return attempt ? attempt : child2->findHitDivider(position);
  182. }
  183. return nullptr;
  184. }
  185. GuiFrameSetCtrl::Frame* GuiFrameSetCtrl::Frame::findFrameWithCtrl(GuiControl* ctrl)
  186. {
  187. if (ctrl == control)
  188. {
  189. return this;
  190. }
  191. else if(child1 && child2)
  192. {
  193. Frame* attempt = child1->findFrameWithCtrl(ctrl);
  194. return attempt ? attempt : child2->findFrameWithCtrl(ctrl);
  195. }
  196. return nullptr;
  197. }
  198. GuiFrameSetCtrl::Frame* GuiFrameSetCtrl::Frame::findFrameWithPoint(const Point2I& point)
  199. {
  200. //Point is local to the frame.
  201. if (control)
  202. {
  203. return this;
  204. }
  205. if (child1 && child2)
  206. {
  207. S32 x = point.x;
  208. S32 y = point.y;
  209. Point2I pos2 = isVertical ? Point2I(x, child1->extent.y + owner->mDividerThickness) : Point2I(child1->extent.x + owner->mDividerThickness, y);
  210. if ((isVertical && y < child1->extent.y) || (!isVertical && x < child1->extent.x))
  211. {
  212. return child1->findFrameWithPoint(point);
  213. }
  214. else if ((isVertical && y > pos2.y && y < (pos2.y + child2->extent.y)) || (!isVertical && x > pos2.x && x < (pos2.x + child2->extent.x)))
  215. {
  216. Point2I pt = Point2I(x - pos2.x, y - pos2.y);
  217. return child2->findFrameWithPoint(pt);
  218. }
  219. }
  220. return nullptr;//This will happen if the mouse is over a divider.
  221. }
  222. //------------------------------------------------------------------------------
  223. IMPLEMENT_CONOBJECT(GuiFrameSetCtrl);
  224. //------------------------------------------------------------------------------
  225. GuiFrameSetCtrl::GuiFrameSetCtrl()
  226. {
  227. mIsContainer = true;
  228. setField("profile", "GuiDefaultProfile");
  229. mRootFrame = Frame(this, nullptr);
  230. mHitDivider = nullptr;
  231. mDividerThickness = 8;
  232. mNextFrameID = 1;
  233. mResizeGuard = false;
  234. mDepressed = false;
  235. mActive = true;
  236. mFrameDragAnchor = 0;
  237. mEaseFillColorHL = EasingFunction::EaseInOut;
  238. mEaseFillColorSL = EasingFunction::EaseOut;
  239. mEaseTimeFillColorHL = 500;
  240. mEaseTimeFillColorSL = 1000;
  241. mDropButtonProfile = NULL;
  242. setField("dropButtonProfile", "GuiButtonProfile");
  243. mTabBookProfile = NULL;
  244. mTabProfile = NULL;
  245. mTabPageProfile = NULL;
  246. setField("tabBookProfile", "GuiDefaultProfile");
  247. setField("tabProfile", "GuiTabProfile");
  248. setField("tabPageProfile", "GuiDefaultProfile");
  249. mLeftRightCursor = NULL;
  250. mUpDownCursor = NULL;
  251. }
  252. GuiFrameSetCtrl::~GuiFrameSetCtrl()
  253. {
  254. mRootFrame.deleteChildren();
  255. }
  256. //------------------------------------------------------------------------------
  257. void GuiFrameSetCtrl::initPersistFields()
  258. {
  259. Parent::initPersistFields();
  260. addField("DividerThickness", TypeS32, Offset(mDividerThickness, GuiFrameSetCtrl));
  261. addField("dropButtonProfile", TypeGuiProfile, Offset(mDropButtonProfile, GuiFrameSetCtrl));
  262. addField("leftRightCursor", TypeGuiCursor, Offset(mLeftRightCursor, GuiFrameSetCtrl));
  263. addField("upDownCursor", TypeGuiCursor, Offset(mUpDownCursor, GuiFrameSetCtrl));
  264. addProtectedField("TabBookProfile", TypeGuiProfile, Offset(mTabBookProfile, GuiFrameSetCtrl), &setBookProfileFn, &defaultProtectedGetFn, &defaultProtectedWriteFn, "");
  265. addProtectedField("TabProfile", TypeGuiProfile, Offset(mTabProfile, GuiFrameSetCtrl), &setTabProfileFn, &defaultProtectedGetFn, &defaultProtectedWriteFn, "");
  266. addProtectedField("TabPageProfile", TypeGuiProfile, Offset(mTabPageProfile, GuiFrameSetCtrl), &setPageProfileFn, &defaultProtectedGetFn, &defaultProtectedWriteFn, "");
  267. }
  268. //------------------------------------------------------------------------------
  269. bool GuiFrameSetCtrl::onWake()
  270. {
  271. if (!Parent::onWake())
  272. return false;
  273. if (mDropButtonProfile != NULL)
  274. mDropButtonProfile->incRefCount();
  275. if (mTabBookProfile != NULL)
  276. mTabBookProfile->incRefCount();
  277. if (mTabProfile != NULL)
  278. mTabProfile->incRefCount();
  279. if (mTabPageProfile != NULL)
  280. mTabPageProfile->incRefCount();
  281. return true;
  282. }
  283. //------------------------------------------------------------------------------
  284. void GuiFrameSetCtrl::onSleep()
  285. {
  286. Parent::onSleep();
  287. if (mDropButtonProfile != NULL)
  288. mDropButtonProfile->decRefCount();
  289. if (mTabBookProfile != NULL)
  290. mTabBookProfile->decRefCount();
  291. if (mTabProfile != NULL)
  292. mTabProfile->decRefCount();
  293. if (mTabPageProfile != NULL)
  294. mTabPageProfile->decRefCount();
  295. }
  296. //------------------------------------------------------------------------------
  297. void GuiFrameSetCtrl::inspectPostApply()
  298. {
  299. resize(getPosition(), getExtent());
  300. Parent::inspectPostApply();
  301. }
  302. //------------------------------------------------------------------------------
  303. void GuiFrameSetCtrl::resize(const Point2I& newPosition, const Point2I& newExtent)
  304. {
  305. if(!mResizeGuard)//Prevent circular resizing
  306. {
  307. mResizeGuard = true;
  308. Point2I actualNewExtent = Point2I(getMax(mMinExtent.x, newExtent.x),
  309. getMax(mMinExtent.y, newExtent.y));
  310. //call set update both before and after
  311. setUpdate();
  312. Point2I origin = Point2I::Zero;
  313. mRootFrame.resize(origin, actualNewExtent);
  314. mBounds.set(newPosition, actualNewExtent);
  315. GuiControl* parent = getParent();
  316. if (parent)
  317. parent->childResized(this);
  318. setUpdate();
  319. mResizeGuard = false;
  320. }
  321. }
  322. bool GuiFrameSetCtrl::onAdd()
  323. {
  324. // Let Parent Do Work.
  325. if (!Parent::onAdd())
  326. return false;
  327. // Always expand to fill the parent (we just ignore the points passed in).
  328. parentResized(Point2I(), Point2I());
  329. // Return Success.
  330. return true;
  331. }
  332. void GuiFrameSetCtrl::parentResized(const Point2I& oldParentExtent, const Point2I& newParentExtent)
  333. {
  334. //In the case of centering, we want to make doubly sure we are using the inner rect.
  335. GuiControl* parent = getParent();
  336. if(parent)
  337. {
  338. Point2I origin = Point2I(0, 0);
  339. Point2I parentInnerExt = getInnerRect(origin, parent->mBounds.extent, NormalState, parent->mProfile).extent;
  340. resize(origin, parentInnerExt);
  341. }
  342. }
  343. void GuiFrameSetCtrl::onChildAdded(GuiControl* child)
  344. {
  345. //Ensure the child isn't positioned to the center
  346. if (child->getHorizSizing() == horizResizeCenter)
  347. {
  348. child->setHorizSizing(horizResizeLeft);
  349. }
  350. if (child->getVertSizing() == vertResizeCenter)
  351. {
  352. child->setVertSizing(vertResizeTop);
  353. }
  354. resize(getPosition(), getExtent());
  355. Parent::onChildAdded(child);
  356. Frame* frame = mRootFrame.findFrameWithCtrl(child);
  357. if(!frame)
  358. {
  359. Frame* emptyFrame = mRootFrame.findEmptyFrame();
  360. if(emptyFrame)
  361. {
  362. emptyFrame->control = child;
  363. }
  364. }
  365. resize(getPosition(), getExtent());
  366. }
  367. void GuiFrameSetCtrl::onChildRemoved(GuiControl* child)
  368. {
  369. Frame* frame = mRootFrame.findFrameWithCtrl(child);
  370. if (frame && frame == &mRootFrame)
  371. {
  372. mRootFrame.control = nullptr;
  373. }
  374. else if(frame)
  375. {
  376. //Remove the frame from the heirarchy
  377. Frame* frameParent = frame->parent;
  378. Frame* frameTwin = frame->twin();
  379. frameParent->control = frameTwin->control;
  380. frameParent->child1 = frameTwin->child1;
  381. frameParent->child2 = frameTwin->child2;
  382. if (frameParent->child1)
  383. {
  384. frameParent->child1->parent = frameParent;
  385. }
  386. if (frameParent->child2)
  387. {
  388. frameParent->child2->parent = frameParent;
  389. }
  390. frameParent->isVertical = frameTwin->isVertical;
  391. delete frame;
  392. delete frameTwin;
  393. }
  394. resize(getPosition(), getExtent());
  395. }
  396. void GuiFrameSetCtrl::childResized(GuiControl* child)
  397. {
  398. Parent::childResized(child);
  399. resize(getPosition(), getExtent());
  400. }
  401. void GuiFrameSetCtrl::childMoved(GuiControl* child)
  402. {
  403. Parent::childMoved(child);
  404. resize(getPosition(), getExtent());
  405. }
  406. void GuiFrameSetCtrl::childrenReordered()
  407. {
  408. resize(getPosition(), getExtent());
  409. Parent::childrenReordered();
  410. }
  411. Point2I GuiFrameSetCtrl::splitFrame(S32 frameID, bool isVertical)
  412. {
  413. Frame* frame = mRootFrame.findFrame(frameID);
  414. if(frame)
  415. {
  416. splitFrame(frame, isVertical ? GuiDirection::Up : GuiDirection::Left);
  417. return Point2I(frame->child1 ? static_cast<S32>(frame->child1->id) : 0, frame->child2 ? static_cast<S32>(frame->child2->id) : 0);
  418. }
  419. return Point2I::Zero;
  420. }
  421. void GuiFrameSetCtrl::splitFrame(GuiFrameSetCtrl::Frame* frame, GuiDirection direction)
  422. {
  423. //The existing control, if any, is moved to the new frame in the direction and anchored. The frame oposite is left empty.
  424. if (!frame->child1 && !frame->child2)
  425. {
  426. GuiControl* ctrl = frame->control;
  427. frame->child1 = new GuiFrameSetCtrl::Frame(this, frame);
  428. frame->child2 = new GuiFrameSetCtrl::Frame(this, frame);
  429. frame->control = nullptr;
  430. frame->child1->control = direction == GuiDirection::Left || direction == GuiDirection::Up ? ctrl : nullptr;
  431. frame->child2->control = direction == GuiDirection::Right || direction == GuiDirection::Down ? ctrl : nullptr;
  432. frame->child1->id = ++mNextFrameID;
  433. frame->child2->id = ++mNextFrameID;
  434. frame->child1->isAnchored = direction == GuiDirection::Left || direction == GuiDirection::Up;
  435. frame->child2->isAnchored = direction == GuiDirection::Right || direction == GuiDirection::Down;
  436. }
  437. frame->isVertical = direction == GuiDirection::Up || direction == GuiDirection::Down;
  438. }
  439. void GuiFrameSetCtrl::anchorFrame(S32 frameID)
  440. {
  441. Frame* frame = mRootFrame.findFrame(frameID);
  442. anchorFrame(frame);
  443. }
  444. void GuiFrameSetCtrl::anchorFrame(GuiFrameSetCtrl::Frame* frame)
  445. {
  446. if (frame && frame != &mRootFrame)//The root frame has no twin and can't be anchored.
  447. {
  448. frame->isAnchored = true;
  449. frame->twin()->isAnchored = false;
  450. }
  451. }
  452. void GuiFrameSetCtrl::setFrameSize(S32 frameID, S32 size)
  453. {
  454. Frame* frame = mRootFrame.findFrame(frameID);
  455. if (frame && frame != &mRootFrame)//The root frame must be the size of the control.
  456. {
  457. if (frame->parent->isVertical)
  458. {
  459. frame->extent.y = size;
  460. frame->twin()->extent.y = getMax(frame->parent->extent.y - (size + mDividerThickness), minSize);
  461. }
  462. else
  463. {
  464. frame->extent.x = size;
  465. frame->twin()->extent.x = getMax(frame->parent->extent.x - (size + mDividerThickness), minSize);
  466. }
  467. //Pass this down to the other frames and then to the child controls
  468. resize(getPosition(), getExtent());
  469. }
  470. }
  471. void GuiFrameSetCtrl::onRender(Point2I offset, const RectI& updateRect)
  472. {
  473. Parent::onRender(offset, updateRect);
  474. if (mHitDivider)
  475. {
  476. GuiControlState currentState = mDepressed ? SelectedState : HighlightState;
  477. mOldHitDivider = mHitDivider;
  478. RectI contentRect = RectI(localToGlobalCoord(mHitDivider->dividerRect.point), mHitDivider->dividerRect.extent);
  479. renderUniversalRect(contentRect, mProfile, currentState, getFillColor(currentState), true);
  480. }
  481. else if (mOldHitDivider && (mCurrentState == HighlightState || mFluidFillColor.isAnimating()))
  482. {
  483. RectI contentRect = RectI(localToGlobalCoord(mOldHitDivider->dividerRect.point), mOldHitDivider->dividerRect.extent);
  484. renderUniversalRect(contentRect, mProfile, NormalState, getFillColor(NormalState), true);
  485. }
  486. else if (mOldHitDivider)
  487. {
  488. mOldHitDivider = nullptr;
  489. }
  490. }
  491. void GuiFrameSetCtrl::onTouchMove(const GuiEvent& event)
  492. {
  493. if (!mVisible || !mAwake)
  494. return;
  495. if(!mDepressed)
  496. {
  497. Point2I localPoint = globalToLocalCoord(event.mousePoint);
  498. mHitDivider = mRootFrame.findHitDivider(localPoint);
  499. }
  500. if (!mHitDivider)
  501. {
  502. Parent::onTouchMove(event);
  503. }
  504. }
  505. void GuiFrameSetCtrl::onTouchDragged(const GuiEvent& event)
  506. {
  507. if (mDepressed && mHitDivider && mHitDivider->child1 && mHitDivider->child2)
  508. {
  509. S32 offset = (mHitDivider->isVertical ? event.mousePoint.y : event.mousePoint.x) - mFrameDragAnchor;
  510. if(offset != 0)
  511. {
  512. if (mHitDivider->isVertical)
  513. {
  514. mHitDivider->child1->extent.y = getMax(minSize, mHitDivider->child1->extent.y + offset);
  515. mHitDivider->child2->extent.y = getMax(minSize, mHitDivider->child2->extent.y - offset);
  516. }
  517. else
  518. {
  519. mHitDivider->child1->extent.x = getMax(minSize, mHitDivider->child1->extent.x + offset);
  520. mHitDivider->child2->extent.x = getMax(minSize, mHitDivider->child2->extent.x - offset);
  521. }
  522. resize(getPosition(), getExtent());
  523. mFrameDragAnchor = mHitDivider->isVertical ? event.mousePoint.y : event.mousePoint.x;
  524. }
  525. }
  526. }
  527. void GuiFrameSetCtrl::onTouchDown(const GuiEvent& event)
  528. {
  529. if (!mActive)
  530. return;
  531. if(mHitDivider)
  532. {
  533. mDepressed = true;
  534. mFrameDragAnchor = mHitDivider->isVertical ? event.mousePoint.y : event.mousePoint.x;
  535. //lock the mouse
  536. mouseLock();
  537. //update
  538. setUpdate();
  539. }
  540. }
  541. void GuiFrameSetCtrl::onTouchUp(const GuiEvent& event)
  542. {
  543. if (!mActive)
  544. return;
  545. if(mHitDivider)
  546. {
  547. mouseUnlock();
  548. mDepressed = false;
  549. //update
  550. setUpdate();
  551. }
  552. }
  553. void GuiFrameSetCtrl::getCursor(GuiCursor*& cursor, bool& showCursor, const GuiEvent& lastGuiEvent)
  554. {
  555. GuiControl* parent = getParent();
  556. if (!parent)
  557. {
  558. return;
  559. }
  560. if (mHitDivider && mHitDivider->isVertical)
  561. {
  562. if (mUpDownCursor == NULL)
  563. {
  564. SimObject* obj;
  565. obj = Sim::findObject("UpDownCursor");
  566. mUpDownCursor = dynamic_cast<GuiCursor*>(obj);
  567. }
  568. if (mUpDownCursor != NULL)
  569. {
  570. cursor = mUpDownCursor;
  571. }
  572. }
  573. else if (mHitDivider && !mHitDivider->isVertical)
  574. {
  575. if (mLeftRightCursor == NULL)
  576. {
  577. SimObject* obj;
  578. obj = Sim::findObject("LeftRightCursor");
  579. mLeftRightCursor = dynamic_cast<GuiCursor*>(obj);
  580. }
  581. if (mLeftRightCursor != NULL)
  582. {
  583. cursor = mLeftRightCursor;
  584. }
  585. }
  586. }
  587. void GuiFrameSetCtrl::renderDropOptions(GuiWindowCtrl* window)
  588. {
  589. Point2I cursorPt = Point2I(0, 0);
  590. GuiCanvas* root = getRoot();
  591. if (root)
  592. {
  593. cursorPt = globalToLocalCoord(root->getCursorPos());
  594. cursorPt.x = getMin(getMax(0, cursorPt.x), mRootFrame.extent.x);
  595. cursorPt.y = getMin(getMax(0, cursorPt.y), mRootFrame.extent.y);
  596. }
  597. Frame* frame = mRootFrame.findFrameWithPoint(cursorPt);
  598. if (frame)
  599. {
  600. ColorI fillColor = mProfile->getFillColor(SelectedState);
  601. fillColor.alpha = 50;
  602. const U32 width = getMax(minSize, getMin(frame->extent.x / 2, window->mBounds.extent.x));
  603. const U32 height = getMax(minSize, getMin(frame->extent.y / 2, window->mBounds.extent.y));
  604. if (frame->hasLeftRightButtons)
  605. {
  606. Point2I fillExt = Point2I(width, frame->extent.y);
  607. renderDropButton(frame, frame->mLeftButtonRect, cursorPt, frame->localPosition, fillExt, GuiDirection::Left);
  608. renderDropButton(frame, frame->mRightButtonRect, cursorPt, Point2I(frame->localPosition.x + frame->extent.x - width, frame->localPosition.y), fillExt, GuiDirection::Right);
  609. }
  610. if (frame->hasTopBottomButtons)
  611. {
  612. Point2I fillExt = Point2I(frame->extent.x, height);
  613. renderDropButton(frame, frame->mTopButtonRect, cursorPt, frame->localPosition, fillExt, GuiDirection::Up);
  614. renderDropButton(frame, frame->mBottomButtonRect, cursorPt, Point2I(frame->localPosition.x, frame->localPosition.y + frame->extent.y - height), fillExt, GuiDirection::Down);
  615. }
  616. if (frame->isAnchored || (!frame->control && !frame->child1 && !frame->child2))
  617. {
  618. renderDropButton(frame, frame->mCenterButtonRect, cursorPt, frame->localPosition, frame->extent, GuiDirection::Center);
  619. }
  620. }
  621. }
  622. void GuiFrameSetCtrl::renderDropButton(const GuiFrameSetCtrl::Frame* frame, const RectI& buttonRect, const Point2I& cursorPt, const Point2I& fillPos, const Point2I& fillExt, GuiDirection direction)
  623. {
  624. GuiControlState state = NormalState;
  625. if (buttonRect.pointInRect(cursorPt))
  626. {
  627. state = HighlightState;
  628. RectI rect = RectI(fillPos, fillExt);
  629. rect.point = localToGlobalCoord(rect.point);
  630. setUpdateRegion(rect.point, rect.extent);
  631. renderUniversalRect(rect, mDropButtonProfile, SelectedState);
  632. }
  633. RectI globalButtonRect = RectI(localToGlobalCoord(buttonRect.point), buttonRect.extent);
  634. renderUniversalRect(globalButtonRect, mDropButtonProfile, state);
  635. ColorI triColor = getFontColor(mDropButtonProfile, state);
  636. if(direction != GuiDirection::Center)
  637. {
  638. renderTriangleIcon(globalButtonRect, triColor, direction, 10);
  639. }
  640. else
  641. {
  642. RectI iconRect = RectI(buttonRect);
  643. iconRect.inset(15, 15);
  644. RectI lineH = RectI(localToGlobalCoord(Point2I(iconRect.point.x, iconRect.point.y + 4)), Point2I(iconRect.extent.x, 2));
  645. RectI lineV = RectI(localToGlobalCoord(Point2I(iconRect.point.x + 4, iconRect.point.y)), Point2I(2, iconRect.extent.y));
  646. dglDrawRectFill(lineH, triColor);
  647. dglDrawRectFill(lineV, triColor);
  648. }
  649. }
  650. void GuiFrameSetCtrl::handleDropButtons(GuiWindowCtrl* window)
  651. {
  652. Point2I cursorPt = Point2I(0, 0);
  653. GuiCanvas* root = getRoot();
  654. if (root)
  655. {
  656. cursorPt = globalToLocalCoord(root->getCursorPos());
  657. cursorPt.x = getMin(getMax(0, cursorPt.x), mRootFrame.extent.x);
  658. cursorPt.y = getMin(getMax(0, cursorPt.y), mRootFrame.extent.y);
  659. }
  660. Frame* frame = mRootFrame.findFrameWithPoint(cursorPt);
  661. if (frame)
  662. {
  663. const U32 width = getMax(minSize, getMin(frame->extent.x / 2, window->mBounds.extent.x));
  664. const U32 height = getMax(minSize, getMin(frame->extent.y / 2, window->mBounds.extent.y));
  665. bool hitButton = false;
  666. if (frame->mLeftButtonRect.pointInRect(cursorPt))
  667. {
  668. splitFrame(frame, GuiDirection::Right);//This existing control goes right, the new window will go left.
  669. anchorFrame(frame->child1);
  670. frame->child1->control = window;
  671. frame->child1->extent = Point2I(width, frame->extent.y);
  672. hitButton = true;
  673. }
  674. else if (frame->mRightButtonRect.pointInRect(cursorPt))
  675. {
  676. splitFrame(frame, GuiDirection::Left);
  677. anchorFrame(frame->child2);
  678. frame->child2->control = window;
  679. frame->child2->extent = Point2I(width, frame->extent.y);
  680. hitButton = true;
  681. }
  682. else if (frame->mTopButtonRect.pointInRect(cursorPt))
  683. {
  684. splitFrame(frame, GuiDirection::Down);
  685. anchorFrame(frame->child1);
  686. frame->child1->control = window;
  687. frame->child1->extent = Point2I(frame->extent.x, height);
  688. hitButton = true;
  689. }
  690. else if (frame->mBottomButtonRect.pointInRect(cursorPt))
  691. {
  692. splitFrame(frame, GuiDirection::Up);
  693. anchorFrame(frame->child2);
  694. frame->child2->control = window;
  695. frame->child2->extent = Point2I(frame->extent.x, height);
  696. hitButton = true;
  697. }
  698. else if (frame->mCenterButtonRect.pointInRect(cursorPt))
  699. {
  700. if (!frame->control)
  701. {
  702. frame->control = window;
  703. hitButton = true;
  704. }
  705. else
  706. {
  707. GuiTabBookCtrl* book = dynamic_cast<GuiTabBookCtrl*>(frame->control);
  708. GuiTabPageCtrl* page = nullptr;
  709. if (!book)
  710. {
  711. book = new GuiTabBookCtrl();
  712. book->setControlProfile(mTabBookProfile);
  713. book->setControlTabProfile(mTabProfile);
  714. book->mBounds.set(frame->localPosition, frame->extent);
  715. book->mIsFrameSetGenerated = true;
  716. book->registerObject();
  717. book->addNewPage();
  718. page = dynamic_cast<GuiTabPageCtrl*>((*book)[0]);
  719. page->setControlProfile(mTabPageProfile);
  720. GuiWindowCtrl* windowChild = dynamic_cast<GuiWindowCtrl*>(frame->control);
  721. GuiControl* child = dynamic_cast<GuiControl*>(frame->control);
  722. if (windowChild)
  723. {
  724. windowChild->dockToPage();
  725. }
  726. page->setText(child->getText());
  727. frame->control = book;
  728. page->addObject(child);
  729. addObject(book);
  730. }
  731. window->dockToPage();
  732. book->addNewPage();
  733. page = dynamic_cast<GuiTabPageCtrl*>((*book)[book->size() - 1]);
  734. page->setControlProfile(mTabPageProfile);
  735. page->setText(window->getText());
  736. page->addObject(window);
  737. book->selectPage(window->getText());
  738. }
  739. }
  740. if (hitButton)
  741. {
  742. addObject(window);
  743. }
  744. }
  745. }
  746. void GuiFrameSetCtrl::setDropButtonProfile(GuiControlProfile* prof)
  747. {
  748. AssertFatal(prof, "GuiFrameSetCtrl::setDropButtonProfile: invalid content profile");
  749. if (prof == mDropButtonProfile)
  750. return;
  751. if (mAwake)
  752. mDropButtonProfile->decRefCount();
  753. mDropButtonProfile = prof;
  754. if (mAwake)
  755. mDropButtonProfile->incRefCount();
  756. }
  757. void GuiFrameSetCtrl::setTabBookProfile(GuiControlProfile* prof)
  758. {
  759. AssertFatal(prof, "GuiFrameSetCtrl::setTabBookProfile: invalid content profile");
  760. if (prof == mTabBookProfile)
  761. return;
  762. if (mAwake)
  763. mTabBookProfile->decRefCount();
  764. mTabBookProfile = prof;
  765. if (mAwake)
  766. mTabBookProfile->incRefCount();
  767. //Cycle through all children and replace the profiles of frameSetGenerated books.
  768. SimSet::iterator i;
  769. for (i = begin(); i != end(); i++)
  770. {
  771. GuiTabBookCtrl* book = static_cast<GuiTabBookCtrl*>(*i);
  772. if (book && book->mIsFrameSetGenerated)
  773. {
  774. book->setControlProfile(prof);
  775. }
  776. }
  777. }
  778. void GuiFrameSetCtrl::setTabProfile(GuiControlProfile* prof)
  779. {
  780. AssertFatal(prof, "GuiFrameSetCtrl::setTabProfile: invalid content profile");
  781. if (prof == mTabProfile)
  782. return;
  783. if (mAwake)
  784. mTabProfile->decRefCount();
  785. mTabProfile = prof;
  786. if (mAwake)
  787. mTabProfile->incRefCount();
  788. SimSet::iterator i;
  789. for (i = begin(); i != end(); i++)
  790. {
  791. GuiTabBookCtrl* book = static_cast<GuiTabBookCtrl*>(*i);
  792. if (book && book->mIsFrameSetGenerated)
  793. {
  794. book->setControlTabProfile(prof);
  795. }
  796. }
  797. }
  798. void GuiFrameSetCtrl::setTabPageProfile(GuiControlProfile* prof)
  799. {
  800. AssertFatal(prof, "GuiFrameSetCtrl::setTabPageProfile: invalid content profile");
  801. if (prof == mTabPageProfile)
  802. return;
  803. if (mAwake)
  804. mTabPageProfile->decRefCount();
  805. mTabPageProfile = prof;
  806. if (mAwake)
  807. mTabPageProfile->incRefCount();
  808. SimSet::iterator i;
  809. for (i = begin(); i != end(); i++)
  810. {
  811. GuiTabBookCtrl* book = static_cast<GuiTabBookCtrl*>(*i);
  812. if (book && book->mIsFrameSetGenerated)
  813. {
  814. SimSet::iterator j;
  815. for (j = begin(); j != end(); j++)
  816. {
  817. GuiTabPageCtrl* page = static_cast<GuiTabPageCtrl*>(*i);
  818. if (page)
  819. {
  820. page->setControlProfile(prof);
  821. }
  822. }
  823. }
  824. }
  825. }
  826. void GuiFrameSetCtrl::setControlLeftRightCursor(GuiCursor* cursor)
  827. {
  828. AssertFatal(cursor, "GuiFrameSetCtrl::setControlLeftRightCursor: invalid cursor");
  829. if (cursor == mLeftRightCursor)
  830. return;
  831. mLeftRightCursor = cursor;
  832. }
  833. void GuiFrameSetCtrl::setControlUpDownCursor(GuiCursor* cursor)
  834. {
  835. AssertFatal(cursor, "GuiFrameSetCtrl::setControlUpDownCursor: invalid cursor");
  836. if (cursor == mUpDownCursor)
  837. return;
  838. mUpDownCursor = cursor;
  839. }