-
Notifications
You must be signed in to change notification settings - Fork 1
Description
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:
- 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.
- 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:
By using the left and right actions, you can switch between the three main controls on this screen:
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.

