Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 11071 was 11071, checked in by landauf, 8 years ago

merged branch cpp11_v3 back to trunk

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