Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Kicked CEGUILua from our repository and adjusted the build system accordingly.
The Linux part is still missing though.

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