//----------------------------------------------------------------------------- // Torque Game Engine // Copyright (C) GarageGames.com, Inc. //----------------------------------------------------------------------------- #include "gui/containers/guiStackCtrl.h" IMPLEMENT_CONOBJECT(GuiStackControl); static EnumTable::Enums stackTypeEnum[] = { { GuiStackControl::stackingTypeVert, "Vertical" }, { GuiStackControl::stackingTypeHoriz,"Horizontal" }, { GuiStackControl::stackingTypeDyn,"Dynamic" } }; static EnumTable gStackTypeTable(3, &stackTypeEnum[0]); static EnumTable::Enums stackHorizEnum[] = { { GuiStackControl::horizStackLeft, "Left to Right" }, { GuiStackControl::horizStackRight,"Right to Left" } }; static EnumTable gStackHorizSizingTable(2, &stackHorizEnum[0]); static EnumTable::Enums stackVertEnum[] = { { GuiStackControl::vertStackTop, "Top to Bottom" }, { GuiStackControl::vertStackBottom,"Bottom to Top" } }; static EnumTable gStackVertSizingTable(2, &stackVertEnum[0]); GuiStackControl::GuiStackControl() { mMinExtent.set(24, 24); mResizing = false; mStackingType = stackingTypeVert; mStackVertSizing = vertStackTop; mStackHorizSizing = horizStackLeft; mPadding = 0; } void GuiStackControl::initPersistFields() { addGroup( "Stacking" ); addField( "StackingType", TypeEnum, Offset(mStackingType, GuiStackControl), 1, &gStackTypeTable); addField( "HorizStacking", TypeEnum, Offset(mStackHorizSizing, GuiStackControl), 1, &gStackHorizSizingTable); addField( "VertStacking", TypeEnum, Offset(mStackVertSizing, GuiStackControl), 1, &gStackVertSizingTable); addField( "Padding", TypeS32, Offset(mPadding, GuiStackControl)); endGroup( "Stacking" ); Parent::initPersistFields(); } ConsoleMethod( GuiStackControl, updateStack, void, 2, 2, "%stackCtrl.updateStack() - Restacks controls it owns") { 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 ) { switch( mStackHorizSizing ) { case horizStackLeft: stackFromLeft(); break; case horizStackRight: stackFromRight(); break; } } // Or, vertically? else if( ( extent.y > extent.x && mStackingType == stackingTypeDyn ) || mStackingType == stackingTypeVert) { switch( mStackVertSizing ) { case vertStackTop: stackFromTop(); break; case vertStackBottom: stackFromBottom(); break; } } // Clear Sizing Flag. mResizing = false; } void GuiStackControl::stackFromBottom() { // Store the sum of the heights of our controls. S32 totalHeight=0; Point2I curPos; // If we go from the bottom, things are basically the same... // except we have to assign positions in an arse backwards way // (literally :P) // Figure out how high everything is going to be... // Place each child... for( S32 i = 0; i < size(); i++ ) { // Place control GuiControl * gc = dynamic_cast(operator [](i)); if(gc && gc->isVisible() ) { Point2I childExtent = gc->getExtent(); totalHeight += childExtent.y; } } // Figure out where we're starting... curPos = getPosition(); curPos.y += totalHeight; // Offset so the bottom control goes in the right place... GuiControl * gc = dynamic_cast(operator [](size()-1)); if(gc) curPos.y -= gc->getExtent().y; // Now work up from there! for(S32 i=size()-1; i>=0; i--) { // Place control GuiControl * gc = dynamic_cast(operator [](i)); if(gc) { // We must place the child... // Make it have our width but keep its height Point2I childExtent = gc->getExtent(); // Update our state... curPos.y -= childExtent.y - mPadding; // And resize... gc->resize(curPos - getPosition(), Point2I(getExtent().x, childExtent.y)); } } } void GuiStackControl::stackFromTop() { // Store the sum of the heights of our controls. S32 totalHeight=0; Point2I curPos; // Position and resize everything... curPos = getPosition(); // Place each child... for(S32 i=0; i(operator [](i)); if(gc && gc->isVisible() ) { // We must place the child... // Make it have our width but keep its height Point2I childExtent = gc->getExtent(); gc->resize(curPos - getPosition(), Point2I(getExtent().x, childExtent.y)); // Update our state... curPos.y += childExtent.y + mPadding; totalHeight += childExtent.y + mPadding; } } // Conform our size to the sum of the child sizes. if( totalHeight > getExtent().y ) { curPos.x = getExtent().x; curPos.y = totalHeight; resize(getPosition(), curPos); } else if( totalHeight < getExtent().y ) { curPos.x = getExtent().x; curPos.y = getMax( totalHeight , mMinExtent.y ); resize(getPosition(), curPos); } } void GuiStackControl::stackFromLeft() { // Store the sum of the heights of our controls. S32 totalWidth=0; Point2I curPos; // Position and resize everything... curPos = getPosition(); // Place each child... for(S32 i=0; i(operator [](i)); if(gc && gc->isVisible() ) { // We must place the child... // Make it have our width but keep its height Point2I childExtent = gc->getExtent(); gc->resize(curPos - getPosition(), Point2I( childExtent.x,getExtent().y)); // Update our state... curPos.x += childExtent.x + mPadding; totalWidth += childExtent.x + mPadding; } } // Conform our size to the sum of the child sizes. if( totalWidth > getExtent().x ) { curPos.x = totalWidth; curPos.y = getExtent().y; resize(getPosition(), curPos); } } void GuiStackControl::stackFromRight() { } void GuiStackControl::resize(const Point2I &newPosition, const Point2I &newExtent) { //call set update both before and after setUpdate(); Point2I actualNewExtent = Point2I( getMax(mMinExtent.x, newExtent.x), getMax(mMinExtent.y, newExtent.y)); mBounds.set(newPosition, actualNewExtent); GuiControl *parent = getParent(); if (parent) parent->childResized(this); setUpdate(); updatePanes(); } 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(); }