Spinning Topp Logo BlackTopp Studios
inc
horizontalcontainer.cpp
1 // © Copyright 2010 - 2016 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 #ifndef _uihorizontalcontainer_cpp
41 #define _uihorizontalcontainer_cpp
42 
43 #include "UI/horizontalcontainer.h"
44 #include "UI/horizontallayoutstrategy.h"
45 
46 #include "UI/horizontalscrollbar.h"
47 #include "UI/spinner.h"
48 
49 #include <algorithm>
50 
51 namespace Mezzanine
52 {
53  namespace UI
54  {
55  const String HorizontalContainer::TypeName = "HorizontalContainer";
56 
57  ///////////////////////////////////////////////////////////////////////////////
58  // HorizontalContainer Methods
59 
61  LinearContainer(Parent)
62  { }
63 
65  LinearContainer(RendName,Parent)
66  { }
67 
68  HorizontalContainer::HorizontalContainer(const String& RendName, const UnifiedRect& RendRect, Screen* Parent) :
69  LinearContainer(RendName,RendRect,Parent)
70  { }
71 
73  LinearContainer(Parent)
74  { this->ProtoDeSerialize(XMLNode); }
75 
77  { }
78 
79  void HorizontalContainer::UpdateContainerDimensionsImpl(const Rect& OldSelfRect, const Rect& NewSelfRect)
80  {
81  // Clear our old data.
82  this->VisibleChildren.clear();
83  this->WorkAreaSize.SetIdentity();
84 
85  // Setup any additional data for the next series of loops.
86  const Real ActPadding = this->LinearPadding.CalculateActualDimension( this->ActDims.Size.X );
87  const Real HalfPadding = ActPadding * 0.5;
88  std::vector< std::pair<Real,Vector2> > ChildTransformCache( this->ChildWidgets.size() );
89 
90  // To determine the visible children we need to know our view position in the work area as determined by the page provider.
91  // To determine our page position we need to know our work area size, which can change when children have their dimensions updated.
92  // So we first need to update the size on every child. We can update our work area at the same time. After that we can update our page provider and determine screen positions.
93  Whole CurrIndex = 0;
94  this->WorkAreaSize.X = HalfPadding;
95  for( ChildIterator SizeIt = this->ChildWidgets.begin() ; SizeIt != this->ChildWidgets.end() ; ++SizeIt )
96  {
97  // Enforce our sizing rules.
98  if( this->ForcedSizingRules & SE_OnUpdate ) {
99  (*SizeIt)->SetSizingPolicy( this->ChildSizing );
100  }
101 
102  // Calculate the sizing with our utility strat, and offset position which we will use later.
103  // Since the constantly updating work area size is tracking the same information as a cursor would, we'll use it as our position cursor.
104  Vector2 ChildSize = this->LayoutStrat->HandleChildSizing(OldSelfRect,NewSelfRect,(*SizeIt));
105 
106  ChildTransformCache.at(CurrIndex).first = this->WorkAreaSize.X;
107  ChildTransformCache.at(CurrIndex).second = ChildSize;
108 
109  // Update the cursor position and work area size.
110  this->WorkAreaSize.X += ( ChildSize.X + ActPadding );
111  if( this->WorkAreaSize.Y < ChildSize.Y )
112  this->WorkAreaSize.Y = ChildSize.Y;
113 
114  // Increment the index before we proceed.
115  ++CurrIndex;
116  }
117  // Trim off half a padding at the end since we were blinding applying full padding for the space between two children.
118  this->WorkAreaSize.X -= HalfPadding;
119 
120  // Now our work area is updated, so we can update our provider and get our target work area position.
121  Real XTarget = 0;
122  if( this->XProvider != NULL ) {
124  Real XTargetLimit = ( this->WorkAreaSize.X + HalfPadding ) - NewSelfRect.Size.X;
125  XTarget = std::min( ( this->XProvider->GetCurrentXPage() - 1 ) * NewSelfRect.Size.X, XTargetLimit );
126  }
127 
128  // Set up our data for the loop (and the loop itself) that will go over all the children that will be "above" the visible children.
129  // Reset the index since we are starting from the beginning again.
130  CurrIndex = 0;
131  ChildIterator ChildUpdateIt = this->ChildWidgets.begin();
132  while( ChildUpdateIt != this->ChildWidgets.end() && ChildTransformCache.at(CurrIndex).first < XTarget )
133  {
134  const Rect OldChildRect = (*ChildUpdateIt)->GetRect();
135  Rect NewChildRect;
136 
137  // Assign a dummy position since this will be invisible
138  NewChildRect.Position = NewSelfRect.Position;
139  NewChildRect.Size = ChildTransformCache.at(CurrIndex).second;
140 
141  // Perform the update
142  (*ChildUpdateIt)->UpdateDimensions(OldChildRect,NewChildRect);
143 
144  // Hide the child
145  (*ChildUpdateIt)->Hide();
146 
147  // Increment the iterator and index before we proceed.
148  ++CurrIndex;
149  ++ChildUpdateIt;
150  }
151 
152  // If we've reached the end of the children, there is nothing to render.
153  if( ChildUpdateIt != this->ChildWidgets.end() )
154  {
155  // If we're here, then we have some visible children.
156  // Set our new target and create a variable that will track the total size of just the visible children.
157  XTarget = NewSelfRect.Size.X;
158  Real TotalLinearSize = HalfPadding;
159 
160  // Before we start a loop that will be altering the index, we need to mark the index of the first visible child in our cache. This will be used in the final processing step.
161  // Once saved, start looping over what will be the visible children. We can (and should) use the index from the previous loop unaltered.
162  const Whole VisibleStartIndex = CurrIndex;
163  while( ChildUpdateIt != this->ChildWidgets.end() )
164  {
165  Vector2 ChildSize = ChildTransformCache.at(CurrIndex).second;
166  // See if our child can fit
167  if( TotalLinearSize + ChildSize.X < XTarget ) {
168  this->VisibleChildren.push_back( (*ChildUpdateIt) );
169  TotalLinearSize += ( ChildSize.X + ActPadding );
170  // Increment the index and iterator before we proceed.
171  ++CurrIndex;
172  ++ChildUpdateIt;
173  }else{
174  break;
175  }
176  }
177 
178  // Any remaining children will be invisible, so put them in the corner with the rest.
179  while( ChildUpdateIt != this->ChildWidgets.end() )
180  {
181  const Rect OldChildRect = (*ChildUpdateIt)->GetRect();
182  Rect NewChildRect;
183 
184  // Assign a dummy position since this will be invisible
185  NewChildRect.Position = NewSelfRect.Position;
186  NewChildRect.Size = ChildTransformCache.at(CurrIndex).second;
187 
188  // Perform the update
189  (*ChildUpdateIt)->UpdateDimensions(OldChildRect,NewChildRect);
190 
191  // Hide the child
192  (*ChildUpdateIt)->Hide();
193 
194  // Increment the iterator and index before we proceed.
195  ++CurrIndex;
196  ++ChildUpdateIt;
197  }
198 
199  // Create the cursor which will be used for visible child placement.
200  Real CurrXPos = 0;
201  // By now all our children have been processed, just have to focus on the last couple steps for visible children. Start by doing our alignment stuff.
202  switch( this->VisibleChildAlign )
203  {
204  case UI::LA_TopLeft: CurrXPos = ( NewSelfRect.Position.X + HalfPadding ); break;
205  case UI::LA_Center: CurrXPos = ( NewSelfRect.Position.X + ( NewSelfRect.Size.X * 0.5 ) ) - ( TotalLinearSize * 0.5 ); break;
206  case UI::LA_BottomRight: CurrXPos = ( NewSelfRect.Position.X + NewSelfRect.Size.X ) - ( TotalLinearSize + HalfPadding ); break;
207  }
208 
209  // Finally, we're at the final processing stage. We have our visible children and enough data to determine their positions, along with their saved sizes from earlier.
210  for( Whole VisIndex = 0 ; VisIndex < this->VisibleChildren.size() ; ++VisIndex )
211  {
212  Widget* VisChild = this->VisibleChildren.at(VisIndex);
213  // Setup child transform data
214  const Rect OldChildRect = VisChild->GetRect();
215  Rect NewChildRect;
216  // Set the Size
217  NewChildRect.Size = ChildTransformCache.at(VisibleStartIndex + VisIndex).second;
218  // Set the Position
219  NewChildRect.Position.X = CurrXPos;
220  NewChildRect.Position.Y = this->LayoutStrat->HandleChildHorizontalPositioning( OldSelfRect, NewSelfRect, NewChildRect.Size, VisChild );
221  // Perform the update
222  VisChild->UpdateDimensions(OldChildRect,NewChildRect);
223  // Increment the cursor
224  CurrXPos += ( NewChildRect.Size.X + ActPadding );
225  // Finally show the child
226  VisChild->SetVisible( this->GetVisible() );
227  }
228  ChildTransformCache.clear();
229  }
230  }
231 
232  ///////////////////////////////////////////////////////////////////////////////
233  // Utility
234 
236  {
237  this->WorkAreaSize.SetIdentity();
238  const Real ActPadding = this->LinearPadding.CalculateActualDimension( this->ParentQuad ? this->ParentQuad->GetActualSize().X : 0 );
239  const Real HalfPadding = ActPadding * 0.5;
240 
241  for( ChildIterator ChildIt = this->ChildWidgets.begin() ; ChildIt != this->ChildWidgets.end() ; ++ChildIt )
242  {
243  Vector2 ChildSize = (*ChildIt)->GetActualSize();
244  this->WorkAreaSize.X += ( ChildSize.X + HalfPadding );
245  if( this->WorkAreaSize.Y < ChildSize.Y )
246  this->WorkAreaSize.Y = ChildSize.Y;
247  }
248  this->WorkAreaSize.X += HalfPadding;
249  }
250 
252  {
253  const Vector2 ActChildSize = ChildSize.CalculateActualDimensions( this->ActDims.Size );
254  const Real ActPadding = this->LinearPadding.CalculateActualDimension( this->ParentQuad ? this->ParentQuad->GetActualSize().X : 0 );
255  const Real HalfPadding = ActPadding * 0.5;
256 
257  if( Adding ) {
258  this->WorkAreaSize.X += ( ActChildSize.X + HalfPadding );
259  if( this->WorkAreaSize.Y < ActChildSize.Y )
260  this->WorkAreaSize.Y = ActChildSize.Y;
261  }else{
262  this->WorkAreaSize.X -= ( ActChildSize.X + HalfPadding );
263  }
264  }
265 
268 
270  { this->SetXProvider(XProv); }
271 
273  {
274  if( this->XProvider != NULL && this->XProvider != XProv ) {
275  this->UnbindProvider(this->XProvider);
276  }
277  this->XProvider = XProv;
278  this->XProvider->_SetContainer(this);
280  }
281 
283  { /* Do Nothing */ }
284 
286  { this->SetXProvider(Prov); }
287 
289  { this->SetProviders(Prov,Prov); }
290 
291  ///////////////////////////////////////////////////////////////////////////////
292  // Child Management
293 
294  ///////////////////////////////////////////////////////////////////////////////
295  // Serialization
296 
298  {
300  }
301 
303  {
305  }
306 
308  {
310  }
311 
312  ///////////////////////////////////////////////////////////////////////////////
313  // Internal Methods
314 
315  ///////////////////////////////////////////////////////////////////////////////
316  // HorizontalContainerFactory Methods
317 
320 
322  {
323  HorizontalContainer* Ret = new HorizontalContainer(RendName,Parent);
324  Ret->_SetLayoutStrat( new LayoutStrategy() );
325  return Ret;
326  }
327 
329  {
330  HorizontalContainer* Ret = new HorizontalContainer(RendName,RendRect,Parent);
331  Ret->_SetLayoutStrat( new LayoutStrategy() );
332  return Ret;
333  }
334 
336  {
337  HorizontalContainer* Ret = new HorizontalContainer(XMLNode,Parent);
338  Ret->_SetLayoutStrat( new LayoutStrategy() );
339  return Ret;
340  }
341 
343  {
344  HorizontalContainer* Ret = new HorizontalContainer(Parent);
345  Ret->_SetLayoutStrat( new LayoutStrategy() );
346  return Ret;
347  }
348 
350  { return this->CreateHorizontalContainer(RendName,Parent); }
351 
352  Widget* HorizontalContainerFactory::CreateWidget(const String& RendName, const UnifiedRect& RendRect, const NameValuePairMap& Params, Screen* Parent)
353  { return this->CreateHorizontalContainer(RendName,RendRect,Parent); }
354 
356  { return this->CreateHorizontalContainer(XMLNode,Parent); }
357 
359  { delete static_cast<HorizontalContainer*>( ToBeDestroyed ); }
360  }//UI
361 }//Mezzanine
362 
363 #endif
virtual Rect GetRect() const
Gets this QuadRenderables' Rect.
UnifiedDim LinearPadding
The amount of space to add to both sides of a child object on the relevant axis.
virtual void QuickUpdateWorkAreaSize(const UnifiedVec2 &ChildSize, Boole Adding)
Quickly updates the work area size based on a single childs' dimensions.
This is a base class for the algorithms used by QuadRenderables to determine how they should update t...
static String GetSerializableName()
Get the name of the the XML tag the Renderable class will leave behind as its instances are serialize...
virtual void ProtoSerializeProperties(XML::Node &SelfRoot) const
Convert the properties of this class to an XML::Node ready for serialization.
bool Boole
Generally acts a single bit, true or false.
Definition: datatypes.h:173
virtual void SetYProvider(PageProvider *YProv)
Sets the PageProvider for the Y axis.
virtual Vector2 HandleChildSizing(const Rect &OldSelfRect, const Rect &NewSelfRect, QuadRenderable *Child)
Handles the sizing of a child that needs it's dimensions updated.
Vector2 Size
Vector2 representing the width and height of the rect.
Definition: rect.h:71
The preset size for children of this container will be enforced constantly on each update...
HorizontalContainer(Screen *Parent)
Blank constructor.
virtual void SetXProvider(PageProvider *XProv)
Sets the PageProvider for the X axis.
This class represents a box shaped area on the screen.
Definition: rect.h:55
virtual void _SetContainer(PagedContainer *ToUpdate)
Sets the container that is using this provider to update which renderables are visible.
PageProvider * XProvider
A pointer to the X axis provider.
Vector2 CalculateActualDimensions(const Vector2 &Actual) const
Calculates the actual values when a Vector2 with actual dimensions has this unified vector2 applied t...
Definition: unifieddim.h:384
This is a simple widget for a numeric variable in a box.
Definition: spinner.h:130
ChildContainer ChildWidgets
This is a container storing all the children that belong to this Quad.
Rect ActDims
The actual (pixel) position and size of this Quad on the screen it belongs to.
float Real
A Datatype used to represent a real floating point number.
Definition: datatypes.h:141
virtual void ProtoDeSerializeProperties(const XML::Node &SelfRoot)
Take the data stored in an XML Node and overwrite the properties of this object with it...
This class represents a 2D rect which can express the size and position of a renderable on screen...
Definition: unifieddim.h:661
virtual Widget * CreateWidget(Screen *Parent)
Creates a Widget of the type represented by this factory.
Real Y
Coordinate on the Y vector.
Definition: vector2.h:69
virtual void ProtoSerializeProperties(XML::Node &SelfRoot) const
Convert the properties of this class to an XML::Node ready for serialization.
A light-weight handle for manipulating nodes in DOM tree.
Definition: node.h:89
Real X
Coordinate on the X vector.
Definition: vector2.h:67
Whole ForcedSizingRules
The current enforcement for child size in this container.
This is used to represent a point on a 2 dimentional area, such as a screen.
Definition: vector2.h:63
This is the base class for all widgets.
Definition: widget.h:126
virtual void UnbindProvider(PageProvider *Prov)
Unbinds a provider being used by this container.
virtual Vector2 GetActualSize() const
Gets the pixel size of this widget.
void SetIdentity()
Sets the values of this vector2 to identity values(0,0).
Definition: vector2.cpp:99
virtual void UpdateContainerDimensionsImpl(const Rect &OldSelfRect, const Rect &NewSelfRect)
The container specific logic for updating it's dimensions.
This is a scrollbar class aligned on the X axis.
virtual void SetProviders(PageProvider *XProv, PageProvider *YProv)
Sets the page providers for both axes.
virtual Boole GetVisible() const
Gets the visibility setting of this renderable.
virtual void UpdateWorkAreaSize()
Checks the size of every child in this container and updates the work area to match the size needed...
virtual void _SetLayoutStrat(LayoutStrategy *ToSet)
Sets a new LayoutStrategy for this quad to use.
SizingInfo ChildSizing
The size given to children layed out by this container.
This is the base class for interpretting widget values to page positions.
Definition: pageprovider.h:55
virtual void SetSpinnerProvider(Spinner *Prov)
Convenience method for configuring a Spinner as the page provider for this container.
virtual void SetScrollbarProvider(HorizontalScrollbar *Prov)
Convenience method for configuring a HorizontalScrollbar as the page provider for this container...
Vector2 WorkAreaSize
Vector2 storing the size for all pages of this container.
virtual const String & GetTypeName() const
Gets the type of widget this is.
virtual void ProtoDeSerializeProperties(const XML::Node &SelfRoot)
Take the data stored in an XML Node and overwrite the properties of this object with it...
virtual void DestroyWidget(Widget *ToBeDestroyed)
Destroys a Widget created by this factory.
The bulk of the engine components go in this namspace.
Definition: actor.cpp:56
unsigned long Whole
Whole is an unsigned integer, it will be at least 32bits in size.
Definition: datatypes.h:151
A layout container that aligns it's children along a common X axis.
virtual String GetWidgetTypeName() const
Gets the name of the Widget that is created by this factory.
UI::LinearAlignment VisibleChildAlign
The alignment to be given to the sequence of children visible in this container.
ChildContainer::iterator ChildIterator
Iterator type for Widget instances stored by this class.
virtual HorizontalContainer * CreateHorizontalContainer(const String &RendName, Screen *Parent)
Creates a new HorizontalContainer.
virtual void SetVisible(Boole CanSee)
Sets the visibility of this renderable.
Definition: widget.cpp:229
This class represents a point in 2D space using UnifiedDim's.
Definition: unifieddim.h:306
virtual Real HandleChildHorizontalPositioning(const Rect &OldSelfRect, const Rect &NewSelfRect, const Vector2 &NewChildSize, QuadRenderable *Child)
Handles the positioning of a child on the X axis.
virtual void _NotifyContainerUpdated()=0
Notifies this provider that the container it is providing page data to has been updated.
virtual void ProtoDeSerialize(const XML::Node &SelfRoot)
Take the data stored in an XML Node and overwrite this object with it.
VisibleChildContainer VisibleChildren
A container of children that meet the criteria for rendering in this container.
virtual void UpdateDimensions()
Updates the dimensions of this QuadRenderable based on the transform of it's parent.
Vector2 Position
Vector2 representing the top-left position of the rect.
Definition: rect.h:69
std::map< String, String > NameValuePairMap
This is a datatype mostly used for describing settings or parameters that can't be declared in advanc...
Definition: datatypes.h:209
This class is a helper class for creating UI's. It is responsible for storing and keeping track of al...
Definition: screen.h:142
LayoutStrategy * LayoutStrat
This is a pointer to the strategy being used by this Quad to determine the positions and sizes of chi...
std::string String
A datatype used to a series of characters.
Definition: datatypes.h:159
QuadRenderable * ParentQuad
This is a pointer to the Quad that owns this Quad and is responsible for transform updates applied to...
Real CalculateActualDimension(const Real &Actual) const
Calculates the actual value when a Real in pixels has this unified dim applied to it...
Definition: unifieddim.h:109
static const String TypeName
String containing the type name for this class: "HorizontalContainer".
This is a container class for placing child objects in succession on a single axis.
virtual ~HorizontalContainer()
Class destructor.