Torque3D Documentation / _generateds / guiSplitContainer.cpp

guiSplitContainer.cpp

Engine/source/gui/containers/guiSplitContainer.cpp

More...

Public Functions

ConsoleDocClass(GuiSplitContainer , "@brief A container that splits its area between two child <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">controls.\n\n</a>" "A <a href="/coding/class/classguisplitcontainer/">GuiSplitContainer</a> can be used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> dynamically subdivide an area between two child controls. " "A splitter bar is placed between the two controls and allows <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> dynamically adjust the sizing " "ratio between the two sides. Splitting can be either horizontal (subdividing top and bottom) " "or vertical (subdividing left and right) depending on #<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">orientation.\n\n</a>" "By using # fixedPanel)
DefineEngineMethod(GuiSplitContainer , setSplitPoint , void , (Point2I splitPoint) , "Set the position of the split handle." )
ImplementEnumType(GuiSplitFixedPanel , "Which side of the splitter <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> keep at <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> fixed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> (<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> any).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup GuiContainers" )
ImplementEnumType(GuiSplitOrientation , "Axis along which <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> divide the container's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">space.\n\n</a>" "@ingroup GuiContainers" )

Detailed Description

Public Functions

ConsoleDocClass(GuiSplitContainer , "@brief A container that splits its area between two child <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">controls.\n\n</a>" "A <a href="/coding/class/classguisplitcontainer/">GuiSplitContainer</a> can be used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> dynamically subdivide an area between two child controls. " "A splitter bar is placed between the two controls and allows <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> dynamically adjust the sizing " "ratio between the two sides. Splitting can be either horizontal (subdividing top and bottom) " "or vertical (subdividing left and right) depending on #<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">orientation.\n\n</a>" "By using # fixedPanel)

DefineEngineMethod(GuiSplitContainer , setSplitPoint , void , (Point2I splitPoint) , "Set the position of the split handle." )

IMPLEMENT_CONOBJECT(GuiSplitContainer )

ImplementEnumType(GuiSplitFixedPanel , "Which side of the splitter <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> keep at <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> fixed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> (<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> any).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup GuiContainers" )

ImplementEnumType(GuiSplitOrientation , "Axis along which <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> divide the container's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">space.\n\n</a>" "@ingroup GuiContainers" )

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