Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/kicklib/src/libraries/core/GUIManager.cc @ 7971

Last change on this file since 7971 was 7971, checked in by rgrieder, 13 years ago

Fixed GUITools.lua for good: both CECGUI 0.6 and 0.7 seem to work. At least I haven't noticed any bogus behaviour in the Credits or in the Quest sheet.

  • Property svn:eol-style set to native
File size: 19.7 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 <memory>
33#include <boost/bind.hpp>
34#include <OgreRenderQueue.h>
35#include <OgreRenderWindow.h>
36
37#include <CEGUIDefaultLogger.h>
38#include <CEGUIExceptions.h>
39#include <CEGUIInputEvent.h>
40#include <CEGUIMouseCursor.h>
41#include <CEGUIResourceProvider.h>
42#include <CEGUISystem.h>
43#include <CEGUIWindow.h>
44#include <CEGUIWindowManager.h>
45#include <elements/CEGUIListbox.h>
46#include <elements/CEGUIListboxItem.h>
47
48#ifdef ORXONOX_OLD_CEGUI
49#  include <CEGUILua.h>
50#  include <ogreceguirenderer/OgreCEGUIRenderer.h>
51#else
52#  include <ScriptingModules/LuaScriptModule/CEGUILua.h>
53#  include <RendererModules/Ogre/CEGUIOgreImageCodec.h>
54#  include <RendererModules/Ogre/CEGUIOgreRenderer.h>
55#  include <RendererModules/Ogre/CEGUIOgreResourceProvider.h>
56#endif
57
58#include "util/Clock.h"
59#include "util/Convert.h"
60#include "util/Debug.h"
61#include "util/Exception.h"
62#include "util/OrxAssert.h"
63#include "ConfigValueIncludes.h"
64#include "Core.h"
65#include "CoreIncludes.h"
66#include "Game.h"
67#include "GraphicsManager.h"
68#include "LuaState.h"
69#include "PathConfig.h"
70#include "Resource.h"
71#include "command/ConsoleCommand.h"
72#include "input/InputManager.h"
73#include "input/InputState.h"
74#include "input/KeyBinderManager.h"
75
76namespace orxonox
77{
78    static void key_esc()
79        { GUIManager::getInstance().keyESC(); }
80    SetConsoleCommand("keyESC", &key_esc);
81
82    class CEGUILogger : public CEGUI::DefaultLogger
83    {
84    public:
85        void logEvent(const CEGUI::String& message, CEGUI::LoggingLevel level = CEGUI::Standard)
86        {
87            int orxonoxLevel = CEGUI::Standard;
88            switch (level)
89            {
90                case CEGUI::Errors:      orxonoxLevel = 1; break;
91                case CEGUI::Warnings:    orxonoxLevel = 2; break;
92                case CEGUI::Standard:    orxonoxLevel = 4; break;
93                case CEGUI::Informative: orxonoxLevel = 5; break;
94                case CEGUI::Insane:      orxonoxLevel = 6; break;
95                default: OrxAssert(false, "CEGUI log level out of range, inspect immediately!");
96            }
97            OutputHandler::getOutStream(orxonoxLevel)
98                << "CEGUI: " << message << std::endl;
99
100            CEGUI::DefaultLogger::logEvent(message, level);
101        }
102    };
103
104    static CEGUI::MouseButton convertButton(MouseButtonCode::ByEnum button);
105
106    GUIManager* GUIManager::singletonPtr_s = 0;
107    /*static*/ const std::string GUIManager::defaultScheme_ = "TaharezGreen";
108
109    SetConsoleCommand("showGUI", &GUIManager::showGUI).defaultValue(1, false).defaultValue(2, false);
110    SetConsoleCommand("hideGUI", &GUIManager::hideGUI);
111
112    /**
113    @brief
114        Constructs the GUIManager by starting up CEGUI
115
116        Creates the interface to Ogre, sets up the CEGUI renderer and the Lua script module together with the Lua engine.
117        The log is set up and connected to the CEGUILogger.
118        After Lua setup tolua++-elements are linked to Lua-state to give Lua access to C++-code.
119        Finally initial Lua code is executed (maybe we can do this with the CEGUI startup script automatically).
120    @return true if success, otherwise false
121    */
122    GUIManager::GUIManager(const std::pair<int, int>& mousePosition)
123        : destroyer_(*this, &GUIManager::cleanup)
124        , guiRenderer_(NULL)
125        , luaState_(NULL)
126        , scriptModule_(NULL)
127        , guiSystem_(NULL)
128        , resourceProvider_(NULL)
129#ifndef ORXONOX_OLD_CEGUI
130        , imageCodec_(NULL)
131#endif
132        , camera_(NULL)
133    {
134        RegisterRootObject(GUIManager);
135        this->setConfigValues();
136
137        using namespace CEGUI;
138
139        COUT(3) << "Initialising CEGUI." << std::endl;
140
141        // Note: No SceneManager specified yet
142#ifdef ORXONOX_OLD_CEGUI
143        guiRenderer_ = new OgreCEGUIRenderer(GraphicsManager::getInstance().getRenderWindow(), Ogre::RENDER_QUEUE_OVERLAY, false, 3000);
144        resourceProvider_ = guiRenderer_->createResourceProvider();
145#else
146        guiRenderer_ = &OgreRenderer::create(*GraphicsManager::getInstance().getRenderWindow());
147        resourceProvider_ = &OgreRenderer::createOgreResourceProvider();
148        imageCodec_ = &OgreRenderer::createOgreImageCodec();
149#endif
150        resourceProvider_->setDefaultResourceGroup("General");
151
152        // Setup scripting
153        luaState_ = new LuaState();
154        rootFileInfo_ = Resource::getInfo("InitialiseGUI.lua");
155        // This is necessary to ensure that input events also use the right resource info when triggering lua functions
156        luaState_->setDefaultResourceInfo(this->rootFileInfo_);
157#ifdef ORXONOX_OLD_CEGUI
158        scriptModule_ = new LuaScriptModule(luaState_->getInternalLuaState());
159        luaState_->doString("ORXONOX_OLD_CEGUI = true");
160#else
161        scriptModule_ = &LuaScriptModule::create(luaState_->getInternalLuaState());
162#endif
163        scriptModule_->setDefaultPCallErrorHandler(LuaState::ERROR_HANDLER_NAME);
164
165        // Create our own logger to specify the filepath
166        std::auto_ptr<CEGUILogger> ceguiLogger(new CEGUILogger());
167        ceguiLogger->setLogFilename(PathConfig::getLogPathString() + "cegui.log");
168        // Set the log level according to ours (translate by subtracting 1)
169        ceguiLogger->setLoggingLevel(
170            static_cast<LoggingLevel>(OutputHandler::getInstance().getSoftDebugLevel("logFile") - 1));
171        this->ceguiLogger_ = ceguiLogger.release();
172
173        // Create the CEGUI system singleton
174#ifdef ORXONOX_OLD_CEGUI
175        guiSystem_ = new System(guiRenderer_, resourceProvider_, 0, scriptModule_);
176        // Add functions that have been renamed in newer versions
177        luaState_->doString("CEGUI.SchemeManager.create = CEGUI.SchemeManager.loadScheme");
178        luaState_->doString("CEGUI.Window.getUnclippedOuterRect = CEGUI.Window.getUnclippedPixelRect");
179#else
180        guiSystem_ = &System::create(*guiRenderer_, resourceProvider_, 0, imageCodec_, scriptModule_);
181#endif
182
183        // Align CEGUI mouse with OIS mouse
184        guiSystem_->injectMousePosition((float)mousePosition.first, (float)mousePosition.second);
185
186        // Initialise the Lua framework and load the schemes
187        this->luaState_->doFile("InitialiseGUI.lua");
188
189        // Create the root nodes
190        this->rootWindow_ = CEGUI::WindowManager::getSingleton().createWindow("MenuWidgets/StaticImage", "AbsoluteRootWindow");
191        this->rootWindow_->setProperty("FrameEnabled", "False");
192        this->hudRootWindow_ = CEGUI::WindowManager::getSingleton().createWindow("DefaultWindow", "HUDRootWindow");
193        this->menuRootWindow_ = CEGUI::WindowManager::getSingleton().createWindow("DefaultWindow", "MenuRootWindow");
194        // And connect them
195        CEGUI::System::getSingleton().setGUISheet(this->rootWindow_);
196        this->rootWindow_->addChildWindow(this->hudRootWindow_);
197        this->rootWindow_->addChildWindow(this->menuRootWindow_);
198
199        // No background to start with (sets the alpha value to 0)
200        this->setBackgroundImage("");
201
202        // Set up the sheet manager in the Lua framework
203        this->luaState_->doFile("SheetManager.lua");
204    }
205
206    void GUIManager::cleanup()
207    {
208        using namespace CEGUI;
209
210#ifdef ORXONOX_OLD_CEGUI
211        delete guiSystem_;
212        delete guiRenderer_;
213        delete scriptModule_;
214#else
215        System::destroy();
216        OgreRenderer::destroyOgreResourceProvider(*resourceProvider_);
217        OgreRenderer::destroyOgreImageCodec(*imageCodec_);
218        OgreRenderer::destroy(*guiRenderer_);
219        LuaScriptModule::destroy(*scriptModule_);
220#endif
221        delete luaState_;
222    }
223
224    void GUIManager::setConfigValues(void)
225    {
226        SetConfigValue(guiScheme_, GUIManager::defaultScheme_) .description("Changes the current GUI scheme.") .callback(this, &GUIManager::changedGUIScheme);
227    }
228
229    void GUIManager::changedGUIScheme(void)
230    {
231
232    }
233
234    /**
235    @brief
236        used to tick the GUI
237    @param time
238        clock which provides time value for the GUI System
239
240        Ticking the GUI means updating it with a certain regularity.
241        The elapsed time since the last call is given in the time value provided by the clock.
242        This time value is then used to provide a fluent animation of the GUI.
243    */
244    void GUIManager::preUpdate(const Clock& time)
245    {
246        assert(guiSystem_);
247        this->protectedCall(boost::bind(&CEGUI::System::injectTimePulse, _1, time.getDeltaTime()));
248    }
249
250    /**
251    @brief
252        Tells the GUIManager which SceneManager to use
253    @param camera
254        The current camera on which the GUI should be displayed on.
255
256        In fact the GUIManager needs the SceneManager and not the Camera to display the GUI.
257        This means the GUI is not bound to a camera but rather to the SceneManager.
258        Hiding the GUI when needed can therefore not be resolved by just NOT setting the current camera.
259    */
260    void GUIManager::setCamera(Ogre::Camera* camera)
261    {
262        this->camera_ = camera;
263#ifdef ORXONOX_OLD_CEGUI
264        if (camera == NULL)
265            this->guiRenderer_->setTargetSceneManager(0);
266        else
267            this->guiRenderer_->setTargetSceneManager(camera->getSceneManager());
268#endif
269    }
270
271    /**
272    @brief
273        Executes Lua code
274    @param str
275        reference to string object holding the Lua code which is to be executed
276    */
277    void GUIManager::executeCode(const std::string& str)
278    {
279        this->luaState_->doString(str, rootFileInfo_);
280    }
281
282    /** Loads a GUI sheet by Lua script
283    @param name
284        The name of the GUI (like the script name, but without the extension)
285    */
286    void GUIManager::loadGUI(const std::string& name)
287    {
288        this->executeCode("loadSheet(\"" + name + "\")");
289    }
290
291    /**
292    @brief
293        Displays specified GUI on screen
294    @param name
295        The name of the GUI
296    @param bHidePrevious
297        If true all displayed GUIs on the stack, that are below this GUI are hidden.
298    @param bNoInput
299        If true the GUI is transparent to input.
300
301        The function executes the Lua function with the same name in case the GUIManager is ready.
302    */
303    /*static*/ void GUIManager::showGUI(const std::string& name, bool bHidePrevious, bool bNoInput)
304    {
305        GUIManager::getInstance().executeCode("showMenuSheet(\"" + name + "\", " + multi_cast<std::string>(bHidePrevious) + ", " + multi_cast<std::string>(bNoInput) + ")");
306    }
307
308    /**
309    @brief
310        Hack-ish. Needed for GUIOverlay.
311    */
312    void GUIManager::showGUIExtra(const std::string& name, const std::string& ptr, bool bHidePrevious, bool bNoInput)
313    {
314        this->executeCode("showMenuSheet(\"" + name + "\", " + multi_cast<std::string>(bHidePrevious) + ", " + multi_cast<std::string>(bNoInput) + ", " + ptr + ")");
315    }
316
317    /**
318    @brief
319        Hides specified GUI.
320    @param name
321        The name of the GUI.
322    */
323    /*static*/ void GUIManager::hideGUI(const std::string& name)
324    {
325        GUIManager::getInstance().executeCode("hideMenuSheet(\"" + name + "\")");
326    }
327
328    const std::string& GUIManager::createInputState(const std::string& name, TriBool::Value showCursor, TriBool::Value useKeyboard, bool bBlockJoyStick)
329    {
330        InputState* state = InputManager::getInstance().createInputState(name);
331        if (!state)
332            return BLANKSTRING;
333
334        /* Table that maps isFullScreen() and showCursor to mouseExclusive
335        isFullscreen / showCursor | True  | False | Dontcare
336        ----------------------------------------------------
337        true                      | True  | True  | Dontcare
338        ----------------------------------------------------
339        false                     | False | True  | Dontcare
340        */
341        if (showCursor == TriBool::Dontcare)
342            state->setMouseExclusive(TriBool::Dontcare);
343        else if (GraphicsManager::getInstance().isFullScreen() || showCursor == TriBool::False)
344            state->setMouseExclusive(TriBool::True);
345        else
346            state->setMouseExclusive(TriBool::False);
347
348        if (showCursor == TriBool::True)
349            state->setMouseHandler(this);
350        else if (showCursor == TriBool::False)
351            state->setMouseHandler(&InputHandler::EMPTY);
352
353        if (useKeyboard == TriBool::True)
354            state->setKeyHandler(this);
355        else if (useKeyboard == TriBool::False)
356            state->setKeyHandler(&InputHandler::EMPTY);
357
358        if (bBlockJoyStick)
359            state->setJoyStickHandler(&InputHandler::EMPTY);
360
361        return state->getName();
362    }
363
364    void GUIManager::keyESC()
365    {
366        this->executeCode("keyESC()");
367    }
368
369    void GUIManager::setBackgroundImage(const std::string& imageSet, const std::string imageName)
370    {
371        if (imageSet.empty() || imageName.empty())
372            this->setBackgroundImage("");
373        else
374            this->setBackgroundImage("set: " + imageSet + " image: " + imageName);
375    }
376
377    void GUIManager::setBackgroundImage(const std::string& image)
378    {
379        if (image.empty())
380            this->rootWindow_->setProperty("Alpha", "0.0");
381        else
382            this->rootWindow_->setProperty("Alpha", "1.0");
383        this->rootWindow_->setProperty("Image", image);
384    }
385
386    void GUIManager::buttonPressed(const KeyEvent& evt)
387    {
388        this->protectedCall(boost::bind(&CEGUI::System::injectKeyDown, _1, evt.getKeyCode()));
389        this->protectedCall(boost::bind(&CEGUI::System::injectChar, _1, evt.getText()));
390    }
391
392    void GUIManager::buttonReleased(const KeyEvent& evt)
393    {
394        this->protectedCall(boost::bind(&CEGUI::System::injectKeyUp, _1, evt.getKeyCode()));
395    }
396
397    /**
398    @brief
399        Function receiving a mouse button pressed event.
400    @param id
401        ID of the mouse button which got pressed
402
403        This function is inherited by MouseHandler and injects the event into CEGUI.
404        It is for CEGUI to process the event.
405    */
406    void GUIManager::buttonPressed(MouseButtonCode::ByEnum id)
407    {
408        this->protectedCall(boost::bind(&CEGUI::System::injectMouseButtonDown, _1, convertButton(id)));
409    }
410
411    /**
412    @brief
413        Function receiving a mouse button released event.
414    @param id
415        ID of the mouse button which got released
416
417        This function is inherited by MouseHandler and injects the event into CEGUI.
418        It is for CEGUI to process the event.
419    */
420    void GUIManager::buttonReleased(MouseButtonCode::ByEnum id)
421    {
422        this->protectedCall(boost::bind(&CEGUI::System::injectMouseButtonUp, _1, convertButton(id)));
423    }
424
425    void GUIManager::mouseMoved(IntVector2 abs, IntVector2 rel, IntVector2 clippingSize)
426    {
427        this->protectedCall(boost::bind(&CEGUI::System::injectMousePosition, _1, (float)abs.x, (float)abs.y));
428    }
429
430    void GUIManager::mouseScrolled(int abs, int rel)
431    {
432        this->protectedCall(boost::bind(&CEGUI::System::injectMouseWheelChange, _1, (float)rel));
433    }
434
435    /**
436        @brief Indicates that the mouse left the application's window.
437    */
438    void GUIManager::mouseLeft()
439    {
440        this->protectedCall(boost::bind(&CEGUI::System::injectMouseLeaves, _1));
441    }
442
443    /**
444    @brief
445        converts mouse event code to CEGUI event code
446    @param button
447        code of the mouse button as we use it in Orxonox
448    @return
449        code of the mouse button as it is used by CEGUI
450
451        Simple conversion from mouse event code in Orxonox to the one used in CEGUI.
452     */
453    static inline CEGUI::MouseButton convertButton(MouseButtonCode::ByEnum button)
454    {
455        switch (button)
456        {
457        case MouseButtonCode::Left:
458            return CEGUI::LeftButton;
459
460        case MouseButtonCode::Right:
461            return CEGUI::RightButton;
462
463        case MouseButtonCode::Middle:
464            return CEGUI::MiddleButton;
465
466        case MouseButtonCode::Button3:
467            return CEGUI::X1Button;
468
469        case MouseButtonCode::Button4:
470            return CEGUI::X2Button;
471
472        default:
473            return CEGUI::NoButton;
474        }
475    }
476
477    /** Executes a CEGUI function normally, but catches CEGUI::ScriptException.
478        When a ScriptException occurs, the error message will be displayed and
479        the program carries on.
480    @remarks
481        The exception behaviour may pose problems if the code is not written
482        exception-safe (and you can forget about that in Lua). The program might
483        be left in an undefined state. But otherwise one script error would
484        terminate the whole program...
485    @note
486        Your life gets easier if you use boost::bind to create the object/function.
487    @param function
488        Any callable object/function that takes this->guiSystem_ as its only parameter.
489    @return
490        True if input was handled, false otherwise. A caught exception yields true.
491    */
492    template <typename FunctionType>
493    bool GUIManager::protectedCall(FunctionType function)
494    {
495        try
496        {
497            return function(this->guiSystem_);
498        }
499        catch (CEGUI::ScriptException& ex)
500        {
501            // Display the error and proceed. See @remarks why this can be dangerous.
502            COUT(1) << ex.getMessage() << std::endl;
503            return true;
504        }
505    }
506
507    /**
508    @brief
509        Subscribe the input function to the input event for the input window.
510        This is a helper to be used in lua, because subscribeScriptedEvent() doesn't work in lua.
511    @param window
512        The window for which the event is subscribed.
513    @param event
514        The type of event to which we subscribe.
515    @param function
516        The function that is called when the event occurs.
517    */
518    void GUIManager::subscribeEventHelper(CEGUI::Window* window, const std::string& event, const std::string& function)
519    {
520        window->subscribeScriptedEvent(event, function);
521    }
522
523    /**
524    @brief
525        Set the input tooltip text for the input ListboxItem.
526    @param item
527        The ListboxItem for which the tooltip should be set.
528    @param tooltip
529        The tooltip text that should be set.
530    */
531    void GUIManager::setTooltipTextHelper(CEGUI::ListboxItem* item, const std::string& tooltip)
532    {
533        item->setTooltipText(tooltip);
534    }
535
536    /**
537    @brief
538        Set whether the tooltips for the input Listbox are enabled.
539    @param listbox
540        The Listbox for which to enable (or disable) tooltips.
541    @param enabled
542        Whether to enable or disable the tooltips.
543    */
544    void GUIManager::setItemTooltipsEnabledHelper(CEGUI::Listbox* listbox, bool enabled)
545    {
546        listbox->setItemTooltipsEnabled(enabled);
547    }
548
549    /**
550        @brief Callback of window event listener, called if the window is resized. Sets the display size of CEGUI.
551    */
552    void GUIManager::windowResized(unsigned int newWidth, unsigned int newHeight)
553    {
554#ifdef ORXONOX_OLD_CEGUI
555        this->guiRenderer_->setDisplaySize(CEGUI::Size(newWidth, newHeight));
556#else
557        this->guiRenderer_->setDisplaySize(CEGUI::Size((float)newWidth, (float)newHeight));
558#endif
559    }
560
561    /**
562        @brief Notify CEGUI if the windows loses the focus (stops highlight of menu items, etc).
563    */
564    void GUIManager::windowFocusChanged(bool bFocus)
565    {
566        if (!bFocus)
567            this->mouseLeft();
568    }
569
570}
Note: See TracBrowser for help on using the repository browser.