From 8a3bcdaa0313813b96ef93a5650444292f29d782 Mon Sep 17 00:00:00 2001 From: auria Date: Sat, 31 Oct 2009 19:09:45 +0000 Subject: [PATCH] Yay for another mammoth commit! Totally refactored focus handling code; ditched irrlicht code, completely switched to my own. Things are now much clearer. A few known glitches were introduced and should be corrected soon git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/irrlicht@4180 178a84e3-b1eb-0310-8ba1-8eac791a3b58 --- src/guiengine/engine.cpp | 34 ++- src/guiengine/engine.hpp | 24 +- src/guiengine/event_handler.cpp | 211 +++++++----------- src/guiengine/modaldialog.cpp | 2 +- src/guiengine/screen.cpp | 6 +- src/guiengine/skin.cpp | 44 +++- src/guiengine/widget.cpp | 27 +-- src/guiengine/widget.hpp | 12 +- .../widgets/dynamic_ribbon_widget.cpp | 40 ++-- .../widgets/dynamic_ribbon_widget.hpp | 4 +- src/guiengine/widgets/ribbon_widget.cpp | 44 ++-- src/guiengine/widgets/ribbon_widget.hpp | 2 +- src/guiengine/widgets/spinner_widget.cpp | 6 +- .../dialogs/enter_player_name_dialog.cpp | 5 +- .../dialogs/player_info_dialog.cpp | 9 +- .../dialogs/race_paused_dialog.cpp | 4 +- .../dialogs/track_info_dialog.cpp | 3 +- src/states_screens/kart_selection.cpp | 46 ++-- src/states_screens/options_screen_av.cpp | 4 +- src/states_screens/options_screen_input.cpp | 3 +- 20 files changed, 282 insertions(+), 248 deletions(-) diff --git a/src/guiengine/engine.cpp b/src/guiengine/engine.cpp index df7d3621f..f59d86f35 100644 --- a/src/guiengine/engine.cpp +++ b/src/guiengine/engine.cpp @@ -35,8 +35,7 @@ using namespace irr::video; namespace GUIEngine { - Widget* g_focus_for_player[MAX_PLAYER_COUNT]; // unused for player 0, player 0's focus is tracked by irrlicht - + namespace Private { IGUIEnvironment* g_env; @@ -46,9 +45,10 @@ namespace GUIEngine IVideoDriver* g_driver; Screen* g_current_screen = NULL; AbstractStateManager* g_state_manager = NULL; + Widget* g_focus_for_player[MAX_PLAYER_COUNT]; // unused for player 0, player 0's focus is tracked by irrlicht } using namespace Private; - + ptr_vector needsUpdate; ptr_vector g_loaded_screens; @@ -58,6 +58,34 @@ namespace GUIEngine { return dt; } + + Widget* getFocusForPlayer(const int playerID) + { + assert(playerID >= 0); + assert(playerID < MAX_PLAYER_COUNT); + + return g_focus_for_player[playerID]; + } + void focusNothingForPlayer(const int playerID) + { + Widget* focus = getFocusForPlayer(playerID); + if (focus != NULL) focus->unsetFocusForPlayer(playerID); + + g_focus_for_player[playerID] = NULL; + } + bool isFocusedForPlayer(const Widget* w, const int playerID) + { + assert(w != NULL); + assert(playerID >= 0); + assert(playerID < MAX_PLAYER_COUNT); + + // If no focus + if (g_focus_for_player[playerID] == NULL) return false; + + // otherwise check if the focus is the given widget + return g_focus_for_player[playerID]->isSameIrrlichtWidgetAs(w); + } + // ----------------------------------------------------------------------------- void clear() { diff --git a/src/guiengine/engine.hpp b/src/guiengine/engine.hpp index 1d916d5c8..e63b396f8 100644 --- a/src/guiengine/engine.hpp +++ b/src/guiengine/engine.hpp @@ -205,14 +205,31 @@ being left, allowing for setup/clean-up. #include "utils/ptr_vector.hpp" namespace GUIEngine -{ - extern Widget* g_focus_for_player[MAX_PLAYER_COUNT]; // unused for player 0, player 0's focus is tracked by irrlicht; - +{ class Screen; 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) */ + 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) */ + 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) */ + 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. namespace Private { extern irr::gui::IGUIEnvironment* g_env; @@ -222,6 +239,7 @@ namespace GUIEngine extern irr::video::IVideoDriver* g_driver; extern Screen* g_current_screen; extern AbstractStateManager* g_state_manager; + extern Widget* g_focus_for_player[MAX_PLAYER_COUNT]; } inline IrrlichtDevice* getDevice() { return Private::g_device; } diff --git a/src/guiengine/event_handler.cpp b/src/guiengine/event_handler.cpp index 08c6cea4b..1fa30d96d 100644 --- a/src/guiengine/event_handler.cpp +++ b/src/guiengine/event_handler.cpp @@ -97,12 +97,13 @@ EventPropagation EventHandler::onGUIEvent(const SEvent& event) const int playerID = 0; // FIXME : don't hardcode player 0 if (ribbon->mouseHovered(w) == EVENT_LET) transmitEvent(ribbon, ribbon->m_properties[PROP_ID], playerID); if (ribbon->m_event_handler != NULL) ribbon->m_event_handler->mouseHovered(w); - getGUIEnv()->setFocus(ribbon->m_element); + ribbon->setFocusForPlayer(playerID); } else { // focus on hover for other widgets - getGUIEnv()->setFocus(w->m_element); + const int playerID = 0; // FIXME: don't hardcode player 0 ? + w->setFocusForPlayer(playerID); } break; @@ -116,11 +117,13 @@ EventPropagation EventHandler::onGUIEvent(const SEvent& event) break; } */ - case EGET_ELEMENT_FOCUSED: + case EGET_ELEMENT_FOCUSED: // FIXME: is this still used with the new focus implementation? { Widget* w = GUIEngine::getWidget(id); if (w == NULL) break; + std::cout << "==== irrlicht widget focused : " << w->m_properties[PROP_ID] << std::endl; + // FIXME: don't hardcode player 0 return w->focused(0); @@ -210,21 +213,7 @@ void EventHandler::processAction(const int action, const unsigned int value, Inp { case PA_LEFT: { - Widget* w = NULL; - - // TODO : unify player 0 and players > 0 focus navigation to eliminate this kind of branching - if (playerID == 0) - { - IGUIElement *el = GUIEngine::getGUIEnv()->getFocus(); - if (el == NULL) break; - - w = GUIEngine::getWidget( el->getID() ); - } - else - { - w = GUIEngine::g_focus_for_player[playerID]; - } - + Widget* w = GUIEngine::getFocusForPlayer(playerID); if (w == NULL) break; Widget* widget_to_call = w; @@ -235,34 +224,24 @@ void EventHandler::processAction(const int action, const unsigned int value, Inp 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) { - widget_to_call->leftPressed(playerID); + if (widget_to_call->leftPressed(playerID) == EVENT_LET) + { + transmitEvent(w, w->m_properties[PROP_ID], playerID); + } widget_to_call = widget_to_call->m_event_handler; } if (widget_to_call->leftPressed(playerID) == EVENT_LET) { - transmitEvent(w, w->m_properties[PROP_ID], playerID); + transmitEvent(widget_to_call, widget_to_call->m_properties[PROP_ID], playerID); } } break; case PA_RIGHT: { - Widget* w = NULL; - - // TODO : unify player 0 and players > 0 focus navigation to eliminate this kind of branching - if (playerID == 0) - { - IGUIElement *el = GUIEngine::getGUIEnv()->getFocus(); - if(el == NULL) break; - w = GUIEngine::getWidget( el->getID() ); - } - else - { - w = GUIEngine::g_focus_for_player[playerID]; - } - + Widget* w = GUIEngine::getFocusForPlayer(playerID); if (w == NULL) break; Widget* widget_to_call = w; @@ -272,13 +251,16 @@ void EventHandler::processAction(const int action, const unsigned int value, Inp On the way, also notify everyone in the chain of the right press */ while (widget_to_call->m_event_handler != NULL && widget_to_call->m_event_handler != widget_to_call) { - widget_to_call->rightPressed(playerID); + if (widget_to_call->rightPressed(playerID) == EVENT_LET) + { + transmitEvent(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, w->m_properties[PROP_ID], playerID); + transmitEvent(widget_to_call, widget_to_call->m_properties[PROP_ID], playerID); } } break; @@ -298,19 +280,7 @@ void EventHandler::processAction(const int action, const unsigned int value, Inp case PA_FIRE: if (pressedDown) { - Widget* w = NULL; - - // FIXME: remove special case for player 0 - if (playerID == 0) - { - IGUIElement* element = GUIEngine::getGUIEnv()->getFocus(); - if (element == NULL) break; - w = GUIEngine::getWidget( element->getID() ); - } - else - { - w = GUIEngine::g_focus_for_player[playerID]; - } + Widget* w = GUIEngine::getFocusForPlayer(playerID); if (w == NULL) break; // FIXME : consider returned value? onWidgetActivated( w, playerID ); @@ -338,23 +308,11 @@ void EventHandler::processAction(const int action, const unsigned int value, Inp void EventHandler::navigateUp(const int playerID, Input::InputType type, const bool pressedDown) { + std::cout << "Naviagte up!\n"; IGUIElement *el = NULL, *first=NULL, *closest=NULL; - // TODO : unify player 0 and players > 0 focus navigation to eliminate this kind of branching - if (playerID == 0) - { - el = GUIEngine::getGUIEnv()->getFocus(); - } - else - { - Widget* widget = g_focus_for_player[playerID]; - if (widget != NULL) - { - el = widget->m_element; - } - } - - Widget* w = (el == NULL) ? NULL : GUIEngine::getWidget( el->getID() ); + Widget* w = GUIEngine::getFocusForPlayer(playerID); + if (w != NULL) el = w->getIrrlichtElement(); // list widgets are a bit special, because up/down keys are also used // to navigate between various list items, not only to navigate between @@ -365,7 +323,7 @@ void EventHandler::navigateUp(const int playerID, Input::InputType type, const b assert(list != NULL); const bool stay_within_list = list->getSelected() > 0; - + /* if (type == Input::IT_STICKMOTION) { // simulate a key press @@ -376,33 +334,40 @@ void EventHandler::navigateUp(const int playerID, Input::InputType type, const b wrapper.KeyInput = evt; wrapper.EventType = EET_KEY_INPUT_EVENT; GUIEngine::getDevice()->postEventFromUser(wrapper); - } + }*/ - if (stay_within_list) return; - else list->setSelected(-1); + if (stay_within_list) + { + list->setSelected(list->getSelected()-1); + return; + } + else + { + list->setSelected(-1); + } } - if (w != NULL && w->m_tab_up_root != -1) el = GUIEngine::getWidget( w->m_tab_up_root )->getIrrlichtElement(); - if (el == NULL) + if (w != NULL && w->m_tab_up_root != -1) { - std::cerr << "WARNING : m_tab_down_root is set to an ID for which I can't find the widget\n"; - return; + Widget* up = GUIEngine::getWidget( w->m_tab_up_root ); + assert( up != NULL ); + el = up->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; + } } + // find closest widget if (el != NULL && el->getTabGroup() != NULL && el->getTabGroup()->getNextElement(el->getTabOrder(), true /* reverse */, false /* group */, first, closest)) { + std::cout << "Navigating up to " << closest->getID() << std::endl; Widget* w = GUIEngine::getWidget( closest->getID() ); - - if (playerID == 0) - { - GUIEngine::getGUIEnv()->setFocus(closest); - } - else if (w != NULL) - { - w->setFocusForPlayer(playerID); - } + 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) @@ -418,6 +383,10 @@ void EventHandler::navigateUp(const int playerID, Input::InputType type, const b else { std::cout << "EventHandler::navigateUp : warp around, selecting the last widget\n"; + //if (el == NULL) std::cout << " because el is null\n"; + //else if (el->getTabGroup() == NULL) std::cout << " because el's tab group is null\n"; + //else if (!el->getTabGroup()->getNextElement(el->getTabOrder(), true, false, first, closest))std::cout << " because el (" << core::stringc(el->getText()).c_str() << ", tab order " << el->getTabOrder() << ") has no known previous\n"; + // select the last widget Widget* w = NULL; @@ -432,13 +401,7 @@ void EventHandler::navigateUp(const int playerID, Input::InputType type, const b w = screen->getLastWidget(); } - if (w != NULL) - { - if (playerID == 0) - GUIEngine::getGUIEnv()->setFocus( w->m_element ); - else - w->setFocusForPlayer(playerID); - } + if (w != NULL) w->setFocusForPlayer(playerID); } } @@ -446,21 +409,12 @@ void EventHandler::navigateUp(const int playerID, Input::InputType type, const b void EventHandler::navigateDown(const int playerID, Input::InputType type, const bool pressedDown) { + std::cout << "Naviagte down!\n"; + IGUIElement *el = NULL, *first = NULL, *closest = NULL; - // TODO : unify player 0 and players > 0 focus navigation to eliminate this kind of branching - if (playerID == 0) - { - el = GUIEngine::getGUIEnv()->getFocus(); - } - else - { - Widget* widget = GUIEngine::g_focus_for_player[playerID]; - if (widget != NULL) el = widget->m_element; - } - - Widget* w = (el == NULL) ? NULL : GUIEngine::getWidget( el->getID() ); - + Widget* w = GUIEngine::getFocusForPlayer(playerID); + if (w != NULL) el = w->getIrrlichtElement(); //std::cout << "!!! Player " << playerID << " navigating down of " << w->m_element->getID() << std::endl; // list widgets are a bit special, because up/down keys are also used @@ -473,6 +427,7 @@ void EventHandler::navigateDown(const int playerID, Input::InputType type, const const bool stay_within_list = list->getSelected() < (int)list->getItemCount()-1; + /* if (type == Input::IT_STICKMOTION) { // simulate a key press @@ -483,39 +438,51 @@ void EventHandler::navigateDown(const int playerID, Input::InputType type, const wrapper.KeyInput = evt; wrapper.EventType = EET_KEY_INPUT_EVENT; GUIEngine::getDevice()->postEventFromUser(wrapper); + }*/ + + if (stay_within_list) + { + list->setSelected(list->getSelected()+1); + return; + } + else + { + list->setSelected(-1); } - - if (stay_within_list) return; - else list->setSelected(-1); } if (w != NULL && w->m_tab_down_root != -1) { + //std::cout << " w->m_tab_down_root=" << w->m_tab_down_root << std::endl; Widget* down = GUIEngine::getWidget( w->m_tab_down_root ); //std::cout << "navigateDown : setting root to " << w->m_tab_down_root << std::endl; assert(down != NULL); el = down->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; + } } - 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; - } + if (el != NULL && el->getTabGroup() != NULL && el->getTabGroup()->getNextElement(el->getTabOrder(), false, false, first, closest)) { - //std::cout << "!!! Player " << playerID << " navigating down to " << closest->getID() << std::endl; + //std::cout << "Navigating down to " << closest->getID() << std::endl; - // FIXME : remove the special case for player 0 - if (playerID == 0) + Widget* w = GUIEngine::getWidget( closest->getID() ); + assert( w != NULL ); + w->setFocusForPlayer(playerID); + + // another list exception : when entering a list, select the first item + if (w->m_type == WTYPE_LIST) { - GUIEngine::getGUIEnv()->setFocus(closest); - } - else - { - Widget* w = GUIEngine::getWidget( closest->getID() ); - w->setFocusForPlayer(playerID); + IGUIListBox* list = (IGUIListBox*)(w->m_element); + assert(list != NULL); + + list->setSelected(0); } } else @@ -542,13 +509,7 @@ void EventHandler::navigateDown(const int playerID, Input::InputType type, const w = screen->getFirstWidget(); } - if(w != NULL) - { - if (playerID == 0) - GUIEngine::getGUIEnv()->setFocus( w->m_element ); - else - w->setFocusForPlayer(playerID); - } + if (w != NULL) w->setFocusForPlayer(playerID); } } diff --git a/src/guiengine/modaldialog.cpp b/src/guiengine/modaldialog.cpp index 7a5b49b75..ea519590e 100644 --- a/src/guiengine/modaldialog.cpp +++ b/src/guiengine/modaldialog.cpp @@ -70,7 +70,7 @@ ModalDialog::~ModalDialog() m_irrlicht_window->remove(); - if(modalWindow == this) modalWindow = NULL; + if (modalWindow == this) modalWindow = NULL; } void ModalDialog::clearWindow() diff --git a/src/guiengine/screen.cpp b/src/guiengine/screen.cpp index a7f027314..a41355bcb 100644 --- a/src/guiengine/screen.cpp +++ b/src/guiengine/screen.cpp @@ -264,9 +264,13 @@ void Screen::addWidgets() addWidgetsRecursively( m_widgets ); + //std::cout << "*****ScreenAddWidgets " << m_filename.c_str() << " : focusing the first widget*****\n"; + // select the first widget Widget* w = getFirstWidget(); - if(w != NULL) GUIEngine::getGUIEnv()->setFocus( w->m_element ); + //std::cout << "First widget is " << (w == NULL ? "null" : w->m_properties[PROP_ID].c_str()) << std::endl; + if (w != NULL) w->setFocusForPlayer( 0 ); // FIXME: don't hardcode player ID 0 + else std::cerr << "Couldn't select first widget, NULL was returned\n"; } // ----------------------------------------------------------------------------- void Screen::addWidgetsRecursively(ptr_vector& widgets, Widget* parent) diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index b0bafff13..8643daf5b 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -600,7 +600,15 @@ void Skin::drawRibbonChild(const core::rect< s32 > &rect, Widget* widget, const bool mark_selected = widget->isSelected(); bool always_show_selection = false; - const bool parent_focused = GUIEngine::getGUIEnv()->getFocus() == widget->m_event_handler->m_element; + const int playerID = 0; // FIXME : don't hardcode player 0 ? + + IGUIElement* focusedElem = NULL; + if (GUIEngine::getFocusForPlayer(playerID) != NULL) + { + focusedElem = GUIEngine::getFocusForPlayer(playerID)->getIrrlichtElement(); + } + + const bool parent_focused = (focusedElem == widget->m_event_handler->m_element); RibbonWidget* parentRibbon = (RibbonWidget*)widget->m_event_handler; RibbonType type = parentRibbon->getRibbonType(); @@ -658,7 +666,7 @@ void Skin::drawRibbonChild(const core::rect< s32 > &rect, Widget* widget, const if(w->getRibbonType() == RIBBON_COMBO) always_show_selection = true; } - const bool mark_focused = focused || (parent_focused && w != NULL && w->m_focus == widget) || + const bool mark_focused = focused || (parent_focused && w != NULL && w->m_mouse_focus == widget) || (mark_selected && !always_show_selection && parent_focused); @@ -780,8 +788,13 @@ void Skin::drawSpinnerBody(const core::rect< s32 > &rect, Widget* widget, const { if (!focused) { - IGUIElement* focused_widget = GUIEngine::getGUIEnv()->getFocus(); + IGUIElement* focused_widget = NULL; + const int playerID = 0; + if (GUIEngine::getFocusForPlayer(playerID) != NULL) + { + focused_widget = GUIEngine::getFocusForPlayer(playerID)->getIrrlichtElement(); + } if (focused_widget != NULL && widget->m_children.size()>2) { if (widget->m_children[0].id == focused_widget->getID() || @@ -957,13 +970,13 @@ void Skin::draw2DRectangle (IGUIElement *element, const video::SColor &color, co { if (GUIEngine::getStateManager()->getGameState() == GUIEngine::GAME) return; // ignore in game mode - //const bool focused = GUIEngine::getGUIEnv()->hasFocus(element); const int id = element->getID(); Widget* widget = GUIEngine::getWidget(id); - if(widget == NULL) return; + if (widget == NULL) return; - const bool focused = GUIEngine::getGUIEnv()->hasFocus(element); + const int playerID = 0; // FIXME: don't hardcode player 0? + const bool focused = GUIEngine::isFocusedForPlayer(widget, playerID); const WidgetType type = widget->m_type; if(type == WTYPE_LIST) @@ -973,14 +986,17 @@ void Skin::draw2DRectangle (IGUIElement *element, const video::SColor &color, co } } void Skin::process3DPane(IGUIElement *element, const core::rect< s32 > &rect, const bool pressed) -{ - const bool focused = GUIEngine::getGUIEnv()->hasFocus(element); - +{ const int id = element->getID(); Widget* widget = NULL; if (id != -1) widget = GUIEngine::getWidget(id); + if (widget == NULL) return; + + const int playerID = 0; // FIXME: don't hardcode player 0? + const bool focused = GUIEngine::isFocusedForPlayer(widget, playerID); + /* std::cout << "Skin (3D Pane) : " << (widget == NULL ? "NULL!!" : widget->m_properties[PROP_ID].c_str()) << std::endl; if (widget == NULL) std::cout << "Null widget: ID=" << id << " type=" << element->getTypeName() << @@ -1091,7 +1107,15 @@ void Skin::draw3DSunkenPane (IGUIElement *element, video::SColor bgcolor, bool f const WidgetType type = widget->m_type; - const bool focused = GUIEngine::getGUIEnv()->getFocus() == element; + const int playerID = 0; // FIXME : don't hardcode player 0 ? + + IGUIElement* focusedElem = NULL; + if (GUIEngine::getFocusForPlayer(playerID) != NULL) + { + focusedElem = GUIEngine::getFocusForPlayer(playerID)->getIrrlichtElement(); + } + + const bool focused = (focusedElem == element); if (type == WTYPE_LIST) { diff --git a/src/guiengine/widget.cpp b/src/guiengine/widget.cpp index 1455f0d59..36e0bd9c9 100644 --- a/src/guiengine/widget.cpp +++ b/src/guiengine/widget.cpp @@ -85,7 +85,6 @@ Widget::Widget(bool reserve_id) for (int n=0; nm_player_focus[playerID] = false; + GUIEngine::getFocusForPlayer(playerID)->m_player_focus[playerID] = false; } m_player_focus[playerID] = true; - GUIEngine::g_focus_for_player[playerID] = this; - - // Player 0 uses irrLicht focus - FIXME : unify focus handling to remove this branching - if (playerID == 0) - { - requestFocus(); - } - else - { - this->focused(playerID); - } + GUIEngine::Private::g_focus_for_player[playerID] = this; + + // Callback + this->focused(playerID); } void Widget::unsetFocusForPlayer(const int playerID) @@ -142,11 +134,6 @@ bool Widget::isFocusedForPlayer(const int playerID) } -void Widget::requestFocus() -{ - GUIEngine::getGUIEnv()->setFocus(m_element); -} - /** * Receives as string the raw property value retrieved from XML file. * Will try to make sense of it, as an absolute value or a percentage. diff --git a/src/guiengine/widget.hpp b/src/guiengine/widget.hpp index 08148b091..ccfb9ee69 100644 --- a/src/guiengine/widget.hpp +++ b/src/guiengine/widget.hpp @@ -108,8 +108,9 @@ namespace GUIEngine /** * called when left/right keys pressed and focus is on widget. - * Returns 'true' if main event handler should be notified of a change. - * Override in children to be notified of left/right events. + * Returns 'EVENT_LET' if user's event handler should be notified of a change. + * Override in children to be notified of left/right events and/or make + * the event propagate to the user's event handler. */ virtual EventPropagation rightPressed(const int playerID) { return EVENT_BLOCK; } virtual EventPropagation leftPressed(const int playerID) { return EVENT_BLOCK; } @@ -164,6 +165,8 @@ namespace GUIEngine bool m_reserve_id; + friend void GUIEngine::focusNothingForPlayer(const int playerID); + public: /** * This is set to NULL by default; set to something else in a widget to mean @@ -256,6 +259,7 @@ namespace GUIEngine */ bool isFocusedForPlayer(const int playerID); + /** Internal method, do not call it. Call the functions in GUIEngine instead to unset focus. */ void unsetFocusForPlayer(const int playerID); /** @@ -266,8 +270,8 @@ namespace GUIEngine bool isSelected() const { return m_selected; } - void requestFocus(); - + bool isSameIrrlichtWidgetAs(const Widget* ref) const { return m_element == ref->m_element; } + /** * These methods provide new unique IDs each time you call them. * Since IDs are used to determine tabbing order, "non-tabbable" diff --git a/src/guiengine/widgets/dynamic_ribbon_widget.cpp b/src/guiengine/widgets/dynamic_ribbon_widget.cpp index b036d9ecb..93d7b8a19 100644 --- a/src/guiengine/widgets/dynamic_ribbon_widget.cpp +++ b/src/guiengine/widgets/dynamic_ribbon_widget.cpp @@ -298,33 +298,18 @@ RibbonWidget* DynamicRibbonWidget::getRowContaining(Widget* w) const // ----------------------------------------------------------------------------- RibbonWidget* DynamicRibbonWidget::getSelectedRibbon(const int playerID) const { - if (playerID == 0) + + const int row_amount = m_rows.size(); + for(int n=0; nhasFocus(row->m_element) || - m_element->isMyChild( GUIEngine::getGUIEnv()->getFocus() ) ) return (RibbonWidget*)row; - } + return (RibbonWidget*)row; } } - else - { - const int row_amount = m_rows.size(); - for(int n=0; ngetSelectionText(playerID), playerID); } } + std::cout << "rightpressed (dynamic ribbon)\n"; if (m_rows[0].m_ribbon_type == RIBBON_TOOLBAR) return EVENT_BLOCK; + std::cout << " rightpressed returning EVENT_LET\n"; + return EVENT_LET; } // ----------------------------------------------------------------------------- @@ -604,7 +592,7 @@ void DynamicRibbonWidget::updateItemDisplay() } // next row } // ----------------------------------------------------------------------------- -bool DynamicRibbonWidget::setSelection(int item_id, const int playerID) +bool DynamicRibbonWidget::setSelection(int item_id, const int playerID, const bool focusIt) { //printf("****DynamicRibbonWidget::setSelection()****\n"); @@ -635,20 +623,20 @@ bool DynamicRibbonWidget::setSelection(int item_id, const int playerID) //std::cout << "Player " << playerID << " has item " << item_id << " (" << name.c_str() << ") in row " << row << std::endl; m_rows[row].setSelection(id, playerID); - m_rows[row].setFocusForPlayer(playerID); + if (focusIt) m_rows[row].setFocusForPlayer(playerID); propagateSelection(); return true; } // ----------------------------------------------------------------------------- -bool DynamicRibbonWidget::setSelection(const std::string item_codename, const int playerID) +bool DynamicRibbonWidget::setSelection(const std::string item_codename, const int playerID, const bool focusIt) { const int item_count = m_items.size(); for (int n=0; nsetFocus(m_focus->m_element); + //m_focus->setFocusForPlayer( playerID ); // FIXME : unclean, children ribbons shouldn't need to know about their parent ((DynamicRibbonWidget*)m_event_handler)->onRowChange( this, playerID ); @@ -287,7 +305,7 @@ EventPropagation RibbonWidget::mouseHovered(Widget* child) { const int subbuttons_amount = m_children.size(); - m_focus = child; + m_mouse_focus = child; for (int i=0; i 0 && m_ribbon_type == RIBBON_TOOLBAR) m_focus = m_children.get(m_selection[0]); + if (subbuttons_amount > 0 && m_ribbon_type == RIBBON_TOOLBAR) m_mouse_focus = m_children.get(m_selection[0]); } // ----------------------------------------------------------------------------- EventPropagation RibbonWidget::transmitEvent(Widget* w, std::string& originator, const int playerID) @@ -342,7 +360,7 @@ EventPropagation RibbonWidget::transmitEvent(Widget* w, std::string& originator, updateSelection(); // bring focus back to enclosing ribbon widget - GUIEngine::getGUIEnv()->setFocus(m_element); + this->setFocusForPlayer( playerID ); return EVENT_LET; } diff --git a/src/guiengine/widgets/ribbon_widget.hpp b/src/guiengine/widgets/ribbon_widget.hpp index 0c4b1be93..90a20ab22 100644 --- a/src/guiengine/widgets/ribbon_widget.hpp +++ b/src/guiengine/widgets/ribbon_widget.hpp @@ -65,7 +65,7 @@ namespace GUIEngine /** Contains which element within the ribbon is currently focused (used by the skin to show mouse hovers over items that are not selected) */ - Widget* m_focus; + Widget* m_mouse_focus; RibbonWidget(const RibbonType type=RIBBON_COMBO); virtual ~RibbonWidget() {} diff --git a/src/guiengine/widgets/spinner_widget.cpp b/src/guiengine/widgets/spinner_widget.cpp index 8fc4a1acf..307b2a078 100644 --- a/src/guiengine/widgets/spinner_widget.cpp +++ b/src/guiengine/widgets/spinner_widget.cpp @@ -185,7 +185,7 @@ EventPropagation SpinnerWidget::rightPressed(const int playerID) //std::cout << "Right pressed\n"; if (m_value+1 <= m_max) setValue(m_value+1); - GUIEngine::transmitEvent( this, m_properties[PROP_ID], playerID ); + //GUIEngine::transmitEvent( this, m_properties[PROP_ID], playerID ); return EVENT_LET; } @@ -195,7 +195,7 @@ EventPropagation SpinnerWidget::leftPressed(const int playerID) //std::cout << "Left pressed\n"; if (m_value-1 >= m_min) setValue(m_value-1); - GUIEngine::transmitEvent( this, m_properties[PROP_ID], playerID ); + //GUIEngine::transmitEvent( this, m_properties[PROP_ID], playerID ); return EVENT_LET; } @@ -205,7 +205,7 @@ EventPropagation SpinnerWidget::transmitEvent(Widget* w, std::string& originator if (originator == "left") leftPressed(playerID); else if (originator == "right") rightPressed(playerID); - GUIEngine::getGUIEnv()->setFocus(m_element); + this->setFocusForPlayer( playerID ); return EVENT_LET; } // ----------------------------------------------------------------------------- diff --git a/src/states_screens/dialogs/enter_player_name_dialog.cpp b/src/states_screens/dialogs/enter_player_name_dialog.cpp index a996c7026..e4420fe92 100644 --- a/src/states_screens/dialogs/enter_player_name_dialog.cpp +++ b/src/states_screens/dialogs/enter_player_name_dialog.cpp @@ -60,7 +60,7 @@ EnterPlayerNameDialog::EnterPlayerNameDialog(const float w, const float h) : textCtrl->setParent(m_irrlicht_window); m_children.push_back(textCtrl); textCtrl->add(); - GUIEngine::getGUIEnv()->setFocus( textCtrl->getIrrlichtElement() ); + textCtrl->setFocusForPlayer(0); // FIXME : don't hardcode player 0 ? // TODO : add Ok button @@ -93,7 +93,8 @@ GUIEngine::EventPropagation EnterPlayerNameDialog::processEvent(std::string& eve void EnterPlayerNameDialog::onEnterPressedInternal() { // ---- Cancel button pressed - if( GUIEngine::getGUIEnv()->hasFocus(cancelButton->getIrrlichtElement()) ) + const int playerID = 0; // FIXME: don't ahrdcode player 0? + if (GUIEngine::isFocusedForPlayer(cancelButton, playerID)) { std::string fakeEvent = "cancel"; processEvent(fakeEvent); diff --git a/src/states_screens/dialogs/player_info_dialog.cpp b/src/states_screens/dialogs/player_info_dialog.cpp index c2685d378..6a44ef5bb 100644 --- a/src/states_screens/dialogs/player_info_dialog.cpp +++ b/src/states_screens/dialogs/player_info_dialog.cpp @@ -59,7 +59,9 @@ void PlayerInfoDialog::showRegularDialog() textCtrl->setParent(m_irrlicht_window); m_children.push_back(textCtrl); textCtrl->add(); - GUIEngine::getGUIEnv()->setFocus( textCtrl->getIrrlichtElement() ); + + const int playerID = 0; // FIXME: don't hardcode player ID + textCtrl->setFocusForPlayer( playerID ); } { @@ -172,8 +174,9 @@ void PlayerInfoDialog::showConfirmDialog() widget->setParent(m_irrlicht_window); m_children.push_back(widget); widget->add(); - GUIEngine::getGUIEnv()->setFocus( widget->getIrrlichtElement() ); - + + const int playerID = 0; // FIXME: don't hardcode player ID + widget->setFocusForPlayer( playerID ); } } diff --git a/src/states_screens/dialogs/race_paused_dialog.cpp b/src/states_screens/dialogs/race_paused_dialog.cpp index 178177b90..0c3e46d7d 100644 --- a/src/states_screens/dialogs/race_paused_dialog.cpp +++ b/src/states_screens/dialogs/race_paused_dialog.cpp @@ -66,7 +66,9 @@ RacePausedDialog::RacePausedDialog(const float percentWidth, const float percent back_btn->setParent(m_irrlicht_window); m_children.push_back(back_btn); back_btn->add(); - GUIEngine::getGUIEnv()->setFocus( back_btn->getIrrlichtElement() ); + + const int playerID = 0; // FIXME: don't hardcode player ID + back_btn->setFocusForPlayer( playerID ); // ---- Choice ribbon m_choice_ribbon = new RibbonWidget(RIBBON_TOOLBAR); diff --git a/src/states_screens/dialogs/track_info_dialog.cpp b/src/states_screens/dialogs/track_info_dialog.cpp index 5644b799a..7816a5557 100644 --- a/src/states_screens/dialogs/track_info_dialog.cpp +++ b/src/states_screens/dialogs/track_info_dialog.cpp @@ -82,7 +82,8 @@ TrackInfoDialog::TrackInfoDialog(const std::string& trackIdent, const irr::core: okBtn->getIrrlichtElement()->setTabStop(true); okBtn->getIrrlichtElement()->setTabGroup(false); - GUIEngine::getGUIEnv()->setFocus( okBtn->getIrrlichtElement() ); + const int playerID = 0; // FIXME: don't hardcode + okBtn->setFocusForPlayer( playerID ); // ---- Track title core::rect< s32 > area_top(0, 0, m_area.getWidth(), y1); diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index 2baba324a..ea99cd5a2 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -303,10 +303,9 @@ FocusDispatcher* g_dispatcher = NULL; ~PlayerKartWidget() { - if (GUIEngine::g_focus_for_player[m_playerID] == this) + if (GUIEngine::getFocusForPlayer(m_playerID) == this) { - unsetFocusForPlayer(m_playerID); - GUIEngine::g_focus_for_player[m_playerID] = NULL; + GUIEngine::focusNothingForPlayer(m_playerID); } if (playerIDLabel->getIrrlichtElement() != NULL) @@ -334,12 +333,14 @@ FocusDispatcher* g_dispatcher = NULL; assert(false); } - Widget* focus = GUIEngine::g_focus_for_player[m_playerID]; - if (focus != NULL) focus->unsetFocusForPlayer(m_playerID); - GUIEngine::g_focus_for_player[m_playerID] = NULL; + // Remove current focus, but rembmer it + Widget* focus = GUIEngine::getFocusForPlayer(m_playerID); + GUIEngine::focusNothingForPlayer(m_playerID); + // Change the player ID m_playerID = newPlayerID; + // restore previous focus, but with new player ID if (focus != NULL) focus->setFocusForPlayer(m_playerID); //I18N: In kart selection screen (Will read like 'Player 1 (foobartech gamepad)') @@ -626,7 +627,7 @@ public: DynamicRibbonWidget* w = m_parent->getWidget("karts"); assert(w != NULL); - w->setSelection(m_parent->m_kart_widgets[playerID].m_kartInternalName, playerID); + w->setSelection(m_parent->m_kart_widgets[playerID].m_kartInternalName, playerID, true); return; } @@ -746,8 +747,10 @@ bool KartSelectionScreen::playerJoin(InputDevice* device, bool firstPlayer) // ---- Focus a kart for this player const int playerID = amount-1; - w->setSelection(playerID, playerID); - + if (!firstPlayer) + { + w->setSelection(playerID, playerID, true); + } return true; } @@ -790,11 +793,7 @@ bool KartSelectionScreen::playerQuit(ActivePlayer* player) assert( m_kart_widgets.size() == StateManager::get()->activePlayerCount() ); // unset selection of this player - if (GUIEngine::g_focus_for_player[playerID] != NULL) - { - GUIEngine::g_focus_for_player[playerID]->unsetFocusForPlayer(playerID); - } - GUIEngine::g_focus_for_player[playerID] = NULL; + GUIEngine::focusNothingForPlayer(playerID); // keep the removed kart a while, for the 'disappear' animation to take place removedWidget = m_kart_widgets.remove(playerID); @@ -926,8 +925,7 @@ void KartSelectionScreen::init() } // Player 0 select first kart (Tux) - w->setSelection(0, 0); - w->m_rows[0].requestFocus(); + w->setSelection(0, 0, true); } // ----------------------------------------------------------------------------- @@ -1077,14 +1075,10 @@ void KartSelectionScreen::eventCallback(Widget* widget, const std::string& name, const int num_players = m_kart_widgets.size(); for (int n=0; nunsetFocusForPlayer(n); - } - GUIEngine::g_focus_for_player[n] = NULL; + GUIEngine::focusNothingForPlayer(n); const std::string& selection = m_kart_widgets[n].getKartInternalName(); - if (!w->setSelection( selection, n )) + if (!w->setSelection( selection, n, true )) { std::cout << "Player " << n << " lost their selection when switching tabs!!!\n"; // For now, select a random kart in this case (TODO : maybe do something better? ) @@ -1093,7 +1087,7 @@ void KartSelectionScreen::eventCallback(Widget* widget, const std::string& name, if (count > 0) { const int randomID = random.get( count ); - w->setSelection( randomID, n ); + w->setSelection( randomID, n, true ); } else { @@ -1201,12 +1195,12 @@ EventPropagation FocusDispatcher::focused(const int playerID) std::cout << "--> Redirecting focus for player " << playerID << " from FocusDispatcher " << " (ID " << m_element->getID() << ") to spinner " << n << " (ID " << m_parent->m_kart_widgets[n].playerName->getIrrlichtElement()->getID() << ")" << std::endl; - int IDbefore = GUIEngine::getGUIEnv()->getFocus()->getID(); + //int IDbefore = GUIEngine::getGUIEnv()->getFocus()->getID(); m_parent->m_kart_widgets[n].playerName->setFocusForPlayer(playerID); - int IDafter = GUIEngine::getGUIEnv()->getFocus()->getID(); - std::cout << "--> ID before : " << IDbefore << "; ID after : " << IDafter << std::endl; + //int IDafter = GUIEngine::getGUIEnv()->getFocus()->getID(); + //std::cout << "--> ID before : " << IDbefore << "; ID after : " << IDafter << std::endl; return GUIEngine::EVENT_BLOCK; } diff --git a/src/states_screens/options_screen_av.cpp b/src/states_screens/options_screen_av.cpp index f93a7551b..7be9832f3 100644 --- a/src/states_screens/options_screen_av.cpp +++ b/src/states_screens/options_screen_av.cpp @@ -111,7 +111,7 @@ void OptionsScreenAV::init() res->updateItemDisplay(); - // ---- select curernt resolution every time + // ---- select current resolution every time const std::vector& modes = irr_driver->getVideoModes(); const int amount = modes.size(); for(int n=0; nsetSelection(n, playerID); + res->setSelection(n, playerID, false); break; } } // end for diff --git a/src/states_screens/options_screen_input.cpp b/src/states_screens/options_screen_input.cpp index aeb1399b5..265d528e5 100644 --- a/src/states_screens/options_screen_input.cpp +++ b/src/states_screens/options_screen_input.cpp @@ -223,7 +223,8 @@ void OptionsScreenInput::gotSensedInput(Input* sensedInput) // re-select the previous button ButtonWidget* btn = this->getWidget(binding_to_set_button.c_str()); - if(btn != NULL) GUIEngine::getGUIEnv()->setFocus( btn->getIrrlichtElement() ); + const int playerID = 0; // FIXME: don't hardcode player ID + if(btn != NULL) btn->setFocusForPlayer(playerID); // save new binding to file input_manager->getDeviceList()->serialize();