2015-03-30 11:42:50 +11:00

333 lines
11 KiB
C++

// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2010-2015 Marianne Gagnon
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_SCREEN_HPP
#define HEADER_SCREEN_HPP
#include <map>
#include <string>
#include <typeinfo>
#include "utils/cpp2011.hpp"
#include <irrString.h>
#include <IXMLReader.h>
namespace irr
{
namespace gui { class IGUIElement; }
}
using namespace irr;
#include "config/stk_config.hpp"
#include "guiengine/abstract_top_level_container.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/event_handler.hpp"
#include "guiengine/widget.hpp"
#include "input/input.hpp"
#include "utils/ptr_vector.hpp"
#include "utils/leak_check.hpp"
/**
* \ingroup guiengine
*/
namespace GUIEngine
{
#define DEFINE_SCREEN_SINGLETON( ClassName ) \
template<> ClassName* GUIEngine::ScreenSingleton< ClassName >::singleton = NULL
/**
* \brief Declares a class to be a singleton.
* Normally, all screens will be singletons.
* Note that you need to use the 'DEFINE_SCREEN_SINGLETON' macro in a .
* cpp file to actually define the instance (as this can't be done in a .h)
* \ingroup guiengine
*/
template<typename SCREEN>
class ScreenSingleton
{
protected:
static SCREEN* singleton;
public:
~ScreenSingleton()
{
singleton = NULL;
}
static SCREEN* getInstance()
{
if (singleton == NULL)
{
singleton = new SCREEN();
GUIEngine::addScreenToList(singleton);
}
return singleton;
}
};
/**
* \brief Represents a single GUI screen.
* Mainly responsible of its children widgets; Screen lays them
* out, asks them to add themselves, asks them to remove themselves, etc.
*
* Also initiates the read of GUI files, even though most of that work is
* done in "screen_loader.cpp"
*
* \ingroup guiengine
*/
class Screen : public AbstractTopLevelContainer
{
private:
/** True if the race (if it is running) should be paused when this
* screen is shown. The RaceResultGUI uses this to leave the race
* running while it is being shown. */
bool m_pause_race;
friend class Skin;
bool m_loaded;
std::string m_filename;
/** Will be called to determine if the 3D scene must be rendered when
* at this screen.
*/
bool m_render_3d;
/** to catch errors as early as possible, for debugging purposes only */
unsigned int m_magic_number;
protected:
bool m_throttle_FPS;
public:
LEAK_CHECK()
/**
* \ingroup guiengine
* \brief Loads a GUI screen from its XML file.
*
* Builds a hierarchy of Widget objects whose contents are a direct
* transcription of the XML file, with little analysis or layout
* performed on them.
*/
static void parseScreenFileDiv(irr::io::IXMLReader* xml,
PtrVector<Widget>& append_to,
irr::gui::IGUIElement* parent = NULL);
Screen(bool pause_race=true);
Screen(const char* filename, bool pause_race=true);
virtual ~Screen();
bool operator ==(const char* filename) const { return m_filename == filename; }
void loadFromFile();
/** \return whether this screen is currently loaded */
bool isLoaded() const { return m_loaded; }
bool throttleFPS() const { return m_throttle_FPS; }
void addWidgets();
void calculateLayout();
void manualAddWidget(Widget* w);
void manualRemoveWidget(Widget* w);
/** \return the name of this menu (which is the name of the file) */
const std::string& getName() const { return m_filename; }
virtual void unload();
/** Will be called to determine if the 3D scene must be rendered when
* at this screen
*/
bool needs3D() { return m_render_3d; }
/** \brief Invoke this method for screens that use a 3D scene as
* background.
*
* (if this method is not invoked with 'true' as parameter, the menu
* background will be rendered instead).
*
* \note To create the 3D background, use the facilities provided by
* the irrLicht scene manager, this class will not set up any
* 3D scene.
*/
void setNeeds3D(bool needs3D) { m_render_3d = needs3D; }
/**
* \brief Callback invoked when loading this menu.
*
* \pre Children widgets of this menu have been created by the time
* this callback is invoked.
* \note This method is not called everytime the screen is shown.
* Screen::init is.
* Use this method for persistent setup code (namely, that
* deals with setting up children widget objects and needs not
* be done everytime we visit the screen).
* \note A Screen object instance may be unloaded then loaded back.
* This method might thus be called more than once in the
* lifetime of a Screen object, however there will always
* be an 'unload' event in-between calls to this method.
*/
virtual void loadedFromFile() = 0;
/**
* \brief Callback invoked when this screen is being unloaded.
* Override this method in children classes if you need to be
* notified of this.
* \note A Screen object instance may be unloaded then loaded back
* at will.
* \note An unloaded Screen object does not have its children widgets
* anymore, it only retains its members (most importantly the
* path to its GUI file) so that it can be loaded back later.
*/
virtual void unloaded() {}
/**
* \brief Optional callback invoked very early, before widgets have
* been added (contrast with init(), which is invoked afer
* widgets were added)
*/
virtual void beforeAddingWidget() {}
/**
* \brief Callback invoked when entering this menu (after the
* widgets have been added).
*
* \note The same instance of your object may be entered/left more
* than once, so make sure that one instance of your object
* can be used several times if the same screen is visited
* several times.
*/
virtual void init();
/** Displays this screen bu pushing it onto the stack of screen
* in the state manager. */
void push();
/**
* \brief Callback invoked before leaving this menu.
*
* \note The same instance of your object may be entered/left more
* than once, so make sure that one instance of your object can
* be used several times if the same screen is visited several
* times.
*/
virtual void tearDown();
/**
* \brief Called when escape is pressed.
* \return true if the screen should be closed,
* false if you handled the press another way
*/
virtual bool onEscapePressed() { return true; }
/**
* \brief will be called everytime something happens.
*
* Events are generally a widget state change. In this case, a pointer
* to the said widget is passed along its name, so you get its new
* state and/or act. There are two special events, passed with a NULL
* widget, and which bear the names "init" and "tearDown", called
* respectively when a screen is being made visible and when it's being
* left, allowing for setup/clean-up.
*/
virtual void eventCallback(Widget* widget, const std::string& name, const int playerID) = 0;
/**
* \brief optional callback you can override to be notified at every frame.
*/
virtual void onUpdate(float dt) { };
/**
* \return which music to play at this screen
*/
virtual MusicInformation* getMusic() const { return stk_config->m_title_music; }
/**
* \return which music to play at this screen, if accessed in "in-game-menu" mode
*/
virtual MusicInformation* getInGameMenuMusic() const { return NULL; }
virtual int getWidth();
virtual int getHeight();
/**
* \brief Override this if you need to be notified of player actions
* in subclasses.
*/
virtual EventPropagation filterActions(PlayerAction action,
int deviceID,
const unsigned int value,
Input::InputType type,
int playerId)
{ return EVENT_LET; }
/** Callback you can use if you want to know when the user pressed
* on a disabled ribbon item.
* (the main use I see for this is to give feedback)
*/
virtual void onDisabledItemClicked(const std::string& item) {}
/**
* \brief Override this if you need to be notified of raw input in
* subclasses.
*/
virtual void filterInput(Input::InputType type,
int deviceID,
int btnID,
int axisDir,
int value) {}
/** Callback that gets called when a dialog is closed.
* Can be used to set focus for instance.
*/
virtual void onDialogClose() {}
/** Callback called when focus changes */
virtual void onFocusChanged(Widget* previous, Widget* focus, int playerID) {}
};
class CutsceneScreen : public Screen
{
public:
CutsceneScreen(const char* name) : Screen(name, false)
{
setNeeds3D(true);
m_throttle_FPS = false;
}
virtual void onCutsceneEnd() = 0;
};
}
#endif