mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 12:44:46 +00:00
A lot of instances where some function args are not actually modified in any way, meaning that it is better for performance to convert them into const references. This prevents an additional copy, which can help performance.
616 lines
21 KiB
C++
616 lines
21 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Copyright (c) 2012 GarageGames, LLC
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to
|
|
// deal in the Software without restriction, including without limitation the
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
// IN THE SOFTWARE.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "platform/platform.h"
|
|
#include "gui/containers/guiSplitContainer.h"
|
|
|
|
#include "gui/core/guiCanvas.h"
|
|
#include "console/consoleTypes.h"
|
|
#include "gfx/gfxDrawUtil.h"
|
|
|
|
|
|
IMPLEMENT_CONOBJECT( GuiSplitContainer );
|
|
|
|
ConsoleDocClass( GuiSplitContainer,
|
|
"@brief A container that splits its area between two child controls.\n\n"
|
|
|
|
"A GuiSplitContainer can be used to dynamically subdivide an area between two child controls. "
|
|
"A splitter bar is placed between the two controls and allows to 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 #orientation.\n\n"
|
|
|
|
"By using #fixedPanel, one of the panels can be chosen to remain at a fixed size (#fixedSize)."
|
|
|
|
"@tsexample\n"
|
|
"// Create a vertical splitter with a fixed-size left panel.\n"
|
|
"%splitter = new GuiSplitContainer()\n"
|
|
"{\n"
|
|
" orientation = \"Vertical\";\n"
|
|
" fixedPanel = \"FirstPanel\";\n"
|
|
" fixedSize = 100;\n"
|
|
"\n"
|
|
" new GuiScrollCtrl()\n"
|
|
" {\n"
|
|
" new GuiMLTextCtrl()\n"
|
|
" {\n"
|
|
" text = %longText;\n"
|
|
" };\n"
|
|
" };\n"
|
|
"\n"
|
|
" new GuiScrollCtrl()\n"
|
|
" {\n"
|
|
" new GuiMLTextCtrl()\n"
|
|
" {\n"
|
|
" text = %moreLongText;\n"
|
|
" };\n"
|
|
" };\n"
|
|
"};\n"
|
|
"@endtsexample\n\n"
|
|
|
|
"@note The children placed inside GuiSplitContainers must be GuiContainers.\n\n"
|
|
|
|
"@ingroup GuiContainers"
|
|
);
|
|
|
|
|
|
ImplementEnumType( GuiSplitOrientation,
|
|
"Axis along which to divide the container's space.\n\n"
|
|
"@ingroup GuiContainers" )
|
|
{ GuiSplitContainer::Vertical, "Vertical", "Divide vertically placing one child left and one child right." },
|
|
{ GuiSplitContainer::Horizontal, "Horizontal", "Divide horizontally placing one child on top and one child below." }
|
|
EndImplementEnumType;
|
|
|
|
ImplementEnumType( GuiSplitFixedPanel,
|
|
"Which side of the splitter to keep at a fixed size (if any).\n\n"
|
|
"@ingroup GuiContainers" )
|
|
{ GuiSplitContainer::None, "None", "Allow both childs to resize (default)." },
|
|
{ GuiSplitContainer::FirstPanel, "FirstPanel", "Keep " },
|
|
{ GuiSplitContainer::SecondPanel, "SecondPanel" }
|
|
EndImplementEnumType;
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
GuiSplitContainer::GuiSplitContainer()
|
|
: mFixedPanel( None ),
|
|
mFixedPanelSize( 100 ),
|
|
mOrientation( Vertical ),
|
|
mSplitterSize( 2 ),
|
|
mSplitPoint( 0, 0 ),
|
|
mSplitRect( 0, 0, mSplitterSize, mSplitterSize ),
|
|
mDragging( false )
|
|
{
|
|
setMinExtent( Point2I(64,64) );
|
|
setExtent(200,200);
|
|
setDocking( Docking::dockNone );
|
|
|
|
mSplitPoint.set( 300, 100 );
|
|
|
|
// We only support client docked items in a split container
|
|
mValidDockingMask = Docking::dockClient;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void GuiSplitContainer::initPersistFields()
|
|
{
|
|
addGroup( "Splitter", "Options to configure split panels contained by this control" );
|
|
|
|
addField( "orientation", TYPEID< Orientation >(), Offset( mOrientation, GuiSplitContainer),
|
|
"Whether to split between top and bottom (horizontal) or between left and right (vertical)." );
|
|
addField( "splitterSize", TypeS32, Offset( mSplitterSize, GuiSplitContainer),
|
|
"Width of the splitter bar between the two sides. Default is 2." );
|
|
addField( "splitPoint", TypePoint2I, Offset( mSplitPoint, GuiSplitContainer),
|
|
"Point on control through which the splitter goes.\n\n"
|
|
"Changed relatively if size of control changes." );
|
|
addField( "fixedPanel", TYPEID< FixedPanel >(), Offset( mFixedPanel, GuiSplitContainer),
|
|
"Which (if any) side of the splitter to keep at a fixed size." );
|
|
addField( "fixedSize", TypeS32, Offset( mFixedPanelSize, GuiSplitContainer),
|
|
"Width of the fixed panel specified by #fixedPanel (if any)." );
|
|
|
|
endGroup( "Splitter" );
|
|
|
|
Parent::initPersistFields();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool GuiSplitContainer::onAdd()
|
|
{
|
|
if ( !Parent::onAdd() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool GuiSplitContainer::onWake()
|
|
{
|
|
if ( !Parent::onWake() )
|
|
return false;
|
|
|
|
// Create Panel 1
|
|
if ( empty() )
|
|
{
|
|
GuiPanel *newPanel = new GuiPanel();
|
|
AssertFatal( newPanel, "GuiSplitContainer::onAdd - Cannot create subordinate panel #1!" );
|
|
newPanel->registerObject();
|
|
newPanel->setInternalName( "Panel1" );
|
|
newPanel->setDocking( Docking::dockClient );
|
|
addObject( (SimObject*)newPanel );
|
|
}
|
|
else
|
|
{
|
|
GuiContainer *containerCtrl = dynamic_cast<GuiContainer*>( at(0) );
|
|
if ( containerCtrl )
|
|
{
|
|
containerCtrl->setInternalName( "Panel1" );
|
|
containerCtrl->setDocking( Docking::dockClient );
|
|
}
|
|
}
|
|
|
|
if ( size() == 1 )
|
|
{
|
|
// Create Panel 2
|
|
GuiPanel *newPanel = new GuiPanel();
|
|
AssertFatal( newPanel, "GuiSplitContainer::onAdd - Cannot create subordinate panel #2!" );
|
|
newPanel->registerObject();
|
|
newPanel->setInternalName( "Panel2" );
|
|
newPanel->setDocking( Docking::dockClient );
|
|
addObject( (SimObject*)newPanel );
|
|
}
|
|
else
|
|
{
|
|
GuiContainer *containerCtrl = dynamic_cast<GuiContainer*>( at(1) );
|
|
if ( containerCtrl )
|
|
{
|
|
containerCtrl->setInternalName( "Panel2" );
|
|
containerCtrl->setDocking( Docking::dockClient );
|
|
}
|
|
}
|
|
|
|
// Has FixedWidth been specified?
|
|
if ( mFixedPanelSize == 0 )
|
|
{
|
|
// Nope, so try to guess as best we can
|
|
GuiContainer *firstPanel = dynamic_cast<GuiContainer*>( at(0) );
|
|
GuiContainer *secondPanel = dynamic_cast<GuiContainer*>( at(1) );
|
|
if ( mFixedPanel == FirstPanel )
|
|
{
|
|
if ( mOrientation == Horizontal )
|
|
mFixedPanelSize = firstPanel->getExtent().y;
|
|
else
|
|
mFixedPanelSize = firstPanel->getExtent().x;
|
|
|
|
mSplitPoint = Point2I( mFixedPanelSize, mFixedPanelSize );
|
|
}
|
|
else if ( mFixedPanel == SecondPanel )
|
|
{
|
|
if ( mOrientation == Horizontal )
|
|
mFixedPanelSize = getExtent().y - secondPanel->getExtent().y;
|
|
else
|
|
mFixedPanelSize = getExtent().x - secondPanel->getExtent().x;
|
|
|
|
mSplitPoint = getExtent() - Point2I( mFixedPanelSize, mFixedPanelSize );
|
|
}
|
|
|
|
}
|
|
|
|
setUpdateLayout();
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void GuiSplitContainer::onRender( Point2I offset, const RectI &updateRect )
|
|
{
|
|
Parent::onRender( offset, updateRect );
|
|
|
|
// Only render if we're dragging the splitter
|
|
if ( mDragging && mSplitRect.isValidRect() )
|
|
{
|
|
// Splitter Rectangle (will adjust positioning only)
|
|
RectI splitterRect = mSplitRect;
|
|
|
|
// Currently being dragged to Rect
|
|
Point2I splitterPoint = localToGlobalCoord( mSplitRect.point );
|
|
splitterRect.point = localToGlobalCoord( mSplitPoint );
|
|
|
|
RectI clientRect = getClientRect();
|
|
clientRect.point = localToGlobalCoord( clientRect.point );
|
|
|
|
if ( mOrientation == Horizontal )
|
|
{
|
|
splitterRect.point.y -= mSplitterSize;
|
|
splitterRect.point.x = splitterPoint.x;
|
|
}
|
|
else
|
|
{
|
|
splitterRect.point.x -= mSplitterSize;
|
|
splitterRect.point.y = splitterPoint.y;
|
|
}
|
|
|
|
RectI oldClip = GFX->getClipRect();
|
|
GFX->setClipRect( clientRect );
|
|
GFX->getDrawUtil()->drawRectFill( splitterRect, mProfile->mFillColorHL );
|
|
GFX->setClipRect( oldClip );
|
|
|
|
}
|
|
else
|
|
{
|
|
RectI splitterRect = mSplitRect;
|
|
splitterRect.point += offset;
|
|
GFX->getDrawUtil()->drawRectFill( splitterRect, mProfile->mFillColor );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Point2I GuiSplitContainer::getMinExtent() const
|
|
{
|
|
GuiContainer *panelOne = dynamic_cast<GuiContainer*>( at(0) );
|
|
GuiContainer *panelTwo = dynamic_cast<GuiContainer*>( at(1) );
|
|
|
|
if ( !panelOne || !panelTwo )
|
|
return Parent::getMinExtent();
|
|
|
|
Point2I minExtent = Point2I(0,0);
|
|
Point2I panelOneMinExtent = panelOne->getMinExtent();
|
|
Point2I panelTwoMinExtent = panelTwo->getMinExtent();
|
|
|
|
if ( mOrientation == Horizontal )
|
|
{
|
|
minExtent.y = 2 * mSplitterSize + panelOneMinExtent.y + panelTwoMinExtent.y;
|
|
minExtent.x = getMax( panelOneMinExtent.x, panelTwoMinExtent.x );
|
|
}
|
|
else
|
|
{
|
|
minExtent.x = 2 * mSplitterSize + panelOneMinExtent.x + panelTwoMinExtent.x;
|
|
minExtent.y = getMax( panelOneMinExtent.y, panelTwoMinExtent.y );
|
|
}
|
|
|
|
return minExtent;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void GuiSplitContainer::parentResized( const RectI &oldParentRect, const RectI &newParentRect )
|
|
{
|
|
Parent::parentResized( oldParentRect, newParentRect );
|
|
return;
|
|
|
|
// TODO: Is this right James? This isn't needed anymore?
|
|
/*
|
|
|
|
// GuiSplitContainer overrides parentResized to make sure that the proper fixed frame's width/height
|
|
// is not compromised in the call
|
|
|
|
if ( size() < 2 )
|
|
return;
|
|
|
|
GuiContainer *panelOne = dynamic_cast<GuiContainer*>( at(0) );
|
|
GuiContainer *panelTwo = dynamic_cast<GuiContainer*>( at(1) );
|
|
|
|
AssertFatal( panelOne && panelTwo, "GuiSplitContainer::parentResized - Missing/Invalid Subordinate Controls! Split contained controls must derive from GuiContainer!" );
|
|
|
|
Point2I newDragPos;
|
|
if ( mFixedPanel == FirstPanel )
|
|
{
|
|
newDragPos = panelOne->getExtent();
|
|
newDragPos += Point2I( mSplitterSize, mSplitterSize );
|
|
}
|
|
else if ( mFixedPanel == SecondPanel )
|
|
{
|
|
newDragPos = getExtent() - panelTwo->getExtent();
|
|
newDragPos -= Point2I( mSplitterSize, mSplitterSize );
|
|
}
|
|
else // None
|
|
newDragPos.set( 1, 1);
|
|
|
|
RectI clientRect = getClientRect();
|
|
solvePanelConstraints( newDragPos, panelOne, panelTwo, clientRect );
|
|
|
|
setUpdateLayout();
|
|
*/
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool GuiSplitContainer::resize( const Point2I &newPosition, const Point2I &newExtent )
|
|
{
|
|
// Save previous extent.
|
|
Point2I oldExtent = getExtent();
|
|
|
|
// Resize ourselves.
|
|
if ( !Parent::resize( newPosition, newExtent ) || size() < 2 )
|
|
return false;
|
|
|
|
GuiContainer *panelOne = dynamic_cast<GuiContainer*>( at(0) );
|
|
GuiContainer *panelTwo = dynamic_cast<GuiContainer*>( at(1) );
|
|
|
|
//
|
|
AssertFatal( panelOne && panelTwo, "GuiSplitContainer::resize - Missing/Invalid Subordinate Controls! Split contained controls must derive from GuiContainer!" );
|
|
|
|
// We only need to update the split point if our second panel is fixed.
|
|
// If the first is fixed, then we can leave the split point alone because
|
|
// the remainder of the size will be added to or taken from the second panel
|
|
Point2I newDragPos;
|
|
if ( mFixedPanel == SecondPanel )
|
|
{
|
|
S32 deltaX = newExtent.x - oldExtent.x;
|
|
S32 deltaY = newExtent.y - oldExtent.y;
|
|
|
|
if( mOrientation == Horizontal )
|
|
mSplitPoint.y += deltaY;
|
|
else
|
|
mSplitPoint.x += deltaX;
|
|
}
|
|
|
|
// If we got here, parent returned true
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool GuiSplitContainer::layoutControls( RectI &clientRect )
|
|
{
|
|
if ( size() < 2 )
|
|
return false;
|
|
|
|
GuiContainer *panelOne = dynamic_cast<GuiContainer*>( at(0) );
|
|
GuiContainer *panelTwo = dynamic_cast<GuiContainer*>( at(1) );
|
|
|
|
//
|
|
AssertFatal( panelOne && panelTwo, "GuiSplitContainer::layoutControl - Missing/Invalid Subordinate Controls! Split contained controls must derive from GuiContainer!" );
|
|
|
|
RectI panelOneRect = RectI( clientRect.point, Point2I( 0, 0 ) );
|
|
RectI panelTwoRect;
|
|
RectI splitRect;
|
|
|
|
solvePanelConstraints( getSplitPoint(), panelOne, panelTwo, clientRect );
|
|
|
|
switch( mOrientation )
|
|
{
|
|
case Horizontal:
|
|
panelOneRect.extent = Point2I( clientRect.extent.x, getSplitPoint().y );
|
|
panelTwoRect = panelOneRect;
|
|
panelTwoRect.intersect( clientRect );
|
|
panelTwoRect.point.y = panelOneRect.extent.y;
|
|
panelTwoRect.extent.y = clientRect.extent.y - panelOneRect.extent.y;
|
|
|
|
// Generate new Splitter Rectangle
|
|
splitRect = panelTwoRect;
|
|
splitRect.extent.y = 0;
|
|
splitRect.inset( 0, -mSplitterSize );
|
|
|
|
panelOneRect.extent.y -= mSplitterSize;
|
|
panelTwoRect.point.y += mSplitterSize;
|
|
panelTwoRect.extent.y -= mSplitterSize;
|
|
|
|
break;
|
|
|
|
case Vertical:
|
|
panelOneRect.extent = Point2I( getSplitPoint().x, clientRect.extent.y );
|
|
panelTwoRect = panelOneRect;
|
|
panelTwoRect.intersect( clientRect );
|
|
panelTwoRect.point.x = panelOneRect.extent.x;
|
|
panelTwoRect.extent.x = clientRect.extent.x - panelOneRect.extent.x;
|
|
|
|
// Generate new Splitter Rectangle
|
|
splitRect = panelTwoRect;
|
|
splitRect.extent.x = 0;
|
|
splitRect.inset( -mSplitterSize, 0 );
|
|
|
|
panelOneRect.extent.x -= mSplitterSize;
|
|
panelTwoRect.point.x += mSplitterSize;
|
|
panelTwoRect.extent.x -= mSplitterSize;
|
|
|
|
break;
|
|
}
|
|
|
|
// Update Split Rect
|
|
mSplitRect = splitRect;
|
|
|
|
// Dock Appropriately
|
|
if( !( mFixedPanel == FirstPanel && !panelOne->isVisible() ) )
|
|
dockControl( panelOne, panelOne->getDocking(), panelOneRect );
|
|
if( !( mFixedPanel == FirstPanel && !panelTwo->isVisible() ) )
|
|
dockControl( panelTwo, panelOne->getDocking(), panelTwoRect );
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void GuiSplitContainer::solvePanelConstraints(Point2I newDragPos, GuiContainer * firstPanel, GuiContainer * secondPanel, const RectI& clientRect)
|
|
{
|
|
if( !firstPanel || !secondPanel )
|
|
return;
|
|
|
|
if ( mOrientation == Horizontal )
|
|
{
|
|
// Constrain based on Y axis (Horizontal Splitter)
|
|
|
|
// This accounts for the splitter width
|
|
S32 splitterSize = (S32)(mSplitRect.extent.y * 0.5);
|
|
|
|
// Collapsed fixed panel
|
|
if ( mFixedPanel == SecondPanel && !secondPanel->isVisible() )
|
|
{
|
|
newDragPos = Point2I(mSplitPoint.x, getExtent().y - splitterSize );
|
|
}
|
|
else if( mFixedPanel == SecondPanel && !firstPanel->isVisible() )
|
|
{
|
|
newDragPos = Point2I(mSplitPoint.x, splitterSize );
|
|
}
|
|
else // Normal constraints
|
|
{
|
|
//newDragPos.y -= splitterSize;
|
|
S32 newPosition = mClamp( newDragPos.y,
|
|
firstPanel->getMinExtent().y + splitterSize,
|
|
getExtent().y - secondPanel->getMinExtent().y - splitterSize );
|
|
newDragPos = Point2I( mSplitPoint.x, newPosition );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Constrain based on X axis (Vertical Splitter)
|
|
|
|
// This accounts for the splitter width
|
|
S32 splitterSize = (S32)(mSplitRect.extent.x * 0.5);
|
|
|
|
// Collapsed fixed panel
|
|
if ( mFixedPanel == SecondPanel && !secondPanel->isVisible() )
|
|
{
|
|
newDragPos = Point2I(getExtent().x - splitterSize, mSplitPoint.y );
|
|
}
|
|
else if ( mFixedPanel == FirstPanel && !firstPanel->isVisible() )
|
|
{
|
|
newDragPos = Point2I( splitterSize, mSplitPoint.x );
|
|
}
|
|
else // Normal constraints
|
|
{
|
|
S32 newPosition = mClamp( newDragPos.x, firstPanel->getMinExtent().x + splitterSize,
|
|
getExtent().x - secondPanel->getMinExtent().x - splitterSize );
|
|
newDragPos = Point2I( newPosition, mSplitPoint.y );
|
|
}
|
|
}
|
|
|
|
// Just in case, clamp to bounds of controls
|
|
newDragPos.x = mClamp( newDragPos.x, clientRect.point.x, clientRect.point.x + clientRect.extent.x );
|
|
newDragPos.y = mClamp( newDragPos.y, clientRect.point.y, clientRect.point.y + clientRect.extent.y );
|
|
|
|
mSplitPoint = newDragPos;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void GuiSplitContainer::getCursor( GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent )
|
|
{
|
|
GuiCanvas *rootCtrl = getRoot();
|
|
if ( !rootCtrl )
|
|
return;
|
|
|
|
S32 desiredCursor = 0;
|
|
RectI splitRect = getSplitRect();
|
|
|
|
// Figure out which cursor we want if we need one
|
|
if ( mOrientation == Horizontal )
|
|
desiredCursor = PlatformCursorController::curResizeHorz;
|
|
else if ( mOrientation == Vertical )
|
|
desiredCursor = PlatformCursorController::curResizeVert;
|
|
|
|
PlatformWindow *platformWindow = static_cast<GuiCanvas*>(getRoot())->getPlatformWindow();
|
|
AssertFatal( platformWindow != NULL,"GuiControl without owning platform window! This should not be possible." );
|
|
|
|
PlatformCursorController *cusrorController = platformWindow->getCursorController();
|
|
AssertFatal( cusrorController != NULL,"PlatformWindow without an owned CursorController!" );
|
|
|
|
// Check to see if we need one or just the default...
|
|
|
|
Point2I localPoint = Point2I( globalToLocalCoord( lastGuiEvent.mousePoint ) );
|
|
if ( splitRect.pointInRect( localPoint ) || mDragging )
|
|
{
|
|
// Do we need to change it or is it already set?
|
|
if ( rootCtrl->mCursorChanged != desiredCursor )
|
|
{
|
|
// We've already changed the cursor, so set it back
|
|
if ( rootCtrl->mCursorChanged != -1 )
|
|
cusrorController->popCursor();
|
|
|
|
// Now change the cursor shape
|
|
cusrorController->pushCursor( desiredCursor );
|
|
rootCtrl->mCursorChanged = desiredCursor;
|
|
}
|
|
}
|
|
else if ( rootCtrl->mCursorChanged != -1 )
|
|
{
|
|
// Just the default
|
|
cusrorController->popCursor();
|
|
rootCtrl->mCursorChanged = -1;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void GuiSplitContainer::onMouseDown( const GuiEvent &event )
|
|
{
|
|
GuiContainer *firstPanel = dynamic_cast<GuiContainer*>(at(0));
|
|
GuiContainer *secondPanel = dynamic_cast<GuiContainer*>(at(1));
|
|
|
|
// This function will constrain the panels to their minExtents and update the mSplitPoint
|
|
if ( firstPanel && secondPanel )
|
|
{
|
|
mouseLock();
|
|
mDragging = true;
|
|
|
|
RectI clientRect = getClientRect();
|
|
Point2I newDragPos = globalToLocalCoord( event.mousePoint );
|
|
|
|
solvePanelConstraints(newDragPos, firstPanel, secondPanel, clientRect);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void GuiSplitContainer::onMouseUp( const GuiEvent &event )
|
|
{
|
|
// If we've been dragging, we need to update the fixed panel extent.
|
|
// NOTE : This should ONLY ever happen in this function. the Fixed panel
|
|
// is to REMAIN FIXED unless the user changes it.
|
|
if ( mDragging )
|
|
{
|
|
Point2I newSplitPoint = getSplitPoint();
|
|
|
|
// Update Fixed Panel Extent
|
|
if ( mFixedPanel == FirstPanel )
|
|
mFixedPanelSize = ( mOrientation == Horizontal ) ? newSplitPoint.y : newSplitPoint.x;
|
|
else
|
|
mFixedPanelSize = ( mOrientation == Horizontal ) ? getExtent().y - newSplitPoint.y : getExtent().x - newSplitPoint.x;
|
|
|
|
setUpdateLayout();
|
|
}
|
|
|
|
mDragging = false;
|
|
mouseUnlock();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void GuiSplitContainer::onMouseDragged( const GuiEvent &event )
|
|
{
|
|
GuiContainer *firstPanel = dynamic_cast<GuiContainer*>(at(0));
|
|
GuiContainer *secondPanel = dynamic_cast<GuiContainer*>(at(1));
|
|
|
|
// This function will constrain the panels to their minExtents and update the mSplitPoint
|
|
if ( mDragging && firstPanel && secondPanel )
|
|
{
|
|
RectI clientRect = getClientRect();
|
|
Point2I newDragPos = globalToLocalCoord( event.mousePoint );
|
|
|
|
solvePanelConstraints(newDragPos, firstPanel, secondPanel, clientRect);
|
|
}
|
|
}
|