Torque3D Documentation / _generateds / guiRolloutCtrl.cpp

guiRolloutCtrl.cpp

Engine/source/gui/containers/guiRolloutCtrl.cpp

More...

Public Functions

ConsoleDocClass(GuiRolloutCtrl , "@brief A container that shows <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single child with an optional header bar that can be used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> collapse and expand the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rollout.\n\n</a>" "A rollout is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> container that can be collapsed and expanded using smooth animation. By default, rollouts will display <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> header " "with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> caption along the top edge of the <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> which can be clicked by the user <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> toggle the collapse state of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rollout.\n\n</a>" "Rollouts will automatically <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> themselves <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> exactly fit around their child control. They will also automatically position their child " "<a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> in their upper left corner below the header(<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> present).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " @note GuiRolloutCtrls will only work correctly with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single child control. To put multiple controls in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> rollout, put them " "in their own group using <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classguicontrol/">GuiControl</a> which then can be put inside the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rollout.\n\n</a>" " @ingroup GuiContainers" )
DefineEngineMethod(GuiRolloutCtrl , collapse , void , () , "Collapse the rollout <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it is currently expanded. This will make the rollout's child <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">invisible.\n\n</a>" "@note The rollout will animate <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> collapsed state. To instantly collapse without animation, use instantCollapse()." )
DefineEngineMethod(GuiRolloutCtrl , expand , void , () , "Expand the rollout <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it is currently collapsed. This will make the rollout's child <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">visible.\n\n</a>" "@note The rollout will animate <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> expanded state. To instantly expand without animation, use instantExpand()." )
DefineEngineMethod(GuiRolloutCtrl , instantCollapse , void , () , "Instantly collapse the rollout without animation. To smoothly slide the rollout <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> collapsed state, use collapse()." )
DefineEngineMethod(GuiRolloutCtrl , instantExpand , void , () , "Instantly expand the rollout without animation. To smoothly slide the rollout <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> expanded state, use expand()." )
DefineEngineMethod(GuiRolloutCtrl , isExpanded , bool , () , "Determine whether the rollout is currently expanded, i.e. whether the child <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">visible.\n\n</a>" " @return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the rollout is expanded, false <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> not." )
DefineEngineMethod(GuiRolloutCtrl , sizeToContents , void , () , "Resize the rollout <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> exactly fit around its child control. This can be used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> manually trigger <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> recomputation of " "the rollout size." )
DefineEngineMethod(GuiRolloutCtrl , toggleCollapse , void , () , "Toggle the current collapse state of the rollout. If it is currently expanded, then collapse it. If it " "is currently collapsed, then expand it." )
DefineEngineMethod(GuiRolloutCtrl , toggleExpanded , void , (bool instantly) , (false) , "Toggle the current expansion state of the rollout If it is currently expanded, then collapse it. If it " "is currently collapsed, then expand <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">it.\n\n</a>" " @param instant If true, the rollout will toggle its state without animation. Otherwise, the rollout will " "smoothly slide into the opposite state." )
IMPLEMENT_CALLBACK(GuiRolloutCtrl , onCollapsed , void , () , () , "Called when the rollout is collapsed." )
IMPLEMENT_CALLBACK(GuiRolloutCtrl , onExpanded , void , () , () , "Called when the rollout is expanded." )
IMPLEMENT_CALLBACK(GuiRolloutCtrl , onHeaderRightClick , void , () , () , "Called when the user right-clicks on the rollout's header. This is useful <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> implementing " "context menus <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> rollouts." )

Detailed Description

Public Functions

ConsoleDocClass(GuiRolloutCtrl , "@brief A container that shows <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single child with an optional header bar that can be used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> collapse and expand the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rollout.\n\n</a>" "A rollout is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> container that can be collapsed and expanded using smooth animation. By default, rollouts will display <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> header " "with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> caption along the top edge of the <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> which can be clicked by the user <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> toggle the collapse state of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rollout.\n\n</a>" "Rollouts will automatically <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> themselves <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> exactly fit around their child control. They will also automatically position their child " "<a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> in their upper left corner below the header(<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> present).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " @note GuiRolloutCtrls will only work correctly with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single child control. To put multiple controls in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> rollout, put them " "in their own group using <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classguicontrol/">GuiControl</a> which then can be put inside the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rollout.\n\n</a>" " @ingroup GuiContainers" )

DefineEngineMethod(GuiRolloutCtrl , collapse , void , () , "Collapse the rollout <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it is currently expanded. This will make the rollout's child <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">invisible.\n\n</a>" "@note The rollout will animate <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> collapsed state. To instantly collapse without animation, use instantCollapse()." )

DefineEngineMethod(GuiRolloutCtrl , expand , void , () , "Expand the rollout <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it is currently collapsed. This will make the rollout's child <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">visible.\n\n</a>" "@note The rollout will animate <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> expanded state. To instantly expand without animation, use instantExpand()." )

DefineEngineMethod(GuiRolloutCtrl , instantCollapse , void , () , "Instantly collapse the rollout without animation. To smoothly slide the rollout <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> collapsed state, use collapse()." )

DefineEngineMethod(GuiRolloutCtrl , instantExpand , void , () , "Instantly expand the rollout without animation. To smoothly slide the rollout <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> expanded state, use expand()." )

DefineEngineMethod(GuiRolloutCtrl , isExpanded , bool , () , "Determine whether the rollout is currently expanded, i.e. whether the child <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">visible.\n\n</a>" " @return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the rollout is expanded, false <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> not." )

DefineEngineMethod(GuiRolloutCtrl , sizeToContents , void , () , "Resize the rollout <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> exactly fit around its child control. This can be used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> manually trigger <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> recomputation of " "the rollout size." )

DefineEngineMethod(GuiRolloutCtrl , toggleCollapse , void , () , "Toggle the current collapse state of the rollout. If it is currently expanded, then collapse it. If it " "is currently collapsed, then expand it." )

DefineEngineMethod(GuiRolloutCtrl , toggleExpanded , void , (bool instantly) , (false) , "Toggle the current expansion state of the rollout If it is currently expanded, then collapse it. If it " "is currently collapsed, then expand <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">it.\n\n</a>" " @param instant If true, the rollout will toggle its state without animation. Otherwise, the rollout will " "smoothly slide into the opposite state." )

IMPLEMENT_CALLBACK(GuiRolloutCtrl , onCollapsed , void , () , () , "Called when the rollout is collapsed." )

IMPLEMENT_CALLBACK(GuiRolloutCtrl , onExpanded , void , () , () , "Called when the rollout is expanded." )

IMPLEMENT_CALLBACK(GuiRolloutCtrl , onHeaderRightClick , void , () , () , "Called when the user right-clicks on the rollout's header. This is useful <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> implementing " "context menus <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> rollouts." )

IMPLEMENT_CONOBJECT(GuiRolloutCtrl )

  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 "gui/containers/guiRolloutCtrl.h"
 25#include "gui/containers/guiScrollCtrl.h"
 26#include "gfx/gfxDrawUtil.h"
 27#include "console/engineAPI.h"
 28
 29
 30IMPLEMENT_CONOBJECT( GuiRolloutCtrl );
 31
 32ConsoleDocClass( GuiRolloutCtrl,
 33   "@brief A container that shows a single child with an optional header bar that can be used to collapse and expand the rollout.\n\n"
 34   
 35   "A rollout is a container that can be collapsed and expanded using smooth animation.  By default, rollouts will display a header "
 36   "with a caption along the top edge of the control which can be clicked by the user to toggle the collapse state of the rollout.\n\n"
 37   
 38   "Rollouts will automatically size themselves to exactly fit around their child control.  They will also automatically position their child "
 39   "control in their upper left corner below the header (if present).\n\n"
 40      
 41   "@note GuiRolloutCtrls will only work correctly with a single child control.  To put multiple controls in a rollout, put them "
 42      "in their own group using a new GuiControl which then can be put inside the rollout.\n\n"
 43   
 44   "@ingroup GuiContainers"
 45);
 46
 47IMPLEMENT_CALLBACK( GuiRolloutCtrl, onHeaderRightClick, void, (), (),
 48   "Called when the user right-clicks on the rollout's header.  This is useful for implementing "
 49   "context menus for rollouts." );
 50
 51IMPLEMENT_CALLBACK( GuiRolloutCtrl, onExpanded, void, (), (),
 52   "Called when the rollout is expanded." );
 53
 54IMPLEMENT_CALLBACK( GuiRolloutCtrl, onCollapsed, void, (), (),
 55   "Called when the rollout is collapsed." );
 56
 57//-----------------------------------------------------------------------------
 58
 59GuiRolloutCtrl::GuiRolloutCtrl()
 60 : mHeader(0,0,0,0),
 61   mExpanded(0,0,0,0),
 62   mChildRect(0,0,0,0),
 63   mMargin(0,0,0,0)
 64{
 65   mExpanded.set(0,0,200,60);
 66   mCaption             = StringTable->EmptyString();
 67   mIsExpanded          = true;
 68   mIsAnimating         = false;
 69   mCollapsing          = false;
 70   mAnimateDestHeight   = 40;
 71   mAnimateStep         = 1;
 72   mDefaultHeight       = 40;
 73   mHideHeader          = false;
 74   mMargin.set( 0, 0, 0, 0 );
 75   mIsContainer = true;
 76   mCanCollapse = true;
 77   mAutoCollapseSiblings = false;
 78   mDefaultCursor = NULL;
 79   mVertSizingCursor = NULL;
 80   mHasTexture = false;
 81   mBitmapBounds = NULL;
 82   // Make sure we receive our ticks.
 83   setProcessTicks();
 84}
 85
 86//-----------------------------------------------------------------------------
 87
 88GuiRolloutCtrl::~GuiRolloutCtrl()
 89{
 90}
 91
 92//-----------------------------------------------------------------------------
 93
 94void GuiRolloutCtrl::initPersistFields()
 95{
 96   addGroup( "Rollout" );
 97   
 98      addField( "caption", TypeRealString, Offset( mCaption, GuiRolloutCtrl ),
 99         "Text label to display on the rollout header." );
100      addField( "margin", TypeRectI, Offset( mMargin, GuiRolloutCtrl ),
101         "Margin to put around child control." );
102      addField( "defaultHeight", TypeS32, Offset( mDefaultHeight, GuiRolloutCtrl ),
103         "Default height of the client area.  This is used when no child control has been added to the rollout." );
104      addProtectedField( "expanded", TypeBool, Offset( mIsExpanded, GuiRolloutCtrl), &setExpanded, &defaultProtectedGetFn,
105         "The current rollout expansion state." );
106      addField( "clickCollapse", TypeBool, Offset( mCanCollapse, GuiRolloutCtrl ),
107         "Whether the rollout can be collapsed by clicking its header." );
108      addField( "hideHeader", TypeBool, Offset( mHideHeader, GuiRolloutCtrl ),
109         "Whether to render the rollout header.\n\n"
110         "@note If this is false, the user cannot toggle the rollout state with the mouse." );
111      addField( "autoCollapseSiblings", TypeBool, Offset( mAutoCollapseSiblings, GuiRolloutCtrl ),
112         "Whether to automatically collapse sibling rollouts.\n\n"
113         "If this is true, the rollout will automatically collapse all sibling rollout controls when it "
114         "is expanded.  If this is false, the auto-collapse behavior can be triggered by CTRL (CMD on MAC) "
115         "clicking the rollout header.  CTRL/CMD clicking also works if this is false, in which case the "
116         "auto-collapsing of sibling controls will be temporarily deactivated." );
117         
118   endGroup( "Rollout" );
119
120   Parent::initPersistFields();
121}
122
123//=============================================================================
124//    Events.
125//=============================================================================
126// MARK: ---- Events ----
127
128//-----------------------------------------------------------------------------
129
130bool GuiRolloutCtrl::onAdd()
131{
132   if ( !Parent::onAdd() )
133      return false;
134
135   mHasTexture = ( mProfile ? mProfile->constructBitmapArray() > 0 : false );
136   if ( mHasTexture )
137      mBitmapBounds = mProfile->mBitmapArrayRects.address();
138
139   // Calculate Heights for this control
140   calculateHeights();
141
142   return true;
143}
144
145//-----------------------------------------------------------------------------
146
147bool GuiRolloutCtrl::onWake()
148{
149   if (! Parent::onWake())
150      return false;
151
152   if( !mIsAnimating && mIsExpanded )
153      sizeToContents();
154
155   return true;
156}
157
158//-----------------------------------------------------------------------------
159
160void GuiRolloutCtrl::addObject( SimObject *obj )
161{
162   // Call Parent.
163   Parent::addObject( obj );
164
165   sizeToContents();
166}
167
168//-----------------------------------------------------------------------------
169
170void GuiRolloutCtrl::removeObject( SimObject *obj )
171{
172   // Call Parent.
173   Parent::removeObject( obj );
174
175   // Recalculate our rectangles.
176   calculateHeights();
177}
178
179//-----------------------------------------------------------------------------
180
181void GuiRolloutCtrl::onMouseDown( const GuiEvent &event )
182{
183   mouseLock();
184}
185
186//-----------------------------------------------------------------------------
187
188bool GuiRolloutCtrl::_onMouseUp( const GuiEvent &event, bool lockedMouse )
189{
190   Point2I localPoint = globalToLocalCoord( event.mousePoint );
191   if( mCanCollapse && mHeader.pointInRect( localPoint ) && !mIsAnimating && ( !lockedMouse || isMouseLocked() ) )
192   {
193      // If Ctrl/Cmd-clicking a header, collapse all sibling GuiRolloutCtrls.
194      
195      if( (( mAutoCollapseSiblings && !mIsExpanded && !( event.modifier & SI_PRIMARY_CTRL ))
196          || ( !mAutoCollapseSiblings && event.modifier & SI_PRIMARY_CTRL ) ) )
197      {
198         for( SimSet::iterator iter = getParent()->begin(); iter != getParent()->end(); ++ iter )
199         {
200            GuiRolloutCtrl* ctrl = dynamic_cast< GuiRolloutCtrl* >( *iter );
201            if( ctrl && ctrl != this && ctrl->mCanCollapse )
202               ctrl->instantCollapse();
203         }
204         
205         if( !mIsExpanded )
206            expand();
207      }
208      else
209      {
210         // Toggle expansion.
211         
212         toggleExpanded( false );
213      }
214      
215      return true;
216   }
217   
218   return false;
219}
220
221//-----------------------------------------------------------------------------
222
223void GuiRolloutCtrl::onMouseUp( const GuiEvent &event )
224{
225   _onMouseUp( event, true );
226   if( isMouseLocked() )
227      mouseUnlock();
228}
229
230//-----------------------------------------------------------------------------
231
232void GuiRolloutCtrl::onRightMouseUp( const GuiEvent& event )
233{
234   Parent::onRightMouseUp( event );
235   
236   Point2I localMouse = globalToLocalCoord( event.mousePoint );
237   if( mHeader.pointInRect( localMouse ) )
238      onHeaderRightClick_callback();
239}
240
241//-----------------------------------------------------------------------------
242
243bool GuiRolloutCtrl::onMouseUpEditor( const GuiEvent& event, Point2I offset )
244{
245   return ( event.modifier & SI_PRIMARY_ALT && _onMouseUp( event, false ) );
246}
247
248//=============================================================================
249//    Sizing.
250//=============================================================================
251// MARK: ---- Sizing ----
252
253//-----------------------------------------------------------------------------
254
255void GuiRolloutCtrl::calculateHeights()
256{
257   S32 barHeight = 20;
258
259   if ( mHasTexture && mProfile && mProfile->mBitmapArrayRects.size() >= NumBitmaps )
260   {
261      // Store Header Rectangle
262      mHeader.set( 0, 0, getWidth(), mProfile->mBitmapArrayRects[ CollapsedCenter ].extent.y );
263
264      // Bottom Bar Max
265      barHeight = mProfile->mBitmapArrayRects[ TopLeftHeader ].extent.y;
266   }
267   else
268   {
269      mHeader.set( 0, 0, getWidth(), barHeight );
270   }
271   
272   if ( mHideHeader )
273   {
274      barHeight = 0;
275      mHeader.extent.y = 0;
276   }
277
278   GuiControl *content = static_cast<GuiControl*>( at(0) );
279   if ( content != NULL )
280      mExpanded.set( 0, 0, getWidth(), barHeight + content->getHeight() + ( mMargin.point.y + mMargin.extent.y ) );
281   else
282      mExpanded.set( 0, 0, getWidth(), barHeight + mDefaultHeight );
283}
284
285//-----------------------------------------------------------------------------
286
287bool GuiRolloutCtrl::resize( const Point2I &newPosition, const Point2I &newExtent )
288{
289   if ( !Parent::resize( newPosition, newExtent ) )
290      return false;
291
292   // Recalculate Heights and resize ourself appropriately.
293   calculateHeights();
294
295   GuiControl *content = dynamic_cast<GuiControl*>( at(0) );
296   
297   // Size Content Properly?!
298   if ( mNotifyChildrenResized && content != NULL )
299   {
300      S32 barHeight = ( mHideHeader ) ? 0 : 20;
301      if( !mHideHeader && mHasTexture && mProfile && mProfile->mBitmapArrayRects.size() >= NumBitmaps )
302      {
303         barHeight = mProfile->mBitmapArrayRects[ TopLeftHeader ].extent.y;
304      }
305
306      mChildRect.set( mMargin.point.x, 
307                      mHeader.extent.y + mMargin.point.y, 
308                      getWidth() - ( mMargin.point.x + mMargin.extent.x ), 
309                      getHeight() - ( barHeight + ( mMargin.point.y + mMargin.extent.y ) ) );
310
311      if ( content->resize( mChildRect.point, mChildRect.extent ) )
312         return true;
313   }
314
315   // Nothing sized
316   return false;
317}
318
319//-----------------------------------------------------------------------------
320
321void GuiRolloutCtrl::sizeToContents()
322{
323   calculateHeights();
324
325   // Set destination height
326   if ( size() > 0 )
327      instantExpand();
328   else
329      instantCollapse();
330}
331
332//-----------------------------------------------------------------------------
333
334void GuiRolloutCtrl::instantExpand()
335{
336   mAnimateDestHeight = mExpanded.extent.y;
337   mCollapsing = false;
338   mIsExpanded = true;
339   mIsAnimating = false;
340   resize( getPosition() + mExpanded.point, mExpanded.extent );
341
342   onExpanded_callback();
343}
344
345//-----------------------------------------------------------------------------
346
347void GuiRolloutCtrl::instantCollapse()
348{
349   mAnimateDestHeight = mHeader.extent.y;
350   mCollapsing = false;
351   mIsExpanded = false;
352   mIsAnimating = false;
353   resize( getPosition() + mHeader.point, mHeader.extent );
354
355   onCollapsed_callback();
356}
357
358//-----------------------------------------------------------------------------
359
360void GuiRolloutCtrl::toggleExpanded( bool instant )
361{   
362   if ( mIsExpanded )
363   {
364      if ( instant )
365         instantCollapse();
366      else
367         collapse();
368   }
369   else
370   {
371      if ( instant )
372         instantExpand();
373      else
374         expand();
375   }
376}
377
378//-----------------------------------------------------------------------------
379
380void GuiRolloutCtrl::childResized( GuiControl *child )
381{
382    Parent::childResized( child );
383
384    calculateHeights();
385
386    // While we are animating we are constantly resizing our children
387    // and therefore need to ignore this call to 'instantExpand' which would
388    // halt the animation in some crappy intermediate stage.
389    if ( mIsExpanded && !mIsAnimating )
390    {
391       mNotifyChildrenResized = false;
392       instantExpand();
393       mNotifyChildrenResized = true;
394    }
395}
396
397//=============================================================================
398//    Animation.
399//=============================================================================
400// MARK: ---- Animation ----
401
402//-----------------------------------------------------------------------------
403
404void GuiRolloutCtrl::animateTo( S32 height )
405{
406   // We do nothing if we're already animating
407   if( mIsAnimating )
408      return;
409
410   bool collapsing = (bool)( getHeight() > height );
411
412   // If we're already at the destination height, bail
413   if ( getHeight() >= height && !collapsing )
414   {
415      mIsExpanded = true;
416      return;
417   }
418
419   // If we're already at the destination height, bail
420   if ( getHeight() <= height && collapsing )
421   {
422      mIsExpanded = false;
423      return;
424   }
425
426   // Set destination height
427   mAnimateDestHeight = height;
428
429   // Set Animation Mode
430   mCollapsing = collapsing;
431
432   // Set Animation Step (Increment)
433   if ( collapsing )
434      mAnimateStep = (S32)mFloor( (F32)( getHeight() - height ) / 3.f );
435   else
436      mAnimateStep = (S32)mFloor( (F32)( height - getHeight() ) / 3.f );
437
438   // Start our animation
439   mIsAnimating = true;
440}
441
442//-----------------------------------------------------------------------------
443
444void GuiRolloutCtrl::processTick()
445{
446   // We do nothing here if we're NOT animating
447   if ( !mIsAnimating )
448      return;
449
450   // Sanity check to fix non collapsing panels.
451   if ( mAnimateStep == 0 )
452      mAnimateStep = 1;
453
454   S32 newHeight = getHeight();
455   // We're collapsing ourself down (Hiding our contents)
456   if( mCollapsing )
457   {
458      if ( newHeight < mAnimateDestHeight )
459         newHeight = mAnimateDestHeight;
460      else if ( ( newHeight - mAnimateStep ) < mAnimateDestHeight )
461         newHeight = mAnimateDestHeight;
462
463      if ( newHeight == mAnimateDestHeight )
464         mIsAnimating = false;
465      else
466         newHeight -= mAnimateStep;
467
468      if( !mIsAnimating )
469     {
470         mIsExpanded = false;
471     }
472   }
473   else // We're expanding ourself (Showing our contents)
474   {
475      if ( newHeight > mAnimateDestHeight )
476         newHeight = mAnimateDestHeight;
477      else if ( ( newHeight + mAnimateStep ) > mAnimateDestHeight )
478         newHeight = mAnimateDestHeight;
479
480      if ( newHeight == mAnimateDestHeight )
481         mIsAnimating = false;
482      else
483         newHeight += mAnimateStep;
484
485      if ( !mIsAnimating )
486         mIsExpanded = true;
487   }
488
489   if ( newHeight != getHeight() )
490      setHeight( newHeight );
491
492   if ( !mIsAnimating )
493   {
494      if( mCollapsing )
495         onCollapsed_callback();
496      else if( !mCollapsing )
497         onExpanded_callback();
498
499      calculateHeights();
500   }
501
502   GuiControl* parent = getParent();
503   if ( parent )
504   {
505      parent->childResized( this );
506      // if our parent's parent is a scroll control, scrollvisible.
507      GuiScrollCtrl* scroll = dynamic_cast<GuiScrollCtrl*>( parent->getParent() );
508      if ( scroll )
509      {
510         scroll->scrollRectVisible( getBounds() );
511      }
512   }
513}
514
515//=============================================================================
516//    Rendering.
517//=============================================================================
518// MARK: ---- Rendering ----
519
520//-----------------------------------------------------------------------------
521
522void GuiRolloutCtrl::onRender( Point2I offset, const RectI &updateRect )
523{
524   if( !mProfile || mProfile->mFont == NULL )
525      return;
526
527   // Calculate actual world bounds for rendering
528   RectI worldBounds( offset, getExtent() );
529
530   // if opaque, fill the update rect with the fill color
531   if ( mProfile->mOpaque )
532      GFX->getDrawUtil()->drawRectFill( worldBounds, mProfile->mFillColor );
533
534   if ( mProfile->mBitmapArrayRects.size() >= NumBitmaps )
535   {
536      GFX->getDrawUtil()->clearBitmapModulation();
537
538      // Draw Rollout From Skin
539      if ( !mIsExpanded && !mIsAnimating )
540         renderFixedBitmapBordersFilled( worldBounds, 1, mProfile );
541      else if ( mHideHeader )
542         renderSizableBitmapBordersFilledIndex( worldBounds, MidPageLeft, mProfile );
543      else
544         renderSizableBitmapBordersFilledIndex( worldBounds, TopLeftHeader, mProfile );
545   }
546
547   if ( !(mIsExpanded && mHideHeader ) )
548   {
549      // Draw Caption ( Vertically Centered )
550      ColorI currColor;
551      GFX->getDrawUtil()->getBitmapModulation( &currColor );
552      Point2I textPosition = mHeader.point + offset + mProfile->mTextOffset;
553      GFX->getDrawUtil()->setBitmapModulation( mProfile->mFontColor );
554      renderJustifiedText( textPosition, mHeader.extent, mCaption );
555      GFX->getDrawUtil()->setBitmapModulation( currColor );
556   }
557
558   // If we're collapsed we contain the first child as our content
559   // thus we don't render it when collapsed.  but to support modified
560   // rollouts with custom header buttons etc we still render our other
561   // children. -JDD
562   GuiControl *pChild = dynamic_cast<GuiControl*>( at(0) );
563   if ( pChild )
564   {
565      if ( !mIsExpanded && !mIsAnimating && pChild->isVisible() )
566     {
567         pChild->setVisible( false );
568     }
569      else if ( (mIsExpanded || mIsAnimating) && !pChild->isVisible() )
570     {
571         pChild->setVisible( true );
572     }
573   }
574   renderChildControls( offset, updateRect );
575
576   // Render our border should we have it specified in our profile.
577   renderBorder(worldBounds, mProfile);
578}
579
580//=============================================================================
581//    Console Methods.
582//=============================================================================
583// MARK: ---- Console Methods ----
584
585//-----------------------------------------------------------------------------
586
587DefineEngineMethod( GuiRolloutCtrl, isExpanded, bool, (),,
588   "Determine whether the rollout is currently expanded, i.e. whether the child control is visible.\n\n"
589   "@return True if the rollout is expanded, false if not." )
590{
591   return object->isExpanded();
592}
593
594//-----------------------------------------------------------------------------
595
596DefineEngineMethod( GuiRolloutCtrl, collapse, void, (),,
597   "Collapse the rollout if it is currently expanded.  This will make the rollout's child control invisible.\n\n"
598   "@note The rollout will animate to collapsed state.  To instantly collapse without animation, use instantCollapse()." )
599{
600   object->collapse();
601}
602
603//-----------------------------------------------------------------------------
604
605DefineEngineMethod( GuiRolloutCtrl, expand, void, (),,
606   "Expand the rollout if it is currently collapsed.  This will make the rollout's child control visible.\n\n"
607   "@note The rollout will animate to expanded state.  To instantly expand without animation, use instantExpand()." )
608{
609   object->expand();
610}
611
612//-----------------------------------------------------------------------------
613
614DefineEngineMethod( GuiRolloutCtrl, toggleCollapse, void, (),,
615   "Toggle the current collapse state of the rollout.  If it is currently expanded, then collapse it.  If it "
616   "is currently collapsed, then expand it." )
617{
618   if( object->isExpanded() )
619      object->collapse();
620   else
621     object->expand();
622}
623
624//-----------------------------------------------------------------------------
625
626DefineEngineMethod( GuiRolloutCtrl, toggleExpanded, void, ( bool instantly ), ( false ),
627   "Toggle the current expansion state of the rollout  If it is currently expanded, then collapse it.  If it "
628   "is currently collapsed, then expand it.\n\n"
629   "@param instant If true, the rollout will toggle its state without animation.  Otherwise, the rollout will "
630      "smoothly slide into the opposite state." )
631{
632   object->toggleExpanded( instantly );
633}
634
635//-----------------------------------------------------------------------------
636
637DefineEngineMethod( GuiRolloutCtrl, instantCollapse, void, (),,
638   "Instantly collapse the rollout without animation.  To smoothly slide the rollout to collapsed state, use collapse()." )
639{
640   object->instantCollapse();
641}
642
643//-----------------------------------------------------------------------------
644
645DefineEngineMethod( GuiRolloutCtrl, instantExpand, void, (),,
646   "Instantly expand the rollout without animation.  To smoothly slide the rollout to expanded state, use expand()." )
647{
648   object->instantExpand();
649}
650
651//-----------------------------------------------------------------------------
652
653DefineEngineMethod( GuiRolloutCtrl, sizeToContents, void, (),,
654   "Resize the rollout to exactly fit around its child control.  This can be used to manually trigger a recomputation of "
655   "the rollout size." )
656{
657   object->sizeToContents();
658}
659