Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7983 was 7876, checked in by dafrick, 14 years ago

Extending startGame and similar console commands, now also the level to be started (or in case of startClient, the destination) can be specified (but doesn't have to).
Additionally startMainMenu is now in GSLevel and can only be executed in a Level, as opposed to only in the MainMenu as it was before.
Added changeGame console command which works in a level in standalone mode to change to a different level.

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