1 //  SuperTuxKart - a fun racing game with go-kart
2 //  Copyright (C) 2010-2015 Marianne Gagnon
3 //
4 //  This program is free software; you can redistribute it and/or
5 //  modify it under the terms of the GNU General Public License
6 //  as published by the Free Software Foundation; either version 3
7 //  of the License, or (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program; if not, write to the Free Software
16 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 
18 
19 #ifndef HEADER_SCREEN_HPP
20 #define HEADER_SCREEN_HPP
21 
22 #include <map>
23 #include <string>
24 #include <typeinfo>
25 #include "utils/cpp2011.hpp"
26 
27 #include <irrString.h>
28 #include <IXMLReader.h>
29 
30 namespace irr
31 {
32     namespace gui { class IGUIElement; }
33 }
34 using namespace irr;
35 
36 #include "config/stk_config.hpp"
37 #include "guiengine/abstract_top_level_container.hpp"
38 #include "guiengine/engine.hpp"
39 #include "guiengine/event_handler.hpp"
40 #include "guiengine/widget.hpp"
41 #include "input/input.hpp"
42 #include "utils/leak_check.hpp"
43 #include "utils/ptr_vector.hpp"
44 
45 #include <functional>
46 
47 /**
48  * \ingroup guiengine
49  */
50 namespace GUIEngine
51 {
52     /**
53      * \brief Declares a class to be a singleton.
54      * Normally, all screens will be singletons.
55      * \ingroup guiengine
56      */
57     template<typename SCREEN>
58     class ScreenSingleton
59     {
60     protected:
61         static SCREEN* singleton;
62     public:
63 
~ScreenSingleton()64         ~ScreenSingleton()
65         {
66             singleton = NULL;
67         }
68 
getInstance()69         static SCREEN* getInstance()
70         {
71             if (singleton == NULL)
72             {
73                 singleton = new SCREEN();
74                 std::function<SCREEN*()> new_screen_function = []()
75                     { return ScreenSingleton::getInstance(); };
76                 singleton->setScreenPointerFunction(new_screen_function);
77                 GUIEngine::addScreenToList(singleton);
78             }
79 
80             return singleton;
81         }
82     };
83     template <typename SCREEN> SCREEN*
84         ScreenSingleton<SCREEN>::singleton = nullptr;
85 
86     /**
87      * \brief Represents a single GUI screen.
88      * Mainly responsible of its children widgets; Screen lays them
89      * out, asks them to add themselves, asks them to remove themselves, etc.
90      *
91      * Also initiates the read of GUI files, even though most of that work is
92      * done in "screen_loader.cpp"
93      *
94      * \ingroup guiengine
95      */
96     class Screen : public AbstractTopLevelContainer
97     {
98 protected:
99         /** True if this screen is resizable
100          */
101         bool m_resizable;
102 
103         bool m_throttle_FPS;
104     private:
105         /** True if the race (if it is running) should be paused when this
106          *  screen is shown. The RaceResultGUI uses this to leave the race
107          *  running while it is being shown. */
108         bool m_pause_race;
109 
110         bool m_loaded;
111 
112         /** Will be called to determine if the 3D scene must be rendered when
113          *  at this screen.
114          */
115         bool m_render_3d;
116 
117         /** When set to true it updates the screen even if modal dialog is
118          *  opened
119          */
120         bool m_update_in_background;
121 
122         /** to catch errors as early as possible, for debugging purposes only */
123         unsigned int m_magic_number;
124 
125         unsigned m_width, m_height;
126 
127         friend class Skin;
128 
129         std::string m_filename;
130         /** For runtime screen reloading without template */
131         std::function<Screen*()> m_screen_func;
132     public:
133 
134         LEAK_CHECK()
135 
136         /**
137          * \ingroup guiengine
138          * \brief Loads a GUI screen from its XML file.
139          *
140          * Builds a hierarchy of Widget objects whose contents are a direct
141          * transcription of the XML file, with little analysis or layout
142          * performed on them.
143          */
144         static void parseScreenFileDiv(irr::io::IXMLReader* xml,
145                                        PtrVector<Widget>& append_to,
146                                        irr::gui::IGUIElement* parent = NULL);
147 
148         /** Save the function before GUIEngine::clearScreenCache, call it after
149          * to get the new screen instance pointer
150          */
getNewScreenPointer() const151         std::function<Screen*()> getNewScreenPointer() const { return m_screen_func; }
152 
setScreenPointerFunction(const std::function<Screen * ()> & f)153         void setScreenPointerFunction(const std::function<Screen*()>& f) { m_screen_func = f; }
154 
155         Screen(bool pause_race=true);
156 
157         Screen(const char* filename, bool pause_race=true);
158 
159         virtual ~Screen();
160 
operator ==(const char * filename) const161         bool operator ==(const char* filename) const { return m_filename == filename; }
162 
163         void loadFromFile();
164 
165         /** \return whether this screen is currently loaded */
isLoaded() const166         bool isLoaded() const { return m_loaded; }
167 
throttleFPS() const168         bool throttleFPS() const { return m_throttle_FPS; }
169 
170         void addWidgets();
171 
172         void calculateLayout();
173 
174         void manualAddWidget(Widget* w);
175 
176         void manualRemoveWidget(Widget* w);
177 
178         /** When set to true it updates the screen even if modal dialog is
179          *  opened
180          */
setUpdateInBackground(bool value)181         void setUpdateInBackground(bool value) {m_update_in_background = value;}
getUpdateInBackground()182         bool getUpdateInBackground() {return m_update_in_background;}
183 
184         /** \return the name of this menu (which is the name of the file) */
getName() const185         const std::string& getName() const { return m_filename; }
186 
187         virtual void unload();
188 
189         /** Will be called to determine if the 3D scene must be rendered when
190          *  at this screen
191          */
needs3D()192         bool needs3D() { return m_render_3d; }
193 
194         /** \brief Invoke this method for screens that use a 3D scene as
195          *         background.
196          *
197          *  (if this method is not invoked with 'true' as parameter, the menu
198          *  background will be rendered instead).
199          *
200          *  \note To create the 3D background, use the facilities provided by
201          *        the irrLicht scene manager, this class will not set up any
202          *        3D scene.
203          */
setNeeds3D(bool needs3D)204         void setNeeds3D(bool needs3D) { m_render_3d = needs3D; }
205 
206         /**
207          * \brief Callback invoked when loading this menu.
208          *
209          * \pre   Children widgets of this menu have been created by the time
210          *        this callback is invoked.
211          * \note  This method is not called everytime the screen is shown.
212          *        Screen::init is.
213          *        Use this method for persistent setup code (namely, that
214          *        deals with setting up children widget objects and needs not
215          *        be done everytime we visit the screen).
216          * \note  A Screen object instance may be unloaded then loaded back.
217          *        This method might thus be called more than once in the
218          *        lifetime of a Screen object, however there will always
219          *        be an 'unload' event in-between calls to this method.
220          */
221         virtual void loadedFromFile() = 0;
222 
223         /**
224           * \brief Callback invoked when this screen is being unloaded.
225           *        Override this method in children classes if you need to be
226           *        notified of this.
227           * \note  A Screen object instance may be unloaded then loaded back
228           *        at will.
229           * \note  An unloaded Screen object does not have its children widgets
230           *        anymore, it only retains its members (most importantly the
231           *        path to its GUI file) so that it can be loaded back later.
232           */
unloaded()233         virtual void unloaded() {}
234 
235         /**
236           * \brief Optional callback invoked very early, before widgets have
237           *        been added (contrast with init(), which is invoked afer
238           *        widgets were added)
239           */
beforeAddingWidget()240         virtual void beforeAddingWidget() {}
241 
242         /**
243           * \brief Callback invoked when entering this menu (after the
244           *        widgets have been added).
245           *
246           * \note  The same instance of your object may be entered/left more
247           *        than once, so make sure that one instance of your object
248           *        can be used several times if the same screen is visited
249           *        several times.
250           */
251         virtual void init();
252 
253         /** Displays this screen bu pushing it onto the stack of screen
254          *  in the state manager. */
255         void push();
256 
257         /**
258           * \brief Callback invoked before leaving this menu.
259           *
260           * \note  The same instance of your object may be entered/left more
261           *        than once, so make sure that one instance of your object can
262           *        be used several times if the same screen is visited several
263           *        times.
264           */
265         virtual void tearDown();
266 
267         /**
268           * \brief  Called when escape is pressed.
269           * \return true if the screen should be closed,
270           *         false if you handled the press another way
271           */
onEscapePressed()272         virtual bool onEscapePressed() { return true; }
273 
274         /**
275          * \brief will be called everytime something happens.
276          *
277          * Events are generally a widget state change. In this case, a pointer
278          * to the said widget is passed along its name, so you get its new
279          * state and/or act. There are two special events, passed with a NULL
280          * widget, and which bear the names "init" and "tearDown", called
281          * respectively when a screen is being made visible and when it's being
282          * left, allowing for setup/clean-up.
283          */
284         virtual void eventCallback(Widget* widget, const std::string& name, const int playerID) = 0;
285 
286         /**
287          * \brief optional callback you can override to be notified at every frame.
288          */
onUpdate(float dt)289         virtual void onUpdate(float dt) { };
290 
291         /**
292          * \brief optional callback you can override to be notified at every frame.
293          */
onDraw(float dt)294         virtual void onDraw(float dt) { };
295 
296         /**
297          * \return which music to play at this screen
298          */
getMusic() const299         virtual MusicInformation* getMusic() const { return stk_config->m_title_music; }
300 
301         /**
302          * \return which music to play at this screen, if accessed in "in-game-menu" mode
303          */
getInGameMenuMusic() const304         virtual MusicInformation* getInGameMenuMusic() const { return NULL; }
305 
getWidth()306         virtual int getWidth() { return m_width; }
307 
getHeight()308         virtual int getHeight() { return m_height; }
309 
isResizable() const310         virtual bool isResizable() const { return m_resizable; }
311         /**
312          * \brief Override this if you need to be notified of player actions
313          *        in subclasses.
314          */
filterActions(PlayerAction action,int deviceID,const unsigned int value,Input::InputType type,int playerId)315         virtual EventPropagation filterActions(PlayerAction action,
316                                                int deviceID,
317                                                const unsigned int value,
318                                                Input::InputType type,
319                                                int playerId)
320             { return EVENT_LET; }
321 
322         /** Callback you can use if you want to know when the user pressed
323          *  on a disabled ribbon item.
324          *  (the main use I see for this is to give feedback)
325          */
onDisabledItemClicked(const std::string & item)326         virtual void onDisabledItemClicked(const std::string& item) {}
327 
328         /**
329          * \brief Override this if you need to be notified of raw input in
330          *        subclasses.
331          */
filterInput(Input::InputType type,int deviceID,int btnID,int axisDir,int value)332         virtual void filterInput(Input::InputType type,
333                                  int deviceID,
334                                  int btnID,
335                                  int axisDir,
336                                  int value) {}
337 
338         /** Callback that gets called when a dialog is closed.
339          *  Can be used to set focus for instance.
340          */
onDialogClose()341         virtual void onDialogClose() {}
342 
343         /** Callback called when focus changes */
onFocusChanged(Widget * previous,Widget * focus,int playerID)344         virtual void onFocusChanged(Widget* previous, Widget* focus, int playerID) {}
345     };
346 
347     class CutsceneScreen : public Screen
348     {
349     public:
CutsceneScreen(const char * name)350         CutsceneScreen(const char* name) : Screen(name, false)
351         {
352             setNeeds3D(true);
353             m_throttle_FPS = false;
354         }
355 
356         virtual void onCutsceneEnd() = 0;
357     };
358 }
359 
360 #endif
361