Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/usability/src/libraries/core/GUIManager.cc @ 8030

Last change on this file since 8030 was 7994, checked in by rgrieder, 14 years ago

Fixed msvc warnings and a typo.

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