2009-07-18 12:04:45 -04:00
|
|
|
// 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.
|
|
|
|
|
2009-07-18 13:48:36 -04:00
|
|
|
#include "guiengine/event_handler.hpp"
|
2009-07-20 00:05:21 -04:00
|
|
|
|
|
|
|
#include "guiengine/abstract_state_manager.hpp"
|
2009-07-18 13:48:36 -04:00
|
|
|
#include "guiengine/engine.hpp"
|
|
|
|
#include "guiengine/modaldialog.hpp"
|
|
|
|
#include "guiengine/screen.hpp"
|
2009-07-20 00:05:21 -04:00
|
|
|
#include "guiengine/widget.hpp"
|
2009-07-18 12:04:45 -04:00
|
|
|
#include "input/input_manager.hpp"
|
|
|
|
|
|
|
|
using GUIEngine::EventHandler;
|
2009-09-27 15:43:22 -04:00
|
|
|
using GUIEngine::EventPropagation;
|
2009-07-18 12:04:45 -04:00
|
|
|
|
2009-10-12 19:43:14 -04:00
|
|
|
using namespace irr::gui;
|
|
|
|
|
2009-08-28 11:16:57 -04:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
2009-07-18 12:04:45 -04:00
|
|
|
EventHandler::EventHandler()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-08-28 11:16:57 -04:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
2009-07-18 12:04:45 -04:00
|
|
|
EventHandler::~EventHandler()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-08-28 11:16:57 -04:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
2009-07-18 12:04:45 -04:00
|
|
|
bool EventHandler::OnEvent (const SEvent &event)
|
|
|
|
{
|
|
|
|
if(event.EventType == EET_GUI_EVENT ||
|
2009-09-06 14:45:38 -04:00
|
|
|
(GUIEngine::getStateManager()->getGameState() != GUIEngine::GAME && event.EventType != EET_KEY_INPUT_EVENT &&
|
2009-07-18 13:48:36 -04:00
|
|
|
event.EventType != EET_JOYSTICK_INPUT_EVENT)
|
2009-07-18 12:04:45 -04:00
|
|
|
)
|
|
|
|
{
|
2009-09-27 15:43:22 -04:00
|
|
|
return onGUIEvent(event) == EVENT_BLOCK;
|
2009-07-18 12:04:45 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// FIXME : it's a bit unclean that all input events go trough the gui module
|
2009-09-27 15:43:22 -04:00
|
|
|
const EventPropagation blockPropagation = input_manager->input(event);
|
|
|
|
return blockPropagation == EVENT_BLOCK;
|
2009-07-18 12:04:45 -04:00
|
|
|
}
|
2009-07-18 13:48:36 -04:00
|
|
|
|
|
|
|
// to shut up a warning. gcc is too stupid too see the code will never get here
|
|
|
|
return false;
|
2009-07-18 12:04:45 -04:00
|
|
|
}
|
|
|
|
|
2009-08-28 11:16:57 -04:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
2009-09-27 15:43:22 -04:00
|
|
|
EventPropagation EventHandler::onGUIEvent(const SEvent& event)
|
2009-07-18 12:04:45 -04:00
|
|
|
{
|
2009-08-28 11:16:57 -04:00
|
|
|
if (event.EventType == EET_GUI_EVENT)
|
2009-07-18 12:04:45 -04:00
|
|
|
{
|
|
|
|
const s32 id = event.GUIEvent.Caller->getID();
|
|
|
|
|
2009-08-28 11:16:57 -04:00
|
|
|
switch (event.GUIEvent.EventType)
|
2009-07-18 12:04:45 -04:00
|
|
|
{
|
|
|
|
case EGET_BUTTON_CLICKED:
|
|
|
|
case EGET_SCROLL_BAR_CHANGED:
|
|
|
|
case EGET_CHECKBOX_CHANGED:
|
|
|
|
case EGET_LISTBOX_SELECTED_AGAIN:
|
|
|
|
{
|
2009-09-01 14:11:26 -04:00
|
|
|
Widget* w = GUIEngine::getWidget(id);
|
2009-10-20 14:25:14 -04:00
|
|
|
if (w == NULL) break;
|
2009-07-18 12:04:45 -04:00
|
|
|
|
2009-08-27 14:41:20 -04:00
|
|
|
// FIXME: don't hardcode player 0
|
|
|
|
return onWidgetActivated(w, 0);
|
2009-07-18 12:04:45 -04:00
|
|
|
}
|
|
|
|
case EGET_ELEMENT_HOVERED:
|
|
|
|
{
|
2009-09-01 14:11:26 -04:00
|
|
|
Widget* w = GUIEngine::getWidget(id);
|
2009-09-01 20:25:17 -04:00
|
|
|
if (w == NULL) break;
|
2009-07-18 12:04:45 -04:00
|
|
|
|
|
|
|
// select ribbons on hover
|
2009-09-01 20:25:17 -04:00
|
|
|
if (w->m_event_handler != NULL && w->m_event_handler->m_type == WTYPE_RIBBON)
|
2009-07-18 12:04:45 -04:00
|
|
|
{
|
|
|
|
RibbonWidget* ribbon = dynamic_cast<RibbonWidget*>(w->m_event_handler);
|
2009-09-27 15:43:22 -04:00
|
|
|
if (ribbon == NULL) break;
|
2009-10-28 19:04:38 -04:00
|
|
|
const int playerID = 0; // FIXME : don't hardcode player 0
|
|
|
|
if (ribbon->mouseHovered(w) == EVENT_LET) transmitEvent(ribbon, ribbon->m_properties[PROP_ID], playerID);
|
2009-09-27 15:43:22 -04:00
|
|
|
if (ribbon->m_event_handler != NULL) ribbon->m_event_handler->mouseHovered(w);
|
2009-07-18 12:04:45 -04:00
|
|
|
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:
|
|
|
|
{
|
2009-09-27 15:06:14 -04:00
|
|
|
Widget* w = GUIEngine::getWidget(id);
|
|
|
|
if (w == NULL) break;
|
2009-07-18 12:04:45 -04:00
|
|
|
|
2009-08-28 18:58:32 -04:00
|
|
|
// FIXME: don't hardcode player 0
|
2009-09-27 15:06:14 -04:00
|
|
|
return w->focused(0);
|
2009-07-18 12:04:45 -04:00
|
|
|
|
|
|
|
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,
|
|
|
|
*/
|
2009-09-27 15:43:22 -04:00
|
|
|
return EVENT_LET;
|
2009-07-18 12:04:45 -04:00
|
|
|
}
|
|
|
|
|
2009-08-28 11:16:57 -04:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
2009-09-27 15:43:22 -04:00
|
|
|
EventPropagation EventHandler::onWidgetActivated(GUIEngine::Widget* w, const int playerID)
|
2009-07-18 12:04:45 -04:00
|
|
|
{
|
2009-09-04 21:50:37 -04:00
|
|
|
if (ModalDialog::isADialogActive())
|
2009-07-18 12:04:45 -04:00
|
|
|
{
|
2009-10-20 14:25:14 -04:00
|
|
|
if (ModalDialog::getCurrent()->processEvent(w->m_properties[PROP_ID]) == EVENT_BLOCK) return EVENT_BLOCK;
|
2009-09-27 15:43:22 -04:00
|
|
|
if (w->m_event_handler == NULL) return EVENT_LET;
|
2009-07-18 12:04:45 -04:00
|
|
|
}
|
|
|
|
|
2009-10-21 19:00:12 -04:00
|
|
|
//std::cout << "**** widget activated : " << w->m_properties[PROP_ID].c_str() << " ****" << std::endl;
|
2009-08-10 20:55:48 -04:00
|
|
|
|
2009-07-18 12:04:45 -04:00
|
|
|
Widget* parent = w->m_event_handler;
|
2009-08-27 14:41:20 -04:00
|
|
|
if (w->m_event_handler != NULL)
|
2009-07-18 12:04:45 -04:00
|
|
|
{
|
2009-08-02 15:20:27 -04:00
|
|
|
/* Find all parents. Stop looping if a widget event handler's is itself, to not fall
|
2009-07-18 12:04:45 -04:00
|
|
|
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. ) */
|
2009-08-27 14:41:20 -04:00
|
|
|
while (parent->m_event_handler != NULL && parent->m_event_handler != parent)
|
2009-08-02 15:20:27 -04:00
|
|
|
{
|
2009-08-27 14:41:20 -04:00
|
|
|
parent->transmitEvent(w, w->m_properties[PROP_ID], playerID);
|
2009-09-05 11:46:24 -04:00
|
|
|
|
2009-07-18 12:04:45 -04:00
|
|
|
parent = parent->m_event_handler;
|
2009-08-02 15:20:27 -04:00
|
|
|
}
|
2009-07-18 12:04:45 -04:00
|
|
|
|
|
|
|
/* notify the found event event handler, and also notify the main callback if the
|
|
|
|
parent event handler says so */
|
2009-09-27 15:43:22 -04:00
|
|
|
if (parent->transmitEvent(w, w->m_properties[PROP_ID], playerID) == EVENT_LET)
|
2009-08-02 15:20:27 -04:00
|
|
|
{
|
2009-09-05 11:46:24 -04:00
|
|
|
// notify modal dialog too
|
|
|
|
if (ModalDialog::isADialogActive())
|
|
|
|
{
|
2009-10-20 14:29:51 -04:00
|
|
|
if (ModalDialog::getCurrent()->processEvent(parent->m_properties[PROP_ID]) == EVENT_BLOCK) return EVENT_BLOCK;
|
2009-09-05 11:46:24 -04:00
|
|
|
}
|
|
|
|
|
2009-10-28 19:04:38 -04:00
|
|
|
transmitEvent(parent, parent->m_properties[PROP_ID], playerID);
|
2009-08-02 15:20:27 -04:00
|
|
|
}
|
2009-07-18 12:04:45 -04:00
|
|
|
}
|
2009-10-28 19:04:38 -04:00
|
|
|
else transmitEvent(w, w->m_properties[PROP_ID], playerID);
|
2009-07-18 12:04:45 -04:00
|
|
|
|
2009-09-27 15:43:22 -04:00
|
|
|
return EVENT_BLOCK;
|
2009-07-18 12:04:45 -04:00
|
|
|
}
|
|
|
|
|
2009-08-28 11:16:57 -04:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
2009-07-18 12:04:45 -04:00
|
|
|
/**
|
|
|
|
* Called by the input module
|
|
|
|
*/
|
2009-08-27 14:41:20 -04:00
|
|
|
void EventHandler::processAction(const int action, const unsigned int value, Input::InputType type, const int playerID)
|
2009-07-18 12:04:45 -04:00
|
|
|
{
|
|
|
|
const bool pressedDown = value > Input::MAX_VALUE*2/3;
|
|
|
|
|
2009-08-27 14:41:20 -04:00
|
|
|
if (!pressedDown && type == Input::IT_STICKMOTION) return;
|
2009-07-18 12:04:45 -04:00
|
|
|
|
2009-08-27 14:41:20 -04:00
|
|
|
switch (action)
|
2009-07-18 12:04:45 -04:00
|
|
|
{
|
|
|
|
case PA_LEFT:
|
|
|
|
{
|
2009-08-28 11:16:57 -04:00
|
|
|
Widget* w = NULL;
|
|
|
|
|
2009-08-28 11:36:26 -04:00
|
|
|
// TODO : unify player 0 and players > 0 focus navigation to eliminate this kind of branching
|
2009-08-28 11:16:57 -04:00
|
|
|
if (playerID == 0)
|
|
|
|
{
|
|
|
|
IGUIElement *el = GUIEngine::getGUIEnv()->getFocus();
|
|
|
|
if (el == NULL) break;
|
|
|
|
|
2009-09-01 14:11:26 -04:00
|
|
|
w = GUIEngine::getWidget( el->getID() );
|
2009-08-28 11:16:57 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
w = GUIEngine::g_focus_for_player[playerID];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (w == NULL) break;
|
2009-08-02 14:53:50 -04:00
|
|
|
|
2009-07-18 12:04:45 -04:00
|
|
|
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
|
2009-08-02 14:53:50 -04:00
|
|
|
notified of clicks onto themselves so they can toggle their state. )
|
|
|
|
On the way, also notify everyone in the chain of the left press. */
|
|
|
|
while (widget_to_call->m_event_handler != NULL && widget_to_call->m_event_handler != widget_to_call)
|
|
|
|
{
|
2009-08-27 14:41:20 -04:00
|
|
|
widget_to_call->leftPressed(playerID);
|
2009-07-18 12:04:45 -04:00
|
|
|
widget_to_call = widget_to_call->m_event_handler;
|
2009-08-02 14:53:50 -04:00
|
|
|
}
|
|
|
|
|
2009-07-18 12:04:45 -04:00
|
|
|
|
2009-10-28 19:04:38 -04:00
|
|
|
if (widget_to_call->leftPressed(playerID) == EVENT_LET)
|
|
|
|
{
|
|
|
|
transmitEvent(w, w->m_properties[PROP_ID], playerID);
|
|
|
|
}
|
2009-07-18 12:04:45 -04:00
|
|
|
}
|
2009-10-28 19:04:38 -04:00
|
|
|
break;
|
2009-07-18 12:04:45 -04:00
|
|
|
|
|
|
|
case PA_RIGHT:
|
|
|
|
{
|
2009-08-28 11:16:57 -04:00
|
|
|
Widget* w = NULL;
|
|
|
|
|
2009-08-28 11:36:26 -04:00
|
|
|
// TODO : unify player 0 and players > 0 focus navigation to eliminate this kind of branching
|
2009-08-28 11:16:57 -04:00
|
|
|
if (playerID == 0)
|
|
|
|
{
|
|
|
|
IGUIElement *el = GUIEngine::getGUIEnv()->getFocus();
|
|
|
|
if(el == NULL) break;
|
2009-09-01 14:11:26 -04:00
|
|
|
w = GUIEngine::getWidget( el->getID() );
|
2009-08-28 11:16:57 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
w = GUIEngine::g_focus_for_player[playerID];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (w == NULL) break;
|
2009-07-18 12:04:45 -04:00
|
|
|
|
|
|
|
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
|
2009-08-02 14:53:50 -04:00
|
|
|
notified of clicks onto themselves so they can toggle their state. )
|
|
|
|
On the way, also notify everyone in the chain of the right press */
|
2009-08-28 11:16:57 -04:00
|
|
|
while (widget_to_call->m_event_handler != NULL && widget_to_call->m_event_handler != widget_to_call)
|
2009-08-02 14:53:50 -04:00
|
|
|
{
|
2009-08-27 14:41:20 -04:00
|
|
|
widget_to_call->rightPressed(playerID);
|
2009-07-18 12:04:45 -04:00
|
|
|
widget_to_call = widget_to_call->m_event_handler;
|
2009-08-02 14:53:50 -04:00
|
|
|
}
|
2009-07-18 12:04:45 -04:00
|
|
|
|
2009-10-28 19:04:38 -04:00
|
|
|
if (widget_to_call->rightPressed(playerID) == EVENT_LET)
|
|
|
|
{
|
|
|
|
transmitEvent(widget_to_call, w->m_properties[PROP_ID], playerID);
|
|
|
|
}
|
2009-07-18 12:04:45 -04:00
|
|
|
}
|
2009-10-28 19:04:38 -04:00
|
|
|
break;
|
2009-07-18 12:04:45 -04:00
|
|
|
|
|
|
|
case PA_ACCEL:
|
2009-08-28 11:16:57 -04:00
|
|
|
navigateUp(playerID, type, pressedDown);
|
2009-07-18 12:04:45 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PA_BRAKE:
|
2009-08-28 11:16:57 -04:00
|
|
|
navigateDown(playerID, type, pressedDown);
|
2009-07-18 12:04:45 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PA_RESCUE:
|
2009-10-28 19:04:38 -04:00
|
|
|
if (pressedDown) GUIEngine::getStateManager()->escapePressed();
|
2009-07-18 12:04:45 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PA_FIRE:
|
2009-08-10 20:55:48 -04:00
|
|
|
if (pressedDown)
|
2009-07-18 12:04:45 -04:00
|
|
|
{
|
2009-08-10 20:55:48 -04:00
|
|
|
IGUIElement* element = GUIEngine::getGUIEnv()->getFocus();
|
2009-09-01 14:11:26 -04:00
|
|
|
Widget* w = GUIEngine::getWidget( element->getID() );
|
2009-10-20 14:25:14 -04:00
|
|
|
if (w == NULL) break;
|
|
|
|
// FIXME : consider returned value?
|
2009-08-27 14:41:20 -04:00
|
|
|
onWidgetActivated( w, playerID );
|
2009-07-18 12:04:45 -04:00
|
|
|
}
|
2009-08-10 20:55:48 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
// 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);
|
|
|
|
*/
|
2009-07-18 12:04:45 -04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-28 11:16:57 -04:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void EventHandler::navigateUp(const int playerID, Input::InputType type, const bool pressedDown)
|
|
|
|
{
|
2009-08-28 14:46:02 -04:00
|
|
|
IGUIElement *el = NULL, *first=NULL, *closest=NULL;
|
2009-08-28 11:16:57 -04:00
|
|
|
|
2009-08-28 11:36:26 -04:00
|
|
|
// TODO : unify player 0 and players > 0 focus navigation to eliminate this kind of branching
|
2009-08-28 11:16:57 -04:00
|
|
|
if (playerID == 0)
|
2009-08-28 14:46:02 -04:00
|
|
|
{
|
2009-08-28 11:16:57 -04:00
|
|
|
el = GUIEngine::getGUIEnv()->getFocus();
|
2009-08-28 14:46:02 -04:00
|
|
|
}
|
2009-08-28 11:16:57 -04:00
|
|
|
else
|
2009-08-28 14:46:02 -04:00
|
|
|
{
|
|
|
|
Widget* widget = g_focus_for_player[playerID];
|
2009-09-27 16:38:40 -04:00
|
|
|
if (widget != NULL)
|
|
|
|
{
|
|
|
|
el = widget->m_element;
|
|
|
|
}
|
2009-08-28 14:46:02 -04:00
|
|
|
}
|
2009-08-28 11:16:57 -04:00
|
|
|
|
2009-09-01 14:11:26 -04:00
|
|
|
Widget* w = (el == NULL) ? NULL : GUIEngine::getWidget( el->getID() );
|
2009-08-28 11:16:57 -04:00
|
|
|
|
|
|
|
// 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) return;
|
|
|
|
else list->setSelected(-1);
|
|
|
|
}
|
|
|
|
|
2009-09-27 16:38:40 -04:00
|
|
|
if (w->m_tab_up_root != -1) el = GUIEngine::getWidget( w->m_tab_up_root )->getIrrlichtElement();
|
|
|
|
if (el == NULL)
|
|
|
|
{
|
|
|
|
std::cerr << "WARNING : m_tab_down_root is set to an ID for which I can't find the widget\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-08-28 11:16:57 -04:00
|
|
|
// find closest widget
|
|
|
|
if (el != NULL && el->getTabGroup() != NULL &&
|
|
|
|
el->getTabGroup()->getNextElement(el->getTabOrder(), true /* reverse */, false /* group */, first, closest))
|
|
|
|
{
|
2009-09-01 14:11:26 -04:00
|
|
|
Widget* w = GUIEngine::getWidget( closest->getID() );
|
2009-08-28 11:16:57 -04:00
|
|
|
|
|
|
|
if (playerID == 0)
|
|
|
|
{
|
|
|
|
GUIEngine::getGUIEnv()->setFocus(closest);
|
|
|
|
}
|
|
|
|
else if (w != NULL)
|
|
|
|
{
|
|
|
|
w->setFocusForPlayer(playerID);
|
|
|
|
}
|
|
|
|
|
|
|
|
// when focusing a list by going up, select the last item of the list
|
|
|
|
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
|
|
|
|
{
|
|
|
|
// select the last widget
|
2009-09-05 13:27:14 -04:00
|
|
|
Widget* w = NULL;
|
|
|
|
|
|
|
|
if (ModalDialog::isADialogActive())
|
|
|
|
{
|
|
|
|
// TODO : select last widget in modal dialogs
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Screen* screen = GUIEngine::getCurrentScreen();
|
|
|
|
if (screen == NULL) return;
|
|
|
|
w = screen->getLastWidget();
|
|
|
|
}
|
2009-08-28 11:16:57 -04:00
|
|
|
|
|
|
|
if (w != NULL)
|
|
|
|
{
|
|
|
|
if (playerID == 0)
|
|
|
|
GUIEngine::getGUIEnv()->setFocus( w->m_element );
|
|
|
|
else
|
|
|
|
w->setFocusForPlayer(playerID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void EventHandler::navigateDown(const int playerID, Input::InputType type, const bool pressedDown)
|
|
|
|
{
|
2009-08-28 14:46:02 -04:00
|
|
|
IGUIElement *el = NULL, *first = NULL, *closest = NULL;
|
2009-08-28 11:16:57 -04:00
|
|
|
|
2009-08-28 11:36:26 -04:00
|
|
|
// TODO : unify player 0 and players > 0 focus navigation to eliminate this kind of branching
|
2009-08-28 11:16:57 -04:00
|
|
|
if (playerID == 0)
|
2009-08-28 14:46:02 -04:00
|
|
|
{
|
2009-08-28 11:16:57 -04:00
|
|
|
el = GUIEngine::getGUIEnv()->getFocus();
|
2009-08-28 14:46:02 -04:00
|
|
|
}
|
2009-08-28 11:16:57 -04:00
|
|
|
else
|
2009-08-28 14:46:02 -04:00
|
|
|
{
|
|
|
|
Widget* widget = GUIEngine::g_focus_for_player[playerID];
|
|
|
|
if (widget != NULL) el = widget->m_element;
|
|
|
|
}
|
2009-08-28 11:16:57 -04:00
|
|
|
|
2009-09-01 14:11:26 -04:00
|
|
|
Widget* w = (el == NULL) ? NULL : GUIEngine::getWidget( el->getID() );
|
2009-08-28 11:16:57 -04:00
|
|
|
|
2009-10-21 18:51:23 -04:00
|
|
|
//std::cout << "!!! Player " << playerID << " navigating down of " << w->m_element->getID() << std::endl;
|
2009-09-27 16:38:40 -04:00
|
|
|
|
2009-08-28 11:16:57 -04:00
|
|
|
// 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) return;
|
|
|
|
else list->setSelected(-1);
|
|
|
|
}
|
|
|
|
|
2009-09-27 16:38:40 -04:00
|
|
|
if (w->m_tab_down_root != -1) el = GUIEngine::getWidget( w->m_tab_down_root )->getIrrlichtElement();
|
|
|
|
if (el == NULL)
|
|
|
|
{
|
|
|
|
std::cerr << "WARNING : m_tab_down_root is set to an ID for which I can't find the widget\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-08-28 11:16:57 -04:00
|
|
|
if (el != NULL && el->getTabGroup() != NULL &&
|
|
|
|
el->getTabGroup()->getNextElement(el->getTabOrder(), false, false, first, closest))
|
|
|
|
{
|
2009-10-21 18:51:23 -04:00
|
|
|
// std::cout << "!!! Player " << playerID << " navigating to " << closest->getID() << std::endl;
|
2009-09-27 16:38:40 -04:00
|
|
|
|
2009-08-28 11:16:57 -04:00
|
|
|
if (playerID == 0)
|
|
|
|
{
|
|
|
|
GUIEngine::getGUIEnv()->setFocus(closest);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-09-01 14:11:26 -04:00
|
|
|
Widget* w = GUIEngine::getWidget( closest->getID() );
|
2009-08-28 11:16:57 -04:00
|
|
|
w->setFocusForPlayer(playerID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-10-21 18:51:23 -04:00
|
|
|
//std::cout << "!!! Player " << playerID << " cannot navigating down, no next widget found;\n";
|
2009-09-27 16:38:40 -04:00
|
|
|
|
2009-08-28 11:16:57 -04:00
|
|
|
// select the first widget
|
2009-09-05 13:27:14 -04:00
|
|
|
Widget* w = NULL;
|
|
|
|
|
|
|
|
if (ModalDialog::isADialogActive())
|
|
|
|
{
|
|
|
|
// TODO : select first widget in modal dialogs
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Screen* screen = GUIEngine::getCurrentScreen();
|
|
|
|
if (screen == NULL) return;
|
|
|
|
w = screen->getFirstWidget();
|
|
|
|
}
|
|
|
|
|
2009-08-28 11:16:57 -04:00
|
|
|
if(w != NULL)
|
|
|
|
{
|
|
|
|
if (playerID == 0)
|
|
|
|
GUIEngine::getGUIEnv()->setFocus( w->m_element );
|
|
|
|
else
|
|
|
|
w->setFocusForPlayer(playerID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2009-07-18 12:04:45 -04:00
|
|
|
|
|
|
|
EventHandler* event_handler_singleton = NULL;
|
|
|
|
|
|
|
|
EventHandler* EventHandler::get()
|
|
|
|
{
|
|
|
|
if (event_handler_singleton == NULL)
|
|
|
|
{
|
|
|
|
event_handler_singleton = new EventHandler();
|
|
|
|
}
|
|
|
|
return event_handler_singleton;
|
|
|
|
}
|