From fee6866c6da1471ba629136bcd34a9b08c3b214c Mon Sep 17 00:00:00 2001 From: Alayan-stk-2 Date: Fri, 22 Jun 2018 02:44:35 +0200 Subject: [PATCH] Navigation improvements (#3325) * Don't focus empty lists and ribbons * Don't navigate to deactivated children of a ribbon * Clarify log message --- src/guiengine/event_handler.cpp | 19 ++++++- src/guiengine/widgets/ribbon_widget.cpp | 73 +++++++++++++++++-------- src/guiengine/widgets/ribbon_widget.hpp | 8 ++- 3 files changed, 73 insertions(+), 27 deletions(-) diff --git a/src/guiengine/event_handler.cpp b/src/guiengine/event_handler.cpp index 86d4faab8..f2e3029f2 100644 --- a/src/guiengine/event_handler.cpp +++ b/src/guiengine/event_handler.cpp @@ -496,7 +496,8 @@ void EventHandler::navigate(const NavigationDirection nav, const int playerID) } // navigate -/* This function use simple heuristic to find the closest widget +/** + * This function use simple heuristic to find the closest widget * in the requested direction, * It prioritize widgets close vertically to widget close horizontally, * as it is expected behavior in any direction. @@ -536,6 +537,22 @@ int EventHandler::findIDClosestWidget(const NavigationDirection nav, const int p (playerID != PLAYER_ID_GAME_MASTER && !w_test->m_supports_multiplayer)) continue; + // Ignore empty ribbon widgets and lists + if (w_test->m_type == GUIEngine::WTYPE_RIBBON) + { + RibbonWidget* ribbon = dynamic_cast(w_test); + assert(ribbon != NULL); + if (ribbon->getActiveChildrenNumber(playerID) == 0) + continue; + } + else if (w_test->m_type == WTYPE_LIST) + { + ListWidget* list = (ListWidget*) w_test; + assert(list != NULL); + if (list->getItemCount() == 0) + continue; + } + // if a dialog is shown, restrict to items in the dialog if (ScreenKeyboard::isActive()) { diff --git a/src/guiengine/widgets/ribbon_widget.cpp b/src/guiengine/widgets/ribbon_widget.cpp index d84ce134c..28a7bbc36 100644 --- a/src/guiengine/widgets/ribbon_widget.cpp +++ b/src/guiengine/widgets/ribbon_widget.cpp @@ -593,31 +593,12 @@ EventPropagation RibbonWidget::moveToNextItem(const bool horizontally, const boo // Do nothing and do not block navigating out of the widget if (result == EVENT_BLOCK) return result; - if (reverse) - m_selection[playerID]--; - else - m_selection[playerID]++; + int old_selection = m_selection[playerID]; + selectNextActiveWidget(horizontally, reverse, playerID, old_selection); - if (m_selection[playerID] >= int(m_active_children.size()) || m_selection[playerID] < 0) - { - // In vertical tabs, don't loop when reaching the top or bottom - if (!horizontally) - { - if (reverse) - m_selection[playerID]++; - else - m_selection[playerID]--; + if (m_selection[playerID] == old_selection && !horizontally) + return EVENT_BLOCK; - return EVENT_BLOCK; - } - bool left = (m_selection[playerID] < 0); - - if (m_listener != NULL) m_listener->onRibbonWidgetScroll(left ? -1 : 1); - - bool select_zero = (m_event_handler && left) || (!m_event_handler && !left); - - m_selection[playerID] = select_zero ? 0 : m_active_children.size()-1; - } updateSelection(); if (m_ribbon_type == RIBBON_COMBO || m_ribbon_type == RIBBON_TABS || @@ -666,6 +647,52 @@ EventPropagation RibbonWidget::propagationType(const bool horizontally) return result; } +/** + * Move to the next child widget in the requested direction. + * If it is inactive, move again, until it finds an activated child or test all childs + */ +void RibbonWidget::selectNextActiveWidget(const bool horizontally, const bool reverse, + const int playerID, const int old_selection) +{ + int loop_counter = 0; + do + { + if (reverse) + m_selection[playerID]--; + else + m_selection[playerID]++; + + if (m_selection[playerID] >= int(m_active_children.size()) || m_selection[playerID] < 0) + { + // In vertical tabs, don't loop when reaching the top or bottom + if (!horizontally) + { + if (reverse) + m_selection[playerID] = old_selection; + else + m_selection[playerID] = old_selection; + + return; + } + bool left = (m_selection[playerID] < 0); + + if (m_listener != NULL) m_listener->onRibbonWidgetScroll(left ? -1 : 1); + + bool select_zero = (m_event_handler && left) || (!m_event_handler && !left); + + m_selection[playerID] = select_zero ? 0 : m_active_children.size()-1; + } + + loop_counter++; + if (loop_counter > m_active_children.size()) + { + Log::warn("RibbonWidget", "All the buttons of the focused ribbon" + " are deactivated !"); + break; + } + } while (!m_active_children.get(m_selection[playerID])->isActivated()); +} + // ---------------------------------------------------------------------------- EventPropagation RibbonWidget::focused(const int playerID) diff --git a/src/guiengine/widgets/ribbon_widget.hpp b/src/guiengine/widgets/ribbon_widget.hpp index b6431ba3b..39a9afcaf 100644 --- a/src/guiengine/widgets/ribbon_widget.hpp +++ b/src/guiengine/widgets/ribbon_widget.hpp @@ -77,11 +77,13 @@ namespace GUIEngine /** Callbacks */ virtual EventPropagation rightPressed(const int playerID=0) OVERRIDE; - virtual EventPropagation leftPressed(const int playerID=0) OVERRIDE; - virtual EventPropagation upPressed(const int playerID=0) OVERRIDE; - virtual EventPropagation downPressed(const int playerID=0) OVERRIDE; + virtual EventPropagation leftPressed (const int playerID=0) OVERRIDE; + virtual EventPropagation upPressed (const int playerID=0) OVERRIDE; + virtual EventPropagation downPressed (const int playerID=0) OVERRIDE; EventPropagation moveToNextItem(const bool horizontally, const bool reverse, const int playerID); EventPropagation propagationType(const bool horizontally); + void selectNextActiveWidget(const bool horizontally, const bool reverse, + const int playerID, const int old_selection); virtual EventPropagation mouseHovered(Widget* child, const int playerID) OVERRIDE; virtual EventPropagation transmitEvent(Widget* w,