2
0

guiSplitContainer.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "gui/containers/guiSplitContainer.h"
  24. #include "gui/core/guiCanvas.h"
  25. #include "console/consoleTypes.h"
  26. #include "gfx/gfxDrawUtil.h"
  27. IMPLEMENT_CONOBJECT( GuiSplitContainer );
  28. ConsoleDocClass( GuiSplitContainer,
  29. "@brief A container that splits its area between two child controls.\n\n"
  30. "A GuiSplitContainer can be used to dynamically subdivide an area between two child controls. "
  31. "A splitter bar is placed between the two controls and allows to dynamically adjust the sizing "
  32. "ratio between the two sides. Splitting can be either horizontal (subdividing top and bottom) "
  33. "or vertical (subdividing left and right) depending on #orientation.\n\n"
  34. "By using #fixedPanel, one of the panels can be chosen to remain at a fixed size (#fixedSize)."
  35. "@tsexample\n"
  36. "// Create a vertical splitter with a fixed-size left panel.\n"
  37. "%splitter = new GuiSplitContainer()\n"
  38. "{\n"
  39. " orientation = \"Vertical\";\n"
  40. " fixedPanel = \"FirstPanel\";\n"
  41. " fixedSize = 100;\n"
  42. "\n"
  43. " new GuiScrollCtrl()\n"
  44. " {\n"
  45. " new GuiMLTextCtrl()\n"
  46. " {\n"
  47. " text = %longText;\n"
  48. " };\n"
  49. " };\n"
  50. "\n"
  51. " new GuiScrollCtrl()\n"
  52. " {\n"
  53. " new GuiMLTextCtrl()\n"
  54. " {\n"
  55. " text = %moreLongText;\n"
  56. " };\n"
  57. " };\n"
  58. "};\n"
  59. "@endtsexample\n\n"
  60. "@note The children placed inside GuiSplitContainers must be GuiContainers.\n\n"
  61. "@ingroup GuiContainers"
  62. );
  63. ImplementEnumType( GuiSplitOrientation,
  64. "Axis along which to divide the container's space.\n\n"
  65. "@ingroup GuiContainers" )
  66. { GuiSplitContainer::Vertical, "Vertical", "Divide vertically placing one child left and one child right." },
  67. { GuiSplitContainer::Horizontal, "Horizontal", "Divide horizontally placing one child on top and one child below." }
  68. EndImplementEnumType;
  69. ImplementEnumType( GuiSplitFixedPanel,
  70. "Which side of the splitter to keep at a fixed size (if any).\n\n"
  71. "@ingroup GuiContainers" )
  72. { GuiSplitContainer::None, "None", "Allow both childs to resize (default)." },
  73. { GuiSplitContainer::FirstPanel, "FirstPanel", "Keep " },
  74. { GuiSplitContainer::SecondPanel, "SecondPanel" }
  75. EndImplementEnumType;
  76. //-----------------------------------------------------------------------------
  77. GuiSplitContainer::GuiSplitContainer()
  78. : mFixedPanel( None ),
  79. mFixedPanelSize( 100 ),
  80. mOrientation( Vertical ),
  81. mSplitterSize( 2 ),
  82. mSplitPoint( 0, 0 ),
  83. mSplitRect( 0, 0, mSplitterSize, mSplitterSize ),
  84. mDragging( false )
  85. {
  86. setMinExtent( Point2I(64,64) );
  87. setExtent(200,200);
  88. setDocking( Docking::dockNone );
  89. mSplitPoint.set( 300, 100 );
  90. // We only support client docked items in a split container
  91. mValidDockingMask = Docking::dockClient;
  92. }
  93. //-----------------------------------------------------------------------------
  94. void GuiSplitContainer::initPersistFields()
  95. {
  96. addGroup( "Splitter", "Options to configure split panels contained by this control" );
  97. addField( "orientation", TYPEID< Orientation >(), Offset( mOrientation, GuiSplitContainer),
  98. "Whether to split between top and bottom (horizontal) or between left and right (vertical)." );
  99. addField( "splitterSize", TypeS32, Offset( mSplitterSize, GuiSplitContainer),
  100. "Width of the splitter bar between the two sides. Default is 2." );
  101. addField( "splitPoint", TypePoint2I, Offset( mSplitPoint, GuiSplitContainer),
  102. "Point on control through which the splitter goes.\n\n"
  103. "Changed relatively if size of control changes." );
  104. addField( "fixedPanel", TYPEID< FixedPanel >(), Offset( mFixedPanel, GuiSplitContainer),
  105. "Which (if any) side of the splitter to keep at a fixed size." );
  106. addField( "fixedSize", TypeS32, Offset( mFixedPanelSize, GuiSplitContainer),
  107. "Width of the fixed panel specified by #fixedPanel (if any)." );
  108. endGroup( "Splitter" );
  109. Parent::initPersistFields();
  110. }
  111. //-----------------------------------------------------------------------------
  112. bool GuiSplitContainer::onAdd()
  113. {
  114. if ( !Parent::onAdd() )
  115. return false;
  116. return true;
  117. }
  118. //-----------------------------------------------------------------------------
  119. bool GuiSplitContainer::onWake()
  120. {
  121. if ( !Parent::onWake() )
  122. return false;
  123. // Create Panel 1
  124. if ( empty() )
  125. {
  126. GuiPanel *newPanel = new GuiPanel();
  127. AssertFatal( newPanel, "GuiSplitContainer::onAdd - Cannot create subordinate panel #1!" );
  128. newPanel->registerObject();
  129. newPanel->setInternalName( "Panel1" );
  130. newPanel->setDocking( Docking::dockClient );
  131. addObject( (SimObject*)newPanel );
  132. }
  133. else
  134. {
  135. GuiContainer *containerCtrl = dynamic_cast<GuiContainer*>( at(0) );
  136. if ( containerCtrl )
  137. {
  138. containerCtrl->setInternalName( "Panel1" );
  139. containerCtrl->setDocking( Docking::dockClient );
  140. }
  141. }
  142. if ( size() == 1 )
  143. {
  144. // Create Panel 2
  145. GuiPanel *newPanel = new GuiPanel();
  146. AssertFatal( newPanel, "GuiSplitContainer::onAdd - Cannot create subordinate panel #2!" );
  147. newPanel->registerObject();
  148. newPanel->setInternalName( "Panel2" );
  149. newPanel->setDocking( Docking::dockClient );
  150. addObject( (SimObject*)newPanel );
  151. }
  152. else
  153. {
  154. GuiContainer *containerCtrl = dynamic_cast<GuiContainer*>( at(1) );
  155. if ( containerCtrl )
  156. {
  157. containerCtrl->setInternalName( "Panel2" );
  158. containerCtrl->setDocking( Docking::dockClient );
  159. }
  160. }
  161. // Has FixedWidth been specified?
  162. if ( mFixedPanelSize == 0 )
  163. {
  164. // Nope, so try to guess as best we can
  165. GuiContainer *firstPanel = dynamic_cast<GuiContainer*>( at(0) );
  166. GuiContainer *secondPanel = dynamic_cast<GuiContainer*>( at(1) );
  167. if ( mFixedPanel == FirstPanel )
  168. {
  169. if ( mOrientation == Horizontal )
  170. mFixedPanelSize = firstPanel->getExtent().y;
  171. else
  172. mFixedPanelSize = firstPanel->getExtent().x;
  173. mSplitPoint = Point2I( mFixedPanelSize, mFixedPanelSize );
  174. }
  175. else if ( mFixedPanel == SecondPanel )
  176. {
  177. if ( mOrientation == Horizontal )
  178. mFixedPanelSize = getExtent().y - secondPanel->getExtent().y;
  179. else
  180. mFixedPanelSize = getExtent().x - secondPanel->getExtent().x;
  181. mSplitPoint = getExtent() - Point2I( mFixedPanelSize, mFixedPanelSize );
  182. }
  183. }
  184. setUpdateLayout();
  185. return true;
  186. }
  187. //-----------------------------------------------------------------------------
  188. void GuiSplitContainer::onRender( Point2I offset, const RectI &updateRect )
  189. {
  190. Parent::onRender( offset, updateRect );
  191. // Only render if we're dragging the splitter
  192. if ( mDragging && mSplitRect.isValidRect() )
  193. {
  194. // Splitter Rectangle (will adjust positioning only)
  195. RectI splitterRect = mSplitRect;
  196. // Currently being dragged to Rect
  197. Point2I splitterPoint = localToGlobalCoord( mSplitRect.point );
  198. splitterRect.point = localToGlobalCoord( mSplitPoint );
  199. RectI clientRect = getClientRect();
  200. clientRect.point = localToGlobalCoord( clientRect.point );
  201. if ( mOrientation == Horizontal )
  202. {
  203. splitterRect.point.y -= mSplitterSize;
  204. splitterRect.point.x = splitterPoint.x;
  205. }
  206. else
  207. {
  208. splitterRect.point.x -= mSplitterSize;
  209. splitterRect.point.y = splitterPoint.y;
  210. }
  211. RectI oldClip = GFX->getClipRect();
  212. GFX->setClipRect( clientRect );
  213. GFX->getDrawUtil()->drawRectFill( splitterRect, mProfile->mFillColorHL );
  214. GFX->setClipRect( oldClip );
  215. }
  216. else
  217. {
  218. RectI splitterRect = mSplitRect;
  219. splitterRect.point += offset;
  220. GFX->getDrawUtil()->drawRectFill( splitterRect, mProfile->mFillColor );
  221. }
  222. }
  223. //-----------------------------------------------------------------------------
  224. Point2I GuiSplitContainer::getMinExtent() const
  225. {
  226. GuiContainer *panelOne = dynamic_cast<GuiContainer*>( at(0) );
  227. GuiContainer *panelTwo = dynamic_cast<GuiContainer*>( at(1) );
  228. if ( !panelOne || !panelTwo )
  229. return Parent::getMinExtent();
  230. Point2I minExtent = Point2I(0,0);
  231. Point2I panelOneMinExtent = panelOne->getMinExtent();
  232. Point2I panelTwoMinExtent = panelTwo->getMinExtent();
  233. if ( mOrientation == Horizontal )
  234. {
  235. minExtent.y = 2 * mSplitterSize + panelOneMinExtent.y + panelTwoMinExtent.y;
  236. minExtent.x = getMax( panelOneMinExtent.x, panelTwoMinExtent.x );
  237. }
  238. else
  239. {
  240. minExtent.x = 2 * mSplitterSize + panelOneMinExtent.x + panelTwoMinExtent.x;
  241. minExtent.y = getMax( panelOneMinExtent.y, panelTwoMinExtent.y );
  242. }
  243. return minExtent;
  244. }
  245. //-----------------------------------------------------------------------------
  246. void GuiSplitContainer::parentResized( const RectI &oldParentRect, const RectI &newParentRect )
  247. {
  248. Parent::parentResized( oldParentRect, newParentRect );
  249. return;
  250. // TODO: Is this right James? This isn't needed anymore?
  251. /*
  252. // GuiSplitContainer overrides parentResized to make sure that the proper fixed frame's width/height
  253. // is not compromised in the call
  254. if ( size() < 2 )
  255. return;
  256. GuiContainer *panelOne = dynamic_cast<GuiContainer*>( at(0) );
  257. GuiContainer *panelTwo = dynamic_cast<GuiContainer*>( at(1) );
  258. AssertFatal( panelOne && panelTwo, "GuiSplitContainer::parentResized - Missing/Invalid Subordinate Controls! Split contained controls must derive from GuiContainer!" );
  259. Point2I newDragPos;
  260. if ( mFixedPanel == FirstPanel )
  261. {
  262. newDragPos = panelOne->getExtent();
  263. newDragPos += Point2I( mSplitterSize, mSplitterSize );
  264. }
  265. else if ( mFixedPanel == SecondPanel )
  266. {
  267. newDragPos = getExtent() - panelTwo->getExtent();
  268. newDragPos -= Point2I( mSplitterSize, mSplitterSize );
  269. }
  270. else // None
  271. newDragPos.set( 1, 1);
  272. RectI clientRect = getClientRect();
  273. solvePanelConstraints( newDragPos, panelOne, panelTwo, clientRect );
  274. setUpdateLayout();
  275. */
  276. }
  277. //-----------------------------------------------------------------------------
  278. bool GuiSplitContainer::resize( const Point2I &newPosition, const Point2I &newExtent )
  279. {
  280. // Save previous extent.
  281. Point2I oldExtent = getExtent();
  282. // Resize ourselves.
  283. if ( !Parent::resize( newPosition, newExtent ) || size() < 2 )
  284. return false;
  285. GuiContainer *panelOne = dynamic_cast<GuiContainer*>( at(0) );
  286. GuiContainer *panelTwo = dynamic_cast<GuiContainer*>( at(1) );
  287. //
  288. AssertFatal( panelOne && panelTwo, "GuiSplitContainer::resize - Missing/Invalid Subordinate Controls! Split contained controls must derive from GuiContainer!" );
  289. // We only need to update the split point if our second panel is fixed.
  290. // If the first is fixed, then we can leave the split point alone because
  291. // the remainder of the size will be added to or taken from the second panel
  292. Point2I newDragPos;
  293. if ( mFixedPanel == SecondPanel )
  294. {
  295. S32 deltaX = newExtent.x - oldExtent.x;
  296. S32 deltaY = newExtent.y - oldExtent.y;
  297. if( mOrientation == Horizontal )
  298. mSplitPoint.y += deltaY;
  299. else
  300. mSplitPoint.x += deltaX;
  301. }
  302. // If we got here, parent returned true
  303. return true;
  304. }
  305. //-----------------------------------------------------------------------------
  306. bool GuiSplitContainer::layoutControls( RectI &clientRect )
  307. {
  308. if ( size() < 2 )
  309. return false;
  310. GuiContainer *panelOne = dynamic_cast<GuiContainer*>( at(0) );
  311. GuiContainer *panelTwo = dynamic_cast<GuiContainer*>( at(1) );
  312. //
  313. AssertFatal( panelOne && panelTwo, "GuiSplitContainer::layoutControl - Missing/Invalid Subordinate Controls! Split contained controls must derive from GuiContainer!" );
  314. RectI panelOneRect = RectI( clientRect.point, Point2I( 0, 0 ) );
  315. RectI panelTwoRect;
  316. RectI splitRect;
  317. solvePanelConstraints( getSplitPoint(), panelOne, panelTwo, clientRect );
  318. switch( mOrientation )
  319. {
  320. case Horizontal:
  321. panelOneRect.extent = Point2I( clientRect.extent.x, getSplitPoint().y );
  322. panelTwoRect = panelOneRect;
  323. panelTwoRect.intersect( clientRect );
  324. panelTwoRect.point.y = panelOneRect.extent.y;
  325. panelTwoRect.extent.y = clientRect.extent.y - panelOneRect.extent.y;
  326. // Generate new Splitter Rectangle
  327. splitRect = panelTwoRect;
  328. splitRect.extent.y = 0;
  329. splitRect.inset( 0, -mSplitterSize );
  330. panelOneRect.extent.y -= mSplitterSize;
  331. panelTwoRect.point.y += mSplitterSize;
  332. panelTwoRect.extent.y -= mSplitterSize;
  333. break;
  334. case Vertical:
  335. panelOneRect.extent = Point2I( getSplitPoint().x, clientRect.extent.y );
  336. panelTwoRect = panelOneRect;
  337. panelTwoRect.intersect( clientRect );
  338. panelTwoRect.point.x = panelOneRect.extent.x;
  339. panelTwoRect.extent.x = clientRect.extent.x - panelOneRect.extent.x;
  340. // Generate new Splitter Rectangle
  341. splitRect = panelTwoRect;
  342. splitRect.extent.x = 0;
  343. splitRect.inset( -mSplitterSize, 0 );
  344. panelOneRect.extent.x -= mSplitterSize;
  345. panelTwoRect.point.x += mSplitterSize;
  346. panelTwoRect.extent.x -= mSplitterSize;
  347. break;
  348. }
  349. // Update Split Rect
  350. mSplitRect = splitRect;
  351. // Dock Appropriately
  352. if( !( mFixedPanel == FirstPanel && !panelOne->isVisible() ) )
  353. dockControl( panelOne, panelOne->getDocking(), panelOneRect );
  354. if( !( mFixedPanel == FirstPanel && !panelTwo->isVisible() ) )
  355. dockControl( panelTwo, panelOne->getDocking(), panelTwoRect );
  356. //
  357. return false;
  358. }
  359. //-----------------------------------------------------------------------------
  360. void GuiSplitContainer::solvePanelConstraints(Point2I newDragPos, GuiContainer * firstPanel, GuiContainer * secondPanel, const RectI& clientRect)
  361. {
  362. if( !firstPanel || !secondPanel )
  363. return;
  364. if ( mOrientation == Horizontal )
  365. {
  366. // Constrain based on Y axis (Horizontal Splitter)
  367. // This accounts for the splitter width
  368. S32 splitterSize = (S32)(mSplitRect.extent.y * 0.5);
  369. // Collapsed fixed panel
  370. if ( mFixedPanel == SecondPanel && !secondPanel->isVisible() )
  371. {
  372. newDragPos = Point2I(mSplitPoint.x, getExtent().y - splitterSize );
  373. }
  374. else if( mFixedPanel == SecondPanel && !firstPanel->isVisible() )
  375. {
  376. newDragPos = Point2I(mSplitPoint.x, splitterSize );
  377. }
  378. else // Normal constraints
  379. {
  380. //newDragPos.y -= splitterSize;
  381. S32 newPosition = mClamp( newDragPos.y,
  382. firstPanel->getMinExtent().y + splitterSize,
  383. getExtent().y - secondPanel->getMinExtent().y - splitterSize );
  384. newDragPos = Point2I( mSplitPoint.x, newPosition );
  385. }
  386. }
  387. else
  388. {
  389. // Constrain based on X axis (Vertical Splitter)
  390. // This accounts for the splitter width
  391. S32 splitterSize = (S32)(mSplitRect.extent.x * 0.5);
  392. // Collapsed fixed panel
  393. if ( mFixedPanel == SecondPanel && !secondPanel->isVisible() )
  394. {
  395. newDragPos = Point2I(getExtent().x - splitterSize, mSplitPoint.y );
  396. }
  397. else if ( mFixedPanel == FirstPanel && !firstPanel->isVisible() )
  398. {
  399. newDragPos = Point2I( splitterSize, mSplitPoint.x );
  400. }
  401. else // Normal constraints
  402. {
  403. S32 newPosition = mClamp( newDragPos.x, firstPanel->getMinExtent().x + splitterSize,
  404. getExtent().x - secondPanel->getMinExtent().x - splitterSize );
  405. newDragPos = Point2I( newPosition, mSplitPoint.y );
  406. }
  407. }
  408. // Just in case, clamp to bounds of controls
  409. newDragPos.x = mClamp( newDragPos.x, clientRect.point.x, clientRect.point.x + clientRect.extent.x );
  410. newDragPos.y = mClamp( newDragPos.y, clientRect.point.y, clientRect.point.y + clientRect.extent.y );
  411. mSplitPoint = newDragPos;
  412. }
  413. //-----------------------------------------------------------------------------
  414. void GuiSplitContainer::getCursor( GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent )
  415. {
  416. GuiCanvas *rootCtrl = getRoot();
  417. if ( !rootCtrl )
  418. return;
  419. S32 desiredCursor = 0;
  420. RectI splitRect = getSplitRect();
  421. // Figure out which cursor we want if we need one
  422. if ( mOrientation == Horizontal )
  423. desiredCursor = PlatformCursorController::curResizeHorz;
  424. else if ( mOrientation == Vertical )
  425. desiredCursor = PlatformCursorController::curResizeVert;
  426. PlatformWindow *platformWindow = static_cast<GuiCanvas*>(getRoot())->getPlatformWindow();
  427. AssertFatal( platformWindow != NULL,"GuiControl without owning platform window! This should not be possible." );
  428. PlatformCursorController *cusrorController = platformWindow->getCursorController();
  429. AssertFatal( cusrorController != NULL,"PlatformWindow without an owned CursorController!" );
  430. // Check to see if we need one or just the default...
  431. Point2I localPoint = Point2I( globalToLocalCoord( lastGuiEvent.mousePoint ) );
  432. if ( splitRect.pointInRect( localPoint ) || mDragging )
  433. {
  434. // Do we need to change it or is it already set?
  435. if ( rootCtrl->mCursorChanged != desiredCursor )
  436. {
  437. // We've already changed the cursor, so set it back
  438. if ( rootCtrl->mCursorChanged != -1 )
  439. cusrorController->popCursor();
  440. // Now change the cursor shape
  441. cusrorController->pushCursor( desiredCursor );
  442. rootCtrl->mCursorChanged = desiredCursor;
  443. }
  444. }
  445. else if ( rootCtrl->mCursorChanged != -1 )
  446. {
  447. // Just the default
  448. cusrorController->popCursor();
  449. rootCtrl->mCursorChanged = -1;
  450. }
  451. }
  452. //-----------------------------------------------------------------------------
  453. void GuiSplitContainer::onMouseDown( const GuiEvent &event )
  454. {
  455. GuiContainer *firstPanel = dynamic_cast<GuiContainer*>(at(0));
  456. GuiContainer *secondPanel = dynamic_cast<GuiContainer*>(at(1));
  457. // This function will constrain the panels to their minExtents and update the mSplitPoint
  458. if ( firstPanel && secondPanel )
  459. {
  460. mouseLock();
  461. mDragging = true;
  462. RectI clientRect = getClientRect();
  463. Point2I newDragPos = globalToLocalCoord( event.mousePoint );
  464. solvePanelConstraints(newDragPos, firstPanel, secondPanel, clientRect);
  465. }
  466. }
  467. //-----------------------------------------------------------------------------
  468. void GuiSplitContainer::onMouseUp( const GuiEvent &event )
  469. {
  470. // If we've been dragging, we need to update the fixed panel extent.
  471. // NOTE : This should ONLY ever happen in this function. the Fixed panel
  472. // is to REMAIN FIXED unless the user changes it.
  473. if ( mDragging )
  474. {
  475. Point2I newSplitPoint = getSplitPoint();
  476. // Update Fixed Panel Extent
  477. if ( mFixedPanel == FirstPanel )
  478. mFixedPanelSize = ( mOrientation == Horizontal ) ? newSplitPoint.y : newSplitPoint.x;
  479. else
  480. mFixedPanelSize = ( mOrientation == Horizontal ) ? getExtent().y - newSplitPoint.y : getExtent().x - newSplitPoint.x;
  481. setUpdateLayout();
  482. }
  483. mDragging = false;
  484. mouseUnlock();
  485. }
  486. //-----------------------------------------------------------------------------
  487. void GuiSplitContainer::onMouseDragged( const GuiEvent &event )
  488. {
  489. GuiContainer *firstPanel = dynamic_cast<GuiContainer*>(at(0));
  490. GuiContainer *secondPanel = dynamic_cast<GuiContainer*>(at(1));
  491. // This function will constrain the panels to their minExtents and update the mSplitPoint
  492. if ( mDragging && firstPanel && secondPanel )
  493. {
  494. RectI clientRect = getClientRect();
  495. Point2I newDragPos = globalToLocalCoord( event.mousePoint );
  496. solvePanelConstraints(newDragPos, firstPanel, secondPanel, clientRect);
  497. }
  498. }
  499. void GuiSplitContainer::setSplitPoint(Point2I splitPoint)
  500. {
  501. GuiContainer *firstPanel = dynamic_cast<GuiContainer*>(at(0));
  502. GuiContainer *secondPanel = dynamic_cast<GuiContainer*>(at(1));
  503. // This function will constrain the panels to their minExtents and update the mSplitPoint
  504. if (firstPanel && secondPanel)
  505. {
  506. RectI clientRect = getClientRect();
  507. solvePanelConstraints(splitPoint, firstPanel, secondPanel, clientRect);
  508. layoutControls(clientRect);
  509. }
  510. }
  511. DefineEngineMethod(GuiSplitContainer, setSplitPoint, void, (Point2I splitPoint), ,
  512. "Set the position of the split handle.")
  513. {
  514. object->setSplitPoint(splitPoint);
  515. }