Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/cpp11_v2/src/libraries/core/GUIManager.cc @ 11000

Last change on this file since 11000 was 10845, checked in by landauf, 9 years ago

always use 'virtual' in the declaration of virtual functions even if they are inherited

  • Property svn:eol-style set to native
File size: 33.4 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Reto Grieder
24 *      Benjamin Knecht
25 *   Co-authors:
26 *      ...
27 *
28 */
29
30#include "GUIManager.h"
31
32#include <fstream>
33#include <memory>
34#include <functional>
35#include <OgreRenderQueue.h>
36#include <OgreRenderWindow.h>
37
38#if CEGUI_VERSION >= 0x000800
39#   include <CEGUI/DefaultLogger.h>
40#   include <CEGUI/Exceptions.h>
41#   include <CEGUI/FontManager.h>
42#   include <CEGUI/InputEvent.h>
43#   include <CEGUI/MouseCursor.h>
44#   include <CEGUI/ResourceProvider.h>
45#   include <CEGUI/System.h>
46#   include <CEGUI/Window.h>
47#   include <CEGUI/WindowManager.h>
48#   include <CEGUI/XMLAttributes.h>
49#   include <CEGUI/widgets/Listbox.h>
50#   include <CEGUI/widgets/ListboxItem.h>
51#else
52#   include <CEGUIDefaultLogger.h>
53#   include <CEGUIExceptions.h>
54#   include <CEGUIFontManager.h>
55#   include <CEGUIInputEvent.h>
56#   include <CEGUIMouseCursor.h>
57#   include <CEGUIResourceProvider.h>
58#   include <CEGUISystem.h>
59#   include <CEGUIWindow.h>
60#   include <CEGUIWindowManager.h>
61#   include <CEGUIXMLAttributes.h>
62#   include <elements/CEGUIListbox.h>
63#   include <elements/CEGUIListboxItem.h>
64#endif
65
66#ifdef ORXONOX_OLD_CEGUI
67#   include <CEGUILua.h>
68#   include <ogreceguirenderer/OgreCEGUIRenderer.h>
69extern "C" {
70#   include <lauxlib.h>
71}
72#else
73#   if CEGUI_VERSION >= 0x000800
74#       include <CEGUI/ScriptModules/Lua/ScriptModule.h>
75#       include <CEGUI/RendererModules/Ogre/ImageCodec.h>
76#       include <CEGUI/RendererModules/Ogre/Renderer.h>
77#       include <CEGUI/RendererModules/Ogre/ResourceProvider.h>
78#   else
79#       include <ScriptingModules/LuaScriptModule/CEGUILua.h>
80#       include <RendererModules/Ogre/CEGUIOgreImageCodec.h>
81#       include <RendererModules/Ogre/CEGUIOgreRenderer.h>
82#       include <RendererModules/Ogre/CEGUIOgreResourceProvider.h>
83#   endif
84#   include <OgreCamera.h>
85#   include <OgreRenderQueueListener.h>
86#   include <OgreRenderSystem.h>
87#   include <OgreRoot.h>
88#   include <OgreSceneManager.h>
89#endif
90
91#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(ORXONOX_COMPILER_MINGW)
92#  include <windows.h>
93#endif
94
95#include "util/Clock.h"
96#include "util/Convert.h"
97#include "util/Output.h"
98#include "util/Exception.h"
99#include "util/Math.h"
100#include "util/OrxAssert.h"
101#include "util/output/BaseWriter.h"
102#include "config/ConfigValueIncludes.h"
103#include "Core.h"
104#include "CoreIncludes.h"
105#include "Game.h"
106#include "GraphicsManager.h"
107#include "LuaState.h"
108#include "ConfigurablePaths.h"
109#include "Resource.h"
110#include "command/ConsoleCommandIncludes.h"
111#include "input/InputManager.h"
112#include "input/InputState.h"
113#include "input/KeyBinderManager.h"
114
115namespace orxonox
116{
117    namespace arg = std::placeholders;
118
119    static void key_esc()
120        { GUIManager::getInstance().keyESC(); }
121    SetConsoleCommand("keyESC", &key_esc);
122
123    class CEGUILogger : public CEGUI::DefaultLogger
124    {
125    public:
126        virtual void logEvent(const CEGUI::String& message, CEGUI::LoggingLevel level = CEGUI::Standard) override
127        {
128            OutputLevel orxonoxLevel = level::debug_output;
129            switch (level)
130            {
131                case CEGUI::Errors:      orxonoxLevel = level::internal_error; break;
132                case CEGUI::Warnings:    orxonoxLevel = level::internal_warning; break;
133                case CEGUI::Standard:    orxonoxLevel = level::verbose; break;
134                case CEGUI::Informative: orxonoxLevel = level::verbose_more; break;
135                case CEGUI::Insane:      orxonoxLevel = level::verbose_ultra; break;
136                default: OrxAssert(false, "CEGUI log level out of range, inspect immediately!");
137            }
138
139            orxout(orxonoxLevel, context::cegui) << message << endl;
140
141            CEGUI::DefaultLogger::logEvent(message, level);
142        }
143
144        /// Carbon copy from CEGUIDefaultLogger.cpp with a bugfix for Windows
145        virtual void setLogFilename(const CEGUI::String& filename, bool append = false) override
146        {
147            // Close current log file (if any)
148            if (d_ostream.is_open())
149                d_ostream.close();
150
151#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(ORXONOX_COMPILER_MINGW)
152            // filename.c_str() is UTF-8 encoded, but Windows expects characters
153            // according to the current codepage or UTF-16 (wchar)
154            d_ostream.open(utf8ToUtf16(filename.c_str()).c_str(), std::ios_base::out | (append ? std::ios_base::app : std::ios_base::trunc));
155#else
156            d_ostream.open(filename.c_str(), std::ios_base::out | (append ? std::ios_base::app : std::ios_base::trunc));
157#endif
158            if (!d_ostream)
159                ThrowException(General, "Setting the CEGUI log filename failed");
160
161            // Initialise width for date & time alignment.
162            d_ostream.width(2);
163
164            // Write out cached log strings.
165            if (d_caching)
166            {
167                d_caching = false;
168
169                std::vector<std::pair<CEGUI::String, CEGUI::LoggingLevel>>::iterator it = d_cache.begin();
170
171                while (it != d_cache.end())
172                {
173                    if (d_level >= it->second)
174                    {
175                        d_ostream << it->first;
176                        // Ensure new event is written to the file, rather than just being buffered.
177                        d_ostream.flush();
178                    }
179                    ++it;
180                }
181
182                d_cache.clear();
183            }
184        }
185
186#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(ORXONOX_COMPILER_MINGW)
187        /// Converts a UTF-8 character sequence to Windows UTF-16
188        static std::wstring utf8ToUtf16(const std::string& utf8text)
189        {
190            const int textLen = MultiByteToWideChar(CP_UTF8, 0, utf8text.c_str(),
191                utf8text.size() + 1, 0, 0);
192
193            if (textLen == 0)
194                ThrowException(General, "Utf8ToUtf16 - MultiByteToWideChar failed");
195
196            std::wstring wideStr(textLen, 0);
197            MultiByteToWideChar(CP_UTF8, 0, utf8text.c_str(), utf8text.size() + 1,
198                &wideStr[0], wideStr.size());
199            return wideStr;
200        }
201#endif
202    };
203
204#ifdef ORXONOX_OLD_CEGUI
205    /** Class with the same memory layout as CEGUI::LuaScriptModule. <br>
206        We need this to fix a problem with an uninitialised member variable
207        in CEGUI < 0.7 <br>
208        Notice the "public" modifier for the otherwise private variables.
209    */
210    class LuaScriptModuleWorkaround : public CEGUI::ScriptModule
211    {
212    public:
213        LuaScriptModuleWorkaround();
214        ~LuaScriptModuleWorkaround();
215
216    public:
217        bool d_ownsState;
218        lua_State* d_state;
219        CEGUI::String d_errFuncName;
220        int d_errFuncIndex;
221        CEGUI::String d_activeErrFuncName;
222        int d_activeErrFuncIndex;
223    };
224#else
225    /// RenderQueueListener based class used to hook into the ogre rendering system
226    class RQListener : public Ogre::RenderQueueListener
227    {
228    public:
229        /// Callback from Ogre invoked before other stuff in our target queue is rendered
230        virtual void renderQueueStarted(Ogre::uint8 id, const Ogre::String& invocation, bool& skipThisQueue) override
231        {
232            if (id == Ogre::RENDER_QUEUE_OVERLAY && invocation.empty())
233            {
234#if CEGUI_VERSION >= 0x000800
235                CEGUI::System::getSingleton().renderAllGUIContexts();
236#else
237                CEGUI::System::getSingleton().renderGUI();
238#endif
239
240                // Important workaround! (at least required by CEGUI 0.7.5)
241                // If we don't reset the scissor test, OGRE will only render overlays
242                // in the area where CEGUI last drew, which is usually nothing
243                // or a little box where the focused element is.
244                Ogre::Root::getSingleton().getRenderSystem()->setScissorTest(false);
245            }
246        }
247    };
248#endif
249
250    static CEGUI::MouseButton convertButton(MouseButtonCode::ByEnum button);
251
252    GUIManager* GUIManager::singletonPtr_s = nullptr;
253    /*static*/ const std::string GUIManager::defaultScheme_ = "TaharezGreen"; //Alternative: Orxonox (not fully complete yet, see the graphics menu)
254
255    SetConsoleCommand("showGUI", &GUIManager::showGUI).defaultValue(1, false).defaultValue(2, false);
256    SetConsoleCommand("hideGUI", &GUIManager::hideGUI);
257    SetConsoleCommand("toggleGUI", &GUIManager::toggleGUI).defaultValue(1, false).defaultValue(2, false);
258
259    RegisterAbstractClass(GUIManager).inheritsFrom<WindowEventListener>();
260
261    /**
262    @brief
263        Constructs the GUIManager by starting up CEGUI
264
265        Creates the interface to Ogre, sets up the CEGUI renderer and the Lua script module together with the Lua engine.
266        The log is set up and connected to the CEGUILogger.
267        After Lua setup tolua++-elements are linked to Lua-state to give Lua access to C++-code.
268        Finally initial Lua code is executed (maybe we can do this with the CEGUI startup script automatically).
269    @return true if success, otherwise false
270    */
271    GUIManager::GUIManager(const std::pair<int, int>& mousePosition)
272        : guiRenderer_(nullptr)
273        , resourceProvider_(nullptr)
274#ifndef ORXONOX_OLD_CEGUI
275        , rqListener_(nullptr)
276        , imageCodec_(nullptr)
277#endif
278        , luaState_(nullptr)
279        , scriptModule_(nullptr)
280        , guiSystem_(nullptr)
281        , ceguiLogger_(nullptr)
282        , rootWindow_(nullptr)
283        , hudRootWindow_(nullptr)
284        , menuRootWindow_(nullptr)
285        , camera_(nullptr)
286        , destructionHelper_(this)
287    {
288        RegisterObject(GUIManager);
289
290        orxout(internal_status) << "initializing GUIManager..." << endl;
291
292        this->setConfigValues();
293
294        using namespace CEGUI;
295
296        orxout(internal_info) << "Initialising CEGUI." << endl;
297
298        this->oldCEGUI_ = false;
299
300        // Note: No SceneManager specified yet
301#ifdef ORXONOX_OLD_CEGUI
302        guiRenderer_ = new OgreCEGUIRenderer(GraphicsManager::getInstance().getRenderWindow(), Ogre::RENDER_QUEUE_OVERLAY, false, 3000);
303        resourceProvider_ = guiRenderer_->createResourceProvider();
304        this->oldCEGUI_ = true;
305#else
306        guiRenderer_ = &OgreRenderer::create(*GraphicsManager::getInstance().getRenderWindow());
307        // We use our own RenderQueueListener so we can draw UNDER overlays
308        guiRenderer_->setFrameControlExecutionEnabled(false);
309        rqListener_ = new RQListener();
310        resourceProvider_ = &OgreRenderer::createOgreResourceProvider();
311        imageCodec_ = &OgreRenderer::createOgreImageCodec();
312#endif
313        resourceProvider_->setDefaultResourceGroup("General");
314
315        // Setup scripting
316        luaState_ = new LuaState();
317        rootFileInfo_ = Resource::getInfo("InitialiseGUI.lua");
318        // This is necessary to ensure that input events also use the right resource info when triggering lua functions
319        luaState_->setDefaultResourceInfo(this->rootFileInfo_);
320#ifdef ORXONOX_OLD_CEGUI
321        scriptModule_ = new LuaScriptModule(luaState_->getInternalLuaState());
322        // Ugly workaround: older CEGUILua versions don't initialise the member
323        // d_activeErrFuncIndex at all. That leads to "error in error handling"
324        // problems when a Lua error occurs.
325        // We fix this by setting the member manually.
326        reinterpret_cast<LuaScriptModuleWorkaround*>(scriptModule_)->d_activeErrFuncIndex = LUA_NOREF;
327        luaState_->doString("ORXONOX_OLD_CEGUI = true");
328#else
329        scriptModule_ = &LuaScriptModule::create(luaState_->getInternalLuaState());
330#endif
331        scriptModule_->setDefaultPCallErrorHandler(LuaState::ERROR_HANDLER_NAME);
332
333        // Create our own logger to specify the filepath
334        std::unique_ptr<CEGUILogger> ceguiLogger(new CEGUILogger());
335        ceguiLogger->setLogFilename(ConfigurablePaths::getLogPathString() + "cegui.log");
336        ceguiLogger->setLoggingLevel(static_cast<CEGUI::LoggingLevel>(this->outputLevelCeguiLog_));
337        this->ceguiLogger_ = ceguiLogger.release();
338
339        // Create the CEGUI system singleton
340#ifdef ORXONOX_OLD_CEGUI
341        guiSystem_ = new System(guiRenderer_, resourceProvider_, nullptr, scriptModule_);
342        // Add functions that have been renamed in newer versions
343        luaState_->doString("CEGUI.SchemeManager.create = CEGUI.SchemeManager.loadScheme");
344        luaState_->doString("CEGUI.Window.getUnclippedOuterRect = CEGUI.Window.getUnclippedPixelRect");
345        luaState_->doString("CEGUI.ImagesetManager.createFromImageFile= CEGUI.ImagesetManager.createImagesetFromImageFile");
346#else
347        guiSystem_ = &System::create(*guiRenderer_, resourceProvider_, nullptr, imageCodec_, scriptModule_);
348#endif
349
350        CEGUI::String defaultXMLParserName = CEGUI::System::getSingleton().getDefaultXMLParserName();
351        try
352        {
353            // Force Xerces parser (CEGUI 0.7.5+)
354            CEGUI::System::getSingleton().setXMLParser("XercesParser");
355        }
356        catch (const CEGUI::GenericException&)
357        {
358            // Fall back to default parser
359            orxout(internal_warning) << "Cannot use XercesParser for CEGUI - using " << defaultXMLParserName << " instead" << endl;
360            CEGUI::System::getSingleton().setXMLParser(defaultXMLParserName);
361        }
362
363        // Align CEGUI mouse with OIS mouse
364#if CEGUI_VERSION >= 0x000800
365        guiSystem_->getDefaultGUIContext().injectMousePosition((float)mousePosition.first, (float)mousePosition.second);
366#else
367        guiSystem_->injectMousePosition((float)mousePosition.first, (float)mousePosition.second);
368#endif
369
370        // Initialise the Lua framework and load the schemes
371        orxout(user_info) << "Loading user interface..." << endl;
372        this->luaState_->doFile("InitialiseGUI.lua");
373
374        // Create the root nodes
375        this->rootWindow_ = CEGUI::WindowManager::getSingleton().createWindow("MenuWidgets/StaticImage", "AbsoluteRootWindow");
376        this->rootWindow_->setProperty("FrameEnabled", "False");
377        this->hudRootWindow_ = CEGUI::WindowManager::getSingleton().createWindow("DefaultWindow", "HUDRootWindow");
378        this->menuRootWindow_ = CEGUI::WindowManager::getSingleton().createWindow("DefaultWindow", "MenuRootWindow");
379        // And connect them
380#if CEGUI_VERSION >= 0x000800
381        CEGUI::System::getSingleton().getDefaultGUIContext().setRootWindow(this->rootWindow_);
382        this->rootWindow_->addChild(this->hudRootWindow_);
383        this->rootWindow_->addChild(this->menuRootWindow_);
384#else
385        CEGUI::System::getSingleton().setGUISheet(this->rootWindow_);
386        this->rootWindow_->addChildWindow(this->hudRootWindow_);
387        this->rootWindow_->addChildWindow(this->menuRootWindow_);
388#endif
389
390        // No background to start with (sets the alpha value to 0)
391        this->setBackgroundImage("");
392
393        // Set up the sheet manager in the Lua framework
394        this->luaState_->doFile("SheetManager.lua");
395
396        orxout(internal_status) << "finished initializing GUIManager" << endl;
397    }
398
399    void GUIManager::destroy()
400    {
401        orxout(internal_status) << "destroying GUIManager..." << endl;
402
403        using namespace CEGUI;
404
405#ifdef ORXONOX_OLD_CEGUI
406        safeObjectDelete(&guiSystem_);
407        safeObjectDelete(&guiRenderer_);
408        safeObjectDelete(&scriptModule_);
409#else
410        System::destroy();
411        OgreRenderer::destroyOgreResourceProvider(*resourceProvider_);
412        OgreRenderer::destroyOgreImageCodec(*imageCodec_);
413        OgreRenderer::destroy(*guiRenderer_);
414        LuaScriptModule::destroy(*scriptModule_);
415        safeObjectDelete(&ceguiLogger_);
416        safeObjectDelete(&rqListener_);
417#endif
418        safeObjectDelete(&luaState_);
419
420        orxout(internal_status) << "finished destroying GUIManager" << endl;
421    }
422
423    void GUIManager::setConfigValues(void)
424    {
425        SetConfigValue(guiScheme_, GUIManager::defaultScheme_).description("Changes the current GUI scheme.").callback(this, &GUIManager::changedGUIScheme);
426        SetConfigValue(numScrollLines_, 1).description("How many lines to scroll in a list if the scroll wheel is used");
427        SetConfigValue(bPreloadMenuSheets_, false).description("Pre-load menu sheets during startup");
428
429        SetConfigValueExternal(outputLevelCeguiLog_, BaseWriter::getConfigurableSectionName(), "outputLevelCeguiLog", CEGUI::Standard).description("The log level of the CEGUI log file").callback(this, &GUIManager::changedCeguiOutputLevel);
430    }
431
432    void GUIManager::changedGUIScheme(void)
433    {
434    }
435
436    void GUIManager::changedCeguiOutputLevel()
437    {
438        if (this->ceguiLogger_)
439            this->ceguiLogger_->setLoggingLevel(static_cast<CEGUI::LoggingLevel>(this->outputLevelCeguiLog_));
440    }
441
442    /**
443    @brief
444        used to tick the GUI
445    @param time
446        clock which provides time value for the GUI System
447
448        Ticking the GUI means updating it with a certain regularity.
449        The elapsed time since the last call is given in the time value provided by the clock.
450        This time value is then used to provide a fluent animation of the GUI.
451    */
452    void GUIManager::preUpdate(const Clock& time)
453    {
454        assert(guiSystem_);
455        this->protectedCeguiSystemCall(std::bind(&CEGUI::System::injectTimePulse, arg::_1, time.getDeltaTime()));
456    }
457
458    /**
459    @brief
460        Tells the GUIManager which SceneManager to use
461    @param camera
462        The current camera on which the GUI should be displayed on.
463
464        In fact the GUIManager needs the SceneManager and not the Camera to display the GUI.
465        This means the GUI is not bound to a camera but rather to the SceneManager.
466        Hiding the GUI when needed can therefore not be resolved by just NOT setting the current camera.
467    */
468    void GUIManager::setCamera(Ogre::Camera* camera)
469    {
470#ifdef ORXONOX_OLD_CEGUI
471        if (camera == nullptr)
472            this->guiRenderer_->setTargetSceneManager(nullptr);
473        else
474            this->guiRenderer_->setTargetSceneManager(camera->getSceneManager());
475#else
476        if (camera_ != nullptr && camera_->getSceneManager() != nullptr)
477            camera_->getSceneManager()->removeRenderQueueListener(rqListener_);
478        if (camera != nullptr && camera->getSceneManager() != nullptr)
479            camera->getSceneManager()->addRenderQueueListener(rqListener_);
480#endif
481        this->camera_ = camera;
482    }
483
484    /**
485    @brief
486        Executes Lua code
487    @param str
488        reference to string object holding the Lua code which is to be executed
489    */
490    void GUIManager::executeCode(const std::string& str)
491    {
492        this->luaState_->doString(str, rootFileInfo_);
493    }
494
495    /** Loads a GUI sheet by Lua script
496    @param name
497        The name of the GUI (like the script name, but without the extension)
498    */
499    void GUIManager::loadGUI(const std::string& name)
500    {
501        this->executeCode("loadSheet(\"" + name + "\")");
502    }
503
504    /**
505    @brief
506        Displays specified GUI on screen
507    @param name
508        The name of the GUI
509    @param bHidePrevious
510        If true all displayed GUIs on the stack, that are below this GUI are hidden.
511    @param bNoInput
512        If true the GUI is transparent to input.
513
514        The function executes the Lua function with the same name in case the GUIManager is ready.
515    */
516    /*static*/ void GUIManager::showGUI(const std::string& name, bool bHidePrevious, bool bNoInput)
517    {
518        GUIManager::getInstance().executeCode("showMenuSheet(\"" + name + "\", " + multi_cast<std::string>(bHidePrevious) + ", " + multi_cast<std::string>(bNoInput) + ")");
519    }
520
521    /**
522    @brief
523        Hack-ish. Needed for GUIOverlay.
524    */
525    void GUIManager::showGUIExtra(const std::string& name, const std::string& ptr, bool bHidePrevious, bool bNoInput)
526    {
527        this->executeCode("showMenuSheet(\"" + name + "\", " + multi_cast<std::string>(bHidePrevious) + ", " + multi_cast<std::string>(bNoInput) + ", " + ptr + ")");
528    }
529
530    /**
531    @brief
532        Hides specified GUI.
533    @param name
534        The name of the GUI.
535    */
536    /*static*/ void GUIManager::hideGUI(const std::string& name)
537    {
538        GUIManager::getInstance().executeCode("hideMenuSheet(\"" + name + "\")");
539    }
540
541    /**
542    @brief
543        Toggles specified GUI.
544        If the GUI with the input name is already shown and on the top, it is hidden, else it is shown.
545    */
546    /*static*/ void GUIManager::toggleGUI(const std::string& name, bool bHidePrevious, bool bNoInput)
547    {
548        GUIManager::getInstance().executeCode("getGUIFirstActive(\"" + name + "\", " + multi_cast<std::string>(bHidePrevious) + ", " + multi_cast<std::string>(bNoInput) + ")");
549    }
550
551    /**
552    @brief
553        Helper method to toggle a specified GUI.
554        Is called by lua.
555    */
556    void GUIManager::toggleGUIHelper(const std::string& name, bool bHidePrevious, bool bNoInput, bool show)
557    {
558        if(show)
559            GUIManager::showGUI(name, bHidePrevious, bNoInput);
560        else
561            GUIManager::hideGUI(name);
562    }
563
564    const std::string& GUIManager::createInputState(const std::string& name, tribool showCursor, tribool useKeyboard, bool bBlockJoyStick)
565    {
566        InputState* state = InputManager::getInstance().createInputState(name);
567        if (!state)
568            return BLANKSTRING;
569
570        /* Table that maps isFullScreen() and showCursor to mouseExclusive
571        isFullscreen / showCursor | True  | False | Dontcare
572        ----------------------------------------------------
573        true                      | True  | True  | Dontcare
574        ----------------------------------------------------
575        false                     | False | True  | Dontcare
576        */
577
578#ifdef ORXONOX_PLATFORM_APPLE
579        // There is no non exclusive mode on OS X yet
580        state->setMouseExclusive(true);
581#else
582        if (showCursor == dontcare)
583            state->setMouseExclusive(dontcare);
584        else if (GraphicsManager::getInstance().isFullScreen() || showCursor == false)
585            state->setMouseExclusive(true);
586        else
587            state->setMouseExclusive(false);
588#endif
589
590        if (showCursor == true)
591            state->setMouseHandler(this);
592        else if (showCursor == false)
593            state->setMouseHandler(&InputHandler::EMPTY);
594
595        if (useKeyboard == true)
596            state->setKeyHandler(this);
597        else if (useKeyboard == false)
598            state->setKeyHandler(&InputHandler::EMPTY);
599
600        if (bBlockJoyStick)
601            state->setJoyStickHandler(&InputHandler::EMPTY);
602
603        return state->getName();
604    }
605
606    void GUIManager::keyESC()
607    {
608        this->executeCode("keyESC()");
609    }
610
611    void GUIManager::setBackgroundImage(const std::string& imageSet, const std::string imageName)
612    {
613        if (imageSet.empty() || imageName.empty())
614            this->setBackgroundImage("");
615        else
616            this->setBackgroundImage("set: " + imageSet + " image: " + imageName);
617    }
618
619    void GUIManager::setBackgroundImage(const std::string& image)
620    {
621        if (image.empty())
622            this->rootWindow_->setProperty("Alpha", "0.0");
623        else
624            this->rootWindow_->setProperty("Alpha", "1.0");
625        this->rootWindow_->setProperty("Image", image);
626    }
627
628    void GUIManager::buttonPressed(const KeyEvent& evt)
629    {
630#if CEGUI_VERSION >= 0x000800
631        this->protectedCeguiContextCall(std::bind(&CEGUI::GUIContext::injectKeyDown, arg::_1, (CEGUI::Key::Scan) evt.getKeyCode())); // TODO: will this cast always work?
632        this->protectedCeguiContextCall(std::bind(&CEGUI::GUIContext::injectChar, arg::_1, evt.getText()));
633#else
634        this->protectedCeguiSystemCall(std::bind(&CEGUI::System::injectKeyDown, arg::_1, evt.getKeyCode()));
635        this->protectedCeguiSystemCall(std::bind(&CEGUI::System::injectChar, arg::_1, evt.getText()));
636#endif
637    }
638
639    void GUIManager::buttonReleased(const KeyEvent& evt)
640    {
641#if CEGUI_VERSION >= 0x000800
642        this->protectedCeguiContextCall(std::bind(&CEGUI::GUIContext::injectKeyUp, arg::_1, (CEGUI::Key::Scan) evt.getKeyCode())); // TODO: will this cast always work?
643#else
644        this->protectedCeguiSystemCall(std::bind(&CEGUI::System::injectKeyUp, arg::_1, evt.getKeyCode()));
645#endif
646    }
647
648    /**
649    @brief
650        Function receiving a mouse button pressed event.
651    @param id
652        ID of the mouse button which got pressed
653
654        This function is inherited by MouseHandler and injects the event into CEGUI.
655        It is for CEGUI to process the event.
656    */
657    void GUIManager::buttonPressed(MouseButtonCode::ByEnum id)
658    {
659#if CEGUI_VERSION >= 0x000800
660        this->protectedCeguiContextCall(std::bind(&CEGUI::GUIContext::injectMouseButtonDown, arg::_1, convertButton(id)));
661#else
662        this->protectedCeguiSystemCall(std::bind(&CEGUI::System::injectMouseButtonDown, arg::_1, convertButton(id)));
663#endif
664    }
665
666    /**
667    @brief
668        Function receiving a mouse button released event.
669    @param id
670        ID of the mouse button which got released
671
672        This function is inherited by MouseHandler and injects the event into CEGUI.
673        It is for CEGUI to process the event.
674    */
675    void GUIManager::buttonReleased(MouseButtonCode::ByEnum id)
676    {
677#if CEGUI_VERSION >= 0x000800
678        this->protectedCeguiContextCall(std::bind(&CEGUI::GUIContext::injectMouseButtonUp, arg::_1, convertButton(id)));
679#else
680        this->protectedCeguiSystemCall(std::bind(&CEGUI::System::injectMouseButtonUp, arg::_1, convertButton(id)));
681#endif
682    }
683
684    void GUIManager::mouseMoved(IntVector2 abs, IntVector2 rel, IntVector2 clippingSize)
685    {
686#if CEGUI_VERSION >= 0x000800
687        this->protectedCeguiContextCall(std::bind(&CEGUI::GUIContext::injectMousePosition, arg::_1, (float)abs.x, (float)abs.y));
688#else
689        this->protectedCeguiSystemCall(std::bind(&CEGUI::System::injectMousePosition, arg::_1, (float)abs.x, (float)abs.y));
690#endif
691    }
692
693    void GUIManager::mouseScrolled(int abs, int rel)
694    {
695#if CEGUI_VERSION >= 0x000800
696        this->protectedCeguiContextCall(std::bind(&CEGUI::GUIContext::injectMouseWheelChange, arg::_1, (float)sgn(rel) * this->numScrollLines_));
697#else
698        this->protectedCeguiSystemCall(std::bind(&CEGUI::System::injectMouseWheelChange, arg::_1, (float)sgn(rel) * this->numScrollLines_));
699#endif
700    }
701
702    /**
703        @brief Indicates that the mouse left the application's window.
704    */
705    void GUIManager::mouseLeft()
706    {
707#if CEGUI_VERSION >= 0x000800
708        this->protectedCeguiContextCall(std::bind(&CEGUI::GUIContext::injectMouseLeaves, arg::_1));
709#else
710        this->protectedCeguiSystemCall(std::bind(&CEGUI::System::injectMouseLeaves, arg::_1));
711#endif
712    }
713
714    /**
715    @brief
716        converts mouse event code to CEGUI event code
717    @param button
718        code of the mouse button as we use it in Orxonox
719    @return
720        code of the mouse button as it is used by CEGUI
721
722        Simple conversion from mouse event code in Orxonox to the one used in CEGUI.
723     */
724    static inline CEGUI::MouseButton convertButton(MouseButtonCode::ByEnum button)
725    {
726        switch (button)
727        {
728        case MouseButtonCode::Left:
729            return CEGUI::LeftButton;
730
731        case MouseButtonCode::Right:
732            return CEGUI::RightButton;
733
734        case MouseButtonCode::Middle:
735            return CEGUI::MiddleButton;
736
737        case MouseButtonCode::Button3:
738            return CEGUI::X1Button;
739
740        case MouseButtonCode::Button4:
741            return CEGUI::X2Button;
742
743        default:
744            return CEGUI::NoButton;
745        }
746    }
747
748    /** Executes a CEGUI function normally, but catches CEGUI::ScriptException.
749        When a ScriptException occurs, the error message will be displayed and
750        the program carries on.
751    @remarks
752        The exception behaviour may pose problems if the code is not written
753        exception-safe (and you can forget about that in Lua). The program might
754        be left in an undefined state. But otherwise one script error would
755        terminate the whole program...
756    @note
757        Your life gets easier if you use std::bind to create the object/function.
758    @param function
759        Any callable object/function that takes this->guiSystem_ as its only parameter.
760    @return
761        True if input was handled, false otherwise. A caught exception yields true.
762    */
763    template <typename FunctionType, typename ObjectType>
764    bool GUIManager::protectedCall(FunctionType function, ObjectType object)
765    {
766        try
767        {
768            return function(object);
769        }
770        catch (CEGUI::ScriptException& ex)
771        {
772            // Display the error and proceed. See @remarks why this can be dangerous.
773            orxout(internal_error) << ex.getMessage() << endl;
774            return true;
775        }
776    }
777
778    template <typename FunctionType>
779    bool GUIManager::protectedCeguiSystemCall(FunctionType function)
780    {
781        return this->protectedCall(function, this->guiSystem_);
782    }
783
784#if CEGUI_VERSION >= 0x000800
785    template <typename FunctionType>
786    bool GUIManager::protectedCeguiContextCall(FunctionType function)
787    {
788        return this->protectedCall(function, this->guiSystem_->getDefaultGUIContext());
789    }
790#endif
791
792    /**
793    @brief
794        Subscribe the input function to the input event for the input window.
795        This is a helper to be used in lua, because subscribeScriptedEvent() doesn't work in lua.
796    @param window
797        The window for which the event is subscribed.
798    @param event
799        The type of event to which we subscribe.
800    @param function
801        The function that is called when the event occurs.
802    */
803    void GUIManager::subscribeEventHelper(CEGUI::Window* window, const std::string& event, const std::string& function)
804    {
805        window->subscribeScriptedEvent(event, function);
806    }
807
808    /**
809    @brief
810        Set the input tooltip text for the input ListboxItem.
811    @param item
812        The ListboxItem for which the tooltip should be set.
813    @param tooltip
814        The tooltip text that should be set.
815    */
816    void GUIManager::setTooltipTextHelper(CEGUI::ListboxItem* item, const std::string& tooltip)
817    {
818        item->setTooltipText(tooltip);
819    }
820
821    /**
822    @brief
823        Set whether the tooltips for the input Listbox are enabled.
824    @param listbox
825        The Listbox for which to enable (or disable) tooltips.
826    @param enabled
827        Whether to enable or disable the tooltips.
828    */
829    void GUIManager::setItemTooltipsEnabledHelper(CEGUI::Listbox* listbox, bool enabled)
830    {
831        listbox->setItemTooltipsEnabled(enabled);
832    }
833
834    /** Helper method to get the developer's mode without having to export Core.h.
835    @see Core::inDevMode
836    */
837    /*static*/ bool GUIManager::inDevMode()
838    {
839         return Core::getInstance().getConfig()->inDevMode();
840    }
841
842    /**
843        @brief Callback of window event listener, called if the window is resized. Sets the display size of CEGUI.
844    */
845    void GUIManager::windowResized(unsigned int newWidth, unsigned int newHeight)
846    {
847#if CEGUI_VERSION >= 0x000800
848        this->guiRenderer_->setDisplaySize(CEGUI::Sizef((float)newWidth, (float)newHeight));
849#else
850        this->guiRenderer_->setDisplaySize(CEGUI::Size((float)newWidth, (float)newHeight));
851#endif
852        this->rootWindow_->setSize(CEGUI::UVector2(CEGUI::UDim(1, (float)newWidth), CEGUI::UDim(1, (float)newHeight)));
853    }
854
855    /**
856        @brief Notify CEGUI if the windows loses the focus (stops highlighting of menu items, etc).
857    */
858    void GUIManager::windowFocusChanged(bool bFocus)
859    {
860        if (!bFocus)
861            this->mouseLeft();
862    }
863
864    /**
865    @brief
866        Adds a new freetype font to the CEGUI system.
867    @param name
868        The name of the new font.
869    @param size
870        The font size of the new font in pixels.
871        @param fontName
872        The filename of the font.
873    */
874    /*static*/ void GUIManager::addFontHelper(const std::string& name, int size, const std::string& fontName)
875    {
876#ifdef ORXONOX_OLD_CEGUI
877        if(CEGUI::FontManager::getSingleton().isFontPresent(name)) // If a font with that name already exists.
878            return;
879
880        CEGUI::Font* font = nullptr;
881        CEGUI::XMLAttributes xmlAttributes;
882
883        // Attributes specified within CEGUIFont
884        xmlAttributes.add("Name", name);
885        xmlAttributes.add("Filename", fontName);
886        xmlAttributes.add("ResourceGroup", "");
887        xmlAttributes.add("AutoScaled", "true");
888        xmlAttributes.add("NativeHorzRes", "800");
889        xmlAttributes.add("NativeVertRes", "600");
890
891        // Attributes specified within CEGUIXMLAttributes
892        xmlAttributes.add("Size", multi_cast<std::string>(size));
893        xmlAttributes.add("AntiAlias", "true");
894
895        font = CEGUI::FontManager::getSingleton().createFont("FreeType", xmlAttributes);
896        if(font != nullptr)
897            font->load();
898#else
899        if(CEGUI::FontManager::getSingleton().isDefined(name)) // If a font with that name already exists.
900            return;
901
902    #if CEGUI_VERSION >= 0x000800
903        CEGUI::FontManager::getSingleton().createFreeTypeFont(name, (float)size, true, fontName, "", CEGUI::ASM_Both, CEGUI::Sizef(800.0f, 600.0f));
904    #else
905        CEGUI::FontManager::getSingleton().createFreeTypeFont(name, (float)size, true, fontName, "", true, 800.0f, 600.0f);
906    #endif
907#endif
908    }
909
910}
Note: See TracBrowser for help on using the repository browser.