MezzanineEngine 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
uimanager.cpp
1 // © Copyright 2010 - 2014 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 _uiuimanager_cpp
41 #define _uiuimanager_cpp
42 
43 #include "UI/uimanager.h"
44 #include "UI/textureatlashandler.h"
45 #include "UI/textureatlas.h"
46 #include "UI/hotkeyhandler.h"
47 #include "UI/actionhandler.h"
48 #include "UI/screen.h"
49 #include "UI/button.h"
50 #include "UI/widget.h"
51 #include "UI/glyph.h"
52 
53 // includes for the creation and destruction of the global parser
54 #include "UI/defaultmarkupparser.h"
55 
56 #include "Graphics/cameramanager.h"
57 #include "Graphics/graphicsmanager.h"
58 #include "Graphics/viewport.h"
59 #include "Input/inputmanager.h"
60 #include "Input/mouse.h"
61 #include "eventmanager.h"
62 #include "resourcemanager.h"
63 
64 #include "mathtool.h"
65 #include "timer.h"
66 #include "entresol.h"
67 
68 #include <Ogre.h>
69 
70 namespace Mezzanine
71 {
72  template<> UI::UIManager* Singleton<UI::UIManager>::SingletonPtr = NULL;
73 
74  namespace UI
75  {
76  ///////////////////////////////////////////////////////////////////////////////
77  // WidgetUpdateWorkUnit Methods
78 
80  { }
81 
83  { return *this; }
84 
86  TargetManager(Target) { }
87 
89  { }
90 
91  ///////////////////////////////////////////////////////////////////////////////
92  // Utility
93 
95  { this->TargetManager->UpdateScreens(); }
96 
97  ///////////////////////////////////////////////////////////////////////////////
98  // UIManager Methods
99 
101  HoveredWidget(NULL),
102  WidgetFocus(NULL),
103 
104  WidgetUpdateWork(NULL),
105  ThreadResources(NULL),
106 
107  ButtonAutoRegister(false),
108  MouseMoved(false)
109  {
111  this->AtlasHandler = new TextureAtlasHandler();
112  this->HKHandler = new HotKeyHandler();
113  //this->ActHandler = new ActionHandler();
114 
115  // Parser Work
116  MarkupParser* DefaultParser = new DefaultMarkupParser();
117  this->RegisterMarkupParser(DefaultParser->GetName(),DefaultParser);
118  this->RegisterMarkupParser("",DefaultParser);
119 
120  this->WidgetUpdateWork = new WidgetUpdateWorkUnit(this);
121  }
122 
124  HoveredWidget(NULL),
125  WidgetFocus(NULL),
126 
127  WidgetUpdateWork(NULL),
128  ThreadResources(NULL),
129 
130  ButtonAutoRegister(false),
131  MouseMoved(false)
132  {
133  /// @todo This class currently doesn't initialize anything from XML, if that changes this constructor needs to be expanded.
135  this->AtlasHandler = new TextureAtlasHandler();
136  this->HKHandler = new HotKeyHandler();
137  //this->ActHandler = new ActionHandler();
138 
139  // Parser Work
140  MarkupParser* DefaultParser = new DefaultMarkupParser();
141  this->RegisterMarkupParser(DefaultParser->GetName(),DefaultParser);
142  this->RegisterMarkupParser("",DefaultParser);
143 
144  this->WidgetUpdateWork = new WidgetUpdateWorkUnit(this);
145  }
146 
148  {
149  this->Deinitialize();
150  this->DestroyAllScreens();
151 
152  delete this->WidgetUpdateWork;
153  }
154 
156  {
157  if( Code.IsKeyboardEvent() )
158  this->HandlePreFocusKeyboardInput( Code );
159  else if( Code.IsMouseEvent() )
160  this->HandlePreFocusMouseInput( Code );
161  else if( Code.IsControllerEvent() )
162  this->HandlePreFocusControllerInput( Code );
163  /// @todo If other devices are added, appropriate functions should be added to this class, and called here.
164  }
165 
167  {
168  if( Code.IsKeyboardEvent() )
169  this->HandlePostFocusKeyboardInput( Code );
170  else if( Code.IsMouseEvent() )
171  this->HandlePostFocusMouseInput( Code );
172  else if( Code.IsControllerEvent() )
173  this->HandlePostFocusControllerInput( Code );
174  /// @todo If other devices are added, appropriate functions should be added to this class, and called here.
175  }
176 
178  {
179 
180  }
181 
183  {
184  if( Code.IsMouseButton() ) {
185  if( Input::BUTTON_PRESSING == Code.GetMetaValue() ) {
186  // Update the focus
187  //Bool Switched = SwitchFocus(HoveredWidget);
188  this->SwitchFocus(HoveredWidget);
189 
190  // If we got a valid focus, there is more work to be done
191  if( this->WidgetFocus ) {
192  // Regardless of it has changed, lock the focus
193  if( !FocusIsLocked() ) {
194  this->WidgetFocus->_OnFocusLocked();
195  this->FocusLockCode = Code;
196  }
197 
198  // If we have a new focus, inform it of the input
199  // Only do this if we switched because if it's an old focus it already had a chance
200  // at the input code, and we don't want to double dip.
201  //if( Switched )
202  // this->WidgetFocus->_HandleInput(Code);
203  }
204  }else if( Input::BUTTON_LIFTING == Code.GetMetaValue() ) {
205  if( this->WidgetFocus ) {
206  // Check the code to see if we're releasing the focus lock
207  if( this->FocusLockCode.GetCode() == Code.GetCode() ) {
208  this->WidgetFocus->_OnFocusUnlocked();
210  }
211 
212  // Pass on the input
213  //this->WidgetFocus->_HandleInput(Code);
214  }
215  }
216  }
217  }
218 
220  {
221  /// @todo There is currently nothing that the UI system as a whole needs controller inputs.
222  /// Perhaps when we implement consoles this should be expanded, maybe even sooner then that.
223  }
224 
226  {
227 
228  }
229 
231  {
232  if( Code.IsMouseMotionEvent() )
233  {
234 
235  }
236  }
237 
239  {
240  /// @todo There is currently nothing that the UI system as a whole needs controller inputs.
241  /// Perhaps when we implement consoles this should be expanded, maybe even sooner then that.
242  }
243 
245  {
246  // Check if the focus is changing at all
247  if( this->WidgetFocus != NewFocus && !this->FocusIsLocked() )
248  {
249  // If we already have a focus, drop it
250  if( this->WidgetFocus )
251  this->WidgetFocus->_OnFocusLost();
252 
253  // Assign the new focus
254  this->WidgetFocus = NewFocus;
255 
256  // If the new focus is valid, notify it of it's new status
257  if( this->WidgetFocus )
258  this->WidgetFocus->_OnFocusGained();
259 
260  // Acknowledge the focus was changed
261  return true;
262  }
263  // Nothing changed
264  return false;
265  }
266 
268  {
269  return ( Input::KEY_UNKNOWN != FocusLockCode.GetCode() );
270  }
271 
272  ///////////////////////////////////////////////////////////////////////////////
273  // Texture Atlas Management
274 
275  void UIManager::LoadMTA(const String& Name, const String& Group)
276  {
277  this->AtlasHandler->LoadAtlasFromFile(Name,Group);
278  }
279 
281  {
282  return this->AtlasHandler->GetAtlas(AtlasName);
283  }
284 
285  ///////////////////////////////////////////////////////////////////////////////
286  // Screen Management
287 
288  Screen* UIManager::CreateScreen(const String& ScreenName, const String& Atlas, Graphics::Viewport* WindowViewport)
289  {
290  Screen* MezzScreen = new Screen(ScreenName,Atlas,WindowViewport,this);
291  this->Screens.push_back(MezzScreen);
292  return MezzScreen;
293  }
294 
296  {
297  for( ScreenIterator it = this->Screens.begin() ; it != this->Screens.end() ; it++ )
298  {
299  if ( Name == (*it)->GetName() ) {
300  Screen* MezzScreen = (*it);
301  return MezzScreen;
302  }
303  }
304  return 0;
305  }
306 
308  {
309  return this->Screens[Index];
310  }
311 
313  {
314  return this->Screens.size();
315  }
316 
318  {
319  for( ScreenIterator it = this->Screens.begin() ; it != this->Screens.end() ; it++ )
320  {
321  if( Screen == (*it) ) {
322  delete (*it);
323  this->Screens.erase(it);
324  return;
325  }
326  }
327  }
328 
330  {
331  for( ScreenIterator it = this->Screens.begin() ; it != this->Screens.end() ; it++ )
332  {
333  delete (*it);
334  }
335  this->Screens.clear();
336  }
337 
339  {
340  for( ScreenIterator ScreenIt = this->Screens.begin() ; ScreenIt != this->Screens.end() ; ++ScreenIt )
341  {
342  if( (*ScreenIt)->GetViewport() == WindowViewport ) {
343  (*ScreenIt)->Show();
344  }
345  }
346  }
347 
349  {
350  for( ScreenIterator ScreenIt = this->Screens.begin() ; ScreenIt != this->Screens.end() ; ++ScreenIt )
351  {
352  (*ScreenIt)->Show();
353  }
354  }
355 
357  {
358  for( ScreenIterator ScreenIt = this->Screens.begin() ; ScreenIt != this->Screens.end() ; ++ScreenIt )
359  {
360  if( (*ScreenIt)->GetViewport() == WindowViewport ) {
361  (*ScreenIt)->Hide();
362  }
363  }
364  }
365 
367  {
368  for( ScreenIterator ScreenIt = this->Screens.begin() ; ScreenIt != this->Screens.end() ; ++ScreenIt )
369  {
370  (*ScreenIt)->Hide();
371  }
372  }
373 
375  {
376  for( ScreenIterator ScreenIt = this->Screens.begin() ; ScreenIt != this->Screens.end() ; ++ScreenIt )
377  {
378  if( (*ScreenIt)->GetViewport() == WindowViewport && (*ScreenIt)->IsVisible() ) {
379  return (*ScreenIt);
380  }
381  }
382  return NULL;
383  }
384 
385  ///////////////////////////////////////////////////////////////////////////////
386  // HotKey and Activation Management
387 
388  void UIManager::BindHotKey(const Input::MetaCode& HotKey, Button* BoundButton)
389  {
390  this->HKHandler->BindHotKey(HotKey,BoundButton);
391  }
392 
393  void UIManager::UnbindHotKey(const Input::MetaCode& HotKey, Button* BoundButton)
394  {
395  this->HKHandler->UnbindHotKey(HotKey,BoundButton);
396  }
397 
398  ///////////////////////////////////////////////////////////////////////////////
399  // Activation Management
400 
402  {
403  this->ButtonAutoRegister = Enable;
404  }
405 
407  {
408  return this->ButtonAutoRegister;
409  }
410 
412  {
413  for( InputIterator It = this->AutoRegisterCodes.begin() ; It != this->AutoRegisterCodes.end() ; It++ )
414  {
415  if((*It)==Code)
416  return;
417  }
418  this->AutoRegisterCodes.push_back(Code);
419  }
420 
422  {
423  for( InputIterator It = this->AutoRegisterCodes.begin() ; It != this->AutoRegisterCodes.end() ; It++ )
424  {
425  if((*It)==Code) {
426  this->AutoRegisterCodes.erase(It);
427  return;
428  }
429  }
430  }
431 
433  {
434  this->AutoRegisterCodes.clear();
435  }
436 
438  {
439  return &(this->AutoRegisterCodes);
440  }
441 
442  ///////////////////////////////////////////////////////////////////////////////
443  // MarkupParser Management
444 
445  void UIManager::RegisterMarkupParser(const String& ParserName, MarkupParser* ToAdd)
446  {
447  MarkupParserIterator MarkupIt = this->MarkupParsers.find(ParserName);
448  if( MarkupIt != this->MarkupParsers.end() ) {
449  MEZZ_EXCEPTION(Exception::II_DUPLICATE_IDENTITY_EXCEPTION,"A MarkupParser with the name \"" + ParserName + "\" is already registered.");
450  }else{
451  this->MarkupParsers.insert( std::pair<String,UI::MarkupParser*>(ParserName,ToAdd) );
452  }
453  }
454 
455  bool UIManager::IsMarkupParserRegistered(const String& ParserName) const
456  {
457  ConstMarkupParserIterator MarkupIt = this->MarkupParsers.find(ParserName);
458  return ( MarkupIt != this->MarkupParsers.end() );
459  }
460 
462  {
463  ConstMarkupParserIterator MarkupIt = this->MarkupParsers.find(ParserName);
464  if( MarkupIt != this->MarkupParsers.end() ) return (*MarkupIt).second;
465  else return NULL;
466  }
467 
469  {
470  MarkupParserIterator MarkupIt = this->MarkupParsers.find(ParserName);
471  if( MarkupIt != this->MarkupParsers.end() )
472  this->MarkupParsers.erase(MarkupIt);
473  }
474 
476  {
477  this->MarkupParsers.clear();
478  }
479 
480  void UIManager::DestroyMarkupParser(const String& ParserName)
481  {
482  MarkupParserIterator MarkupIt = this->MarkupParsers.find(ParserName);
483  if( MarkupIt != this->MarkupParsers.end() ) {
484  delete (*MarkupIt).second;
485  this->MarkupParsers.erase(MarkupIt);
486  }
487  }
488 
490  {
491  for( MarkupParserIterator MarkupIt = this->MarkupParsers.begin() ; MarkupIt != this->MarkupParsers.end() ; ++MarkupIt )
492  {
493  delete (*MarkupIt).second;
494  }
495  this->MarkupParsers.clear();
496  }
497 
498  ///////////////////////////////////////////////////////////////////////////////
499  // Fetch Methods
500 
502  { return this->HoveredWidget; }
503 
505  { return this->WidgetFocus; }
506 
508  { return this->AtlasHandler; }
509 
510  ///////////////////////////////////////////////////////////////////////////////
511  // Utility
512 
514  {
515  switch( Code.GetCode() )
516  {
517  case Input::MOUSEHORIZONTAL:
518  case Input::MOUSEVERTICAL:
519  {
520  this->MouseMoved = true;
521  break;
522  }
523  default: /* Do Nothing */ break;
524  }
525 
526  this->InjectedInputs.push_back(Code);
527  }
528 
530  {
531  Screen* VisScreen = this->GetVisibleScreenOnViewport(VP);
532  if( VisScreen != NULL ) {
533  Widget* Wid = VisScreen->FindHoveredWidget(Point);
534  return Wid;
535  }
536  return NULL;
537  }
538 
540  {
541  return (HoveredWidget || WidgetFocus);
542  }
543 
545  {
546  TextureAtlas* TheAtlas = AtlasHandler->GetAtlas(Atlas);
547  if(NULL == TheAtlas)
548  {
549  MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Attempting to access TextureAtlas \"" + Atlas + "\", which does not exist or is not loaded.");
550  }
551  TextureAtlas::FontDataContainer& Fonts = TheAtlas->GetFonts();
552  String LargerMatch, SmallerMatch;
553  Real LargerHeight = 0;
554  Real SmallerHeight = 0;
555  Real LargerMatchDiff = 1000000.0;
556  Real SmallerMatchDiff = 1000000.0;
557  Real RequestedHeight = (Real)Height;
558 
559  for( TextureAtlas::FontDataIterator it = Fonts.begin() ; it != Fonts.end() ; it++ )
560  {
561  Real Diff = 0.0;
562  if((*it).second->GetLineHeight() > RequestedHeight)
563  {
564  Diff = (*it).second->GetLineHeight() - RequestedHeight;
565  if(Diff < LargerMatchDiff)
566  {
567  LargerMatch = (*it).first;
568  LargerHeight = (*it).second->GetLineHeight();
569  LargerMatchDiff = Diff;
570  continue;
571  }
572  }else{
573  Diff = RequestedHeight - (*it).second->GetLineHeight();
574  if(Diff < SmallerMatchDiff)
575  {
576  SmallerMatch = (*it).first;
577  SmallerHeight = (*it).second->GetLineHeight();
578  SmallerMatchDiff = Diff;
579  continue;
580  }
581  }
582  }
583 
584  Real Scale = 1;
585  if(!LargerMatch.empty())
586  {
587  Scale = RequestedHeight / LargerHeight;
588  return FontResult(LargerMatch,Scale);
589  }else{
590  Scale = RequestedHeight / SmallerHeight;
591  return FontResult(SmallerMatch,Scale);
592  }
593  }
594 
596  {
597  Input::Mouse* SysMouse = Input::InputManager::GetSingletonPtr()->GetSystemMouse();
598 
599  // Tell all screens to check if the veiwport dimensions have changed
600  for( ScreenIterator ScIt = this->Screens.begin() ; ScIt != this->Screens.end() ; ++ScIt )
601  (*ScIt)->CheckViewportSize();
602 
603  // Inject input delta's from the input system
604  const MetaCodeContainer& Inputs = Input::InputManager::GetSingletonPtr()->GetInputDeltas();
605  // InjectedInputs.insert(InjectedInputs.end(),Inputs.begin(),Inputs.end()); // ©ommented because we want to use "InjectInput()" so we can filter the codes.
606  for( ConstMetaCodeIterator MCIt = Inputs.begin() ; MCIt != Inputs.end() ; ++MCIt )
607  this->InjectInput( (*MCIt) );
608 
609  // Get the hovered quad based on mouse position
610  // We don't care what is hovered so much if the mouse hasn't moved, or is hidden due to relative mode.
611  if( this->MouseMoved && !SysMouse->GetRelativeMode() )
612  {
613  Widget* TempWidget = this->CheckWidgetUnderPoint(SysMouse->GetHoveredViewport(),SysMouse->GetViewportPosition());
614  if( TempWidget != this->HoveredWidget )
615  {
616  if( this->HoveredWidget ) {
617  this->HoveredWidget->_OnMouseExit();
618  }
619 
620  this->HoveredWidget = TempWidget;
621 
622  if( this->HoveredWidget ) {
623  this->HoveredWidget->_OnMouseEnter();
624  TheEntresol->Log( "New Hovered Widget Name: " + this->HoveredWidget->GetName() );
625  }
626  }
627  }
628 
629  // Check the focus to see if it's still visible. Drop focus if it's not.
630  if( this->WidgetFocus && !this->WidgetFocus->GetVisible() )
631  {
632  if( this->FocusIsLocked() ) {
633  this->WidgetFocus->_OnFocusUnlocked();
635  }
636  this->WidgetFocus->_OnFocusLost();
637  this->WidgetFocus = NULL;
638  }
639 
640  // Look at and process all injected inputs accordingly
641  for( InputIterator InIt = this->InjectedInputs.begin() ; InIt != this->InjectedInputs.end() ; ++InIt )
642  {
643  // Allow our pre processes to get first dibs.
644  this->HandlePreFocusInput( (*InIt) );
645 
646  // Allow the focus to consume the input if it needs/wants to.
647  if( this->WidgetFocus && this->WidgetFocus->_HandleInput( (*InIt) ) )
648  continue;
649 
650  // If the focus doesn't consume the input, we pass it back to the system.
651  this->HandlePostFocusInput( (*InIt) );
652  }
653  this->MouseMoved = false;
654  this->InjectedInputs.clear();
655  }
656 
658  {
659  if( !this->Initialized ) {
660  this->TheEntresol->GetScheduler().AddWorkUnitMain( this->WidgetUpdateWork, "WidgetUpdateWork" );
662  if( InputMan )
663  this->WidgetUpdateWork->AddDependency( InputMan->GetDeviceUpdateWork() );
664 
665  this->Initialized = true;
666  }
667  }
668 
670  {
671  if( this->Initialized ) {
674 
675  this->Initialized = false;
676  }
677  }
678 
680  {
681  return this->WidgetUpdateWork;
682  }
683 
684  ///////////////////////////////////////////////////////////////////////////////
685  // Type Identifier Methods
686 
688  { return ManagerBase::MT_UIManager; }
689 
691  { return "DefaultUIManager"; }
692 
693  ///////////////////////////////////////////////////////////////////////////////
694  // DefaultUIManagerFactory Methods
695 
697  { }
698 
700  { }
701 
703  { return "DefaultUIManager"; }
704 
706  {
707  if( UIManager::SingletonValid() ) {
708  /// @todo Add something to log a warning that the manager exists and was requested to be constructed when we have a logging manager set up.
710  }else return new UIManager();
711  }
712 
714  {
715  if( UIManager::SingletonValid() ) {
716  /// @todo Add something to log a warning that the manager exists and was requested to be constructed when we have a logging manager set up.
718  }else return new UIManager(XMLNode);
719  }
720 
722  { delete ToBeDestroyed; }
723  }//UI
724 }//Mezzanine
725 
726 #endif