Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/tutoriallevel/src/libraries/core/GUIManager.cc @ 8498

Last change on this file since 8498 was 7894, checked in by dafrick, 14 years ago

Some extension of NotificationQueue, font size and color can now be specified.

  • Property svn:eol-style set to native
File size: 18.6 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 <CEGUIFontManager.h>
40#include <CEGUIInputEvent.h>
41#include <CEGUIMouseCursor.h>
42#include <CEGUIResourceProvider.h>
43#include <CEGUISystem.h>
44#include <CEGUIWindow.h>
45#include <CEGUIWindowManager.h>
46#include <CEGUIXMLAttributes.h>
47#include <elements/CEGUIListbox.h>
48#include <elements/CEGUIListboxItem.h>
49#include <ogreceguirenderer/OgreCEGUIRenderer.h>
50
51#include "SpecialConfig.h" // Configures the macro below
52#ifdef CEGUILUA_USE_INTERNAL_LIBRARY
53#   include <ceguilua/CEGUILua.h>
54#else
55#   include <CEGUILua.h>
56#endif
57
58#include "util/Clock.h"
59#include "util/Convert.h"
60#include "util/Debug.h"
61#include "util/Exception.h"
62#include "util/OrxAssert.h"
63#include "ConfigValueIncludes.h"
64#include "Core.h"
65#include "CoreIncludes.h"
66#include "GraphicsManager.h"
67#include "LuaState.h"
68#include "PathConfig.h"
69#include "Resource.h"
70#include "command/ConsoleCommand.h"
71#include "input/InputManager.h"
72#include "input/InputState.h"
73#include "input/KeyBinderManager.h"
74
75namespace orxonox
76{
77    static void key_esc()
78        { GUIManager::getInstance().keyESC(); }
79    SetConsoleCommand("keyESC", &key_esc);
80
81    class CEGUILogger : public CEGUI::DefaultLogger
82    {
83    public:
84        void logEvent(const CEGUI::String& message, CEGUI::LoggingLevel level = CEGUI::Standard)
85        {
86            int orxonoxLevel = CEGUI::Standard;
87            switch (level)
88            {
89                case CEGUI::Errors:      orxonoxLevel = 1; break;
90                case CEGUI::Warnings:    orxonoxLevel = 2; break;
91                case CEGUI::Standard:    orxonoxLevel = 4; break;
92                case CEGUI::Informative: orxonoxLevel = 5; break;
93                case CEGUI::Insane:      orxonoxLevel = 6; break;
94                default: OrxAssert(false, "CEGUI log level out of range, inpect immediately!");
95            }
96            OutputHandler::getOutStream(orxonoxLevel)
97                << "CEGUI: " << message << std::endl;
98
99            CEGUI::DefaultLogger::logEvent(message, level);
100        }
101    };
102
103    static CEGUI::MouseButton convertButton(MouseButtonCode::ByEnum button);
104
105    GUIManager* GUIManager::singletonPtr_s = 0;
106    /*static*/ const std::string GUIManager::defaultScheme_ = "TaharezGreen";
107
108    SetConsoleCommand("showGUI", &GUIManager::showGUI).defaultValue(1, false).defaultValue(2, false);
109    SetConsoleCommand("hideGUI", &GUIManager::hideGUI);
110
111    /**
112    @brief
113        Constructs the GUIManager by starting up CEGUI
114
115        Creates the interface to Ogre, sets up the CEGUI renderer and the Lua script module together with the Lua engine.
116        The log is set up and connected to the CEGUILogger.
117        After Lua setup tolua++-elements are linked to Lua-state to give Lua access to C++-code.
118        Finally initial Lua code is executed (maybe we can do this with the CEGUI startup script automatically).
119    @return true if success, otherwise false
120    */
121    GUIManager::GUIManager(const std::pair<int, int>& mousePosition)
122        : resourceProvider_(NULL)
123        , camera_(NULL)
124    {
125        RegisterRootObject(GUIManager);
126        this->setConfigValues();
127
128        using namespace CEGUI;
129
130        COUT(3) << "Initialising CEGUI." << std::endl;
131
132        // Note: No SceneManager specified yet
133        guiRenderer_.reset(new OgreCEGUIRenderer(GraphicsManager::getInstance().getRenderWindow(), Ogre::RENDER_QUEUE_OVERLAY, false, 3000));
134        resourceProvider_ = guiRenderer_->createResourceProvider();
135        resourceProvider_->setDefaultResourceGroup("General");
136
137        // Setup scripting
138        luaState_.reset(new LuaState());
139        rootFileInfo_ = Resource::getInfo("InitialiseGUI.lua");
140        // This is necessary to ensure that input events also use the right resource info when triggering lua functions
141        luaState_->setDefaultResourceInfo(this->rootFileInfo_);
142        scriptModule_.reset(new LuaScriptModule(luaState_->getInternalLuaState()));
143        scriptModule_->setDefaultPCallErrorHandler(LuaState::ERROR_HANDLER_NAME);
144
145        // Create our own logger to specify the filepath
146        std::auto_ptr<CEGUILogger> ceguiLogger(new CEGUILogger());
147        ceguiLogger->setLogFilename(PathConfig::getLogPathString() + "cegui.log");
148        // set the log level according to ours (translate by subtracting 1)
149        ceguiLogger->setLoggingLevel(
150            static_cast<LoggingLevel>(OutputHandler::getInstance().getSoftDebugLevel("logFile") - 1));
151        this->ceguiLogger_ = ceguiLogger.release();
152
153        // Create the CEGUI system singleton
154        guiSystem_.reset(new System(guiRenderer_.get(), resourceProvider_, 0, scriptModule_.get()));
155
156        // Align CEGUI mouse with OIS mouse
157        guiSystem_->injectMousePosition((float)mousePosition.first, (float)mousePosition.second);
158
159        // Initialise the Lua framework and load the schemes
160        this->luaState_->doFile("InitialiseGUI.lua");
161
162        // Create the root nodes
163        this->rootWindow_ = CEGUI::WindowManager::getSingleton().createWindow("MenuWidgets/StaticImage", "AbsoluteRootWindow");
164        this->rootWindow_->setProperty("FrameEnabled", "False");
165        this->hudRootWindow_ = CEGUI::WindowManager::getSingleton().createWindow("DefaultWindow", "HUDRootWindow");
166        this->menuRootWindow_ = CEGUI::WindowManager::getSingleton().createWindow("DefaultWindow", "MenuRootWindow");
167        // And connect them
168        CEGUI::System::getSingleton().setGUISheet(this->rootWindow_);
169        this->rootWindow_->addChildWindow(this->hudRootWindow_);
170        this->rootWindow_->addChildWindow(this->menuRootWindow_);
171
172        // No background to start with (sets the alpha value to 0)
173        this->setBackgroundImage("");
174
175        // Set up the sheet manager in the Lua framework
176        this->luaState_->doFile("SheetManager.lua");
177    }
178
179    /**
180    @brief
181        Basically shuts down CEGUI (member smart pointers) but first unloads our Tolua modules.
182    */
183    GUIManager::~GUIManager()
184    {
185    }
186
187    void GUIManager::setConfigValues(void)
188    {
189        SetConfigValue(guiScheme_, GUIManager::defaultScheme_) .description("Changes the current GUI scheme.") .callback(this, &GUIManager::changedGUIScheme);
190    }
191
192    void GUIManager::changedGUIScheme(void)
193    {
194       
195    }
196
197    /**
198    @brief
199        used to tick the GUI
200    @param time
201        clock which provides time value for the GUI System
202
203        Ticking the GUI means updating it with a certain regularity.
204        The elapsed time since the last call is given in the time value provided by the clock.
205        This time value is then used to provide a fluent animation of the GUI.
206    */
207    void GUIManager::preUpdate(const Clock& time)
208    {
209        assert(guiSystem_);
210        this->protectedCall(boost::bind(&CEGUI::System::injectTimePulse, _1, time.getDeltaTime()));
211    }
212
213    /**
214    @brief
215        Tells the GUIManager which SceneManager to use
216    @param camera
217        The current camera on which the GUI should be displayed on.
218
219        In fact the GUIManager needs the SceneManager and not the Camera to display the GUI.
220        This means the GUI is not bound to a camera but rather to the SceneManager.
221        Hiding the GUI when needed can therefore not be resolved by just NOT setting the current camera.
222    */
223    void GUIManager::setCamera(Ogre::Camera* camera)
224    {
225        this->camera_ = camera;
226        if (camera == NULL)
227            this->guiRenderer_->setTargetSceneManager(0);
228        else
229            this->guiRenderer_->setTargetSceneManager(camera->getSceneManager());
230    }
231
232    /**
233    @brief
234        Executes Lua code
235    @param str
236        reference to string object holding the Lua code which is to be executed
237    */
238    void GUIManager::executeCode(const std::string& str)
239    {
240        this->luaState_->doString(str, rootFileInfo_);
241    }
242
243    /** Loads a GUI sheet by Lua script
244    @param name
245        The name of the GUI (like the script name, but without the extension)
246    */
247    void GUIManager::loadGUI(const std::string& name)
248    {
249        this->executeCode("loadSheet(\"" + name + "\")");
250    }
251
252    /**
253    @brief
254        Displays specified GUI on screen
255    @param name
256        The name of the GUI
257    @param bHidePrevious
258        If true all displayed GUIs on the stack, that are below this GUI are hidden.
259    @param bNoInput
260        If true the GUI is transparent to input.
261
262        The function executes the Lua function with the same name in case the GUIManager is ready.
263    */
264    /*static*/ void GUIManager::showGUI(const std::string& name, bool bHidePrevious, bool bNoInput)
265    {
266        GUIManager::getInstance().executeCode("showMenuSheet(\"" + name + "\", " + multi_cast<std::string>(bHidePrevious) + ", " + multi_cast<std::string>(bNoInput) + ")");
267    }
268
269    /**
270    @brief
271        Hack-ish. Needed for GUIOverlay.
272    */
273    void GUIManager::showGUIExtra(const std::string& name, const std::string& ptr, bool bHidePrevious, bool bNoInput)
274    {
275        this->executeCode("showMenuSheet(\"" + name + "\", " + multi_cast<std::string>(bHidePrevious) + ", " + multi_cast<std::string>(bNoInput) + ", " + ptr + ")");
276    }
277
278    /**
279    @brief
280        Hides specified GUI.
281    @param name
282        The name of the GUI.
283    */
284    /*static*/ void GUIManager::hideGUI(const std::string& name)
285    {
286        GUIManager::getInstance().executeCode("hideMenuSheet(\"" + name + "\")");
287    }
288
289    const std::string& GUIManager::createInputState(const std::string& name, TriBool::Value showCursor, TriBool::Value useKeyboard, bool bBlockJoyStick)
290    {
291        InputState* state = InputManager::getInstance().createInputState(name);
292        if (!state)
293            return BLANKSTRING;
294
295        /* Table that maps isFullScreen() and showCursor to mouseExclusive
296        isFullscreen / showCursor | True  | False | Dontcare
297        ----------------------------------------------------
298        true                      | True  | True  | Dontcare
299        ----------------------------------------------------
300        false                     | False | True  | Dontcare
301        */
302        if (showCursor == TriBool::Dontcare)
303            state->setMouseExclusive(TriBool::Dontcare);
304        else if (GraphicsManager::getInstance().isFullScreen() || showCursor == TriBool::False)
305            state->setMouseExclusive(TriBool::True);
306        else
307            state->setMouseExclusive(TriBool::False);
308
309        if (showCursor == TriBool::True)
310            state->setMouseHandler(this);
311        else if (showCursor == TriBool::False)
312            state->setMouseHandler(&InputHandler::EMPTY);
313
314        if (useKeyboard == TriBool::True)
315            state->setKeyHandler(this);
316        else if (useKeyboard == TriBool::False)
317            state->setKeyHandler(&InputHandler::EMPTY);
318
319        if (bBlockJoyStick)
320            state->setJoyStickHandler(&InputHandler::EMPTY);
321
322        return state->getName();
323    }
324
325    void GUIManager::keyESC()
326    {
327        this->executeCode("keyESC()");
328    }
329
330    void GUIManager::setBackgroundImage(const std::string& imageSet, const std::string imageName)
331    {
332        if (imageSet.empty() || imageName.empty())
333            this->setBackgroundImage("");
334        else
335            this->setBackgroundImage("set: " + imageSet + " image: " + imageName);
336    }
337
338    void GUIManager::setBackgroundImage(const std::string& image)
339    {
340        if (image.empty())
341            this->rootWindow_->setProperty("Alpha", "0.0");
342        else
343            this->rootWindow_->setProperty("Alpha", "1.0");
344        this->rootWindow_->setProperty("Image", image);
345    }
346
347    void GUIManager::buttonPressed(const KeyEvent& evt)
348    {
349        this->protectedCall(boost::bind(&CEGUI::System::injectKeyDown, _1, evt.getKeyCode()));
350        this->protectedCall(boost::bind(&CEGUI::System::injectChar, _1, evt.getText()));
351    }
352
353    void GUIManager::buttonReleased(const KeyEvent& evt)
354    {
355        this->protectedCall(boost::bind(&CEGUI::System::injectKeyUp, _1, evt.getKeyCode()));
356    }
357
358    /**
359    @brief
360        Function receiving a mouse button pressed event.
361    @param id
362        ID of the mouse button which got pressed
363
364        This function is inherited by MouseHandler and injects the event into CEGUI.
365        It is for CEGUI to process the event.
366    */
367    void GUIManager::buttonPressed(MouseButtonCode::ByEnum id)
368    {
369        this->protectedCall(boost::bind(&CEGUI::System::injectMouseButtonDown, _1, convertButton(id)));
370    }
371
372    /**
373    @brief
374        Function receiving a mouse button released event.
375    @param id
376        ID of the mouse button which got released
377
378        This function is inherited by MouseHandler and injects the event into CEGUI.
379        It is for CEGUI to process the event.
380    */
381    void GUIManager::buttonReleased(MouseButtonCode::ByEnum id)
382    {
383        this->protectedCall(boost::bind(&CEGUI::System::injectMouseButtonUp, _1, convertButton(id)));
384    }
385
386    void GUIManager::mouseMoved(IntVector2 abs, IntVector2 rel, IntVector2 clippingSize)
387    {
388        this->protectedCall(boost::bind(&CEGUI::System::injectMousePosition, _1, (float)abs.x, (float)abs.y));
389    }
390
391    void GUIManager::mouseScrolled(int abs, int rel)
392    {
393        this->protectedCall(boost::bind(&CEGUI::System::injectMouseWheelChange, _1, (float)rel));
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
504        Adds a new freetype font to the CEGUI system.
505    @param name
506        The name of the new font.
507    @param size
508        The font size of the new font in pixels.
509        @param fontName
510        The filename of the font.
511    */
512    /*static*/ void GUIManager::addFontHelper(const std::string& name, int size, const std::string& fontName)
513    {
514        if(CEGUI::FontManager::getSingleton().isFontPresent(name)) // If a font with that name already exists.
515            return;
516
517        CEGUI::Font* font = NULL;
518        CEGUI::XMLAttributes xmlAttributes;
519
520        // Attributes specified within CEGUIFont
521        xmlAttributes.add("Name", name);
522        xmlAttributes.add("Filename", fontName);
523        xmlAttributes.add("ResourceGroup", "");
524        xmlAttributes.add("AutoScaled", "true");
525        xmlAttributes.add("NativeHorzRes", "800");
526        xmlAttributes.add("NativeVertRes", "600");
527
528        // Attributes specified within CEGUIXMLAttributes
529        xmlAttributes.add("Size", multi_cast<std::string>(size));
530        xmlAttributes.add("AntiAlias", "true");
531
532        font = CEGUI::FontManager::getSingleton().createFont("FreeType", xmlAttributes);
533        if(font != NULL)
534            font->load();
535    }
536
537}
Note: See TracBrowser for help on using the repository browser.