Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7660 was 7648, checked in by dafrick, 14 years ago

Merged releasetodo, containing a new way to describe and tag levels, back to trunk.

  • Property svn:eol-style set to native
File size: 16.8 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>
34extern "C" {
35#include <lua.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#include <ogreceguirenderer/OgreCEGUIRenderer.h>
48
49#include "SpecialConfig.h" // Configures the macro below
50#ifdef CEGUILUA_USE_INTERNAL_LIBRARY
51#   include <ceguilua/CEGUILua.h>
52#else
53#   include <CEGUILua.h>
54#endif
55
56#include "util/Clock.h"
57#include "util/Convert.h"
58#include "util/Debug.h"
59#include "util/Exception.h"
60#include "util/OrxAssert.h"
61#include "Core.h"
62#include "GraphicsManager.h"
63#include "LuaState.h"
64#include "PathConfig.h"
65#include "Resource.h"
66#include "command/ConsoleCommand.h"
67#include "input/InputManager.h"
68#include "input/InputState.h"
69#include "input/KeyBinderManager.h"
70
71namespace orxonox
72{
73    static void key_esc()
74        { GUIManager::getInstance().keyESC(); }
75    SetConsoleCommand("keyESC", &key_esc);
76
77    class CEGUILogger : public CEGUI::DefaultLogger
78    {
79    public:
80        void logEvent(const CEGUI::String& message, CEGUI::LoggingLevel level = CEGUI::Standard)
81        {
82            int orxonoxLevel = CEGUI::Standard;
83            switch (level)
84            {
85                case CEGUI::Errors:      orxonoxLevel = 1; break;
86                case CEGUI::Warnings:    orxonoxLevel = 2; break;
87                case CEGUI::Standard:    orxonoxLevel = 4; break;
88                case CEGUI::Informative: orxonoxLevel = 5; break;
89                case CEGUI::Insane:      orxonoxLevel = 6; break;
90                default: OrxAssert(false, "CEGUI log level out of range, inpect immediately!");
91            }
92            OutputHandler::getOutStream(orxonoxLevel)
93                << "CEGUI: " << message << std::endl;
94
95            CEGUI::DefaultLogger::logEvent(message, level);
96        }
97    };
98
99    static CEGUI::MouseButton convertButton(MouseButtonCode::ByEnum button);
100
101    GUIManager* GUIManager::singletonPtr_s = 0;
102
103    SetConsoleCommand("showGUI", &GUIManager::showGUI).defaultValue(1, false).defaultValue(2, false);
104    SetConsoleCommand("hideGUI", &GUIManager::hideGUI);
105
106    /**
107    @brief
108        Constructs the GUIManager by starting up CEGUI
109
110        Creates the interface to Ogre, sets up the CEGUI renderer and the Lua script module together with the Lua engine.
111        The log is set up and connected to the CEGUILogger.
112        After Lua setup tolua++-elements are linked to Lua-state to give Lua access to C++-code.
113        Finally initial Lua code is executed (maybe we can do this with the CEGUI startup script automatically).
114    @return true if success, otherwise false
115    */
116    GUIManager::GUIManager(const std::pair<int, int>& mousePosition)
117        : resourceProvider_(NULL)
118        , camera_(NULL)
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("GUI");
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    /**
180    @brief
181        used to tick the GUI
182    @param time
183        clock which provides time value for the GUI System
184
185        Ticking the GUI means updating it with a certain regularity.
186        The elapsed time since the last call is given in the time value provided by the clock.
187        This time value is then used to provide a fluent animation of the GUI.
188    */
189    void GUIManager::preUpdate(const Clock& time)
190    {
191        assert(guiSystem_);
192        this->protectedCall(boost::bind(&CEGUI::System::injectTimePulse, _1, time.getDeltaTime()));
193    }
194
195    /**
196    @brief
197        Tells the GUIManager which SceneManager to use
198    @param camera
199        The current camera on which the GUI should be displayed on.
200
201        In fact the GUIManager needs the SceneManager and not the Camera to display the GUI.
202        This means the GUI is not bound to a camera but rather to the SceneManager.
203        Hiding the GUI when needed can therefore not be resolved by just NOT setting the current camera.
204    */
205    void GUIManager::setCamera(Ogre::Camera* camera)
206    {
207        this->camera_ = camera;
208        if (camera == NULL)
209            this->guiRenderer_->setTargetSceneManager(0);
210        else
211            this->guiRenderer_->setTargetSceneManager(camera->getSceneManager());
212    }
213
214    /**
215    @brief
216        Executes Lua code
217    @param str
218        reference to string object holding the Lua code which is to be executed
219    */
220    void GUIManager::executeCode(const std::string& str)
221    {
222        this->luaState_->doString(str, rootFileInfo_);
223    }
224
225    /** Loads a GUI sheet by Lua script
226    @param name
227        The name of the GUI (like the script name, but without the extension)
228    */
229    void GUIManager::loadGUI(const std::string& name)
230    {
231        this->executeCode("loadSheet(\"" + name + "\")");
232    }
233
234    /**
235    @brief
236        Displays specified GUI on screen
237    @param name
238        The name of the GUI
239    @param bHidePrevious
240        If true all displayed GUIs on the stack, that are below this GUI are hidden.
241    @param bNoInput
242        If true the GUI is transparent to input.
243
244        The function executes the Lua function with the same name in case the GUIManager is ready.
245    */
246    /*static*/ void GUIManager::showGUI(const std::string& name, bool bHidePrevious, bool bNoInput)
247    {
248        GUIManager::getInstance().executeCode("showMenuSheet(\"" + name + "\", " + multi_cast<std::string>(bHidePrevious) + ", " + multi_cast<std::string>(bNoInput) + ")");
249    }
250
251    /**
252    @brief
253        Hack-ish. Needed for GUIOverlay.
254    */
255    void GUIManager::showGUIExtra(const std::string& name, const std::string& ptr, bool bHidePrevious, bool bNoInput)
256    {
257        this->executeCode("showMenuSheet(\"" + name + "\", " + multi_cast<std::string>(bHidePrevious) + ", " + multi_cast<std::string>(bNoInput) + ", " + ptr + ")");
258    }
259
260    /**
261    @brief
262        Hides specified GUI.
263    @param name
264        The name of the GUI.
265    */
266    /*static*/ void GUIManager::hideGUI(const std::string& name)
267    {
268        GUIManager::getInstance().executeCode("hideMenuSheet(\"" + name + "\")");
269    }
270
271    const std::string& GUIManager::createInputState(const std::string& name, TriBool::Value showCursor, TriBool::Value useKeyboard, bool bBlockJoyStick)
272    {
273        InputState* state = InputManager::getInstance().createInputState(name);
274
275        /* Table that maps isFullScreen() and showCursor to mouseExclusive
276        isFullscreen / showCursor | True  | False | Dontcare
277        ----------------------------------------------------
278        true                      | True  | True  | Dontcare
279        ----------------------------------------------------
280        false                     | False | True  | Dontcare
281        */
282        if (showCursor == TriBool::Dontcare)
283            state->setMouseExclusive(TriBool::Dontcare);
284        else if (GraphicsManager::getInstance().isFullScreen() || showCursor == TriBool::False)
285            state->setMouseExclusive(TriBool::True);
286        else
287            state->setMouseExclusive(TriBool::False);
288
289        if (showCursor == TriBool::True)
290            state->setMouseHandler(this);
291        else if (showCursor == TriBool::False)
292            state->setMouseHandler(&InputHandler::EMPTY);
293
294        if (useKeyboard == TriBool::True)
295            state->setKeyHandler(this);
296        else if (useKeyboard == TriBool::False)
297            state->setKeyHandler(&InputHandler::EMPTY);
298
299        if (bBlockJoyStick)
300            state->setJoyStickHandler(&InputHandler::EMPTY);
301
302        return state->getName();
303    }
304
305    void GUIManager::keyESC()
306    {
307        this->executeCode("keyESC()");
308    }
309
310    void GUIManager::setBackgroundImage(const std::string& imageSet, const std::string imageName)
311    {
312        if (imageSet.empty() || imageName.empty())
313            this->setBackgroundImage("");
314        else
315            this->setBackgroundImage("set: " + imageSet + " image: " + imageName);
316    }
317
318    void GUIManager::setBackgroundImage(const std::string& image)
319    {
320        if (image.empty())
321            this->rootWindow_->setProperty("Alpha", "0.0");
322        else
323            this->rootWindow_->setProperty("Alpha", "1.0");
324        this->rootWindow_->setProperty("Image", image);
325    }
326
327    void GUIManager::buttonPressed(const KeyEvent& evt)
328    {
329        this->protectedCall(boost::bind(&CEGUI::System::injectKeyDown, _1, evt.getKeyCode()));
330        this->protectedCall(boost::bind(&CEGUI::System::injectChar, _1, evt.getText()));
331    }
332
333    void GUIManager::buttonReleased(const KeyEvent& evt)
334    {
335        this->protectedCall(boost::bind(&CEGUI::System::injectKeyUp, _1, evt.getKeyCode()));
336    }
337
338    /**
339    @brief
340        Function receiving a mouse button pressed event.
341    @param id
342        ID of the mouse button which got pressed
343
344        This function is inherited by MouseHandler and injects the event into CEGUI.
345        It is for CEGUI to process the event.
346    */
347    void GUIManager::buttonPressed(MouseButtonCode::ByEnum id)
348    {
349        this->protectedCall(boost::bind(&CEGUI::System::injectMouseButtonDown, _1, convertButton(id)));
350    }
351
352    /**
353    @brief
354        Function receiving a mouse button released event.
355    @param id
356        ID of the mouse button which got released
357
358        This function is inherited by MouseHandler and injects the event into CEGUI.
359        It is for CEGUI to process the event.
360    */
361    void GUIManager::buttonReleased(MouseButtonCode::ByEnum id)
362    {
363        this->protectedCall(boost::bind(&CEGUI::System::injectMouseButtonUp, _1, convertButton(id)));
364    }
365
366    void GUIManager::mouseMoved(IntVector2 abs, IntVector2 rel, IntVector2 clippingSize)
367    {
368        this->protectedCall(boost::bind(&CEGUI::System::injectMousePosition, _1, (float)abs.x, (float)abs.y));
369    }
370
371    void GUIManager::mouseScrolled(int abs, int rel)
372    {
373        this->protectedCall(boost::bind(&CEGUI::System::injectMouseWheelChange, _1, (float)rel));
374    }
375
376    /**
377    @brief
378        converts mouse event code to CEGUI event code
379    @param button
380        code of the mouse button as we use it in Orxonox
381    @return
382        code of the mouse button as it is used by CEGUI
383
384        Simple conversion from mouse event code in Orxonox to the one used in CEGUI.
385     */
386    static inline CEGUI::MouseButton convertButton(MouseButtonCode::ByEnum button)
387    {
388        switch (button)
389        {
390        case MouseButtonCode::Left:
391            return CEGUI::LeftButton;
392
393        case MouseButtonCode::Right:
394            return CEGUI::RightButton;
395
396        case MouseButtonCode::Middle:
397            return CEGUI::MiddleButton;
398
399        case MouseButtonCode::Button3:
400            return CEGUI::X1Button;
401
402        case MouseButtonCode::Button4:
403            return CEGUI::X2Button;
404
405        default:
406            return CEGUI::NoButton;
407        }
408    }
409
410    /** Executes a CEGUI function normally, but catches CEGUI::ScriptException.
411        When a ScriptException occurs, the error message will be displayed and
412        the program carries on.
413    @remarks
414        The exception behaviour may pose problems if the code is not written
415        exception-safe (and you can forget about that in Lua). The program might
416        be left in an undefined state. But otherwise one script error would
417        terminate the whole program...
418    @note
419        Your life gets easier if you use boost::bind to create the object/function.
420    @param function
421        Any callable object/function that takes this->guiSystem_ as its only parameter.
422    @return
423        True if input was handled, false otherwise. A caught exception yields true.
424    */
425    template <typename FunctionType>
426    bool GUIManager::protectedCall(FunctionType function)
427    {
428        try
429        {
430            return function(this->guiSystem_);
431        }
432        catch (CEGUI::ScriptException& ex)
433        {
434            // Display the error and proceed. See @remarks why this can be dangerous.
435            COUT(1) << ex.getMessage() << std::endl;
436            return true;
437        }
438    }
439
440    /**
441    @brief
442        Subscribe the input function to the input event for the input window.
443        This is a helper to be used in lua, because subscribeScriptedEvent() doesn't work in lua.
444    @param window
445        The window for which the event is subscribed.
446    @param event
447        The type of event to which we subscribe.
448    @param function
449        The function that is called when the event occurs.
450    */
451    void GUIManager::subscribeEventHelper(CEGUI::Window* window, const std::string& event, const std::string& function)
452    {
453        window->subscribeScriptedEvent(event, function);
454    }
455
456    /**
457    @brief
458        Set the input tooltip text for the input ListboxItem.
459    @param item
460        The ListboxItem for which the tooltip should be set.
461    @param tooltip
462        The tooltip text that should be set.
463    */
464    void GUIManager::setTooltipTextHelper(CEGUI::ListboxItem* item, const std::string& tooltip)
465    {
466        item->setTooltipText(tooltip);
467    }
468
469    /**
470    @brief
471        Set whether the tooltips for the input Listbox are enabled.
472    @param listbox
473        The Listbox for which to enable (or disable) tooltips.
474    @param enabled
475        Whether to enable or disabel the tooltips.
476    */
477    void GUIManager::setItemTooltipsEnabledHelper(CEGUI::Listbox* listbox, bool enabled)
478    {
479        listbox->setItemTooltipsEnabled(enabled);
480    }
481
482}
Note: See TracBrowser for help on using the repository browser.