@@ -446,7 +446,7 @@ void EventHandler::sendNavigationEvent(const NavigationDirection nav, const int
446
446
447
447
if (!handled_by_widget)
448
448
{
449
- navigate (nav, playerID);
449
+ navigate (nav, GUIEngine::getFocusForPlayer (playerID), playerID);
450
450
}
451
451
} // sendNavigationEvent
452
452
@@ -456,11 +456,9 @@ void EventHandler::sendNavigationEvent(const NavigationDirection nav, const int
456
456
*
457
457
* \param nav Determine in which direction to navigate
458
458
*/
459
- void EventHandler::navigate (const NavigationDirection nav, const int playerID)
459
+ void EventHandler::navigate (const NavigationDirection nav, Widget* starting_widget, const int playerID)
460
460
{
461
- Widget* w = GUIEngine::getFocusForPlayer (playerID);
462
-
463
- int next_id = findIDClosestWidget (nav, playerID, w, false );
461
+ int next_id = findIDClosestWidget (nav, playerID, starting_widget, false );
464
462
465
463
if (next_id != -1 )
466
464
{
@@ -507,19 +505,19 @@ void EventHandler::navigate(const NavigationDirection nav, const int playerID)
507
505
} // navigate
508
506
509
507
/* *
510
- * This function use simple heuristic to find the closest widget
511
- * in the requested direction,
508
+ * This function use simple heuristics to find the closest widget
509
+ * in the requested direction.
512
510
* It prioritize widgets close vertically to widget close horizontally,
513
511
* as it is expected behavior in any direction.
514
512
* Several hardcoded values are used, having been found to work well
515
513
* experimentally while keeping simple heuristics.
516
514
*/
517
515
int EventHandler::findIDClosestWidget (const NavigationDirection nav, const int playerID,
518
- GUIEngine:: Widget* w, bool ignore_disabled, int recursion_counter)
516
+ Widget* w, bool ignore_disabled, int recursion_counter)
519
517
{
520
518
int closest_widget_id = -1 ;
521
519
int distance = 0 ;
522
- // So that the UI behavior don 't change when it is upscaled
520
+ // So that the UI behavior doesn 't change when it is upscaled
523
521
const int BIG_DISTANCE = irr_driver->getActualScreenSize ().Width *100 ;
524
522
int smallest_distance = BIG_DISTANCE;
525
523
// Used when there is no suitable widget in the requested direction
@@ -539,7 +537,7 @@ int EventHandler::findIDClosestWidget(const NavigationDirection nav, const int p
539
537
// - it doesn't match a widget
540
538
// - it doesn't match a focusable widget
541
539
// - it corresponds to the current widget
542
- // - it corresponds to an invisible or disabled widget
540
+ // - it corresponds to an invisible or disabled widget (while ignore_disabled is true)
543
541
// - the player is not allowed to select it
544
542
// - Its base coordinates are negative (such as buttons within ribbons)
545
543
if (w_test == NULL || !Widget::isFocusableId (i) || w == w_test ||
@@ -582,16 +580,13 @@ int EventHandler::findIDClosestWidget(const NavigationDirection nav, const int p
582
580
583
581
if (nav == NAV_UP || nav == NAV_DOWN)
584
582
{
583
+ // Compare current top point with other widget lowest point
585
584
if (nav == NAV_UP)
586
- {
587
- // Compare current top point with other widget lowest point
588
585
distance = w->m_y - (w_test->m_y + w_test->m_h );
589
- }
586
+
587
+ // compare current lowest point with other widget top point
590
588
else
591
- {
592
- // compare current lowest point with other widget top point
593
589
distance = w_test->m_y - (w->m_y + w->m_h );
594
- }
595
590
596
591
// Better select an item on the side that one much higher,
597
592
// so make the vertical distance matter much more
@@ -613,16 +608,14 @@ int EventHandler::findIDClosestWidget(const NavigationDirection nav, const int p
613
608
}
614
609
else if (nav == NAV_LEFT || nav == NAV_RIGHT)
615
610
{
611
+ // compare current leftmost point with other widget rightmost
616
612
if (nav == NAV_LEFT)
617
- {
618
- // compare current leftmost point with other widget rightmost
619
613
distance = w->m_x - rightmost;
620
- }
614
+
615
+ // compare current rightmost point with other widget leftmost
621
616
else
622
- {
623
- // compare current rightmost point with other widget leftmost
624
617
distance = w_test->m_x - (w->m_x + w->m_w );
625
- }
618
+
626
619
wrapping_distance = distance;
627
620
628
621
int down_offset = std::max (0 , w_test->m_y - w->m_y );
@@ -677,6 +670,7 @@ int EventHandler::findIDClosestWidget(const NavigationDirection nav, const int p
677
670
678
671
int closest_id = (smallest_distance < BIG_DISTANCE) ? closest_widget_id :
679
672
closest_wrapping_widget_id;
673
+
680
674
Widget* w_test = GUIEngine::getWidget (closest_id);
681
675
682
676
if (w_test == NULL )
@@ -687,21 +681,19 @@ int EventHandler::findIDClosestWidget(const NavigationDirection nav, const int p
687
681
// This allows to skip over disabled/invisible widgets in a grid
688
682
if (!w_test->isVisible () || !w_test->isActivated ())
689
683
{
690
- // Can skip over at most 3 consecutive disabled/invisible widget
684
+ // Can skip over at most 3 consecutive disabled/invisible widgets
691
685
if (recursion_counter <=2 )
692
- {
693
- recursion_counter++;
694
- return findIDClosestWidget (nav, playerID, w_test, /* ignore disabled*/ false , recursion_counter);
695
- }
696
- // If nothing has been found, do a search ignoring disabled/invisible widgets,
697
- // restarting from the initial focused widget (otherwise, it could lead to weird results)
686
+ closest_id = findIDClosestWidget (nav, playerID, w_test, /* ignore disabled*/ false , recursion_counter + 1 );
687
+ // We have only found disabled/invisible widgets on our path
698
688
else if (recursion_counter == 3 )
699
- {
700
- Widget* w_focus = GUIEngine::getFocusForPlayer (playerID);
701
- return findIDClosestWidget (nav, playerID, w_focus, /* ignore disabled*/ true , recursion_counter);
702
- }
689
+ closest_id = -1 ;
703
690
}
704
691
692
+ // If nothing has been found or if we looped back to the starting widget (see issue #5283),
693
+ // do a search ignoring disabled/invisible widgets, restarting from the initial widget
694
+ if (recursion_counter == 0 && (closest_id == -1 || GUIEngine::getWidget (closest_id) == w))
695
+ closest_id = findIDClosestWidget (nav, playerID, w, /* ignore disabled*/ true , 1 /* avoid infinite loops */ );
696
+
705
697
return closest_id;
706
698
} // findIDClosestWidget
707
699
0 commit comments