Torque3D Documentation / _generateds / guiContainer.cpp

guiContainer.cpp

Engine/source/gui/containers/guiContainer.cpp

More...

Public Functions

Detailed Description

Public Functions

ConsoleDocClass(GuiContainer )

IMPLEMENT_CONOBJECT(GuiContainer )

ImplementEnumType(GuiDockingType , "\n\n" "@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/guiContainer.h"
 26
 27#include "gui/containers/guiPanel.h"
 28#include "console/consoleTypes.h"
 29#include "console/engineAPI.h"
 30
 31
 32IMPLEMENT_CONOBJECT( GuiContainer );
 33
 34ConsoleDocClass( GuiContainer,
 35   "@brief Brief Desc.\n\n"
 36   
 37   "@tsexample\n"
 38   "// Comment:\n"
 39   "%okButton = new ClassObject()\n"
 40   "instantiation\n"
 41   "@endtsexample\n\n"
 42   
 43   "@ingroup GuiContainers"
 44);
 45
 46ImplementEnumType( GuiDockingType,
 47   "\n\n"
 48   "@ingroup GuiContainers" )
 49   { Docking::dockNone,         "None"   },
 50   { Docking::dockClient,       "Client" },
 51   { Docking::dockTop,          "Top"    },
 52   { Docking::dockBottom,       "Bottom" },
 53   { Docking::dockLeft,         "Left"   },
 54   { Docking::dockRight,        "Right"  }
 55EndImplementEnumType;
 56
 57
 58//-----------------------------------------------------------------------------
 59
 60GuiContainer::GuiContainer()
 61{
 62   mUpdateLayout = false;
 63   mValidDockingMask =  Docking::dockNone | Docking::dockBottom | 
 64      Docking::dockTop  | Docking::dockClient | 
 65      Docking::dockLeft | Docking::dockRight;
 66   mIsContainer = true;
 67}
 68
 69//-----------------------------------------------------------------------------
 70
 71GuiContainer::~GuiContainer()
 72{
 73}
 74
 75//-----------------------------------------------------------------------------
 76
 77void GuiContainer::initPersistFields()
 78{
 79   Con::setIntVariable("$DOCKING_NONE",   Docking::dockNone);
 80   Con::setIntVariable("$DOCKING_CLIENT", Docking::dockClient);
 81   Con::setIntVariable("$DOCKING_TOP",    Docking::dockTop);
 82   Con::setIntVariable("$DOCKING_BOTTOM", Docking::dockBottom);
 83   Con::setIntVariable("$DOCKING_LEFT",   Docking::dockLeft);
 84   Con::setIntVariable("$DOCKING_RIGHT",  Docking::dockRight);
 85   
 86   addGroup( "Layout" );
 87
 88      addProtectedField("docking",  TYPEID< Docking::DockingType >(),   Offset(mSizingOptions.mDocking, GuiContainer), &setDockingField, &defaultProtectedGetFn, "" );
 89      addField("margin",         TypeRectSpacingI, Offset(mSizingOptions.mPadding, GuiContainer));
 90      addField("padding",        TypeRectSpacingI, Offset(mSizingOptions.mInternalPadding, GuiContainer));
 91      addField("anchorTop",      TypeBool,          Offset(mSizingOptions.mAnchorTop, GuiContainer));
 92      addField("anchorBottom",   TypeBool,          Offset(mSizingOptions.mAnchorBottom, GuiContainer));
 93      addField("anchorLeft",     TypeBool,          Offset(mSizingOptions.mAnchorLeft, GuiContainer));
 94      addField("anchorRight",    TypeBool,          Offset(mSizingOptions.mAnchorRight, GuiContainer));
 95      
 96   endGroup( "Layout" );
 97
 98   Parent::initPersistFields();
 99}
100
101//-----------------------------------------------------------------------------
102
103void GuiContainer::onChildAdded(GuiControl* control)
104{
105   Parent::onChildAdded( control );
106   setUpdateLayout();
107}
108
109//-----------------------------------------------------------------------------
110
111void GuiContainer::onChildRemoved(GuiControl* control)
112{
113   Parent::onChildRemoved( control );
114   setUpdateLayout();
115}
116
117//-----------------------------------------------------------------------------
118
119bool GuiContainer::reOrder(SimObject* obj, SimObject* target)
120{
121   if ( !Parent::reOrder(obj, target) )
122      return false;
123
124   setUpdateLayout();
125   return true;
126}
127
128//-----------------------------------------------------------------------------
129
130bool GuiContainer::resize( const Point2I &newPosition, const Point2I &newExtent )
131{
132   if( !Parent::resize( newPosition, newExtent ) )
133      return false;
134   
135   RectI clientRect = getClientRect();
136   layoutControls( clientRect );
137
138   GuiControl *parent = getParent();
139   S32 docking = getDocking();
140   if( parent && docking != Docking::dockNone && docking != Docking::dockInvalid )
141      setUpdateLayout( updateParent );
142
143   return true;
144}
145
146//-----------------------------------------------------------------------------
147
148void GuiContainer::addObject(SimObject *obj)
149{
150   Parent::addObject(obj);
151
152   setUpdateLayout();
153}
154
155//-----------------------------------------------------------------------------
156
157void GuiContainer::removeObject(SimObject *obj)
158{
159   Parent::removeObject(obj);
160
161   setUpdateLayout();
162}
163
164//-----------------------------------------------------------------------------
165
166void GuiContainer::parentResized(const RectI &oldParentRect, const RectI &newParentRect)
167{
168   //if(!mCanResize)
169   // return;
170
171   // If it's a control that specifies invalid docking, we'll just treat it as an old GuiControl
172   if( getDocking() & Docking::dockInvalid || getDocking() & Docking::dockNone)
173      return Parent::parentResized( oldParentRect, newParentRect );
174
175   S32 deltaX = newParentRect.extent.x - oldParentRect.extent.x;
176   S32 deltaY = newParentRect.extent.y - oldParentRect.extent.y;
177
178   // Update Self
179   RectI oldThisRect = getBounds();
180   anchorControl( this, Point2I( deltaX, deltaY ) );
181   RectI newThisRect = getBounds();
182
183   // Update Deltas to pass on to children
184   deltaX = newThisRect.extent.x - oldThisRect.extent.x;
185   deltaY = newThisRect.extent.y - oldThisRect.extent.y;
186
187   // Iterate over all children and update their anchors
188   iterator nI = begin();
189   for( ; nI != end(); nI++ )
190   {
191      // Sanity
192      GuiControl *control = dynamic_cast<GuiControl*>( (*nI) );
193      if( control )
194         control->parentResized( oldThisRect, newThisRect );
195   }
196}
197
198//-----------------------------------------------------------------------------
199
200void GuiContainer::childResized(GuiControl *child)
201{
202   Parent::childResized( child );
203   setUpdateLayout();
204}
205
206//-----------------------------------------------------------------------------
207
208bool GuiContainer::layoutControls(  RectI &clientRect )
209{
210   // This variable is set to the first 'Client' docking 
211   //  control that is found.  We defer client docking until
212   //  after all other docks have been made since it will consume
213   //  the remaining client area available.
214   GuiContainer *clientDocking = NULL;
215
216   // Iterate over all children and perform docking
217   iterator nI = begin();
218   for( ; nI != end(); nI++ )
219   {
220      // Layout Content with proper docking (Client Default)
221      GuiControl *control = static_cast<GuiControl*>(*nI);
222      
223      // If we're invisible we don't get counted in docking
224      if( control == NULL || !control->isVisible() )
225         continue;
226
227     S32 dockingMode = Docking::dockNone;
228     GuiContainer *container = dynamic_cast<GuiContainer*>(control);
229     if( container != NULL )
230        dockingMode = container->getDocking();
231     else
232        continue;
233
234     // See above note about clientDocking pointer
235     if( dockingMode & Docking::dockClient && clientDocking == NULL )
236        clientDocking = container;
237
238      // Dock Appropriately
239     if( !(dockingMode & Docking::dockClient) )
240        dockControl( container, dockingMode, clientRect );
241   }
242
243   // Do client dock
244   if( clientDocking != NULL )
245      dockControl( clientDocking, Docking::dockClient, clientRect );
246
247   return true;
248}
249
250//-----------------------------------------------------------------------------
251
252bool GuiContainer::dockControl( GuiContainer *control, S32 dockingMode, RectI &clientRect )
253{
254   if( !control )
255      return false;
256
257   // Make sure this class support docking of this type
258   if( !(dockingMode & getValidDockingMask()))
259      return false;
260
261   // If our client rect has run out of room, we can't dock any more
262   if( !clientRect.isValidRect() )
263      return false;
264
265   // Dock Appropriately
266   RectI dockRect;
267   RectSpacingI rectShrinker;
268   ControlSizing sizingOptions = control->getSizingOptions();
269   switch( dockingMode )
270   {
271   case Docking::dockClient:
272
273      // Inset by padding 
274      sizingOptions.mPadding.insetRect(clientRect);
275
276      // Dock to entirety of client rectangle
277      control->resize( clientRect.point, clientRect.extent );
278
279      // Remove Client Rect, can only have one client dock
280      clientRect.set(0,0,0,0);
281      break;
282   case Docking::dockTop:         
283
284      dockRect = clientRect;
285      dockRect.extent.y = getMin( control->getHeight() + sizingOptions.mPadding.top + sizingOptions.mPadding.bottom , clientRect.extent.y );
286
287      // Subtract our rect
288      clientRect.point.y += dockRect.extent.y;
289      clientRect.extent.y -= dockRect.extent.y;
290
291      // Inset by padding 
292      sizingOptions.mPadding.insetRect(dockRect);
293
294      // Resize
295      control->resize( dockRect.point, dockRect.extent );
296
297      break;
298   case Docking::dockBottom:
299
300      dockRect = clientRect;
301      dockRect.extent.y = getMin( control->getHeight() + sizingOptions.mPadding.top + sizingOptions.mPadding.bottom, clientRect.extent.y );
302      dockRect.point.y += clientRect.extent.y - dockRect.extent.y;
303
304      // Subtract our rect
305      clientRect.extent.y -= dockRect.extent.y;
306
307      // Inset by padding 
308      sizingOptions.mPadding.insetRect(dockRect);
309
310      // Resize
311      control->resize( dockRect.point, dockRect.extent );
312
313      break;
314   case Docking::dockLeft:
315
316      dockRect = clientRect;
317      dockRect.extent.x = getMin( control->getWidth() + sizingOptions.mPadding.left + sizingOptions.mPadding.right, clientRect.extent.x );
318
319      // Subtract our rect
320      clientRect.point.x += dockRect.extent.x;
321      clientRect.extent.x -= dockRect.extent.x;
322
323      // Inset by padding 
324      sizingOptions.mPadding.insetRect(dockRect);
325
326      // Resize
327      control->resize( dockRect.point, dockRect.extent );
328
329      break;
330   case Docking::dockRight:
331
332      dockRect = clientRect;
333      dockRect.extent.x = getMin( control->getWidth() + sizingOptions.mPadding.left + sizingOptions.mPadding.right, clientRect.extent.x );
334      dockRect.point.x += clientRect.extent.x - dockRect.extent.x;
335
336      // Subtract our rect
337      clientRect.extent.x -= dockRect.extent.x;
338
339      // Inset by padding 
340      sizingOptions.mPadding.insetRect(dockRect);
341
342      // Resize
343      control->resize( dockRect.point, dockRect.extent );
344
345      break;
346   case Docking::dockNone:
347      control->setUpdateLayout();
348      break;
349   }
350
351   return true;
352}
353
354//-----------------------------------------------------------------------------
355
356bool GuiContainer::anchorControl( GuiControl *control, const Point2I &deltaParentExtent )
357{
358   GuiContainer *container = dynamic_cast<GuiContainer*>( control );
359   if( !control || !container )
360      return false;
361
362   // If we're docked, we don't anchor to anything
363   if( (container->getDocking() & Docking::dockAny) || !(container->getDocking() & Docking::dockInvalid)  )
364      return false;
365
366   if( deltaParentExtent.isZero() )
367      return false;
368
369   RectI oldRect = control->getBounds();
370   RectI newRect = control->getBounds();
371
372   F32 deltaBottom = mSizingOptions.mAnchorBottom ? (F32)deltaParentExtent.y : 0.0f;
373   F32 deltaRight = mSizingOptions.mAnchorRight ? (F32)deltaParentExtent.x : 0.0f;
374   F32 deltaLeft = mSizingOptions.mAnchorLeft ? 0.0f : (F32)deltaParentExtent.x;
375   F32 deltaTop = mSizingOptions.mAnchorTop ? 0.0f : (F32)deltaParentExtent.y;
376
377   // Apply Delta's to newRect
378   newRect.point.x += (S32)deltaLeft;
379   newRect.extent.x += (S32)(deltaRight - deltaLeft);
380   newRect.point.y += (S32)deltaTop;
381   newRect.extent.y += (S32)(deltaBottom - deltaTop);
382
383   Point2I minExtent = control->getMinExtent();
384   // Only resize if our minExtent is satisfied with it.
385   if( !( newRect.extent.x >= minExtent.x && newRect.extent.y >= minExtent.y ) )
386      return false;
387
388   if( newRect.point == oldRect.point && newRect.extent == oldRect.extent )
389      return false;
390
391   // Finally Size the control
392   control->resize( newRect.point, newRect.extent );
393
394   // We made changes
395   return true;
396}
397
398//-----------------------------------------------------------------------------
399
400void GuiContainer::onPreRender()
401{
402   if( mUpdateLayout == updateNone )
403      return;
404
405   RectI clientRect = getClientRect();
406   if( mUpdateLayout & updateSelf )
407      layoutControls( clientRect );
408
409   GuiContainer *parent = dynamic_cast<GuiContainer*>( getParent() );
410   if( parent && ( mUpdateLayout & updateParent ) )
411      parent->setUpdateLayout();
412
413   // Always set AFTER layoutControls call to prevent recursive calling of layoutControls - JDD
414   mUpdateLayout = updateNone;
415
416   Parent::onPreRender();
417}
418
419//-----------------------------------------------------------------------------
420
421const RectI GuiContainer::getClientRect()
422{
423   RectI resRect = RectI( Point2I(0,0), getExtent() );
424
425   // Inset by padding
426   mSizingOptions.mInternalPadding.insetRect( resRect ); 
427
428   return resRect;
429}
430
431//-----------------------------------------------------------------------------
432
433void GuiContainer::setDocking( S32 docking )
434{
435   mSizingOptions.mDocking = docking; 
436   setUpdateLayout( updateParent );
437}
438