123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- //-----------------------------------------------------------------------------
- // 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 "console/engineAPI.h"
- #include "gui/containers/guiStackCtrl.h"
- IMPLEMENT_CONOBJECT(GuiStackControl);
- ConsoleDocClass( GuiStackControl,
- "@brief A container that stacks its children horizontally or vertically.\n\n"
- "This container maintains a horizontal or vertical stack of GUI controls. If "
- "one is added, deleted, or resized, then the stack is resized to fit. The "
- "order of the stack is determined by the internal order of the children (ie. "
- "the order of addition).<br>"
- "@tsexample\n"
- "new GuiStackControl()\n"
- "{\n"
- " stackingType = \"Dynamic\";\n"
- " horizStacking = \"Left to Right\";\n"
- " vertStacking = \"Top to Bottom\";\n"
- " padding = \"4\";\n"
- " dynamicSize = \"1\";\n"
- " dynamicNonStackExtent = \"0\";\n"
- " dynamicPos = \"0\";\n"
- " changeChildSizeToFit = \"1\";\n"
- " changeChildPosition = \"1\";\n"
- " //Properties not specific to this control have been omitted from this example.\n"
- "};\n"
- "@endtsexample\n\n"
- "@ingroup GuiContainers"
- );
- ImplementEnumType( GuiStackingType,
- "Stacking method used to position child controls.\n\n"
- "@ingroup GuiContainers" )
- { GuiStackControl::stackingTypeVert, "Vertical", "Stack children vertically by setting their Y position" },
- { GuiStackControl::stackingTypeHoriz,"Horizontal", "Stack children horizontall by setting their X position" },
- { GuiStackControl::stackingTypeDyn,"Dynamic", "Automatically switch between "
- "Vertical and Horizontal stacking. Vertical stacking is chosen when the "
- "stack control is taller than it is wide, horizontal stacking is chosen "
- "when the stack control is wider than it is tall." }
- EndImplementEnumType;
- ImplementEnumType( GuiHorizontalStackingType,
- "Determines how child controls are stacked horizontally.\n\n"
- "@ingroup GuiContainers" )
- { GuiStackControl::horizStackLeft, "Left to Right", "Child controls are positioned in order from left to right (left-most control is first)" },
- { GuiStackControl::horizStackRight,"Right to Left", "Child controls are positioned in order from right to left (right-most control is first)" }
- EndImplementEnumType;
- ImplementEnumType( GuiVerticalStackingType,
- "Determines how child controls are stacked vertically.\n\n"
- "@ingroup GuiContainers" )
- { GuiStackControl::vertStackTop, "Top to Bottom", "Child controls are positioned in order from top to bottom (top-most control is first)" },
- { GuiStackControl::vertStackBottom,"Bottom to Top", "Child controls are positioned in order from bottom to top (bottom-most control is first)" }
- EndImplementEnumType;
- GuiStackControl::GuiStackControl()
- {
- setMinExtent(Point2I(16,16));
- mResizing = false;
- mStackingType = stackingTypeVert;
- mStackVertSizing = vertStackTop;
- mStackHorizSizing = horizStackLeft;
- mPadding = 0;
- mIsContainer = true;
- mDynamicSize = true;
- mDynamicNonStackExtent = false;
- mDynamicPos = false;
- mChangeChildSizeToFit = true;
- mChangeChildPosition = true;
- }
- void GuiStackControl::initPersistFields()
- {
- addGroup( "Stacking" );
- addField( "stackingType", TYPEID< StackingType >(), Offset(mStackingType, GuiStackControl),
- "Determines the method used to position the child controls.\n\n" );
- addField( "horizStacking", TYPEID< HorizontalType >(), Offset(mStackHorizSizing, GuiStackControl),
- "Controls the type of horizontal stacking to use (<i>Left to Right</i> or "
- "<i>Right to Left</i>)" );
- addField( "vertStacking", TYPEID< VerticalType >(), Offset(mStackVertSizing, GuiStackControl),
- "Controls the type of vertical stacking to use (<i>Top to Bottom</i> or "
- "<i>Bottom to Top</i>)" );
- addField( "padding", TypeS32, Offset(mPadding, GuiStackControl),
- "Distance (in pixels) between stacked child controls." );
- addField( "dynamicSize", TypeBool, Offset(mDynamicSize, GuiStackControl),
- "Determines whether to resize the stack control along the stack axis (change "
- "width for horizontal stacking, change height for vertical stacking).\n\n"
- "If true, the stack width/height will be resized to the sum of the child control widths/heights. "
- "If false, the stack will not be resized." );
- addField( "dynamicNonStackExtent", TypeBool, Offset(mDynamicNonStackExtent, GuiStackControl),
- "Determines whether to resize the stack control along the non-stack axis (change "
- "height for horizontal stacking, change width for vertical stacking). No effect "
- "if dynamicSize is false.\n\n"
- "If true, the stack will be resized to the maximum of the child control widths/heights. "
- "If false, the stack will not be resized." );
- addField( "dynamicPos", TypeBool, Offset(mDynamicPos, GuiStackControl),
- "Determines whether to reposition the stack along the stack axis when it is "
- "auto-resized. No effect if dynamicSize is false.\n\n"
- "If true, the stack will grow left for horizontal stacking, and grow up for vertical stacking.\n"
- "If false, the stack will grow right for horizontal stacking, and grow down for vertical stacking.\n" );
- addField( "changeChildSizeToFit", TypeBool, Offset(mChangeChildSizeToFit, GuiStackControl),
- "Determines whether to resize child controls.\n\n"
- "If true, horizontally stacked children keep their width, but have their "
- "height set to the stack control height. Vertically stacked children keep "
- "their height, but have their width set to the stack control width. If "
- "false, child controls are not resized." );
- addField( "changeChildPosition", TypeBool, Offset(mChangeChildPosition, GuiStackControl),
- "Determines whether to reposition child controls.\n\n"
- "If true, horizontally stacked children are aligned along the top edge of "
- "the stack control. Vertically stacked children are aligned along the left "
- "edge of the stack control. If false, horizontally stacked children retain "
- "their Y position, and vertically stacked children retain their X position." );
- endGroup( "Stacking" );
- Parent::initPersistFields();
- }
- DefineEngineMethod( GuiStackControl, isFrozen, bool, (),,
- "Return whether or not this control is frozen" )
- {
- return object->isFrozen();
- }
- DefineEngineMethod( GuiStackControl, freeze, void, ( bool freeze ),,
- "Prevents control from restacking - useful when adding or removing child controls\n"
- "@param freeze True to freeze the control, false to unfreeze it\n\n"
- "@tsexample\n"
- "%stackCtrl.freeze(true);\n"
- "// add controls to stack\n"
- "%stackCtrl.freeze(false);\n"
- "@endtsexample\n" )
- {
- object->freeze( freeze );
- }
- DefineEngineMethod( GuiStackControl, updateStack, void, (),,
- "Restack the child controls.\n" )
- {
- object->updatePanes();
- }
- bool GuiStackControl::onWake()
- {
- if ( !Parent::onWake() )
- return false;
- updatePanes();
- return true;
- }
- void GuiStackControl::onSleep()
- {
- Parent::onSleep();
- }
- void GuiStackControl::updatePanes()
- {
- // Prevent recursion
- if(mResizing)
- return;
- // Set Resizing.
- mResizing = true;
- Point2I extent = getExtent();
- // Do we need to stack horizontally?
- if( ( extent.x > extent.y && mStackingType == stackingTypeDyn ) || mStackingType == stackingTypeHoriz )
- {
- stackHorizontal( mStackHorizSizing == horizStackLeft );
- }
- // Or, vertically?
- else if( ( extent.y > extent.x && mStackingType == stackingTypeDyn ) || mStackingType == stackingTypeVert)
- {
- stackVertical( mStackVertSizing == vertStackTop );
- }
- // Clear Sizing Flag.
- mResizing = false;
- }
- void GuiStackControl::freeze(bool _shouldfreeze)
- {
- mResizing = _shouldfreeze;
- }
- void GuiStackControl::stackVertical(bool fromTop)
- {
- if( empty() )
- return;
- S32 begin, end, step;
- if ( fromTop )
- {
- // Stack from Child0 at top to ChildN at bottom
- begin = 0;
- end = size();
- step = 1;
- }
- else
- {
- // Stack from ChildN at top to Child0 at bottom
- begin = size()-1;
- end = -1;
- step = -1;
- }
- // Place each visible child control
- S32 maxWidth = 0;
- Point2I curPos(0, 0);
- for ( S32 i = begin; i != end; i += step )
- {
- GuiControl * gc = dynamic_cast<GuiControl*>( at(i) );
- if ( gc && gc->isVisible() )
- {
- // Add padding between controls
- if ( curPos.y > 0 )
- curPos.y += mPadding;
- Point2I childPos = curPos;
- if ( !mChangeChildPosition )
- childPos.x = gc->getLeft();
- Point2I childSize( gc->getExtent() );
- if ( mChangeChildSizeToFit )
- childSize.x = getWidth();
- gc->resize( childPos, childSize );
- curPos.y += gc->getHeight();
- maxWidth = getMax( maxWidth, childPos.x + childSize.x );
- }
- }
- if ( mDynamicSize )
- {
- // Conform our size to the sum of the child sizes.
- Point2I newPos( getPosition() );
- Point2I newSize( mDynamicNonStackExtent ? maxWidth : getWidth(), curPos.y );
- newSize.setMax( getMinExtent() );
- // Grow the stack up instead of down?
- if ( mDynamicPos )
- newPos.y -= ( newSize.y - getHeight() );
- resize( newPos, newSize );
- }
- }
- void GuiStackControl::stackHorizontal(bool fromLeft)
- {
- if( empty() )
- return;
- S32 begin, end, step;
- if ( fromLeft )
- {
- // Stack from Child0 at left to ChildN at right
- begin = 0;
- end = size();
- step = 1;
- }
- else
- {
- // Stack from ChildN at left to Child0 at right
- begin = size()-1;
- end = -1;
- step = -1;
- }
- // Place each visible child control
- S32 maxHeight = 0;
- Point2I curPos(0, 0);
- for ( S32 i = begin; i != end; i += step )
- {
- GuiControl * gc = dynamic_cast<GuiControl*>( at(i) );
- if ( gc && gc->isVisible() )
- {
- // Add padding between controls
- if ( curPos.x > 0 )
- curPos.x += mPadding;
- Point2I childPos = curPos;
- if ( !mChangeChildPosition )
- childPos.y = gc->getTop();
- Point2I childSize( gc->getExtent() );
- if ( mChangeChildSizeToFit )
- childSize.y = getHeight();
- gc->resize( childPos, childSize );
- curPos.x += gc->getWidth();
- maxHeight = getMax( maxHeight, childPos.y + childSize.y );
- }
- }
- if ( mDynamicSize )
- {
- // Conform our size to the sum of the child sizes.
- Point2I newPos( getPosition() );
- Point2I newSize( curPos.x, mDynamicNonStackExtent ? maxHeight : getHeight() );
- newSize.setMax( getMinExtent() );
- // Grow the stack left instead of right?
- if ( mDynamicPos )
- newPos.x -= ( newSize.x - getWidth() );
- resize( newPos, newSize );
- }
- }
- bool GuiStackControl::resize(const Point2I &newPosition, const Point2I &newExtent)
- {
- if( !Parent::resize( newPosition, newExtent ) )
- return false;
- updatePanes();
- // CodeReview This logic should be updated to correctly return true/false
- // based on whether it sized it's children. [7/1/2007 justind]
- return true;
- }
- void GuiStackControl::addObject(SimObject *obj)
- {
- Parent::addObject(obj);
- updatePanes();
- }
- void GuiStackControl::removeObject(SimObject *obj)
- {
- Parent::removeObject(obj);
- updatePanes();
- }
- bool GuiStackControl::reOrder(SimObject* obj, SimObject* target)
- {
- bool ret = Parent::reOrder(obj, target);
- if (ret)
- updatePanes();
- return ret;
- }
- void GuiStackControl::childResized(GuiControl *child)
- {
- updatePanes();
- }
|