Code cleanup and documentation improvements in GUI code; fixed compilation error mysteriously introduced by removing LISP (WTF, I did a clean build, why didn't this error pop up then???)

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@5257 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
auria 2010-04-24 20:08:13 +00:00
parent c7f14ffbe0
commit 400a102241
10 changed files with 256 additions and 92 deletions

View File

@ -313,7 +313,7 @@ void IrrDriver::doApplyResSettings()
kart_properties_manager -> unloadAllKarts();
powerup_manager -> removeTextures();
GUIEngine::clear();
GUIEngine::cleanUp();
GUIEngine::cleanUp(); //FIXME: cleanUp is not called when exiting normally, only when changing resolution!
//std::cout << "^^^^^^^^ Closing m_device ^^^^^^^^\n";
m_device->closeDevice();

View File

@ -21,7 +21,6 @@
#include <vector>
#include "main_loop.hpp"
#include "audio/music_manager.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/screen.hpp"
#include "input/device_manager.hpp"
@ -41,27 +40,22 @@ AbstractStateManager::AbstractStateManager()
#pragma mark Other
#endif
/*
void initGUI()
{
IrrlichtDevice* device = irr_driver->getDevice();
video::IVideoDriver* driver = device->getVideoDriver();
GUIEngine::init(device, driver, &eventCallback);
}
*/
// -----------------------------------------------------------------------------
void AbstractStateManager::enterGameState()
{
if (getCurrentScreen() != NULL) getCurrentScreen()->tearDown();
m_menu_stack.clear();
m_menu_stack.push_back("race");
setGameState(GAME);
cleanForGame();
GUIEngine::cleanForGame();
//FIXME: this probably doesn't belong in the *abstract* state manager
input_manager->setMode(InputManager::INGAME);
}
// -----------------------------------------------------------------------------
GameState AbstractStateManager::getGameState()
{
return m_game_mode;
@ -87,6 +81,8 @@ void AbstractStateManager::pushMenu(std::string name)
if (m_game_mode == GAME)
{
setGameState(INGAME_MENU);
//FIXME: this doesn't go in the *abstract* state manager
if (World::getWorld() != NULL) World::getWorld()->pause();
}
else
@ -113,7 +109,9 @@ void AbstractStateManager::replaceTopMostScreen(Screen* screen)
// Send tear-down event to previous menu
if (m_menu_stack.size() > 0) getCurrentScreen()->tearDown();
//FIXME: this doesn't go in the *abstract* state manager
input_manager->setMode(InputManager::MENU);
m_menu_stack[m_menu_stack.size()-1] = name;
switchToScreen(name.c_str());
@ -150,6 +148,7 @@ void AbstractStateManager::popMenu()
if (m_menu_stack.size() == 0)
{
//FIXME: this doesn't go in the *abstract* state manager
main_loop->abort();
return;
}
@ -161,10 +160,13 @@ void AbstractStateManager::popMenu()
m_menu_stack.push_back("race");
if (m_game_mode == INGAME_MENU)
{
//FIXME: this doesn't go in the *abstract* state manager
if (World::getWorld() != NULL) World::getWorld()->unpause();
}
setGameState(GAME);
cleanForGame();
GUIEngine::cleanForGame();
//FIXME: this doesn't go in the *abstract* state manager
input_manager->setMode(InputManager::INGAME);
}
else
@ -180,23 +182,10 @@ void AbstractStateManager::setGameState(GameState state)
{
if (m_game_mode == state) return; // no change
GameState previous = m_game_mode;
m_game_mode = state;
if (m_game_mode == GAME)
{
irr_driver->hidePointer();
}
else
{
// menu
irr_driver->showPointer();
if (m_game_mode == MENU)
{
//FIXME: not up to the *abstract* state manager to do this
music_manager->startMusic(stk_config->m_title_music);
}
}
onGameStateChange(previous, state);
}
// -----------------------------------------------------------------------------
@ -205,15 +194,21 @@ void AbstractStateManager::resetAndGoToScreen(Screen* screen)
{
std::string name = screen->getName();
//FIXME: this doesn't go in the *abstract* state manager
assert(World::getWorld()==NULL);
if (m_game_mode != GAME) getCurrentScreen()->tearDown();
m_menu_stack.clear();
//FIXME: this doesn't go in the *abstract* state manager
input_manager->setMode(InputManager::MENU);
m_menu_stack.push_back(name);
setGameState(MENU);
//FIXME: this doesn't go in the *abstract* state manager
sfx_manager->positionListener( Vec3(0,0,0), Vec3(0,1,0) );
switchToScreen(name.c_str());
getCurrentScreen()->init();
}
@ -225,6 +220,7 @@ void AbstractStateManager::resetAndSetStack(Screen* screens[])
assert(screens != NULL);
assert(screens[0] != NULL);
//FIXME: this doesn't go in the *abstract* state manager
input_manager->setMode(InputManager::MENU);
if (m_game_mode != GAME) getCurrentScreen()->tearDown();
@ -237,7 +233,9 @@ void AbstractStateManager::resetAndSetStack(Screen* screens[])
setGameState(MENU);
//FIXME: this doesn't go in the *abstract* state manager
sfx_manager->positionListener( Vec3(0,0,0), Vec3(0,1,0) );
switchToScreen(m_menu_stack[m_menu_stack.size()-1].c_str());
getCurrentScreen()->init();
}

View File

@ -44,27 +44,55 @@ namespace GUIEngine
void setGameState(GameState state);
public:
/** inits an AbstractStateManager is MENU state */
AbstractStateManager();
virtual ~AbstractStateManager() { }
/** \brief adds a menu at the top of the screens stack */
void pushScreen(Screen* screen);
/** \brief replaces the menu at the top of the screens stack
* (i.e. pops the topmost screen and adds this one instead, but without
* displaying the second-topmost menu of the stack in-between)
*/
void replaceTopMostScreen(Screen* screen);
/**
* \brief removes the menu at the top of the screens stack
* If the stack becomes empty after performing the pop (i.e. if it contained
* only one item prior to the call), the game is aborted.
* In other cases, the second-topmost screen is displayed.
*/
void popMenu();
/**
* \brief clears the menu stack and starts afresh with a new stack containing only
* the given screen
*/
void resetAndGoToScreen(Screen* screen);
/**
* Sets the whole menu stack. Only the topmost screen will be inited/shown, but others remain
* \brief Sets the whole menu stack.
* Only the topmost screen will be inited/shown, but others remain
* under for cases where the user wants to go back.
* @param screens an array containing the menus that should go into stack. The first item will be
* \param screens an array containing the menus that should go into stack. The first item will be
* the bottom item in the stack, the last item will be the stack top. Array must be
* NULL-terminated.
*/
void resetAndSetStack(Screen* screens[]);
/**
* \brief call to make the state manager enter game mode.
* Causes the menu stack to be cleared; all widgets shown on screen are removed
*/
void enterGameState();
/** \return the current state of the game */
GameState getGameState();
/** \brief to be called after e.g. a resolution switch */
void reshowTopMostMenu();
/* ***********************************
@ -72,10 +100,15 @@ namespace GUIEngine
*********************************** */
/**
* callback called whenever escape was pressed (or any similar cancel operation)
*/
* \brief callback invoked whenever escape was pressed (or any similar cancel operation)
*/
virtual void escapePressed() = 0;
/**
* \brief callback invoked when game mode changes (e.g. goes from "menu" to "in-game")
*/
virtual void onGameStateChange(GameState previousState, GameState newState) = 0;
};
}

View File

@ -410,6 +410,8 @@ namespace GUIEngine
using namespace Private;
ptr_vector<Widget, REF> needsUpdate;
//FIXME: the contents of this vector are never ever freed
ptr_vector<Screen, REF> g_loaded_screens;
float dt = 0;
@ -469,12 +471,16 @@ void clear()
if (g_current_screen != NULL) g_current_screen->elementsWereDeleted();
g_current_screen = NULL;
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
void cleanForGame()
{
clear();
//FIXME: I'm not very sure why this isn't called in the regular clear() method??
needsUpdate.clearWithoutDeleting();
}
// -----------------------------------------------------------------------------
void switchToScreen(const char* screen_name)
{
@ -512,18 +518,21 @@ void switchToScreen(const char* screen_name)
g_current_screen->addWidgets();
}
// -----------------------------------------------------------------------------
void addScreenToList(Screen* cutscene)
{
g_loaded_screens.push_back(cutscene);
}
// -----------------------------------------------------------------------------
/** to be called after e.g. a resolution switch */
void reshowCurrentScreen()
{
needsUpdate.clearWithoutDeleting();
g_state_manager->reshowTopMostMenu();
//g_current_screen->addWidgets();
}
// -----------------------------------------------------------------------------
void cleanUp()
{
@ -614,15 +623,9 @@ void init(IrrlichtDevice* device_a, IVideoDriver* driver_a, AbstractStateManager
// set event receiver
g_device->setEventReceiver(EventHandler::get());
}
// -----------------------------------------------------------------------------
/** transmit event to user event callback (out of encapsulated GUI module) */
void transmitEvent(Widget* widget, std::string& name, const int playerID)
{
assert(g_state_manager != NULL);
getCurrentScreen()->eventCallback(widget, name, playerID);
}
// -----------------------------------------------------------------------------
void render(float elapsed_time)
{
GUIEngine::dt = elapsed_time;

View File

@ -33,7 +33,7 @@
/**
* \ingroup guiengine
* \brief Contains all GUI engine related classes
* \brief Contains all GUI engine related classes and functions
*/
namespace GUIEngine
{
@ -41,26 +41,31 @@ namespace GUIEngine
class CutScene;
class Widget;
/** Returns the widget currently focused by given player, or NULL if none.
Do NOT use irrLicht's GUI focus facilities; it's too limited for our
needs, so we use ours. (i.e. always call these functions are never those
in IGUIEnvironment) */
/** \brief Returns the widget currently focused by given player, or NULL if none.
* \note Do NOT use irrLicht's GUI focus facilities; it's too limited for our
* needs, so we use ours. (i.e. always call these functions are never those
* in IGUIEnvironment)
*/
Widget* getFocusForPlayer(const int playerID);
/** Focuses nothing for given player (removes any selection for this player).
Do NOT use irrLicht's GUI focus facilities; it's too limited for our
needs, so we use ours. (i.e. always call these functions are never those
in IGUIEnvironment) */
/** \brief Focuses nothing for given player (removes any selection for this player).
* \note Do NOT use irrLicht's GUI focus facilities; it's too limited for our
* needs, so we use ours. (i.e. always call these functions are never those
* in IGUIEnvironment)
*/
void focusNothingForPlayer(const int playerID);
/** Returns whether given the widget is currently focused by given player.
Do NOT use irrLicht's GUI focus facilities; it's too limited for our
needs, so we use ours. (i.e. always call these functions are never those
in IGUIEnvironment) */
/** \brief Returns whether given the widget is currently focused by given player.
* \note Do NOT use irrLicht's GUI focus facilities; it's too limited for our
* needs, so we use ours. (i.e. always call these functions are never those
* in IGUIEnvironment)
*/
bool isFocusedForPlayer(const Widget*w, const int playerID);
// In an attempt to make getters as fast as possible by possibly allowing inlining
// These fields should never be accessed outside of the GUI engine.
/**
* In an attempt to make getters as fast as possible, by possibly still allowing inlining
* These fields should never be accessed outside of the GUI engine.
*/
namespace Private
{
extern irr::gui::IGUIEnvironment* g_env;
@ -76,48 +81,127 @@ namespace GUIEngine
extern Widget* g_focus_for_player[MAX_PLAYER_COUNT];
}
inline IrrlichtDevice* getDevice() { return Private::g_device; }
inline irr::gui::IGUIEnvironment* getGUIEnv() { return Private::g_env; }
inline irr::video::IVideoDriver* getDriver() { return Private::g_driver; }
inline irr::gui::IGUIFont* getSmallFont() { return Private::g_small_font; }
inline irr::gui::IGUIFont* getFont() { return Private::g_font; }
inline irr::gui::IGUIFont* getTitleFont() { return Private::g_title_font; }
inline Screen* getCurrentScreen() { return Private::g_current_screen; }
inline AbstractStateManager* getStateManager() { return Private::g_state_manager; }
inline Skin* getSkin() { return Private::g_skin; }
/** Returns the height of the font in pixels */
int getFontHeight();
int getSmallFontHeight();
float getLatestDt();
/** show a warning message to explain to the player that only the game master cn act at this point */
void showMasterOnlyString();
/** Add a cutscene to the list of screens known by the gui engine */
void addScreenToList(Screen* screen);
// Widgets that need to be notified at every frame can add themselves there
/** Widgets that need to be notified at every frame can add themselves there (FIXME: unclean) */
extern ptr_vector<Widget, REF> needsUpdate;
/**
* \brief Call this method to init the GUI engine.
* \precondition A irrlicht device and its corresponding video drivers must have been created
* \param device An initialized irrlicht device object
* \param driver An initialized irrlicht driver object
* \param state_manager An instance of a class derived from abstract base AbstractStateManager
*/
void init(irr::IrrlichtDevice* device, irr::video::IVideoDriver* driver, AbstractStateManager* state_manager);
/**
* \brief frees all resources allocated by GUIEngine::init and subsequent uses of the GUI engine.
*/
void cleanUp();
/** Low-level mean to change current screen. Use a state manager instead to get higher-level functionnality. */
/**
* \return the irrlicht device object
*/
inline IrrlichtDevice* getDevice() { return Private::g_device; }
/**
* \return the irrlicht GUI environment object
*/
inline irr::gui::IGUIEnvironment* getGUIEnv() { return Private::g_env; }
/**
* \return the irrlicht video driver object
*/
inline irr::video::IVideoDriver* getDriver() { return Private::g_driver; }
/**
* \return the smaller font (useful for less important messages)
*/
inline irr::gui::IGUIFont* getSmallFont() { return Private::g_small_font; }
/**
* \return the "normal" font (useful for text)
*/
inline irr::gui::IGUIFont* getFont() { return Private::g_font; }
/**
* \return the "title" font (it's bigger and orange, useful for headers/captions)
*/
inline irr::gui::IGUIFont* getTitleFont() { return Private::g_title_font; }
/**
* \return the currently shown screen, or NULL if none
*/
inline Screen* getCurrentScreen() { return Private::g_current_screen; }
/**
* \return the state manager being used, as passed to GUIEngine::init
*/
inline AbstractStateManager* getStateManager() { return Private::g_state_manager; }
/**
* \precondition GUIEngine::init must have been called first
* \return the skin object used to render widgets
*/
inline Skin* getSkin() { return Private::g_skin; }
/** \return the height of the font in pixels */
int getFontHeight();
/** \return the height of the small font in pixels */
int getSmallFontHeight();
/**
* \precondition the value returned by this function is only valid when invoked from GUIEngine::render
* \return the time delta between the last two frames
*/
float getLatestDt();
/** \brief show a warning message to explain to the player that only the game master
* can act at this point
*/
void showMasterOnlyString();
/** \brief Add a screen to the list of screens known by the gui engine */
void addScreenToList(Screen* screen);
/** \brief Low-level mean to change current screen.
* \note Do not use directly. Use a state manager instead to get higher-level functionnality.
*/
void switchToScreen(const char* );
/** \brief erases the currently displayed screen, removing all added irrLicht widgets
* \note Do not use directly. Use a state manager instead to get higher-level functionnality.
*/
void clear();
/** \brief like GUIEngine::clear, but to be called before going into game */
void cleanForGame();
/** \brief to be called after e.g. a resolution switch */
void reshowCurrentScreen();
/**
* \brief called on every frame to trigger the rendering of the GUI
*/
void render(float dt);
/** \brief renders a "loading" screen */
void renderLoading();
void transmitEvent(Widget* widget, std::string& name, const int playerID);
//void transmitEvent(Widget* widget, std::string& name, const int playerID);
/** \brief Finds a widget from its name (PROP_ID) in the current screen/dialog
* \param name the name (PROP_ID) of the widget to search for
* \return the widget that bears that name, or NULL if it was not found
*/
Widget* getWidget(const char* name);
/** \brief Finds a widget from its irrlicht widget ID in the current screen/dialog
* \param name the irrlicht widget ID (not to be confused with PROP_ID, which is a string)
* of the widget to search for
* \return the widget that bears that irrlicht ID, or NULL if it was not found
*/
Widget* getWidget(const int id);
}

View File

@ -141,7 +141,7 @@ EventPropagation EventHandler::onGUIEvent(const SEvent& event)
if (playerID == -1) break;
if (input_manager->masterPlayerOnly() && playerID != 0) break;
if (ribbon->mouseHovered(w, playerID) == EVENT_LET) transmitEvent(ribbon, ribbon->m_properties[PROP_ID], playerID);
if (ribbon->mouseHovered(w, playerID) == EVENT_LET) sendEventToUser(ribbon, ribbon->m_properties[PROP_ID], playerID);
if (ribbon->m_event_handler != NULL) ribbon->m_event_handler->mouseHovered(w, playerID);
ribbon->setFocusForPlayer(playerID);
}
@ -265,10 +265,10 @@ EventPropagation EventHandler::onWidgetActivated(GUIEngine::Widget* w, const int
if (ModalDialog::getCurrent()->processEvent(parent->m_properties[PROP_ID]) == EVENT_BLOCK) return EVENT_BLOCK;
}
transmitEvent(parent, parent->m_properties[PROP_ID], playerID);
sendEventToUser(parent, parent->m_properties[PROP_ID], playerID);
}
}
else transmitEvent(w, w->m_properties[PROP_ID], playerID);
else sendEventToUser(w, w->m_properties[PROP_ID], playerID);
return EVENT_BLOCK;
}
@ -301,7 +301,7 @@ void EventHandler::processAction(const int action, const unsigned int value, Inp
{
if (widget_to_call->leftPressed(playerID) == EVENT_LET)
{
transmitEvent(w, w->m_properties[PROP_ID], playerID);
sendEventToUser(w, w->m_properties[PROP_ID], playerID);
}
widget_to_call = widget_to_call->m_event_handler;
}
@ -309,7 +309,7 @@ void EventHandler::processAction(const int action, const unsigned int value, Inp
if (widget_to_call->leftPressed(playerID) == EVENT_LET)
{
transmitEvent(widget_to_call, widget_to_call->m_properties[PROP_ID], playerID);
sendEventToUser(widget_to_call, widget_to_call->m_properties[PROP_ID], playerID);
}
}
break;
@ -328,14 +328,14 @@ void EventHandler::processAction(const int action, const unsigned int value, Inp
{
if (widget_to_call->rightPressed(playerID) == EVENT_LET)
{
transmitEvent(widget_to_call, w->m_properties[PROP_ID], playerID);
sendEventToUser(widget_to_call, w->m_properties[PROP_ID], playerID);
}
widget_to_call = widget_to_call->m_event_handler;
}
if (widget_to_call->rightPressed(playerID) == EVENT_LET)
{
transmitEvent(widget_to_call, widget_to_call->m_properties[PROP_ID], playerID);
sendEventToUser(widget_to_call, widget_to_call->m_properties[PROP_ID], playerID);
}
}
break;
@ -572,6 +572,13 @@ void EventHandler::navigateDown(const int playerID, Input::InputType type, const
// -----------------------------------------------------------------------------
void EventHandler::sendEventToUser(Widget* widget, std::string& name, const int playerID)
{
getCurrentScreen()->eventCallback(widget, name, playerID);
}
// -----------------------------------------------------------------------------
EventHandler* event_handler_singleton = NULL;
EventHandler* EventHandler::get()

View File

@ -57,6 +57,13 @@ namespace GUIEngine
void navigateUp(const int playerID, Input::InputType type, const bool pressedDown);
void navigateDown(const int playerID, Input::InputType type, const bool pressedDown);
/** \brief send an event to the GUI module user's event callback
* \param widget the widget that triggerred this event
* \param name the name/ID (PROP_ID) of the widget that triggerred this event
* \param playerID ID of the player that triggerred this event
*/
void sendEventToUser(Widget* widget, std::string& name, const int playerID);
public:
EventHandler();
~EventHandler();

View File

@ -24,7 +24,6 @@
#include <vector>
#include <map>
#include "items/item.hpp"
#include "lisp/lisp.hpp"
class Kart;

View File

@ -18,6 +18,8 @@
#include "states_screens/state_manager.hpp"
#include "audio/music_manager.hpp"
#include "config/stk_config.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/modaldialog.hpp"
#include "guiengine/screen.hpp"
@ -170,6 +172,27 @@ void StateManager::escapePressed()
}
}
// ----------------------------------------------------------------------------
void StateManager::onGameStateChange(GameState previousState, GameState newState)
{
if (newState == GAME)
{
irr_driver->hidePointer();
}
else // menu (including in-game menu)
{
irr_driver->showPointer();
if (m_game_mode == MENU)
{
music_manager->startMusic(stk_config->m_title_music);
}
}
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
#if 0
#pragma mark -
@ -191,12 +214,14 @@ StateManager::ActivePlayer::~ActivePlayer()
} // ~ActivePlayer
// ----------------------------------------------------------------------------
void StateManager::ActivePlayer::setPlayerProfile(PlayerProfile* player)
{
m_player = player;
} // setPlayerProfile
// ----------------------------------------------------------------------------
void StateManager::ActivePlayer::setDevice(InputDevice* device)
{
// unset player from previous device he was assigned to, if any

View File

@ -119,17 +119,25 @@ public:
* so no need to delete it yourself.
*/
// void addActivePlayer(ActivePlayer* p);
int createActivePlayer(PlayerProfile *profile, InputDevice *device);
void removeActivePlayer(int id);
int activePlayerCount();
void resetActivePlayers();
/** \return whether to reduce FPS at the moment
* \note this can be useful to avoid being too CPU/GPU intensive in parts of the
* game that don't require high framerates, like menus
*/
bool throttleFPS();
/** \brief implementing callback from base class AbstractStateManager */
void escapePressed();
//void eventCallback(GUIEngine::Widget* widget, const std::string& name);
/** \brief implementing callback from base class AbstractStateManager */
virtual void onGameStateChange(GUIEngine::GameState previousState, GUIEngine::GameState newState);
// singleton
static StateManager* get();