Skip to content

Implement focus groups #7

@tomrijnbeek

Description

@tomrijnbeek

For example, a menu you can navigate through with up/down arrows.

My first idea on how to implement this is to make a FocusGroup control. When instantiating the focus group control, you define what keys/buttons move focus from one control to the next. Within the focus group, the order in which controls are added will define the order in which the elements are focused.

Nested focus groups should also be trivially supported. Since focus is something that is propagated along an entire path in the control tree, a focus group will only update the focus of its children when it itself is focused. If there is a focus group inside another one with different keys to move focus, this will work without much problem. As long as the inner focus group is focused inside the outer focus group, the inner focus group can respond to those focus buttons. Roughly (pseudo-code):

public void override KeyHit(Key k) {
  if (!IsFocused) return;
  if (nextFocusKeys.Contains(k)) moveFocusForward();
  if (prevFocusKeys.Contains(k)) moveFocusBackward();
}

If there is a focus group within a focus group that uses the same keys as an ancestor focus group, this can be supported easily as well. A focus group will mark an event as handled if it has moved focus to the next element. When trying to move the focus forward without there being a control left, the focus group could do one of two things:

  1. It doesn't handle the event, making the event propagate upwards in the control tree, and the ancestor focus group will receive the event instead. We let the focus escape the focus group.
  2. It handles the focus by cycling the focus back to the first element. The ancestor never receives the key event. The control captures the focus.

I think with these rules, focus within a group should be relatively easy thing to implement, and also appears to cover the major use cases. I also think using a builder pattern, we can make this very descriptive and easy to use. For example:

  FocusGroup.Builder()
    .AddForwardKey(Key.Down)
    .AddForwardKey(Key.S)
    .AddBackwardKey(Key.Up)
    .AddBackwardKey(Key.W)
    .AddForwardButton(Button.Down)
    .AddBackwardButton(Button.Up)
    .Build();

This would create a focus group where up and down on they arrow keys, WASD keys, and gamepad would navigate forward and backwards. To make sure the focus cycles back to the top, another .MakeCyclic() call could be added.

I looked at the Roche Fusion main menu screen to check if it is possible to implement that using the focus group rules I outlined above. The screen looks like this:

image

By using the left and right actions, you can switch between the three main controls on this screen:

image

Within both the menu on the right and the vertical highscore navigation, the up and down actions navigate through the options. However, to switch between "easy" and "normal", you use the same directions as you would switch between the high level groups. Once you move "right" from the "normal" option though, it switches back to the vertical highscore controls.

All in all, it seems this implementation will make it easy to implement menus, and make it possible to build in keyboard and gamepad support in menus with ease.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions