cleanup in GUI module (moved event handling out of Screen)
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/irrlicht@3763 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
@@ -76,6 +76,8 @@ supertuxkart_SOURCES = \
|
||||
gui/credits.hpp \
|
||||
gui/engine.cpp \
|
||||
gui/engine.hpp \
|
||||
gui/event_handler.cpp \
|
||||
gui/event_handler.hpp \
|
||||
gui/kart_selection.cpp \
|
||||
gui/kart_selection.hpp \
|
||||
gui/modaldialog.cpp \
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "input/input_manager.hpp"
|
||||
#include "gui/credits.hpp"
|
||||
#include "gui/screen.hpp"
|
||||
#include "gui/event_handler.hpp"
|
||||
#include "gui/kart_selection.hpp"
|
||||
#include "gui/skin.hpp"
|
||||
#include "gui/state_manager.hpp"
|
||||
@@ -50,30 +51,6 @@ namespace GUIEngine
|
||||
return dt;
|
||||
}
|
||||
|
||||
class IrrlichtEventCore : public IEventReceiver
|
||||
{
|
||||
public:
|
||||
IrrlichtEventCore()
|
||||
{
|
||||
}
|
||||
~IrrlichtEventCore()
|
||||
{
|
||||
}
|
||||
bool OnEvent (const SEvent &event)
|
||||
{
|
||||
if(event.EventType == EET_GUI_EVENT ||
|
||||
(!StateManager::isGameState() && event.EventType != EET_KEY_INPUT_EVENT && event.EventType != EET_JOYSTICK_INPUT_EVENT)
|
||||
)
|
||||
{
|
||||
if(g_current_screen == NULL) return false;
|
||||
g_current_screen->OnEvent(event);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return input_manager->input(event);
|
||||
}
|
||||
};
|
||||
IrrlichtEventCore* g_irrlicht_event_core = NULL;
|
||||
// -----------------------------------------------------------------------------
|
||||
IrrlichtDevice* getDevice()
|
||||
{
|
||||
@@ -105,8 +82,6 @@ void cleanForGame()
|
||||
{
|
||||
clear();
|
||||
needsUpdate.clearWithoutDeleting();
|
||||
if(g_irrlicht_event_core == NULL) g_irrlicht_event_core = new IrrlichtEventCore();
|
||||
g_device->setEventReceiver(g_irrlicht_event_core);
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
void switchToScreen(const char* screen_name)
|
||||
@@ -137,16 +112,9 @@ void switchToScreen(const char* screen_name)
|
||||
g_current_screen = new_screen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// show screen
|
||||
g_current_screen->addWidgets();
|
||||
|
||||
// set event listener
|
||||
if(g_irrlicht_event_core == NULL) g_irrlicht_event_core = new IrrlichtEventCore();
|
||||
g_device->setEventReceiver(g_irrlicht_event_core);
|
||||
//g_env->setUserEventReceiver(g_irrlicht_event_core);
|
||||
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
/** to be called after e.g. a resolution switch */
|
||||
@@ -195,6 +163,9 @@ void init(IrrlichtDevice* device_a, IVideoDriver* driver_a, void (*eventCallback
|
||||
if (g_font) g_skin->setFont(g_font);
|
||||
|
||||
//g_skin->setFont(g_env->getBuiltInFont(), EGDF_TOOLTIP);
|
||||
|
||||
// set event receiver
|
||||
g_device->setEventReceiver(EventHandler::get());
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
/** transmit event to user event callback (out of encapsulated GUI module) */
|
||||
|
||||
372
src/gui/event_handler.cpp
Normal file
372
src/gui/event_handler.cpp
Normal file
@@ -0,0 +1,372 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2009 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.
|
||||
|
||||
|
||||
#include "gui/event_handler.hpp"
|
||||
#include "gui/engine.hpp"
|
||||
#include "gui/modaldialog.hpp"
|
||||
#include "gui/screen.hpp"
|
||||
#include "gui/state_manager.hpp"
|
||||
#include "input/input_manager.hpp"
|
||||
|
||||
using GUIEngine::EventHandler;
|
||||
|
||||
EventHandler::EventHandler()
|
||||
{
|
||||
}
|
||||
|
||||
EventHandler::~EventHandler()
|
||||
{
|
||||
}
|
||||
|
||||
bool EventHandler::OnEvent (const SEvent &event)
|
||||
{
|
||||
if(event.EventType == EET_GUI_EVENT ||
|
||||
(!StateManager::isGameState() && event.EventType != EET_KEY_INPUT_EVENT && event.EventType != EET_JOYSTICK_INPUT_EVENT)
|
||||
)
|
||||
{
|
||||
return onGUIEvent(event);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME : it's a bit unclean that all input events go trough the gui module
|
||||
return input_manager->input(event);
|
||||
}
|
||||
}
|
||||
|
||||
bool EventHandler::onGUIEvent(const SEvent& event)
|
||||
{
|
||||
if(event.EventType == EET_GUI_EVENT)
|
||||
{
|
||||
const s32 id = event.GUIEvent.Caller->getID();
|
||||
|
||||
switch(event.GUIEvent.EventType)
|
||||
{
|
||||
case EGET_BUTTON_CLICKED:
|
||||
case EGET_SCROLL_BAR_CHANGED:
|
||||
case EGET_CHECKBOX_CHANGED:
|
||||
case EGET_LISTBOX_SELECTED_AGAIN:
|
||||
{
|
||||
Widget* w = GUIEngine::getCurrentScreen()->getWidget(id);
|
||||
if(w == NULL) break;
|
||||
|
||||
return onWidgetActivated(w);
|
||||
}
|
||||
case EGET_ELEMENT_HOVERED:
|
||||
{
|
||||
Widget* w = GUIEngine::getCurrentScreen()->getWidget(id);
|
||||
if(w == NULL) break;
|
||||
|
||||
// select ribbons on hover
|
||||
if(w->m_event_handler != NULL && w->m_event_handler->m_type == WTYPE_RIBBON)
|
||||
{
|
||||
RibbonWidget* ribbon = dynamic_cast<RibbonWidget*>(w->m_event_handler);
|
||||
if(ribbon == NULL) break;
|
||||
if(ribbon->mouseHovered(w))
|
||||
transmitEvent(ribbon, ribbon->m_properties[PROP_ID]);
|
||||
if(ribbon->m_event_handler != NULL) ribbon->m_event_handler->mouseHovered(w);
|
||||
getGUIEnv()->setFocus(ribbon->m_element);
|
||||
}
|
||||
else
|
||||
{
|
||||
// focus on hover for other widgets
|
||||
getGUIEnv()->setFocus(w->m_element);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case EGET_ELEMENT_LEFT:
|
||||
{
|
||||
Widget* el = getWidget(id);
|
||||
if(el == NULL) break;
|
||||
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case EGET_ELEMENT_FOCUSED:
|
||||
{
|
||||
Widget* el = GUIEngine::getCurrentScreen()->getWidget(id);
|
||||
if(el == NULL) break;
|
||||
|
||||
el->focused();
|
||||
|
||||
break;
|
||||
}
|
||||
case EGET_EDITBOX_ENTER:
|
||||
{
|
||||
// currently, enter pressed in text ctrl events can only happen in dialogs.
|
||||
// FIXME : find a cleaner way to route the event to its proper location
|
||||
if (ModalDialog::isADialogActive()) ModalDialog::onEnterPressed();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
} // end switch
|
||||
}
|
||||
|
||||
/*
|
||||
EGET_BUTTON_CLICKED, EGET_SCROLL_BAR_CHANGED, EGET_CHECKBOX_CHANGED, EGET_TAB_CHANGED,
|
||||
EGET_MENU_ITEM_SELECTED, EGET_COMBO_BOX_CHANGED, EGET_SPINBOX_CHANGED, EGET_EDITBOX_ENTER,
|
||||
|
||||
EGET_LISTBOX_CHANGED, EGET_LISTBOX_SELECTED_AGAIN,
|
||||
EGET_FILE_SELECTED, EGET_FILE_CHOOSE_DIALOG_CANCELLED,
|
||||
EGET_MESSAGEBOX_YES, EGET_MESSAGEBOX_NO, EGET_MESSAGEBOX_OK, EGET_MESSAGEBOX_CANCEL,
|
||||
EGET_TABLE_CHANGED, EGET_TABLE_HEADER_CHANGED, EGET_TABLE_SELECTED_AGAIN
|
||||
EGET_ELEMENT_FOCUS_LOST, EGET_ELEMENT_FOCUSED, EGET_ELEMENT_HOVERED, EGET_ELEMENT_LEFT,
|
||||
EGET_ELEMENT_CLOSED,
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventHandler::onWidgetActivated(Widget* w)
|
||||
{
|
||||
if(ModalDialog::isADialogActive() && w->m_event_handler == NULL)
|
||||
{
|
||||
ModalDialog::getCurrent()->processEvent(w->m_properties[PROP_ID]);
|
||||
return false;
|
||||
}
|
||||
|
||||
Widget* parent = w->m_event_handler;
|
||||
if(w->m_event_handler != NULL)
|
||||
{
|
||||
/* Find topmost parent. Stop looping if a widget event handler's is itself, to not fall
|
||||
in an infinite loop (this can happen e.g. in checkboxes, where they need to be
|
||||
notified of clicks onto themselves so they can toggle their state. ) */
|
||||
while(parent->m_event_handler != NULL && parent->m_event_handler != parent)
|
||||
parent = parent->m_event_handler;
|
||||
|
||||
/* notify the found event event handler, and also notify the main callback if the
|
||||
parent event handler says so */
|
||||
if(parent->transmitEvent(w, w->m_properties[PROP_ID]))
|
||||
transmitEvent(parent, parent->m_properties[PROP_ID]);
|
||||
}
|
||||
else transmitEvent(w, w->m_properties[PROP_ID]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the input module
|
||||
*/
|
||||
void EventHandler::processAction(const int action, const unsigned int value, Input::InputType type)
|
||||
{
|
||||
const bool pressedDown = value > Input::MAX_VALUE*2/3;
|
||||
|
||||
if(!pressedDown && type == Input::IT_STICKMOTION) return;
|
||||
|
||||
switch(action)
|
||||
{
|
||||
case PA_LEFT:
|
||||
{
|
||||
IGUIElement *el = GUIEngine::getGUIEnv()->getFocus();
|
||||
if(el == NULL) break;
|
||||
|
||||
Widget* w = GUIEngine::getCurrentScreen()->getWidget( el->getID() );
|
||||
if(w == NULL) break;
|
||||
|
||||
Widget* widget_to_call = w;
|
||||
|
||||
/* Find topmost parent. Stop looping if a widget event handler's is itself, to not fall
|
||||
in an infinite loop (this can happen e.g. in checkboxes, where they need to be
|
||||
notified of clicks onto themselves so they can toggle their state. ) */
|
||||
while(widget_to_call->m_event_handler != NULL && widget_to_call->m_event_handler != widget_to_call)
|
||||
widget_to_call = widget_to_call->m_event_handler;
|
||||
|
||||
if(widget_to_call->leftPressed())
|
||||
transmitEvent(w, w->m_properties[PROP_ID]);
|
||||
}
|
||||
break;
|
||||
|
||||
case PA_RIGHT:
|
||||
{
|
||||
IGUIElement *el = GUIEngine::getGUIEnv()->getFocus();
|
||||
if(el == NULL) break;
|
||||
Widget* w = GUIEngine::getCurrentScreen()->getWidget( el->getID() );
|
||||
if(w == NULL) break;
|
||||
|
||||
Widget* widget_to_call = w;
|
||||
/* Find topmost parent. Stop looping if a widget event handler's is itself, to not fall
|
||||
in an infinite loop (this can happen e.g. in checkboxes, where they need to be
|
||||
notified of clicks onto themselves so they can toggle their state. ) */
|
||||
while(widget_to_call->m_event_handler != NULL && widget_to_call->m_event_handler != widget_to_call)
|
||||
widget_to_call = widget_to_call->m_event_handler;
|
||||
|
||||
if(widget_to_call->rightPressed())
|
||||
transmitEvent(widget_to_call, w->m_properties[PROP_ID]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PA_ACCEL:
|
||||
{
|
||||
IGUIElement *el, *first=NULL, *closest=NULL;
|
||||
el = GUIEngine::getGUIEnv()->getFocus();
|
||||
|
||||
Widget* w = (el == NULL) ? NULL : GUIEngine::getCurrentScreen()->getWidget( el->getID() );
|
||||
|
||||
// list widgets are a bit special, because up/down keys are also used
|
||||
// to navigate between various list items, not only to navigate between
|
||||
// components
|
||||
if(w != NULL && w->m_type == WTYPE_LIST)
|
||||
{
|
||||
IGUIListBox* list = dynamic_cast<IGUIListBox*>(w->m_element);
|
||||
assert(list != NULL);
|
||||
|
||||
const bool stay_within_list = list->getSelected() > 0;
|
||||
|
||||
if(type == Input::IT_STICKMOTION)
|
||||
{
|
||||
// simulate a key press
|
||||
irr::SEvent::SKeyInput evt;
|
||||
evt.PressedDown = pressedDown;
|
||||
evt.Key = KEY_UP;
|
||||
irr::SEvent wrapper;
|
||||
wrapper.KeyInput = evt;
|
||||
wrapper.EventType = EET_KEY_INPUT_EVENT;
|
||||
GUIEngine::getDevice()->postEventFromUser(wrapper);
|
||||
}
|
||||
|
||||
if(stay_within_list) break;
|
||||
else list->setSelected(-1);
|
||||
}
|
||||
|
||||
// find closest widget
|
||||
if(el != NULL && el->getTabGroup() != NULL &&
|
||||
el->getTabGroup()->getNextElement(el->getTabOrder(), true /* reverse */, false /* group */, first, closest))
|
||||
{
|
||||
GUIEngine::getGUIEnv()->setFocus(closest);
|
||||
|
||||
// when focusing a list by going up, select the last item of the list
|
||||
Widget* w = GUIEngine::getCurrentScreen()->getWidget( closest->getID() );
|
||||
if(w != NULL && w->m_type == WTYPE_LIST)
|
||||
{
|
||||
IGUIListBox* list = dynamic_cast<IGUIListBox*>(w->m_element);
|
||||
assert(list != NULL);
|
||||
|
||||
list->setSelected( list->getItemCount()-1 );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Could not find any!\n";
|
||||
|
||||
// select the first widget
|
||||
Widget* w = GUIEngine::getCurrentScreen()->getLastWidget();
|
||||
|
||||
if(w != NULL) GUIEngine::getGUIEnv()->setFocus( w->m_element );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PA_BRAKE:
|
||||
{
|
||||
IGUIElement *el, *first = NULL, *closest = NULL;
|
||||
el = GUIEngine::getGUIEnv()->getFocus();
|
||||
|
||||
Widget* w = (el == NULL) ? NULL : GUIEngine::getCurrentScreen()->getWidget( el->getID() );
|
||||
|
||||
// list widgets are a bit special, because up/down keys are also used
|
||||
// to navigate between various list items, not only to navigate between
|
||||
// components
|
||||
if(w != NULL && w->m_type == WTYPE_LIST)
|
||||
{
|
||||
IGUIListBox* list = dynamic_cast<IGUIListBox*>(w->m_element);
|
||||
assert(list != NULL);
|
||||
|
||||
const bool stay_within_list = list->getSelected() < (int)list->getItemCount()-1;
|
||||
|
||||
if(type == Input::IT_STICKMOTION)
|
||||
{
|
||||
// simulate a key press
|
||||
irr::SEvent::SKeyInput evt;
|
||||
evt.PressedDown = pressedDown;
|
||||
evt.Key = KEY_DOWN;
|
||||
irr::SEvent wrapper;
|
||||
wrapper.KeyInput = evt;
|
||||
wrapper.EventType = EET_KEY_INPUT_EVENT;
|
||||
GUIEngine::getDevice()->postEventFromUser(wrapper);
|
||||
}
|
||||
|
||||
if(stay_within_list) break;
|
||||
else list->setSelected(-1);
|
||||
}
|
||||
|
||||
if(el != NULL && el->getTabGroup() != NULL &&
|
||||
el->getTabGroup()->getNextElement(el->getTabOrder(), false, false, first, closest))
|
||||
{
|
||||
GUIEngine::getGUIEnv()->setFocus(closest);
|
||||
}
|
||||
else
|
||||
{
|
||||
// select the first widget
|
||||
Widget* w = GUIEngine::getCurrentScreen()->getFirstWidget();
|
||||
if(w != NULL) GUIEngine::getGUIEnv()->setFocus( w->m_element );
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PA_RESCUE:
|
||||
if(pressedDown)
|
||||
StateManager::escapePressed();
|
||||
break;
|
||||
|
||||
case PA_FIRE:
|
||||
if(type == Input::IT_STICKBUTTON)
|
||||
{
|
||||
if (pressedDown)
|
||||
{
|
||||
IGUIElement* element = GUIEngine::getGUIEnv()->getFocus();
|
||||
Widget* w = GUIEngine::getCurrentScreen()->getWidget( element->getID() );
|
||||
if(w == NULL) break;
|
||||
onWidgetActivated( w );
|
||||
}
|
||||
|
||||
/*
|
||||
// simulate a 'enter' key press
|
||||
irr::SEvent::SKeyInput evt;
|
||||
evt.PressedDown = pressedDown;
|
||||
evt.Key = KEY_SPACE; // FIXME : what if keyboard bindings are not set to use this key?
|
||||
evt.Char = 666; // My magic code to know it's a fake event (FIXME : ugly, but irrlicht doesn't seem to offer better)
|
||||
irr::SEvent wrapper;
|
||||
wrapper.KeyInput = evt;
|
||||
|
||||
wrapper.EventType = EET_KEY_INPUT_EVENT;
|
||||
GUIEngine::getDevice()->postEventFromUser(wrapper);
|
||||
*/
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EventHandler* event_handler_singleton = NULL;
|
||||
|
||||
EventHandler* EventHandler::get()
|
||||
{
|
||||
if (event_handler_singleton == NULL)
|
||||
{
|
||||
event_handler_singleton = new EventHandler();
|
||||
}
|
||||
return event_handler_singleton;
|
||||
}
|
||||
67
src/gui/event_handler.hpp
Normal file
67
src/gui/event_handler.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2009 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 __EVENT_HANDLER_HPP__
|
||||
#define __EVENT_HANDLER_HPP__
|
||||
|
||||
#include "irrlicht.h"
|
||||
#include "input/input.hpp"
|
||||
|
||||
using namespace irr;
|
||||
using namespace core;
|
||||
using namespace scene;
|
||||
using namespace video;
|
||||
using namespace io;
|
||||
using namespace gui;
|
||||
|
||||
namespace GUIEngine
|
||||
{
|
||||
|
||||
class Widget;
|
||||
|
||||
/**
|
||||
* Class to handle irrLicht events (GUI and input as well)
|
||||
* Input events will be redirected to the input module
|
||||
*/
|
||||
class EventHandler : public IEventReceiver
|
||||
{
|
||||
bool onGUIEvent(const SEvent& event);
|
||||
bool onWidgetActivated(Widget* w);
|
||||
public:
|
||||
EventHandler();
|
||||
~EventHandler();
|
||||
|
||||
/**
|
||||
* All irrLicht events will go through this (input as well GUI; input events are
|
||||
* immediately delegated to the input module, GUI events are processed here)
|
||||
*/
|
||||
bool OnEvent (const SEvent &event);
|
||||
|
||||
/**
|
||||
* When the input module is done processing an input and mapped it to an action,
|
||||
* and this action needs to be applied to the GUI (e.g. fire pressed, left
|
||||
* pressed, etc.) this method is called back by the input module.
|
||||
*/
|
||||
void processAction(const int action, const unsigned int value, Input::InputType type);
|
||||
|
||||
// singleton
|
||||
static EventHandler* get();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -238,7 +238,7 @@ void Screen::calculateLayout(ptr_vector<Widget>& widgets, Widget* parent)
|
||||
|
||||
#if 0
|
||||
#pragma mark -
|
||||
#pragma mark Adding widgets
|
||||
#pragma mark Adding/Removing widgets
|
||||
#endif
|
||||
|
||||
|
||||
@@ -432,342 +432,4 @@ Widget* Screen::getLastWidget(ptr_vector<Widget>* within_vector)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#pragma mark -
|
||||
#pragma mark irrLicht events
|
||||
#endif
|
||||
|
||||
bool Screen::onWidgetActivated(Widget* w)
|
||||
{
|
||||
if(ModalDialog::isADialogActive() && w->m_event_handler == NULL)
|
||||
{
|
||||
ModalDialog::getCurrent()->processEvent(w->m_properties[PROP_ID]);
|
||||
return false;
|
||||
}
|
||||
|
||||
Widget* parent = w->m_event_handler;
|
||||
if(w->m_event_handler != NULL)
|
||||
{
|
||||
/* Find topmost parent. Stop looping if a widget event handler's is itself, to not fall
|
||||
in an infinite loop (this can happen e.g. in checkboxes, where they need to be
|
||||
notified of clicks onto themselves so they can toggle their state. ) */
|
||||
while(parent->m_event_handler != NULL && parent->m_event_handler != parent)
|
||||
parent = parent->m_event_handler;
|
||||
|
||||
/* notify the found event event handler, and also notify the main callback if the
|
||||
parent event handler says so */
|
||||
if(parent->transmitEvent(w, w->m_properties[PROP_ID]))
|
||||
transmitEvent(parent, parent->m_properties[PROP_ID]);
|
||||
}
|
||||
else transmitEvent(w, w->m_properties[PROP_ID]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Screen::processAction(const int action, const unsigned int value, Input::InputType type)
|
||||
{
|
||||
const bool pressedDown = value > Input::MAX_VALUE*2/3;
|
||||
|
||||
if(!pressedDown && type == Input::IT_STICKMOTION) return;
|
||||
|
||||
switch(action)
|
||||
{
|
||||
case PA_LEFT:
|
||||
/*
|
||||
if(type == Input::IT_STICKMOTION)
|
||||
{
|
||||
// simulate a key press
|
||||
irr::SEvent::SKeyInput evt;
|
||||
evt.PressedDown = pressedDown;
|
||||
evt.Key = KEY_LEFT; // FIXME : what if keyboard bindings are not set to use this key?
|
||||
irr::SEvent wrapper;
|
||||
wrapper.KeyInput = evt;
|
||||
wrapper.EventType = EET_KEY_INPUT_EVENT;
|
||||
GUIEngine::getDevice()->postEventFromUser(wrapper);
|
||||
}
|
||||
*/
|
||||
{
|
||||
IGUIElement *el = GUIEngine::getGUIEnv()->getFocus();
|
||||
if(el == NULL) break;
|
||||
|
||||
Widget* w = getWidget( el->getID() );
|
||||
if(w == NULL) break;
|
||||
|
||||
Widget* widget_to_call = w;
|
||||
|
||||
/* Find topmost parent. Stop looping if a widget event handler's is itself, to not fall
|
||||
in an infinite loop (this can happen e.g. in checkboxes, where they need to be
|
||||
notified of clicks onto themselves so they can toggle their state. ) */
|
||||
while(widget_to_call->m_event_handler != NULL && widget_to_call->m_event_handler != widget_to_call)
|
||||
widget_to_call = widget_to_call->m_event_handler;
|
||||
|
||||
if(widget_to_call->leftPressed())
|
||||
transmitEvent(w, w->m_properties[PROP_ID]);
|
||||
}
|
||||
break;
|
||||
|
||||
case PA_RIGHT:
|
||||
/*
|
||||
if(type == Input::IT_STICKMOTION)
|
||||
{
|
||||
// simulate a key press
|
||||
irr::SEvent::SKeyInput evt;
|
||||
evt.PressedDown = pressedDown;
|
||||
evt.Key = KEY_RIGHT; // FIXME : what if keyboard bindings are not set to use this key?
|
||||
irr::SEvent wrapper;
|
||||
wrapper.KeyInput = evt;
|
||||
wrapper.EventType = EET_KEY_INPUT_EVENT;
|
||||
GUIEngine::getDevice()->postEventFromUser(wrapper);
|
||||
}*/
|
||||
{
|
||||
IGUIElement *el = GUIEngine::getGUIEnv()->getFocus();
|
||||
if(el == NULL) break;
|
||||
Widget* w = getWidget( el->getID() );
|
||||
if(w == NULL) break;
|
||||
|
||||
Widget* widget_to_call = w;
|
||||
/* Find topmost parent. Stop looping if a widget event handler's is itself, to not fall
|
||||
in an infinite loop (this can happen e.g. in checkboxes, where they need to be
|
||||
notified of clicks onto themselves so they can toggle their state. ) */
|
||||
while(widget_to_call->m_event_handler != NULL && widget_to_call->m_event_handler != widget_to_call)
|
||||
widget_to_call = widget_to_call->m_event_handler;
|
||||
|
||||
if(widget_to_call->rightPressed())
|
||||
transmitEvent(widget_to_call, w->m_properties[PROP_ID]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PA_ACCEL:
|
||||
{
|
||||
IGUIElement *el, *first=NULL, *closest=NULL;
|
||||
el = GUIEngine::getGUIEnv()->getFocus();
|
||||
|
||||
Widget* w = (el == NULL) ? NULL : getWidget( el->getID() );
|
||||
|
||||
// list widgets are a bit special, because up/down keys are also used
|
||||
// to navigate between various list items, not only to navigate between
|
||||
// components
|
||||
if(w != NULL && w->m_type == WTYPE_LIST)
|
||||
{
|
||||
IGUIListBox* list = dynamic_cast<IGUIListBox*>(w->m_element);
|
||||
assert(list != NULL);
|
||||
|
||||
const bool stay_within_list = list->getSelected() > 0;
|
||||
|
||||
if(type == Input::IT_STICKMOTION)
|
||||
{
|
||||
// simulate a key press
|
||||
irr::SEvent::SKeyInput evt;
|
||||
evt.PressedDown = pressedDown;
|
||||
evt.Key = KEY_UP;
|
||||
irr::SEvent wrapper;
|
||||
wrapper.KeyInput = evt;
|
||||
wrapper.EventType = EET_KEY_INPUT_EVENT;
|
||||
GUIEngine::getDevice()->postEventFromUser(wrapper);
|
||||
}
|
||||
|
||||
if(stay_within_list) break;
|
||||
else list->setSelected(-1);
|
||||
}
|
||||
|
||||
// find closest widget
|
||||
if(el != NULL && el->getTabGroup() != NULL &&
|
||||
el->getTabGroup()->getNextElement(el->getTabOrder(), true /* reverse */, false /* group */, first, closest))
|
||||
{
|
||||
GUIEngine::getGUIEnv()->setFocus(closest);
|
||||
|
||||
// when focusing a list by going up, select the last item of the list
|
||||
Widget* w = getWidget( closest->getID() );
|
||||
if(w != NULL && w->m_type == WTYPE_LIST)
|
||||
{
|
||||
IGUIListBox* list = dynamic_cast<IGUIListBox*>(w->m_element);
|
||||
assert(list != NULL);
|
||||
|
||||
list->setSelected( list->getItemCount()-1 );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Could not find any!\n";
|
||||
|
||||
// select the first widget
|
||||
Widget* w = getLastWidget();
|
||||
|
||||
if(w != NULL) GUIEngine::getGUIEnv()->setFocus( w->m_element );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PA_BRAKE:
|
||||
{
|
||||
IGUIElement *el, *first = NULL, *closest = NULL;
|
||||
el = GUIEngine::getGUIEnv()->getFocus();
|
||||
|
||||
Widget* w = (el == NULL) ? NULL : getWidget( el->getID() );
|
||||
|
||||
// list widgets are a bit special, because up/down keys are also used
|
||||
// to navigate between various list items, not only to navigate between
|
||||
// components
|
||||
if(w != NULL && w->m_type == WTYPE_LIST)
|
||||
{
|
||||
IGUIListBox* list = dynamic_cast<IGUIListBox*>(w->m_element);
|
||||
assert(list != NULL);
|
||||
|
||||
const bool stay_within_list = list->getSelected() < (int)list->getItemCount()-1;
|
||||
|
||||
if(type == Input::IT_STICKMOTION)
|
||||
{
|
||||
// simulate a key press
|
||||
irr::SEvent::SKeyInput evt;
|
||||
evt.PressedDown = pressedDown;
|
||||
evt.Key = KEY_DOWN;
|
||||
irr::SEvent wrapper;
|
||||
wrapper.KeyInput = evt;
|
||||
wrapper.EventType = EET_KEY_INPUT_EVENT;
|
||||
GUIEngine::getDevice()->postEventFromUser(wrapper);
|
||||
}
|
||||
|
||||
if(stay_within_list) break;
|
||||
else list->setSelected(-1);
|
||||
}
|
||||
|
||||
if(el != NULL && el->getTabGroup() != NULL &&
|
||||
el->getTabGroup()->getNextElement(el->getTabOrder(), false, false, first, closest))
|
||||
{
|
||||
GUIEngine::getGUIEnv()->setFocus(closest);
|
||||
}
|
||||
else
|
||||
{
|
||||
// select the first widget
|
||||
Widget* w = getFirstWidget();
|
||||
if(w != NULL) GUIEngine::getGUIEnv()->setFocus( w->m_element );
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PA_RESCUE:
|
||||
if(pressedDown)
|
||||
StateManager::escapePressed();
|
||||
break;
|
||||
|
||||
case PA_FIRE:
|
||||
if(type == Input::IT_STICKBUTTON)
|
||||
{
|
||||
if (pressedDown)
|
||||
{
|
||||
IGUIElement* element = GUIEngine::getGUIEnv()->getFocus();
|
||||
Widget* w = getWidget( element->getID() );
|
||||
if(w == NULL) break;
|
||||
onWidgetActivated( w );
|
||||
}
|
||||
|
||||
/*
|
||||
// simulate a 'enter' key press
|
||||
irr::SEvent::SKeyInput evt;
|
||||
evt.PressedDown = pressedDown;
|
||||
evt.Key = KEY_SPACE; // FIXME : what if keyboard bindings are not set to use this key?
|
||||
evt.Char = 666; // My magic code to know it's a fake event (FIXME : ugly, but irrlicht doesn't seem to offer better)
|
||||
irr::SEvent wrapper;
|
||||
wrapper.KeyInput = evt;
|
||||
|
||||
wrapper.EventType = EET_KEY_INPUT_EVENT;
|
||||
GUIEngine::getDevice()->postEventFromUser(wrapper);
|
||||
*/
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool Screen::OnEvent(const SEvent& event)
|
||||
{
|
||||
assert(transmitEvent != NULL);
|
||||
|
||||
if(event.EventType == EET_GUI_EVENT)
|
||||
{
|
||||
const s32 id = event.GUIEvent.Caller->getID();
|
||||
|
||||
switch(event.GUIEvent.EventType)
|
||||
{
|
||||
case EGET_BUTTON_CLICKED:
|
||||
case EGET_SCROLL_BAR_CHANGED:
|
||||
case EGET_CHECKBOX_CHANGED:
|
||||
case EGET_LISTBOX_SELECTED_AGAIN:
|
||||
{
|
||||
Widget* w = getWidget(id);
|
||||
if(w == NULL) break;
|
||||
|
||||
return onWidgetActivated(w);
|
||||
}
|
||||
case EGET_ELEMENT_HOVERED:
|
||||
{
|
||||
Widget* w = getWidget(id);
|
||||
if(w == NULL) break;
|
||||
|
||||
// select ribbons on hover
|
||||
if(w->m_event_handler != NULL && w->m_event_handler->m_type == WTYPE_RIBBON)
|
||||
{
|
||||
RibbonWidget* ribbon = dynamic_cast<RibbonWidget*>(w->m_event_handler);
|
||||
if(ribbon == NULL) break;
|
||||
if(ribbon->mouseHovered(w))
|
||||
transmitEvent(ribbon, ribbon->m_properties[PROP_ID]);
|
||||
if(ribbon->m_event_handler != NULL) ribbon->m_event_handler->mouseHovered(w);
|
||||
getGUIEnv()->setFocus(ribbon->m_element);
|
||||
}
|
||||
else
|
||||
{
|
||||
// focus on hover for other widgets
|
||||
getGUIEnv()->setFocus(w->m_element);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case EGET_ELEMENT_LEFT:
|
||||
{
|
||||
Widget* el = getWidget(id);
|
||||
if(el == NULL) break;
|
||||
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case EGET_ELEMENT_FOCUSED:
|
||||
{
|
||||
Widget* el = getWidget(id);
|
||||
if(el == NULL) break;
|
||||
|
||||
el->focused();
|
||||
|
||||
break;
|
||||
}
|
||||
case EGET_EDITBOX_ENTER:
|
||||
{
|
||||
// currently, enter pressed in text ctrl events can only happen in dialogs.
|
||||
// FIXME : find a cleaner way to route the event to its proper location
|
||||
if(ModalDialog::isADialogActive()) ModalDialog::onEnterPressed();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
} // end switch
|
||||
}
|
||||
|
||||
/*
|
||||
EGET_BUTTON_CLICKED, EGET_SCROLL_BAR_CHANGED, EGET_CHECKBOX_CHANGED, EGET_TAB_CHANGED,
|
||||
EGET_MENU_ITEM_SELECTED, EGET_COMBO_BOX_CHANGED, EGET_SPINBOX_CHANGED, EGET_EDITBOX_ENTER,
|
||||
|
||||
EGET_LISTBOX_CHANGED, EGET_LISTBOX_SELECTED_AGAIN,
|
||||
EGET_FILE_SELECTED, EGET_FILE_CHOOSE_DIALOG_CANCELLED,
|
||||
EGET_MESSAGEBOX_YES, EGET_MESSAGEBOX_NO, EGET_MESSAGEBOX_OK, EGET_MESSAGEBOX_CANCEL,
|
||||
EGET_TABLE_CHANGED, EGET_TABLE_HEADER_CHANGED, EGET_TABLE_SELECTED_AGAIN
|
||||
EGET_ELEMENT_FOCUS_LOST, EGET_ELEMENT_FOCUSED, EGET_ELEMENT_HOVERED, EGET_ELEMENT_LEFT,
|
||||
EGET_ELEMENT_CLOSED,
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace GUIEngine
|
||||
|
||||
void parseScreenFileDiv(irr::io::IrrXMLReader* xml, ptr_vector<Widget>& append_to);
|
||||
|
||||
class Screen : public IEventReceiver
|
||||
class Screen
|
||||
{
|
||||
friend class Skin;
|
||||
|
||||
@@ -52,7 +52,6 @@ namespace GUIEngine
|
||||
|
||||
static void addWidgetsRecursively(ptr_vector<Widget>& widgets, Widget* parent=NULL);
|
||||
void calculateLayout(ptr_vector<Widget>& widgets, Widget* parent=NULL);
|
||||
bool onWidgetActivated(Widget* w);
|
||||
public:
|
||||
// current mouse position, read-only...
|
||||
int m_mouse_x, m_mouse_y;
|
||||
@@ -89,10 +88,6 @@ namespace GUIEngine
|
||||
const std::string& getName() const { return m_filename; }
|
||||
|
||||
void elementsWereDeleted(ptr_vector<Widget>* within_vector = NULL);
|
||||
|
||||
virtual bool OnEvent(const SEvent& event);
|
||||
void processAction(const int action, const unsigned int value, Input::InputType type);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ namespace GUIEngine
|
||||
|
||||
class Widget : public SkinWidgetContainer
|
||||
{
|
||||
friend class EventHandler;
|
||||
protected:
|
||||
friend class RibbonWidget;
|
||||
friend class Screen;
|
||||
@@ -269,7 +270,7 @@ namespace GUIEngine
|
||||
class RibbonWidget : public Widget
|
||||
{
|
||||
friend class RibbonGridWidget;
|
||||
friend class Screen;
|
||||
friend class EventHandler;
|
||||
|
||||
int m_selection;
|
||||
RibbonType m_ribbon_type;
|
||||
|
||||
@@ -244,6 +244,7 @@
|
||||
955DE88C1004273B006A4F3C /* check_structure.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 955DE8871004273B006A4F3C /* check_structure.cpp */; };
|
||||
955DE88D1004273B006A4F3C /* checkline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 955DE8891004273B006A4F3C /* checkline.cpp */; };
|
||||
956D36A710095035007FCB95 /* player.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 956D36A610095035007FCB95 /* player.cpp */; };
|
||||
958330391012248A00C5137E /* event_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 958330381012248A00C5137E /* event_handler.cpp */; };
|
||||
95CB476C0FF30EF400413BAE /* bezier_curve.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95CB476B0FF30EF400413BAE /* bezier_curve.cpp */; };
|
||||
95D1F5F70FC8C3E300FF6968 /* input.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95D1F5F60FC8C3E300FF6968 /* input.cpp */; };
|
||||
95D1F6190FC8CDBB00FF6968 /* options_screen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95D1F6180FC8CDBB00FF6968 /* options_screen.cpp */; };
|
||||
@@ -376,6 +377,8 @@
|
||||
955DE8891004273B006A4F3C /* checkline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = checkline.cpp; path = ../../tracks/checkline.cpp; sourceTree = SOURCE_ROOT; };
|
||||
955DE88A1004273B006A4F3C /* checkline.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = checkline.hpp; path = ../../tracks/checkline.hpp; sourceTree = SOURCE_ROOT; };
|
||||
956D36A610095035007FCB95 /* player.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = player.cpp; path = games/supertuxkart/src/config/player.cpp; sourceTree = SYSTEM_DEVELOPER_DIR; };
|
||||
958330371012248A00C5137E /* event_handler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = event_handler.hpp; path = games/supertuxkart/src/gui/event_handler.hpp; sourceTree = SYSTEM_DEVELOPER_DIR; };
|
||||
958330381012248A00C5137E /* event_handler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = event_handler.cpp; path = games/supertuxkart/src/gui/event_handler.cpp; sourceTree = SYSTEM_DEVELOPER_DIR; };
|
||||
95A118290F77EA3100B18B3D /* input.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = input.hpp; path = ../../input/input.hpp; sourceTree = SOURCE_ROOT; };
|
||||
95A1182A0F77EA3100B18B3D /* input_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = input_manager.cpp; path = ../../input/input_manager.cpp; sourceTree = SOURCE_ROOT; };
|
||||
95A1182B0F77EA3100B18B3D /* input_manager.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = input_manager.hpp; path = ../../input/input_manager.hpp; sourceTree = SOURCE_ROOT; };
|
||||
@@ -1022,6 +1025,8 @@
|
||||
951C35BD0FC066ED00A48379 /* credits.hpp */,
|
||||
9505577A0F696A900056E88C /* engine.cpp */,
|
||||
9505577B0F696A900056E88C /* engine.hpp */,
|
||||
958330381012248A00C5137E /* event_handler.cpp */,
|
||||
958330371012248A00C5137E /* event_handler.hpp */,
|
||||
9516162C0FFFB12B004B16D8 /* kart_selection.cpp */,
|
||||
9516164D0FFFB1F0004B16D8 /* kart_selection.hpp */,
|
||||
954A57DB0FEC5AE40073C16C /* modaldialog.cpp */,
|
||||
@@ -2343,6 +2348,7 @@
|
||||
955DE88C1004273B006A4F3C /* check_structure.cpp in Sources */,
|
||||
955DE88D1004273B006A4F3C /* checkline.cpp in Sources */,
|
||||
956D36A710095035007FCB95 /* player.cpp in Sources */,
|
||||
958330391012248A00C5137E /* event_handler.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "gui/state_manager.hpp"
|
||||
#include "gui/modaldialog.hpp"
|
||||
#include "gui/engine.hpp"
|
||||
#include "gui/event_handler.hpp"
|
||||
#include "gui/screen.hpp"
|
||||
#include "input/device_manager.hpp"
|
||||
#include "input/input.hpp"
|
||||
@@ -320,7 +321,7 @@ void InputManager::input(Input::InputType type, int deviceID, int btnID, int axi
|
||||
m_timer_in_use = true;
|
||||
m_timer = 0.25;
|
||||
}
|
||||
GUIEngine::getCurrentScreen()->processAction(action, abs(value), type);
|
||||
GUIEngine::EventHandler::get()->processAction(action, abs(value), type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user