Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7873 was 7873, checked in by landauf, 13 years ago

fixed mouse cursor offset after window resize

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