Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

CEGUISystem.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002         filename:       CEGUISystem.cpp
00003         created:        20/2/2004
00004         author:         Paul D Turner
00005         
00006         purpose:        Implementation of main system object
00007 *************************************************************************/
00008 /*************************************************************************
00009     Crazy Eddie's GUI System (http://www.cegui.org.uk)
00010     Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)
00011 
00012     This library is free software; you can redistribute it and/or
00013     modify it under the terms of the GNU Lesser General Public
00014     License as published by the Free Software Foundation; either
00015     version 2.1 of the License, or (at your option) any later version.
00016 
00017     This library is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020     Lesser General Public License for more details.
00021 
00022     You should have received a copy of the GNU Lesser General Public
00023     License along with this library; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 *************************************************************************/
00026 #include "CEGUISystem.h"
00027 #include "CEGUILogger.h"
00028 #include "CEGUIImagesetManager.h"
00029 #include "CEGUIFontManager.h"
00030 #include "CEGUIWindowFactoryManager.h"
00031 #include "CEGUIWindowManager.h"
00032 #include "CEGUISchemeManager.h"
00033 #include "CEGUIMouseCursor.h"
00034 #include "CEGUIWindow.h"
00035 #include "CEGUIImageset.h"
00036 #include "CEGUIExceptions.h"
00037 #include "elements/CEGUIGUISheet.h"
00038 #include "CEGUIScriptModule.h"
00039 #include "CEGUIConfig_xmlHandler.h"
00040 #include "xercesc/util/PlatformUtils.hpp"
00041 #include "xercesc/util/Janitor.hpp"
00042 #include "xercesc/sax2/DefaultHandler.hpp"
00043 #include "xercesc/sax2/SAX2XMLReader.hpp"
00044 #include "xercesc/sax2/XMLReaderFactory.hpp"
00045 #include "xercesc/framework/MemBufInputSource.hpp"
00046 #include "CEGUIDataContainer.h"
00047 #include "CEGUIResourceProvider.h"
00048 #include "CEGUIGlobalEventSet.h"
00049 #include <time.h>
00050 
00051 
00052 // Start of CEGUI namespace section
00053 namespace CEGUI
00054 {
00055 const String System::EventNamespace("System");
00056 
00061 class SimpleTimer
00062 {
00063         clock_t d_baseTime;
00064 
00065 public:
00066         SimpleTimer() : d_baseTime(clock()) {}
00067 
00068         void    restart()       { d_baseTime = clock(); }
00069         double  elapsed()       { return static_cast<double>((clock() - d_baseTime) / CLOCKS_PER_SEC); }
00070 };
00071         
00077 struct MouseClickTracker
00078 {
00079         MouseClickTracker(void) : d_click_count(0), d_click_area(0, 0, 0, 0) {}
00080 
00081         SimpleTimer             d_timer;                        
00082         int                             d_click_count;          
00083         Rect                    d_click_area;           
00084 };
00085 
00086 
00087 struct MouseClickTrackerImpl
00088 {
00089         MouseClickTracker       click_trackers[MouseButtonCount];
00090 };
00091 
00092 
00093 /*************************************************************************
00094         Constants definitions
00095 *************************************************************************/
00096 const char      System::CEGUIConfigSchemaName[]         = "CEGUIConfig.xsd";
00097 
00098 
00099 /*************************************************************************
00100         Static Data Definitions
00101 *************************************************************************/
00102 // singleton instance pointer
00103 template<> System* Singleton<System>::ms_Singleton      = NULL;
00104 
00105 // click event generation defaults
00106 const double    System::DefaultSingleClickTimeout       = 0.2;
00107 const double    System::DefaultMultiClickTimeout        = 0.33;
00108 const Size              System::DefaultMultiClickAreaSize(12,12);
00109 
00110 // event names
00111 const String System::EventGUISheetChanged( (utf8*)"GUISheetChanged" );
00112 const String System::EventSingleClickTimeoutChanged( (utf8*)"SingleClickTimeoutChanged" );
00113 const String System::EventMultiClickTimeoutChanged( (utf8*)"MultiClickTimeoutChanged" );
00114 const String System::EventMultiClickAreaSizeChanged( (utf8*)"MultiClickAreaSizeChanged" );
00115 const String System::EventDefaultFontChanged( (utf8*)"DefaultFontChanged" );
00116 const String System::EventDefaultMouseCursorChanged( (utf8*)"DefaultMouseCursorChanged" );
00117 const String System::EventMouseMoveScalingChanged( (utf8*)"MouseMoveScalingChanged" );
00118 
00119 
00120 /*************************************************************************
00121         Constructor
00122 *************************************************************************/
00123 System::System(Renderer* renderer, utf8* logFile) :
00124         d_clickTrackerPimpl(new MouseClickTrackerImpl)
00125 {
00126         constructor_impl(renderer, NULL, NULL, (utf8*)"", logFile);
00127 }
00128 /*************************************************************************
00129         Construct a new System object
00130 *************************************************************************/
00131 System::System(Renderer* renderer, ResourceProvider* resourceProvider, utf8* logFile) :
00132         d_clickTrackerPimpl(new MouseClickTrackerImpl)
00133 {
00134         constructor_impl(renderer, resourceProvider, NULL, (utf8*)"", logFile);
00135 }
00136 
00137 /*************************************************************************
00138         Construct a new System object
00139 *************************************************************************/
00140 System::System(Renderer* renderer, ScriptModule* scriptModule, utf8* configFile) :
00141         d_clickTrackerPimpl(new MouseClickTrackerImpl)
00142 {
00143         constructor_impl(renderer, NULL, scriptModule, configFile, (utf8*)"CEGUI.log");
00144 }
00145 
00146 
00147 /*************************************************************************
00148         Construct a new System object
00149 *************************************************************************/
00150 System::System(Renderer* renderer, ScriptModule* scriptModule, ResourceProvider* resourceProvider, utf8* configFile) :
00151         d_clickTrackerPimpl(new MouseClickTrackerImpl)
00152 {
00153         constructor_impl(renderer, resourceProvider, scriptModule, configFile, (utf8*)"CEGUI.log");
00154 }
00155 
00156 
00157 /*************************************************************************
00158         Method to do the work of the constructor
00159 *************************************************************************/
00160 void System::constructor_impl(Renderer* renderer, ResourceProvider* resourceProvider, ScriptModule* scriptModule, const String& configFile, const String& logFile)
00161 {
00162         d_renderer              = renderer;
00163         d_gui_redraw    = false;
00164         d_wndWithMouse  = NULL;
00165         d_activeSheet   = NULL;
00166         d_sysKeys               = 0;
00167 
00168         d_lshift        = false;
00169         d_rshift        = false;
00170         d_lctrl         = false;
00171         d_rctrl         = false;
00172 
00173         d_click_timeout         = DefaultSingleClickTimeout;
00174         d_dblclick_timeout      = DefaultMultiClickTimeout;
00175         d_dblclick_size         = DefaultMultiClickAreaSize;
00176 
00177         d_defaultMouseCursor = NULL;
00178         d_scriptModule           = scriptModule;
00179 
00180         d_mouseScalingFactor = 1.0f;
00181 
00182         // add events for Sytem object
00183         addSystemEvents();
00184 
00185     // if there has been a resource provider supplied use that otherwise create one.
00186     d_resourceProvider = resourceProvider ? resourceProvider : renderer->createResourceProvider();
00187 
00188         // initialise Xerces-C XML system
00189         XERCES_CPP_NAMESPACE_USE
00190         try
00191         {
00192                 XMLPlatformUtils::Initialize();
00193         }
00194         catch(XMLException& exc)
00195         {
00196                 // prepare a message about the failure
00197                 char* excmsg = XMLString::transcode(exc.getMessage());
00198                 String message((utf8*)"An exception occurred while initialising the Xerces-C XML system.  Additional information: ");
00199                 message += (utf8*)excmsg;
00200                 XMLString::release(&excmsg);
00201 
00202                 // throw a std::exception (because it won't try and use logger)
00203                 throw message.c_str();
00204         }
00205 
00206         // strings we may get from the configuration file.
00207         String configLogname, configSchemeName, configLayoutName, configInitScript, defaultFontName;
00208 
00209         // now XML is available, read the configuration file (if any)
00210         if (!configFile.empty())
00211         {
00212                 SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();
00213 
00214                 // set basic settings we want from parser
00215                 parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
00216                 parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
00217                 parser->setFeature(XMLUni::fgXercesSchema, true);
00218                 parser->setFeature(XMLUni::fgXercesValidationErrorAsFatal, true);
00219 
00220 
00221 //        InputSourceContainer configSchemaData;
00222 //        System::getSingleton().getResourceProvider()->loadInputSourceContainer(CEGUIConfigSchemaName, configSchemaData);
00223 //        parser->loadGrammar(*(configSchemaData.getDataPtr()), 
00224 //                Grammar::SchemaGrammarType, true);
00225 
00226         RawDataContainer rawSchemaData;
00227         System::getSingleton().getResourceProvider()->loadRawDataContainer(CEGUIConfigSchemaName, rawSchemaData, "");
00228         MemBufInputSource  configSchemaData(rawSchemaData.getDataPtr(), rawSchemaData.getSize(), CEGUIConfigSchemaName, false);
00229         parser->loadGrammar(configSchemaData, Grammar::SchemaGrammarType, true);
00230 
00231         // enable grammar reuse
00232         parser->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
00233 
00234                 // setup schema for Scheme data
00235                 XMLCh* pval = XMLString::transcode(CEGUIConfigSchemaName);
00236                 parser->setProperty(XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation, pval);
00237                 XMLString::release(&pval);
00238 
00239                 // setup handler object
00240                 Config_xmlHandler handler;
00241                 parser->setContentHandler(&handler);
00242                 parser->setErrorHandler(&handler);
00243 
00244 //        InputSourceContainer configData;
00245 //        d_resourceProvider->loadInputSourceContainer(configFile, configData);
00246 
00247         RawDataContainer rawXMLData;
00248         System::getSingleton().getResourceProvider()->loadRawDataContainer(configFile, rawXMLData, "");
00249         MemBufInputSource  configData(rawXMLData.getDataPtr(), rawXMLData.getSize(), configFile.c_str(), false);
00250 
00251                 // do parsing of xml file
00252                 try
00253                 {
00254 //            parser->parse(*(configData.getDataPtr()));
00255             parser->parse(configData);
00256 
00257                         // get the strings read
00258                         configLogname           = handler.getLogFilename();
00259                         configSchemeName        = handler.getSchemeFilename();
00260                         configLayoutName        = handler.getLayoutFilename();
00261                         defaultFontName         = handler.getDefaultFontName();
00262                         configInitScript        = handler.getInitScriptFilename();
00263                         d_termScriptName        = handler.getTermScriptFilename();
00264 
00265             // set default resource group if it was specified.
00266             if (!handler.getDefaultResourceGroup().empty())
00267             {
00268                 d_resourceProvider->setDefaultResourceGroup(handler.getDefaultResourceGroup());
00269             }
00270                 }
00271                 catch(const XMLException& exc)
00272                 {
00273                         if (exc.getCode() != XMLExcepts::NoError)
00274                         {
00275                                 delete parser;
00276 
00277                                 char* excmsg = XMLString::transcode(exc.getMessage());
00278                                 String message((utf8*)"System::System - An error occurred while parsing configuration file '" + configFile + "'.  Additional information: ");
00279                                 message += excmsg;
00280                                 XMLString::release(&excmsg);
00281 
00282                                 // cleanup XML stuff
00283                                 XERCES_CPP_NAMESPACE_USE
00284                                 XMLPlatformUtils::Terminate();
00285 
00286                                 // throw a std::exception (because it won't try and use logger)
00287                                 throw message.c_str();
00288                         }
00289 
00290                 }
00291                 catch(const SAXParseException& exc)
00292                 {
00293                         delete parser;
00294 
00295                         char* excmsg = XMLString::transcode(exc.getMessage());
00296                         String message((utf8*)"System::System - An error occurred while parsing configuration file '" + configFile + "'.  Additional information: ");
00297                         message += excmsg;
00298                         XMLString::release(&excmsg);
00299 
00300                         // cleanup XML stuff
00301                         XERCES_CPP_NAMESPACE_USE
00302                         XMLPlatformUtils::Terminate();
00303 
00304                         // throw a std::exception (because it won't try and use logger)
00305                         throw message.c_str();
00306                 }
00307                 catch(...)
00308                 {
00309                         delete parser;
00310 
00311                         // cleanup XML stuff
00312                         XERCES_CPP_NAMESPACE_USE
00313                         XMLPlatformUtils::Terminate();
00314 
00315                         // throw a std::exception (because it won't try and use logger)
00316                         throw String((utf8*)"System::System - An unexpected error occurred while parsing configuration file '" + configFile + "'.").c_str();
00317                 }
00318 
00319                 // cleanup parser
00320                 delete parser;
00321         }
00322 
00323         // Start up the logger:
00324         // prefer log filename from config file
00325         if (!configLogname.empty())
00326         {
00327                 new Logger(configLogname);
00328         }
00329         // no log specified in configuration, use default / hard-coded option
00330         else
00331         {
00332                 new Logger(logFile);
00333         }
00334         
00335         // beginning main init
00336         Logger::getSingleton().logEvent((utf8*)"---- Begining CEGUI System initialisation ----");
00337 
00338         // cause creation of other singleton objects
00339         new ImagesetManager();
00340         new FontManager();
00341         new WindowFactoryManager();
00342         new WindowManager();
00343         new SchemeManager();
00344         new MouseCursor();
00345         new GlobalEventSet();
00346 
00347         // add default GUISheet factory - the only UI element we can create "out of the box".
00348         WindowFactoryManager::getSingleton().addFactory(new GUISheetFactory);
00349 
00350         // GUISheet's name was changed, register an alias so both can be used
00351         WindowFactoryManager::getSingleton().addWindowTypeAlias((utf8*)"DefaultGUISheet", GUISheet::WidgetTypeName);
00352 
00353         // success - we are created!  Log it for prosperity :)
00354         Logger::getSingleton().logEvent((utf8*)"CEGUI::System singleton created.");
00355         Logger::getSingleton().logEvent((utf8*)"---- CEGUI System initialisation completed ----");
00356 
00357         // subscribe to hear about display mode changes
00358         d_renderer->subscribeEvent(Renderer::EventDisplaySizeChanged, Event::Subscriber(&CEGUI::System::handleDisplaySizeChange, this));
00359 
00360         // load base scheme
00361         if (!configSchemeName.empty())
00362         {
00363                 try
00364                 {
00365                         SchemeManager::getSingleton().loadScheme(configSchemeName, d_resourceProvider->getDefaultResourceGroup());
00366 
00367                         // set default font if that was specified also
00368                         if (!defaultFontName.empty())
00369                         {
00370                                 setDefaultFont(defaultFontName);
00371                         }
00372 
00373                 }
00374                 catch (CEGUI::Exception exc) {}  // catch exception and try to continue anyway
00375 
00376         }
00377 
00378         // load initial layout
00379         if (!configLayoutName.empty())
00380         {
00381                 try
00382                 {
00383                         setGUISheet(WindowManager::getSingleton().loadWindowLayout(configLayoutName));
00384                 }
00385                 catch (CEGUI::Exception exc) {}  // catch exception and try to continue anyway
00386 
00387         }
00388 
00389         // execute start up script
00390         if (!configInitScript.empty())
00391         {
00392                 try
00393                 {
00394                         executeScriptFile(configInitScript);
00395                 }
00396                 catch (...) {}  // catch all exceptions and try to continue anyway
00397 
00398         }
00399 
00400 }
00401 
00402 
00403 /*************************************************************************
00404         Destructor
00405 *************************************************************************/
00406 System::~System(void)
00407 {
00408         Logger::getSingleton().logEvent((utf8*)"---- Begining CEGUI System destruction ----");
00409 
00410         // execute shut-down script
00411         if (!d_termScriptName.empty())
00412         {
00413                 try
00414                 {
00415                         executeScriptFile(d_termScriptName);
00416                 }
00417                 catch (...) {}  // catch all exceptions and continue system shutdown
00418 
00419         }
00420 
00421         // cleanup XML stuff
00422         XERCES_CPP_NAMESPACE_USE
00423         XMLPlatformUtils::Terminate();
00424 
00425         //
00426         // perform cleanup in correct sequence
00427         //
00428         // destroy windows so it's safe to destroy factories
00429         WindowManager::getSingleton().destroyAllWindows();
00430 
00431         // get pointer to the GUI sheet factory we added
00432         GUISheetFactory* factory = (GUISheetFactory*)WindowFactoryManager::getSingleton().getFactory(GUISheet::WidgetTypeName);
00433 
00434         // remove factories so it's safe to unload GUI modules
00435         WindowFactoryManager::getSingleton().removeAllFactories();
00436 
00437         // destroy GUI sheet factory
00438         delete factory;
00439 
00440         // cleanup singletons
00441         delete  SchemeManager::getSingletonPtr();
00442         delete  WindowManager::getSingletonPtr();
00443         delete  WindowFactoryManager::getSingletonPtr();
00444         delete  FontManager::getSingletonPtr();
00445         delete  MouseCursor::getSingletonPtr();
00446         delete  ImagesetManager::getSingletonPtr();
00447         delete  GlobalEventSet::getSingletonPtr();
00448 
00449         Logger::getSingleton().logEvent((utf8*)"CEGUI::System singleton destroyed.");
00450         Logger::getSingleton().logEvent((utf8*)"---- CEGUI System destruction completed ----");
00451         delete Logger::getSingletonPtr();
00452 
00453         delete d_clickTrackerPimpl;
00454 }
00455 
00456 
00457 /*************************************************************************
00458         Render the GUI for this frame
00459 *************************************************************************/
00460 void System::renderGUI(void)
00461 {
00463         // This makes use of some tricks the Renderer can do so that we do not
00464         // need to do a full redraw every frame - only when some UI element has
00465         // changed.
00466         //
00467         // Since the mouse is likely to move very often, and in order not to
00468         // short-circuit the above optimisation, the mouse is not queued, but is
00469         // drawn directly to the display every frame.
00471         
00472         if (d_gui_redraw)
00473         {
00474                 d_renderer->resetZValue();
00475                 d_renderer->setQueueingEnabled(true);
00476                 d_renderer->clearRenderList();
00477 
00478                 if (d_activeSheet != NULL)
00479                 {
00480                         d_activeSheet->render();
00481                 }
00482 
00483                 d_gui_redraw = false;
00484         }
00485 
00486         d_renderer->doRender();
00487 
00488         // draw mouse
00489         d_renderer->setQueueingEnabled(false);
00490         MouseCursor::getSingleton().draw();
00491 }
00492 
00493 
00494 /*************************************************************************
00495         Set the active GUI sheet (root) window. 
00496 *************************************************************************/
00497 Window* System::setGUISheet(Window* sheet)
00498 {
00499         Window* old = d_activeSheet;
00500         d_activeSheet = sheet;
00501 
00502     // Force and update for the area Rects for 'sheet' so they're correct according
00503     // to the screen size.
00504     if (sheet != 0)
00505     {    
00506         WindowEventArgs sheetargs(0);
00507         sheet->onParentSized(sheetargs);
00508     }
00509     
00510         // fire event
00511         WindowEventArgs args(old);
00512         onGUISheetChanged(args);
00513 
00514         return old;
00515 }
00516 
00517 
00518 /*************************************************************************
00519         Set the default font to be used by the system   
00520 *************************************************************************/
00521 void System::setDefaultFont(const String& name)
00522 {
00523         if (name.empty())
00524         {
00525                 setDefaultFont(NULL);
00526         }
00527         else
00528         {
00529                 setDefaultFont(FontManager::getSingleton().getFont(name));
00530         }
00531 
00532 }
00533 
00534 
00535 /*************************************************************************
00536         Set the default font to be used by the system   
00537 *************************************************************************/
00538 void System::setDefaultFont(Font* font)
00539 {
00540         d_defaultFont = font;
00541         
00542         // fire event
00543         EventArgs args;
00544         onDefaultFontChanged(args);
00545 }
00546 
00547 
00548 /*************************************************************************
00549         Set the image to be used as the default mouse cursor.
00550 *************************************************************************/
00551 void System::setDefaultMouseCursor(const Image* image)
00552 {
00553         if (image == (const Image*)DefaultMouseCursor)
00554         {
00555                 image = NULL;
00556         }
00557 
00558         d_defaultMouseCursor = image;
00559 
00560         // fire off event.
00561         EventArgs args;
00562         onDefaultMouseCursorChanged(args);
00563 }
00564 
00565 
00566 /*************************************************************************
00567         Set the image to be used as the default mouse cursor.
00568 *************************************************************************/
00569 void System::setDefaultMouseCursor(const String& imageset, const String& image_name)
00570 {
00571         setDefaultMouseCursor(&ImagesetManager::getSingleton().getImageset(imageset)->getImage(image_name));
00572 }
00573 
00574 
00575 /*************************************************************************
00576         Return a pointer to the ScriptModule being used for scripting within
00577         the GUI system.
00578 *************************************************************************/
00579 ScriptModule* System::getScriptingModule(void) const
00580 {
00581         return d_scriptModule;
00582 }
00583 
00584 /*************************************************************************
00585         Return a pointer to the ResourceProvider being used for within the GUI 
00586     system.
00587 *************************************************************************/
00588 ResourceProvider* System::getResourceProvider(void) const
00589 {
00590         return d_resourceProvider;
00591 }
00592 
00593 /*************************************************************************
00594         Execute a script file if possible.      
00595 *************************************************************************/
00596 void System::executeScriptFile(const String& filename) const
00597 {
00598         if (d_scriptModule != NULL)
00599         {
00600                 try
00601                 {
00602                         d_scriptModule->executeScriptFile(filename);
00603                 }
00604                 catch(...)
00605                 {
00606                         throw GenericException((utf8*)"System::executeScriptFile - An exception was thrown during the execution of the script file.");
00607                 }
00608 
00609         }
00610         else
00611         {
00612                 Logger::getSingleton().logEvent((utf8*)"System::executeScriptFile - the script named '" + filename +"' could not be executed as no ScriptModule is available.", Errors);
00613         }
00614 
00615 }
00616 
00617 
00618 /*************************************************************************
00619         Execute a scripted global function if possible.  The function should
00620         not take any parameters and should return an integer.
00621 *************************************************************************/
00622 int     System::executeScriptGloabl(const String& function_name) const
00623 {
00624         if (d_scriptModule != NULL)
00625         {
00626                 try
00627                 {
00628                         return d_scriptModule->executeScriptGloabl(function_name);
00629                 }
00630                 catch(...)
00631                 {
00632                         throw GenericException((utf8*)"System::executeScriptGloabl - An exception was thrown during execution of the scripted function.");
00633                 }
00634 
00635         }
00636         else
00637         {
00638                 Logger::getSingleton().logEvent((utf8*)"System::executeScriptGloabl - the global script function named '" + function_name +"' could not be executed as no ScriptModule is available.", Errors);
00639         }
00640 
00641         return 0;
00642 }
00643 
00644 
00645 /*************************************************************************
00646         return the current mouse movement scaling factor.       
00647 *************************************************************************/
00648 float System::getMouseMoveScaling(void) const
00649 {
00650         return d_mouseScalingFactor;
00651 }
00652 
00653 
00654 /*************************************************************************
00655         Set the current mouse movement scaling factor   
00656 *************************************************************************/
00657 void System::setMouseMoveScaling(float scaling)
00658 {
00659         d_mouseScalingFactor = scaling;
00660 
00661         // fire off event.
00662         EventArgs args;
00663         onMouseMoveScalingChanged(args);
00664 }
00665 
00666 
00667 /*************************************************************************
00668         Method that injects a mouse movement event into the system
00669 *************************************************************************/
00670 bool System::injectMouseMove(float delta_x, float delta_y)
00671 {
00672         MouseEventArgs ma(NULL);
00673         MouseCursor& mouse = MouseCursor::getSingleton();
00674 
00675         ma.moveDelta.d_x = delta_x * d_mouseScalingFactor;
00676         ma.moveDelta.d_y = delta_y * d_mouseScalingFactor;
00677         ma.sysKeys = d_sysKeys;
00678         ma.wheelChange = 0;
00679 
00680         // move the mouse cursor & update position in args.
00681         mouse.offsetPosition(ma.moveDelta);
00682         ma.position = mouse.getPosition();
00683 
00684         Window* dest_window = getTargetWindow(ma.position);
00685 
00686         // if there is no GUI sheet, then there is nowhere to send input
00687         if (dest_window != NULL)
00688         {
00689                 if (dest_window != d_wndWithMouse)
00690                 {
00691                         if (d_wndWithMouse != NULL)
00692                         {
00693                                 ma.window = d_wndWithMouse;
00694                                 d_wndWithMouse->onMouseLeaves(ma);
00695                         }
00696 
00697                         d_wndWithMouse = dest_window;
00698                         ma.window = dest_window;
00699                         dest_window->onMouseEnters(ma);
00700                 }
00701 
00702                 // ensure event starts as 'not handled'
00703                 ma.handled = false;
00704 
00705                 // loop backwards until event is handled or we run out of windows.
00706                 while ((!ma.handled) && (dest_window != NULL))
00707                 {
00708                         ma.window = dest_window;
00709                         dest_window->onMouseMove(ma);
00710                         dest_window = dest_window->getParent();
00711                 }
00712 
00713         }
00714 
00715         return ma.handled;
00716 }
00717 
00718 
00719 /*************************************************************************
00720         Method that injects a mouse button down event into the system.
00721 *************************************************************************/
00722 bool System::injectMouseButtonDown(MouseButton button)
00723 {
00724         // update system keys
00725         d_sysKeys |= mouseButtonToSyskey(button);
00726 
00727         MouseEventArgs ma(NULL);
00728         ma.position = MouseCursor::getSingleton().getPosition();
00729         ma.moveDelta = Vector2(0.0f, 0.0f);
00730         ma.button = button;
00731         ma.sysKeys = d_sysKeys;
00732         ma.wheelChange = 0;
00733 
00734         //
00735         // Handling for multi-click generation
00736         //
00737         MouseClickTracker& tkr = d_clickTrackerPimpl->click_trackers[button];
00738 
00739         tkr.d_click_count++;
00740 
00741         // see if we meet multi-click timing
00742         if ((tkr.d_timer.elapsed() > d_dblclick_timeout) ||
00743                 (!tkr.d_click_area.isPointInRect(ma.position)) ||
00744                 (tkr.d_click_count > 3))
00745         {
00746                 // single down event.
00747                 tkr.d_click_count = 1;
00748 
00749                 // build allowable area for multi-clicks
00750                 tkr.d_click_area.setPosition(ma.position);
00751                 tkr.d_click_area.setSize(d_dblclick_size);
00752                 tkr.d_click_area.offset(Point(-(d_dblclick_size.d_width / 2), -(d_dblclick_size.d_height / 2)));
00753         }
00754 
00755         Window* dest_window = getTargetWindow(ma.position);
00756 
00757         // loop backwards until event is handled or we run out of windows.
00758         while ((!ma.handled) && (dest_window != NULL))
00759         {
00760                 ma.window = dest_window;
00761 
00762         if (dest_window->wantsMultiClickEvents())
00763         {
00764             switch (tkr.d_click_count)
00765             {
00766             case 1:
00767                 dest_window->onMouseButtonDown(ma);
00768                 break;
00769 
00770             case 2:
00771                 dest_window->onMouseDoubleClicked(ma);
00772                 break;
00773 
00774             case 3:
00775                 dest_window->onMouseTripleClicked(ma);
00776                 break;
00777             }
00778         }
00779         // current target window does not want multi-clicks,
00780         // so just send a mouse down event instead.
00781         else
00782         {
00783             dest_window->onMouseButtonDown(ma);
00784         }
00785 
00786                 dest_window = dest_window->getParent();
00787         }
00788 
00789         // reset timer for this tracker.
00790         tkr.d_timer.restart();
00791 
00792         return ma.handled;
00793 }
00794 
00795 
00796 /*************************************************************************
00797         Method that injects a mouse button up event into the system.
00798 *************************************************************************/
00799 bool System::injectMouseButtonUp(MouseButton button)
00800 {
00801         // update system keys
00802         d_sysKeys &= ~mouseButtonToSyskey(button);
00803 
00804         MouseEventArgs ma(NULL);
00805         ma.position = MouseCursor::getSingleton().getPosition();
00806         ma.moveDelta = Vector2(0.0f, 0.0f);
00807         ma.button = button;
00808         ma.sysKeys = d_sysKeys;
00809         ma.wheelChange = 0;
00810 
00811         Window* dest_window = getTargetWindow(ma.position);
00812 
00813         // loop backwards until event is handled or we run out of windows.
00814         while ((!ma.handled) && (dest_window != NULL))
00815         {
00816                 ma.window = dest_window;
00817                 dest_window->onMouseButtonUp(ma);
00818                 dest_window = dest_window->getParent();
00819         }
00820 
00821         bool wasUpHandled = ma.handled;
00822 
00823         // check timer for 'button' to see if this up event also constitutes a single 'click'
00824         if (d_clickTrackerPimpl->click_trackers[button].d_timer.elapsed() <= d_click_timeout)
00825         {
00826                 ma.handled = false;
00827                 dest_window = getTargetWindow(ma.position);
00828 
00829                 // loop backwards until event is handled or we run out of windows.
00830                 while ((!ma.handled) && (dest_window != NULL))
00831                 {
00832                         ma.window = dest_window;
00833                         dest_window->onMouseClicked(ma);
00834                         dest_window = dest_window->getParent();
00835                 }
00836 
00837         }
00838 
00839         return (ma.handled | wasUpHandled);
00840 }
00841 
00842 
00843 /*************************************************************************
00844         Method that injects a key down event into the system.
00845 *************************************************************************/
00846 bool System::injectKeyDown(uint key_code)
00847 {
00848         // update system keys
00849         d_sysKeys |= keyCodeToSyskey((Key::Scan)key_code, true);
00850 
00851         KeyEventArgs args(NULL);
00852 
00853         if (d_activeSheet != NULL)
00854         {
00855                 args.scancode = (Key::Scan)key_code;
00856                 args.sysKeys = d_sysKeys;
00857 
00858                 Window* dest = d_activeSheet->getActiveChild();
00859 
00860                 // loop backwards until event is handled or we run out of windows.
00861                 while ((dest != NULL) && (!args.handled))
00862                 {
00863                         args.window = dest;
00864                         dest->onKeyDown(args);
00865                         dest = dest->getParent();
00866                 }
00867 
00868         }
00869 
00870         return args.handled;
00871 }
00872 
00873 
00874 /*************************************************************************
00875         Method that injects a key up event into the system.
00876 *************************************************************************/
00877 bool System::injectKeyUp(uint key_code)
00878 {
00879         // update system keys
00880         d_sysKeys &= ~keyCodeToSyskey((Key::Scan)key_code, false);
00881 
00882         KeyEventArgs args(NULL);
00883 
00884         if (d_activeSheet != NULL)
00885         {
00886                 args.scancode = (Key::Scan)key_code;
00887                 args.sysKeys = d_sysKeys;
00888 
00889                 Window* dest = d_activeSheet->getActiveChild();
00890 
00891                 // loop backwards until event is handled or we run out of windows.
00892                 while ((dest != NULL) && (!args.handled))
00893                 {
00894                         args.window = dest;
00895                         dest->onKeyUp(args);
00896                         dest = dest->getParent();
00897                 }
00898 
00899         }
00900 
00901         return args.handled;
00902 }
00903 
00904 
00905 /*************************************************************************
00906         Method that injects a typed character event into the system.    
00907 *************************************************************************/
00908 bool System::injectChar(utf32 code_point)
00909 {
00910         KeyEventArgs args(NULL);
00911 
00912         if (d_activeSheet != NULL)
00913         {
00914                 args.codepoint = code_point;
00915                 args.sysKeys = d_sysKeys;
00916 
00917                 Window* dest = d_activeSheet->getActiveChild();
00918 
00919                 // loop backwards until event is handled or we run out of windows.
00920                 while ((dest != NULL) && (!args.handled))
00921                 {
00922                         args.window = dest;
00923                         dest->onCharacter(args);
00924                         dest = dest->getParent();
00925                 }
00926                 
00927         }
00928 
00929         return args.handled;
00930 }
00931 
00932 
00933 /*************************************************************************
00934         Method that injects a mouse-wheel / scroll-wheel event into the system. 
00935 *************************************************************************/
00936 bool System::injectMouseWheelChange(float delta)
00937 {
00938         MouseEventArgs ma(NULL);
00939         ma.position = MouseCursor::getSingleton().getPosition();
00940         ma.moveDelta = Vector2(0.0f, 0.0f);
00941         ma.button = NoButton;
00942         ma.sysKeys = d_sysKeys;
00943         ma.wheelChange = delta;
00944 
00945         Window* dest_window = getTargetWindow(ma.position);
00946 
00947         // loop backwards until event is handled or we run out of windows.
00948         while ((!ma.handled) && (dest_window != NULL))
00949         {
00950                 ma.window = dest_window;
00951                 dest_window->onMouseWheel(ma);
00952                 dest_window = dest_window->getParent();
00953         }
00954 
00955         return ma.handled;
00956 }
00957 
00958 
00959 /*************************************************************************
00960         Method that injects a new position for the mouse cursor.
00961 *************************************************************************/
00962 bool System::injectMousePosition(float x_pos, float y_pos)
00963 {
00964         // set new mouse position
00965         MouseCursor::getSingleton().setPosition(Point(x_pos, y_pos));
00966 
00967         // do the real work
00968         return injectMouseMove(0, 0);
00969 }
00970 
00971 
00972 /*************************************************************************
00973         Method to inject time pulses into the system.   
00974 *************************************************************************/
00975 bool System::injectTimePulse(float timeElapsed)
00976 {
00977         if (d_activeSheet != NULL)
00978         {
00979                 d_activeSheet->update(timeElapsed);
00980         }
00981 
00982         return true;
00983 }
00984 
00985 
00986 /*************************************************************************
00987         Return window that should get mouse inouts when mouse it at 'pt'
00988 *************************************************************************/
00989 Window* System::getTargetWindow(const Point& pt) const
00990 {
00991         Window* dest_window = NULL;
00992 
00993         // if there is no GUI sheet, then there is nowhere to send input
00994         if (d_activeSheet != NULL)
00995         {
00996                 dest_window = Window::getCaptureWindow();
00997 
00998                 if (dest_window == NULL)
00999                 {
01000                         dest_window = d_activeSheet->getChildAtPosition(pt);
01001 
01002                         if (dest_window == NULL)
01003                         {
01004                                 dest_window = d_activeSheet;
01005                         }
01006 
01007                 }
01008                 else
01009                 {
01010                         Window* child_window = dest_window->getChildAtPosition(pt);
01011 
01012                         if (child_window != NULL)
01013                         {
01014                                 dest_window = child_window;
01015                         }
01016 
01017                 }
01018 
01019         }
01020 
01021         return dest_window;
01022 }
01023 
01024 
01025 /*************************************************************************
01026         Translate a MouseButton value into the corresponding SystemKey value    
01027 *************************************************************************/
01028 SystemKey System::mouseButtonToSyskey(MouseButton btn) const
01029 {
01030         switch (btn)
01031         {
01032         case LeftButton:
01033                 return LeftMouse;
01034 
01035         case RightButton:
01036                 return RightMouse;
01037 
01038         case MiddleButton:
01039                 return MiddleMouse;
01040 
01041         case X1Button:
01042                 return X1Mouse;
01043 
01044         case X2Button:
01045                 return X2Mouse;
01046 
01047         default:
01048                 throw InvalidRequestException((utf8*)"System::mouseButtonToSyskey - the parameter 'btn' is not a valid MouseButton value.");
01049         }
01050 }
01051 
01052 
01053 /*************************************************************************
01054         Translate a Key::Scan value into the corresponding SystemKey value      
01055 *************************************************************************/
01056 SystemKey System::keyCodeToSyskey(Key::Scan key, bool direction)
01057 {
01058         switch (key)
01059         {
01060         case Key::LeftShift:
01061                 d_lshift = direction;
01062 
01063                 if (!d_rshift)
01064                 {
01065                         return Shift;
01066                 }
01067                 break;
01068 
01069         case Key::RightShift:
01070                 d_rshift = direction;
01071 
01072                 if (!d_lshift)
01073                 {
01074                         return Shift;
01075                 }
01076                 break;
01077 
01078 
01079         case Key::LeftControl:
01080                 d_lctrl = direction;
01081 
01082                 if (!d_rctrl)
01083                 {
01084                         return Control;
01085                 }
01086                 break;
01087 
01088         case Key::RightControl:
01089                 d_rctrl = direction;
01090 
01091                 if (!d_lctrl)
01092                 {
01093                         return Control;
01094                 }
01095                 break;
01096 
01097     default:
01098         break;
01099         }
01100 
01101         // if not a system key or overall state unchanged, return 0.
01102         return (SystemKey)0;
01103 }
01104 
01105 
01106 System& System::getSingleton(void)
01107 {
01108         return Singleton<System>::getSingleton();
01109 }
01110 
01111 
01112 System* System::getSingletonPtr(void)
01113 {
01114         return Singleton<System>::getSingletonPtr();
01115 }
01116 
01117 
01118 
01119 /*************************************************************************
01120         Set the timeout to be used for the generation of single-click events.   
01121 *************************************************************************/
01122 void System::setSingleClickTimeout(double timeout)
01123 {
01124         d_click_timeout = timeout;
01125 
01126         // fire off event.
01127         EventArgs args;
01128         onSingleClickTimeoutChanged(args);
01129 }
01130 
01131 
01132 /*************************************************************************
01133         Set the timeout to be used for the generation of multi-click events.    
01134 *************************************************************************/
01135 void System::setMultiClickTimeout(double timeout)
01136 {
01137         d_dblclick_timeout = timeout;
01138 
01139         // fire off event.
01140         EventArgs args;
01141         onMultiClickTimeoutChanged(args);
01142 }
01143 
01144 
01145 /*************************************************************************
01146         Set the size of the allowable mouse movement tolerance used when
01147         generating multi-click events.  
01148 *************************************************************************/
01149 void System::setMultiClickToleranceAreaSize(const Size& sz)
01150 {
01151         d_dblclick_size = sz;
01152 
01153         // fire off event.
01154         EventArgs args;
01155         onMultiClickAreaSizeChanged(args);
01156 }
01157 
01158 
01159 /*************************************************************************
01160         add events for the System object        
01161 *************************************************************************/
01162 void System::addSystemEvents(void)
01163 {
01164         addEvent(EventGUISheetChanged);
01165         addEvent(EventSingleClickTimeoutChanged);
01166         addEvent(EventMultiClickTimeoutChanged);
01167         addEvent(EventMultiClickAreaSizeChanged);
01168         addEvent(EventDefaultFontChanged);
01169         addEvent(EventDefaultMouseCursorChanged);
01170         addEvent(EventMouseMoveScalingChanged);
01171 }
01172 
01173 
01174 /*************************************************************************
01175         Handler called when the main system GUI Sheet (or root window) is changed
01176 *************************************************************************/
01177 void System::onGUISheetChanged(WindowEventArgs& e)
01178 {
01179         fireEvent(EventGUISheetChanged, e, EventNamespace);
01180 }
01181 
01182 
01183 /*************************************************************************
01184         Handler called when the single-click timeout value is changed.
01185 *************************************************************************/
01186 void System::onSingleClickTimeoutChanged(EventArgs& e)
01187 {
01188         fireEvent(EventSingleClickTimeoutChanged, e, EventNamespace);
01189 }
01190 
01191 
01192 /*************************************************************************
01193         Handler called when the multi-click timeout value is changed.
01194 *************************************************************************/
01195 void System::onMultiClickTimeoutChanged(EventArgs& e)
01196 {
01197         fireEvent(EventMultiClickTimeoutChanged, e, EventNamespace);
01198 }
01199 
01200 
01201 /*************************************************************************
01202         Handler called when the size of the multi-click tolerance area is
01203         changed.
01204 *************************************************************************/
01205 void System::onMultiClickAreaSizeChanged(EventArgs& e)
01206 {
01207         fireEvent(EventMultiClickAreaSizeChanged, e, EventNamespace);
01208 }
01209 
01210 
01211 /*************************************************************************
01212         Handler called when the default system font is changed. 
01213 *************************************************************************/
01214 void System::onDefaultFontChanged(EventArgs& e)
01215 {
01216         fireEvent(EventDefaultFontChanged, e, EventNamespace);
01217 }
01218 
01219 
01220 /*************************************************************************
01221         Handler called when the default system mouse cursor image is changed.   
01222 *************************************************************************/
01223 void System::onDefaultMouseCursorChanged(EventArgs& e)
01224 {
01225         fireEvent(EventDefaultMouseCursorChanged, e, EventNamespace);
01226 }
01227 
01228 
01229 /*************************************************************************
01230         Handler called when the mouse movement scaling factor is changed.       
01231 *************************************************************************/
01232 void System::onMouseMoveScalingChanged(EventArgs& e)
01233 {
01234         fireEvent(EventMouseMoveScalingChanged, e, EventNamespace);
01235 }
01236 
01237 
01238 /*************************************************************************
01239         Handler method for display size change notifications
01240 *************************************************************************/
01241 bool System::handleDisplaySizeChange(const EventArgs& e)
01242 {
01243         // notify gui sheet / root if size change, event propagation will ensure everything else
01244         // gets updated as required.
01245         if (d_activeSheet != NULL)
01246         {
01247                 WindowEventArgs args(NULL);
01248                 d_activeSheet->onParentSized(args);
01249         }
01250 
01251         return true;
01252 }
01253 
01254 
01255 /*************************************************************************
01256         Internal method used to inform the System object whenever a window is
01257         destroyed, so that System can perform any required housekeeping.
01258 *************************************************************************/
01259 void System::notifyWindowDestroyed(const Window* window)
01260 {
01261         if (d_wndWithMouse == window)
01262         {
01263                 d_wndWithMouse = NULL;
01264         }
01265 
01266         if (d_activeSheet == window)
01267         {
01268                 d_activeSheet = NULL;
01269         }
01270 
01271 }
01272 
01273 } // End of  CEGUI namespace section

Generated on Wed Feb 16 12:41:07 2005 for Crazy Eddies GUI System by  doxygen 1.3.9.1