Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Cleaned up macro monstrosities in GUIManager and fixed some typos.

  • 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 CEGUI_OLD_VERSION
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#ifdef CEGUI_OLD_VERSION
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 CEGUI_OLD_VERSION
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 CEGUI_OLD_VERSION
158        scriptModule_ = new LuaScriptModule(luaState_->getInternalLuaState());
159#else
160        scriptModule_ = &LuaScriptModule::create(luaState_->getInternalLuaState());
161#endif
162        scriptModule_->setDefaultPCallErrorHandler(LuaState::ERROR_HANDLER_NAME);
163
164        // Create our own logger to specify the filepath
165        std::auto_ptr<CEGUILogger> ceguiLogger(new CEGUILogger());
166        ceguiLogger->setLogFilename(PathConfig::getLogPathString() + "cegui.log");
167        // Set the log level according to ours (translate by subtracting 1)
168        ceguiLogger->setLoggingLevel(
169            static_cast<LoggingLevel>(OutputHandler::getInstance().getSoftDebugLevel("logFile") - 1));
170        this->ceguiLogger_ = ceguiLogger.release();
171
172        // Create the CEGUI system singleton
173#ifdef CEGUI_OLD_VERSION
174        guiSystem_ = new System(guiRenderer_, resourceProvider_, 0, scriptModule_);
175        // Add functions that have been renamed in newer versions
176        luaState_->doString("CEGUI.SchemeManager.create = CEGUI.SchemeManager.loadScheme");
177        luaState_->doString("CEGUI.Window.getUnclippedOuterRect = CEGUI.Window.getUnclippedPixelRect");
178#else
179        guiSystem_ = &System::create(*guiRenderer_, resourceProvider_, 0, imageCodec_, scriptModule_);
180#endif
181
182        // Align CEGUI mouse with OIS mouse
183        guiSystem_->injectMousePosition((float)mousePosition.first, (float)mousePosition.second);
184
185        // Initialise the Lua framework and load the schemes
186        this->luaState_->doFile("InitialiseGUI.lua");
187
188        // Create the root nodes
189        this->rootWindow_ = CEGUI::WindowManager::getSingleton().createWindow("MenuWidgets/StaticImage", "AbsoluteRootWindow");
190        this->rootWindow_->setProperty("FrameEnabled", "False");
191        this->hudRootWindow_ = CEGUI::WindowManager::getSingleton().createWindow("DefaultWindow", "HUDRootWindow");
192        this->menuRootWindow_ = CEGUI::WindowManager::getSingleton().createWindow("DefaultWindow", "MenuRootWindow");
193        // And connect them
194        CEGUI::System::getSingleton().setGUISheet(this->rootWindow_);
195        this->rootWindow_->addChildWindow(this->hudRootWindow_);
196        this->rootWindow_->addChildWindow(this->menuRootWindow_);
197
198        // No background to start with (sets the alpha value to 0)
199        this->setBackgroundImage("");
200
201        // Set up the sheet manager in the Lua framework
202        this->luaState_->doFile("SheetManager.lua");
203    }
204
205    void GUIManager::cleanup()
206    {
207        using namespace CEGUI;
208
209#ifdef CEGUI_OLD_VERSION
210        delete guiSystem_;
211        delete guiRenderer_;
212        delete scriptModule_;
213#else
214        System::destroy();
215        OgreRenderer::destroyOgreResourceProvider(*resourceProvider_);
216        OgreRenderer::destroyOgreImageCodec(*imageCodec_);
217        OgreRenderer::destroy(*guiRenderer_);
218        LuaScriptModule::destroy(*scriptModule_);
219#endif
220        delete luaState_;
221    }
222
223    void GUIManager::setConfigValues(void)
224    {
225        SetConfigValue(guiScheme_, GUIManager::defaultScheme_) .description("Changes the current GUI scheme.") .callback(this, &GUIManager::changedGUIScheme);
226    }
227
228    void GUIManager::changedGUIScheme(void)
229    {
230
231    }
232
233    /**
234    @brief
235        used to tick the GUI
236    @param time
237        clock which provides time value for the GUI System
238
239        Ticking the GUI means updating it with a certain regularity.
240        The elapsed time since the last call is given in the time value provided by the clock.
241        This time value is then used to provide a fluent animation of the GUI.
242    */
243    void GUIManager::preUpdate(const Clock& time)
244    {
245        assert(guiSystem_);
246        this->protectedCall(boost::bind(&CEGUI::System::injectTimePulse, _1, time.getDeltaTime()));
247    }
248
249    /**
250    @brief
251        Tells the GUIManager which SceneManager to use
252    @param camera
253        The current camera on which the GUI should be displayed on.
254
255        In fact the GUIManager needs the SceneManager and not the Camera to display the GUI.
256        This means the GUI is not bound to a camera but rather to the SceneManager.
257        Hiding the GUI when needed can therefore not be resolved by just NOT setting the current camera.
258    */
259    void GUIManager::setCamera(Ogre::Camera* camera)
260    {
261        this->camera_ = camera;
262#ifdef CEGUI_OLD_VERSION
263        if (camera == NULL)
264            this->guiRenderer_->setTargetSceneManager(0);
265        else
266            this->guiRenderer_->setTargetSceneManager(camera->getSceneManager());
267#endif
268    }
269
270    /**
271    @brief
272        Executes Lua code
273    @param str
274        reference to string object holding the Lua code which is to be executed
275    */
276    void GUIManager::executeCode(const std::string& str)
277    {
278        this->luaState_->doString(str, rootFileInfo_);
279    }
280
281    /** Loads a GUI sheet by Lua script
282    @param name
283        The name of the GUI (like the script name, but without the extension)
284    */
285    void GUIManager::loadGUI(const std::string& name)
286    {
287        this->executeCode("loadSheet(\"" + name + "\")");
288    }
289
290    /**
291    @brief
292        Displays specified GUI on screen
293    @param name
294        The name of the GUI
295    @param bHidePrevious
296        If true all displayed GUIs on the stack, that are below this GUI are hidden.
297    @param bNoInput
298        If true the GUI is transparent to input.
299
300        The function executes the Lua function with the same name in case the GUIManager is ready.
301    */
302    /*static*/ void GUIManager::showGUI(const std::string& name, bool bHidePrevious, bool bNoInput)
303    {
304        GUIManager::getInstance().executeCode("showMenuSheet(\"" + name + "\", " + multi_cast<std::string>(bHidePrevious) + ", " + multi_cast<std::string>(bNoInput) + ")");
305    }
306
307    /**
308    @brief
309        Hack-ish. Needed for GUIOverlay.
310    */
311    void GUIManager::showGUIExtra(const std::string& name, const std::string& ptr, bool bHidePrevious, bool bNoInput)
312    {
313        this->executeCode("showMenuSheet(\"" + name + "\", " + multi_cast<std::string>(bHidePrevious) + ", " + multi_cast<std::string>(bNoInput) + ", " + ptr + ")");
314    }
315
316    /**
317    @brief
318        Hides specified GUI.
319    @param name
320        The name of the GUI.
321    */
322    /*static*/ void GUIManager::hideGUI(const std::string& name)
323    {
324        GUIManager::getInstance().executeCode("hideMenuSheet(\"" + name + "\")");
325    }
326
327    const std::string& GUIManager::createInputState(const std::string& name, TriBool::Value showCursor, TriBool::Value useKeyboard, bool bBlockJoyStick)
328    {
329        InputState* state = InputManager::getInstance().createInputState(name);
330        if (!state)
331            return BLANKSTRING;
332
333        /* Table that maps isFullScreen() and showCursor to mouseExclusive
334        isFullscreen / showCursor | True  | False | Dontcare
335        ----------------------------------------------------
336        true                      | True  | True  | Dontcare
337        ----------------------------------------------------
338        false                     | False | True  | Dontcare
339        */
340        if (showCursor == TriBool::Dontcare)
341            state->setMouseExclusive(TriBool::Dontcare);
342        else if (GraphicsManager::getInstance().isFullScreen() || showCursor == TriBool::False)
343            state->setMouseExclusive(TriBool::True);
344        else
345            state->setMouseExclusive(TriBool::False);
346
347        if (showCursor == TriBool::True)
348            state->setMouseHandler(this);
349        else if (showCursor == TriBool::False)
350            state->setMouseHandler(&InputHandler::EMPTY);
351
352        if (useKeyboard == TriBool::True)
353            state->setKeyHandler(this);
354        else if (useKeyboard == TriBool::False)
355            state->setKeyHandler(&InputHandler::EMPTY);
356
357        if (bBlockJoyStick)
358            state->setJoyStickHandler(&InputHandler::EMPTY);
359
360        return state->getName();
361    }
362
363    void GUIManager::keyESC()
364    {
365        this->executeCode("keyESC()");
366    }
367
368    void GUIManager::setBackgroundImage(const std::string& imageSet, const std::string imageName)
369    {
370        if (imageSet.empty() || imageName.empty())
371            this->setBackgroundImage("");
372        else
373            this->setBackgroundImage("set: " + imageSet + " image: " + imageName);
374    }
375
376    void GUIManager::setBackgroundImage(const std::string& image)
377    {
378        if (image.empty())
379            this->rootWindow_->setProperty("Alpha", "0.0");
380        else
381            this->rootWindow_->setProperty("Alpha", "1.0");
382        this->rootWindow_->setProperty("Image", image);
383    }
384
385    void GUIManager::buttonPressed(const KeyEvent& evt)
386    {
387        this->protectedCall(boost::bind(&CEGUI::System::injectKeyDown, _1, evt.getKeyCode()));
388        this->protectedCall(boost::bind(&CEGUI::System::injectChar, _1, evt.getText()));
389    }
390
391    void GUIManager::buttonReleased(const KeyEvent& evt)
392    {
393        this->protectedCall(boost::bind(&CEGUI::System::injectKeyUp, _1, evt.getKeyCode()));
394    }
395
396    /**
397    @brief
398        Function receiving a mouse button pressed event.
399    @param id
400        ID of the mouse button which got pressed
401
402        This function is inherited by MouseHandler and injects the event into CEGUI.
403        It is for CEGUI to process the event.
404    */
405    void GUIManager::buttonPressed(MouseButtonCode::ByEnum id)
406    {
407        this->protectedCall(boost::bind(&CEGUI::System::injectMouseButtonDown, _1, convertButton(id)));
408    }
409
410    /**
411    @brief
412        Function receiving a mouse button released event.
413    @param id
414        ID of the mouse button which got released
415
416        This function is inherited by MouseHandler and injects the event into CEGUI.
417        It is for CEGUI to process the event.
418    */
419    void GUIManager::buttonReleased(MouseButtonCode::ByEnum id)
420    {
421        this->protectedCall(boost::bind(&CEGUI::System::injectMouseButtonUp, _1, convertButton(id)));
422    }
423
424    void GUIManager::mouseMoved(IntVector2 abs, IntVector2 rel, IntVector2 clippingSize)
425    {
426        this->protectedCall(boost::bind(&CEGUI::System::injectMousePosition, _1, (float)abs.x, (float)abs.y));
427    }
428
429    void GUIManager::mouseScrolled(int abs, int rel)
430    {
431        this->protectedCall(boost::bind(&CEGUI::System::injectMouseWheelChange, _1, (float)rel));
432    }
433
434    /**
435        @brief Indicates that the mouse left the application's window.
436    */
437    void GUIManager::mouseLeft()
438    {
439        this->protectedCall(boost::bind(&CEGUI::System::injectMouseLeaves, _1));
440    }
441
442    /**
443    @brief
444        converts mouse event code to CEGUI event code
445    @param button
446        code of the mouse button as we use it in Orxonox
447    @return
448        code of the mouse button as it is used by CEGUI
449
450        Simple conversion from mouse event code in Orxonox to the one used in CEGUI.
451     */
452    static inline CEGUI::MouseButton convertButton(MouseButtonCode::ByEnum button)
453    {
454        switch (button)
455        {
456        case MouseButtonCode::Left:
457            return CEGUI::LeftButton;
458
459        case MouseButtonCode::Right:
460            return CEGUI::RightButton;
461
462        case MouseButtonCode::Middle:
463            return CEGUI::MiddleButton;
464
465        case MouseButtonCode::Button3:
466            return CEGUI::X1Button;
467
468        case MouseButtonCode::Button4:
469            return CEGUI::X2Button;
470
471        default:
472            return CEGUI::NoButton;
473        }
474    }
475
476    /** Executes a CEGUI function normally, but catches CEGUI::ScriptException.
477        When a ScriptException occurs, the error message will be displayed and
478        the program carries on.
479    @remarks
480        The exception behaviour may pose problems if the code is not written
481        exception-safe (and you can forget about that in Lua). The program might
482        be left in an undefined state. But otherwise one script error would
483        terminate the whole program...
484    @note
485        Your life gets easier if you use boost::bind to create the object/function.
486    @param function
487        Any callable object/function that takes this->guiSystem_ as its only parameter.
488    @return
489        True if input was handled, false otherwise. A caught exception yields true.
490    */
491    template <typename FunctionType>
492    bool GUIManager::protectedCall(FunctionType function)
493    {
494        try
495        {
496            return function(this->guiSystem_);
497        }
498        catch (CEGUI::ScriptException& ex)
499        {
500            // Display the error and proceed. See @remarks why this can be dangerous.
501            COUT(1) << ex.getMessage() << std::endl;
502            return true;
503        }
504    }
505
506    /**
507    @brief
508        Subscribe the input function to the input event for the input window.
509        This is a helper to be used in lua, because subscribeScriptedEvent() doesn't work in lua.
510    @param window
511        The window for which the event is subscribed.
512    @param event
513        The type of event to which we subscribe.
514    @param function
515        The function that is called when the event occurs.
516    */
517    void GUIManager::subscribeEventHelper(CEGUI::Window* window, const std::string& event, const std::string& function)
518    {
519        window->subscribeScriptedEvent(event, function);
520    }
521
522    /**
523    @brief
524        Set the input tooltip text for the input ListboxItem.
525    @param item
526        The ListboxItem for which the tooltip should be set.
527    @param tooltip
528        The tooltip text that should be set.
529    */
530    void GUIManager::setTooltipTextHelper(CEGUI::ListboxItem* item, const std::string& tooltip)
531    {
532        item->setTooltipText(tooltip);
533    }
534
535    /**
536    @brief
537        Set whether the tooltips for the input Listbox are enabled.
538    @param listbox
539        The Listbox for which to enable (or disable) tooltips.
540    @param enabled
541        Whether to enable or disable the tooltips.
542    */
543    void GUIManager::setItemTooltipsEnabledHelper(CEGUI::Listbox* listbox, bool enabled)
544    {
545        listbox->setItemTooltipsEnabled(enabled);
546    }
547
548    /**
549        @brief Callback of window event listener, called if the window is resized. Sets the display size of CEGUI.
550    */
551    void GUIManager::windowResized(unsigned int newWidth, unsigned int newHeight)
552    {
553#ifdef CEGUI_OLD_VERSION
554        this->guiRenderer_->setDisplaySize(CEGUI::Size(newWidth, newHeight));
555#else
556        this->guiRenderer_->setDisplaySize(CEGUI::Size((float)newWidth, (float)newHeight));
557#endif
558    }
559
560    /**
561        @brief Notify CEGUI if the windows loses the focus (stops highlight of menu items, etc).
562    */
563    void GUIManager::windowFocusChanged(bool bFocus)
564    {
565        if (!bFocus)
566            this->mouseLeft();
567    }
568
569}
Note: See TracBrowser for help on using the repository browser.