guiSplitContainer.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  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. TORQUE_UNUSED(panelOne);
  289. TORQUE_UNUSED(panelTwo);
  290. AssertFatal( panelOne && panelTwo, "GuiSplitContainer::resize - Missing/Invalid Subordinate Controls! Split contained controls must derive from GuiContainer!" );
  291. // We only need to update the split point if our second panel is fixed.
  292. // If the first is fixed, then we can leave the split point alone because
  293. // the remainder of the size will be added to or taken from the second panel
  294. Point2I newDragPos;
  295. if ( mFixedPanel == SecondPanel )
  296. {
  297. S32 deltaX = newExtent.x - oldExtent.x;
  298. S32 deltaY = newExtent.y - oldExtent.y;
  299. if( mOrientation == Horizontal )
  300. mSplitPoint.y += deltaY;
  301. else
  302. mSplitPoint.x += deltaX;
  303. }
  304. // If we got here, parent returned true
  305. return true;
  306. }
  307. //-----------------------------------------------------------------------------
  308. bool GuiSplitContainer::layoutControls( RectI &clientRect )
  309. {
  310. if ( size() < 2 )
  311. return false;
  312. GuiContainer *panelOne = dynamic_cast<GuiContainer*>( at(0) );
  313. GuiContainer *panelTwo = dynamic_cast<GuiContainer*>( at(1) );
  314. //
  315. AssertFatal( panelOne && panelTwo, "GuiSplitContainer::layoutControl - Missing/Invalid Subordinate Controls! Split contained controls must derive from GuiContainer!" );
  316. RectI panelOneRect = RectI( clientRect.point, Point2I( 0, 0 ) );
  317. RectI panelTwoRect;
  318. RectI splitRect;
  319. solvePanelConstraints( getSplitPoint(), panelOne, panelTwo, clientRect );
  320. switch( mOrientation )
  321. {
  322. case Horizontal:
  323. panelOneRect.extent = Point2I( clientRect.extent.x, getSplitPoint().y );
  324. panelTwoRect = panelOneRect;
  325. panelTwoRect.intersect( clientRect );
  326. panelTwoRect.point.y = panelOneRect.extent.y;
  327. panelTwoRect.extent.y = clientRect.extent.y - panelOneRect.extent.y;
  328. // Generate new Splitter Rectangle
  329. splitRect = panelTwoRect;
  330. splitRect.extent.y = 0;
  331. splitRect.inset( 0, -mSplitterSize );
  332. panelOneRect.extent.y -= mSplitterSize;
  333. panelTwoRect.point.y += mSplitterSize;
  334. panelTwoRect.extent.y -= mSplitterSize;
  335. break;
  336. case Vertical:
  337. panelOneRect.extent = Point2I( getSplitPoint().x, clientRect.extent.y );
  338. panelTwoRect = panelOneRect;
  339. panelTwoRect.intersect( clientRect );
  340. panelTwoRect.point.x = panelOneRect.extent.x;
  341. panelTwoRect.extent.x = clientRect.extent.x - panelOneRect.extent.x;
  342. // Generate new Splitter Rectangle
  343. splitRect = panelTwoRect;
  344. splitRect.extent.x = 0;
  345. splitRect.inset( -mSplitterSize, 0 );
  346. panelOneRect.extent.x -= mSplitterSize;
  347. panelTwoRect.point.x += mSplitterSize;
  348. panelTwoRect.extent.x -= mSplitterSize;
  349. break;
  350. }
  351. // Update Split Rect
  352. mSplitRect = splitRect;
  353. // Dock Appropriately
  354. if( !( mFixedPanel == FirstPanel && !panelOne->isVisible() ) )
  355. dockControl( panelOne, panelOne->getDocking(), panelOneRect );
  356. if( !( mFixedPanel == FirstPanel && !panelTwo->isVisible() ) )
  357. dockControl( panelTwo, panelOne->getDocking(), panelTwoRect );
  358. //
  359. return false;
  360. }
  361. //-----------------------------------------------------------------------------
  362. void GuiSplitContainer::solvePanelConstraints( Point2I newDragPos, GuiContainer * firstPanel, GuiContainer * secondPanel, RectI clientRect )
  363. {
  364. if( !firstPanel || !secondPanel )
  365. return;
  366. if ( mOrientation == Horizontal )
  367. {
  368. // Constrain based on Y axis (Horizontal Splitter)
  369. // This accounts for the splitter width
  370. S32 splitterSize = (S32)(mSplitRect.extent.y * 0.5);
  371. // Collapsed fixed panel
  372. if ( mFixedPanel == SecondPanel && !secondPanel->isVisible() )
  373. {
  374. newDragPos = Point2I(mSplitPoint.x, getExtent().y - splitterSize );
  375. }
  376. else if( mFixedPanel == SecondPanel && !firstPanel->isVisible() )
  377. {
  378. newDragPos = Point2I(mSplitPoint.x, splitterSize );
  379. }
  380. else // Normal constraints
  381. {
  382. //newDragPos.y -= splitterSize;
  383. S32 newPosition = mClamp( newDragPos.y,
  384. firstPanel->getMinExtent().y + splitterSize,
  385. getExtent().y - secondPanel->getMinExtent().y - splitterSize );
  386. newDragPos = Point2I( mSplitPoint.x, newPosition );
  387. }
  388. }
  389. else
  390. {
  391. // Constrain based on X axis (Vertical Splitter)
  392. // This accounts for the splitter width
  393. S32 splitterSize = (S32)(mSplitRect.extent.x * 0.5);
  394. // Collapsed fixed panel
  395. if ( mFixedPanel == SecondPanel && !secondPanel->isVisible() )
  396. {
  397. newDragPos = Point2I(getExtent().x - splitterSize, mSplitPoint.y );
  398. }
  399. else if ( mFixedPanel == FirstPanel && !firstPanel->isVisible() )
  400. {
  401. newDragPos = Point2I( splitterSize, mSplitPoint.x );
  402. }
  403. else // Normal constraints
  404. {
  405. S32 newPosition = mClamp( newDragPos.x, firstPanel->getMinExtent().x + splitterSize,
  406. getExtent().x - secondPanel->getMinExtent().x - splitterSize );
  407. newDragPos = Point2I( newPosition, mSplitPoint.y );
  408. }
  409. }
  410. // Just in case, clamp to bounds of controls
  411. newDragPos.x = mClamp( newDragPos.x, clientRect.point.x, clientRect.point.x + clientRect.extent.x );
  412. newDragPos.y = mClamp( newDragPos.y, clientRect.point.y, clientRect.point.y + clientRect.extent.y );
  413. mSplitPoint = newDragPos;
  414. }
  415. //-----------------------------------------------------------------------------
  416. void GuiSplitContainer::getCursor( GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent )
  417. {
  418. GuiCanvas *rootCtrl = getRoot();
  419. if ( !rootCtrl )
  420. return;
  421. S32 desiredCursor = 0;
  422. RectI splitRect = getSplitRect();
  423. // Figure out which cursor we want if we need one
  424. if ( mOrientation == Horizontal )
  425. desiredCursor = PlatformCursorController::curResizeHorz;
  426. else if ( mOrientation == Vertical )
  427. desiredCursor = PlatformCursorController::curResizeVert;
  428. PlatformWindow *platformWindow = static_cast<GuiCanvas*>(getRoot())->getPlatformWindow();
  429. AssertFatal( platformWindow != NULL,"GuiControl without owning platform window! This should not be possible." );
  430. PlatformCursorController *cusrorController = platformWindow->getCursorController();
  431. AssertFatal( cusrorController != NULL,"PlatformWindow without an owned CursorController!" );
  432. // Check to see if we need one or just the default...
  433. Point2I localPoint = Point2I( globalToLocalCoord( lastGuiEvent.mousePoint ) );
  434. if ( splitRect.pointInRect( localPoint ) || mDragging )
  435. {
  436. // Do we need to change it or is it already set?
  437. if ( rootCtrl->mCursorChanged != desiredCursor )
  438. {
  439. // We've already changed the cursor, so set it back
  440. if ( rootCtrl->mCursorChanged != -1 )
  441. cusrorController->popCursor();
  442. // Now change the cursor shape
  443. cusrorController->pushCursor( desiredCursor );
  444. rootCtrl->mCursorChanged = desiredCursor;
  445. }
  446. }
  447. else if ( rootCtrl->mCursorChanged != -1 )
  448. {
  449. // Just the default
  450. cusrorController->popCursor();
  451. rootCtrl->mCursorChanged = -1;
  452. }
  453. }
  454. //-----------------------------------------------------------------------------
  455. void GuiSplitContainer::onMouseDown( const GuiEvent &event )
  456. {
  457. GuiContainer *firstPanel = dynamic_cast<GuiContainer*>(at(0));
  458. GuiContainer *secondPanel = dynamic_cast<GuiContainer*>(at(1));
  459. // This function will constrain the panels to their minExtents and update the mSplitPoint
  460. if ( firstPanel && secondPanel )
  461. {
  462. mouseLock();
  463. mDragging = true;
  464. RectI clientRect = getClientRect();
  465. Point2I newDragPos = globalToLocalCoord( event.mousePoint );
  466. solvePanelConstraints(newDragPos, firstPanel, secondPanel, clientRect);
  467. }
  468. }
  469. //-----------------------------------------------------------------------------
  470. void GuiSplitContainer::onMouseUp( const GuiEvent &event )
  471. {
  472. // If we've been dragging, we need to update the fixed panel extent.
  473. // NOTE : This should ONLY ever happen in this function. the Fixed panel
  474. // is to REMAIN FIXED unless the user changes it.
  475. if ( mDragging )
  476. {
  477. Point2I newSplitPoint = getSplitPoint();
  478. // Update Fixed Panel Extent
  479. if ( mFixedPanel == FirstPanel )
  480. mFixedPanelSize = ( mOrientation == Horizontal ) ? newSplitPoint.y : newSplitPoint.x;
  481. else
  482. mFixedPanelSize = ( mOrientation == Horizontal ) ? getExtent().y - newSplitPoint.y : getExtent().x - newSplitPoint.x;
  483. setUpdateLayout();
  484. }
  485. mDragging = false;
  486. mouseUnlock();
  487. }
  488. //-----------------------------------------------------------------------------
  489. void GuiSplitContainer::onMouseDragged( const GuiEvent &event )
  490. {
  491. GuiContainer *firstPanel = dynamic_cast<GuiContainer*>(at(0));
  492. GuiContainer *secondPanel = dynamic_cast<GuiContainer*>(at(1));
  493. // This function will constrain the panels to their minExtents and update the mSplitPoint
  494. if ( mDragging && firstPanel && secondPanel )
  495. {
  496. RectI clientRect = getClientRect();
  497. Point2I newDragPos = globalToLocalCoord( event.mousePoint );
  498. solvePanelConstraints(newDragPos, firstPanel, secondPanel, clientRect);
  499. }
  500. }