Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/GUIManager.cc @ 12219

Last change on this file since 12219 was 11809, checked in by landauf, 7 years ago

added work around for a bug in cegui 0.8 (the cegui lua scripts expect a "Font*" pointer to call getTextExtent(), but cegui 0.8 only returns "const Font*")

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