MezzanineEngine 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
menuentry.cpp
1 //© Copyright 2010 - 2013 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 _uimenuentry_cpp
41 #define _uimenuentry_cpp
42 
43 #include "UI/menuentry.h"
44 #include "UI/menubutton.h"
45 #include "UI/uimanager.h"
46 #include "UI/screen.h"
47 #include "UI/layoutstrategy.h"
48 
49 #include "stringtool.h"
50 #include "exception.h"
51 #include "serialization.h"
52 
53 namespace Mezzanine
54 {
55  namespace UI
56  {
57  const String MenuEntry::TypeName = "MenuEntry";
58 
59  ///////////////////////////////////////////////////////////////////////////////
60  // MenuEntry Methods
61 
63  StackedContainer(Parent),
64  MenuStack(NULL),
65  PushButton(NULL),
66  PopButton(NULL),
67  AutoHideEntry(true)
68  { this->LayoutStrat = new LayoutStrategy(); }
69 
70  MenuEntry::MenuEntry(const String& RendName, Screen* Parent) :
71  StackedContainer(RendName,Parent),
72  MenuStack(NULL),
73  PushButton(NULL),
74  PopButton(NULL),
75  AutoHideEntry(true)
76  { this->LayoutStrat = new LayoutStrategy(); }
77 
78  MenuEntry::MenuEntry(const String& RendName, const UnifiedRect& RendRect, Screen* Parent) :
79  StackedContainer(RendName,RendRect,Parent),
80  MenuStack(NULL),
81  PushButton(NULL),
82  PopButton(NULL),
83  AutoHideEntry(true)
84  { this->LayoutStrat = new LayoutStrategy(); }
85 
86  MenuEntry::MenuEntry(const XML::Node& XMLNode, Screen* Parent) :
87  StackedContainer(Parent),
88  MenuStack(NULL),
89  PushButton(NULL),
90  PopButton(NULL),
91  AutoHideEntry(true)
92  { this->LayoutStrat = new LayoutStrategy(); }
93 
95  {
96  if( this->IsRootEntry() && this->MenuStack ) {
97  this->_NotifyStack(NULL);
98  delete this->MenuStack;
99  }
100  }
101 
103  {
104  if( this->MenuStack ) {
105  if( ( this->IsRootEntry() && this->MenuStack->empty() ) ||
106  ( !(this->MenuStack->empty()) && this->MenuStack->back() == this->ParentQuad ) )
107  {
108  if( !(this->MenuStack->empty()) && this->MenuStack->back()->GetAutoHide() ) {
109  this->MenuStack->back()->Hide();
110  }
111  this->MenuStack->push_back(this);
112  this->Show();
113  return true;
114  }
115  }
116  return false;
117  }
118 
120  {
121  if( this->MenuStack ) {
122  if( !(this->MenuStack->empty()) && this->MenuStack->back() == this ) {
123  this->MenuStack->pop_back();
124  this->Hide();
125  return true;
126  }
127  }
128  return false;
129  }
130 
131  ///////////////////////////////////////////////////////////////////////////////
132  // Utility Methods
133 
134  Boolean MenuEntry::IsRootEntry() const
135  {
136  if( this->ParentQuad->GetRenderableType() == Renderable::RT_Widget ) {
137  return ( static_cast<Widget*>( this->ParentQuad )->GetTypeName() != MenuEntry::TypeName );
138  }else{
139  return true;
140  }
141  }
142 
144  {
145  if( this->PushButton == EntryButton && this->PopButton == EntryButton ) {
147  }else if( this->PushButton == EntryButton ) {
149  }else if( this->PopButton == EntryButton ) {
151  }else{
152  return MenuEntry::BC_Error;
153  }
154  }
155 
157  {
158  if( this->MenuStack ) {
159  if( RollBackTo != NULL && !(this->MenuStack->empty()) ) {
160  Whole Ret = 0;
161  MenuEntryIterator MenuBeg = this->MenuStack->begin();
162  MenuEntryIterator MenuEnd = this->MenuStack->end();
163  while( MenuBeg != MenuEnd )
164  {
165  if( (*MenuBeg) == RollBackTo ) {
166  ++MenuBeg;
167  break;
168  }else{
169  ++MenuBeg;
170  }
171  }
172 
173  for( MenuEntryIterator MenuIt = MenuBeg ; MenuIt != MenuEnd ; ++MenuIt )
174  {
175  (*MenuIt)->Hide();
176  ++Ret;
177  }
178  this->MenuStack->erase(MenuBeg,MenuEnd);
179  RollBackTo->Show();
180  return Ret;
181  }
182  }
183  return 0;
184  }
185 
186  ///////////////////////////////////////////////////////////////////////////////
187  // Visibility and Priority Methods
188 
189  void MenuEntry::SetVisible(Boolean CanSee)
190  {
191  if( CanSee ) {
192  if( !this->AutoHideEntry || ( this->MenuStack ? this->MenuStack->back() == this : false ) ) {
193  this->Widget::SetVisible(CanSee);
194  }
195  }else{
196  this->Widget::SetVisible(CanSee);
197  }
198  }
199 
201  {
202  if( !this->AutoHideEntry || ( this->MenuStack ? this->MenuStack->back() == this : false ) )
203  this->Widget::Show();
204  }
205 
207  {
208  this->Widget::Hide();
209  }
210 
211  ///////////////////////////////////////////////////////////////////////////////
212  // MenuEntry Properties
213 
214  void MenuEntry::SetAutoHide(Boolean AutoHide)
215  { this->AutoHideEntry = AutoHide; }
216 
217  Boolean MenuEntry::GetAutoHide() const
218  { return this->AutoHideEntry; }
219 
220  ///////////////////////////////////////////////////////////////////////////////
221  // Menu Configuration
222 
224  {
225  if( this->PushButton != NULL ) {
226  this->PushButton->_SetBoundMenu(NULL);
228  }
229 
230  this->PushButton = Push;
231 
232  if( this->PushButton != NULL ) {
233  this->PushButton->_SetBoundMenu(this);
235  }
236  }
237 
239  {
240  return this->PushButton;
241  }
242 
244  {
245  if( this->PopButton != NULL ) {
246  this->PopButton->_SetBoundMenu(NULL);
248  }
249 
250  this->PopButton = Pop;
251 
252  if( this->PopButton != NULL ) {
253  this->PopButton->_SetBoundMenu(this);
255  }
256  }
257 
259  {
260  return this->PopButton;
261  }
262 
264  {
265  if( this->PushButton != NULL ) {
266  this->PushButton->_SetBoundMenu(NULL);
268  }
269  if( this->PopButton != NULL ) {
270  this->PopButton->_SetBoundMenu(NULL);
272  }
273 
274  this->PushButton = Toggle;
275  this->PopButton = Toggle;
276 
277  if( this->PushButton != NULL ) {
278  this->PushButton->_SetBoundMenu(this);
280  }
281  }
282 
283  ///////////////////////////////////////////////////////////////////////////////
284  // Serialization
285 
287  {
288  this->Widget::ProtoSerializeProperties(SelfRoot);
289 
290  XML::Node PropertiesNode = SelfRoot.AppendChild( MenuEntry::GetSerializableName() + "Properties" );
291 
292  if( PropertiesNode.AppendAttribute("Version").SetValue("1") &&
293  PropertiesNode.AppendAttribute("AutoHideEntry").SetValue( this->GetAutoHide() ? "true" : "false" ) )
294  {
295  // Only if we have valid bindings
296  if( this->PushButton != NULL ) {
297  if( PropertiesNode.AppendAttribute("PushButtonName").SetValue( this->PushButton->GetName() ) ) {
298  return;
299  }else{
300  SerializeError("Create XML Attribute Values",MenuEntry::GetSerializableName() + "Properties",true);
301  }
302  }
303 
304  if( this->PopButton != NULL ) {
305  if( PropertiesNode.AppendAttribute("PopButtonName").SetValue( this->PopButton->GetName() ) ) {
306  return;
307  }else{
308  SerializeError("Create XML Attribute Values",MenuEntry::GetSerializableName() + "Properties",true);
309  }
310  }
311  }else{
312  SerializeError("Create XML Attribute Values",MenuEntry::GetSerializableName() + "Properties",true);
313  }
314  }
315 
317  {
318  this->Widget::ProtoDeSerializeProperties(SelfRoot);
319 
320  XML::Attribute CurrAttrib;
321  XML::Node PropertiesNode = SelfRoot.GetChild( MenuEntry::GetSerializableName() + "Properties" );
322 
323  if( !PropertiesNode.Empty() ) {
324  if(PropertiesNode.GetAttribute("Version").AsInt() == 1) {
325  CurrAttrib = PropertiesNode.GetAttribute("AutoHideEntry");
326  if( !CurrAttrib.Empty() )
327  this->SetAutoHide( StringTools::ConvertToBool( CurrAttrib.AsString(), true ) );
328 
329  CurrAttrib = PropertiesNode.GetAttribute("PushButtonName");
330  if( !CurrAttrib.Empty() ) {
331  Widget* UncastedButton = this->ParentScreen->GetWidget( CurrAttrib.AsString() );
332  if( UncastedButton->GetTypeName() == MenuButton::TypeName ) {
333  this->SetPushButton( static_cast<MenuButton*>( UncastedButton ) );
334  }else{
335  MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Expected name of MenuButton when deserializing. Named widget is not MenuButton.");
336  }
337  }
338 
339  CurrAttrib = PropertiesNode.GetAttribute("PopButtonName");
340  if( !CurrAttrib.Empty() ) {
341  Widget* UncastedButton = this->ParentScreen->GetWidget( CurrAttrib.AsString() );
342  if( UncastedButton->GetTypeName() == MenuButton::TypeName ) {
343  this->SetPopButton( static_cast<MenuButton*>( UncastedButton ) );
344  }else{
345  MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Expected name of MenuButton when deserializing. Named widget is not MenuButton.");
346  }
347  }
348  }else{
349  MEZZ_EXCEPTION(Exception::INVALID_VERSION_EXCEPTION,"Incompatible XML Version for " + (MenuEntry::GetSerializableName() + "Properties") + ": Not Version 1.");
350  }
351  }else{
352  MEZZ_EXCEPTION(Exception::II_IDENTITY_NOT_FOUND_EXCEPTION,MenuEntry::GetSerializableName() + "Properties" + " was not found in the provided XML node, which was expected.");
353  }
354  }
355 
357  {
358  return MenuEntry::TypeName;
359  }
360 
361  ///////////////////////////////////////////////////////////////////////////////
362  // Internal Event Methods
363 
364 
365 
366  ///////////////////////////////////////////////////////////////////////////////
367  // Internal Methods
368 
370  {
371  return this->MenuStack;
372  }
373 
375  {
376  this->MenuStack = NewStack;
377  for( ChildIterator ChildIt = this->ChildWidgets.begin() ; ChildIt != this->ChildWidgets.end() ; ++ChildIt )
378  {
379  if( (*ChildIt)->GetTypeName() != MenuEntry::TypeName ) {
380  static_cast<MenuEntry*>( (*ChildIt) )->_NotifyStack(NewStack);
381  }
382  }
383  }
384 
386  {
387  const WidgetEventArguments& WidArgs = static_cast<const WidgetEventArguments&>(Args);
388  Widget* EventWidget = this->ParentScreen->GetWidget(WidArgs.WidgetName);
389  //if( EventWidget == NULL )
390  if( EventWidget == NULL || WidArgs.EventName != Button::EventDeactivated )
391  return;
392 
393  if( !(EventWidget->IsHovered()) )
394  return;
395 
396  if( this->PushButton == EventWidget && this->PopButton == EventWidget ) {
397  // Since we are toggling, attempt to push first. It'll automatically do the checks needed for pushing.
398  Boolean PushResult = this->PushOntoStack();
399  if( !PushResult ) {
400  // If it failed to push, try popping.
401  Boolean PopResult = this->PopFromStack();
402  if( !PopResult ) {
403  // If even that failed, then we almost certainly need to do a rollback
404  Boolean IsRoot = this->IsRootEntry();
405  this->RollBackToEntry( IsRoot ? this : static_cast<MenuEntry*>( this->ParentQuad ) );
406  if( !IsRoot ) {
407  // Last attempt
408  this->PushOntoStack();
409  }
410  }
411  }
412  }else if( this->PushButton == EventWidget ) {
413  Boolean PushResult = this->PushOntoStack();
414  if( !PushResult ) {
415  // Attempt a rollback
416  Boolean IsRoot = this->IsRootEntry();
417  this->RollBackToEntry( IsRoot ? this : static_cast<MenuEntry*>( this->ParentQuad ) );
418  if( !IsRoot ) {
419  // Last attempt
420  this->PushOntoStack();
421  }
422  }
423  }else if( this->PopButton == EventWidget ) {
424  this->PopFromStack();
425  /*Bool PopResult = this->PopFromStack();
426  if( !PopResult ) {
427  // Is there anything to do here?
428  }//*/
429  }
430  }
431 
433  {
434  if( this->ParentQuad != NewParent ) {
435  if( this->MenuStack != NULL ) {
436  MenuEntryContainer* OldStack = this->MenuStack;
437  Boolean DestroyOldStack = this->IsRootEntry();
438 
439  this->QuadRenderable::_NotifyParenthood(NewParent);
440 
441  MenuEntryContainer* NewStack = ( this->IsRootEntry() ? new MenuEntryContainer() : static_cast<MenuEntry*>( this->ParentQuad )->_GetMenuStack() );
442  this->_NotifyStack(NewStack);
443 
444  if( DestroyOldStack ) {
445  delete OldStack;
446  OldStack = NULL;
447  }
448  }else{
449  this->QuadRenderable::_NotifyParenthood(NewParent);
450  MenuEntryContainer* NewStack = ( this->IsRootEntry() ? new MenuEntryContainer() : static_cast<MenuEntry*>( this->ParentQuad )->_GetMenuStack() );
451  this->_NotifyStack(NewStack);
452  }
453  }
454  }
455 
457  {
458  if( this->MenuStack ) {
459  ConstMenuEntryIterator MenuIt = std::find(this->MenuStack->begin(),this->MenuStack->end(),this);
460  return ( MenuIt != this->MenuStack->end() );
461  }
462  return false;
463  }
464 
465  ///////////////////////////////////////////////////////////////////////////////
466  // MenuEntryFactory Methods
467 
469  { return MenuEntry::TypeName; }
470 
472  { return new MenuEntry(RendName,Parent); }
473 
474  MenuEntry* MenuEntryFactory::CreateMenuEntry(const String& RendName, const UnifiedRect& RendRect, Screen* Parent)
475  { return new MenuEntry(RendName,RendRect,Parent); }
476 
478  { return new MenuEntry(XMLNode,Parent); }
479 
481  { return new MenuEntry(Parent); }
482 
483  Widget* MenuEntryFactory::CreateWidget(const String& RendName, const NameValuePairMap& Params, Screen* Parent)
484  { return this->CreateMenuEntry(RendName,Parent); }
485 
486  Widget* MenuEntryFactory::CreateWidget(const String& RendName, const UnifiedRect& RendRect, const NameValuePairMap& Params, Screen* Parent)
487  { return this->CreateMenuEntry(RendName,RendRect,Parent); }
488 
490  { return this->CreateMenuEntry(XMLNode,Parent); }
491 
493  { delete static_cast<MenuEntry*>( ToBeDestroyed ); }
494  }//UI
495 }//Mezzanine
496 
497 #endif