Created
August 6, 2023 14:26
-
-
Save fourlastor/d78031ecdfccbd18135de9d39661b67c to your computer and use it in GitHub Desktop.
Stage focus order
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.badlogic.gdx.scenes.scene2d.Actor; | |
import de.golfgl.gdx.controllers.ControllerMenuStage; | |
import de.golfgl.gdx.controllers.IControllerScrollable; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.List; | |
public class ControllerScrollableHelper implements IControllerScrollable { | |
private final ControllerMenuStage stage; | |
private final ControllerMenuStage.MoveFocusDirection mainDirection; | |
private final ControllerMenuStage.MoveFocusDirection crossDirection; | |
private final List<FocusableGroup> groups; | |
public static Builder builder(ControllerMenuStage stage1) { | |
return new Builder(stage1); | |
} | |
private ControllerScrollableHelper( | |
ControllerMenuStage stage, | |
ControllerMenuStage.MoveFocusDirection mainDirection, | |
ControllerMenuStage.MoveFocusDirection crossDirection, | |
List<FocusableGroup> groups) { | |
this.stage = stage; | |
this.mainDirection = mainDirection; | |
this.crossDirection = crossDirection; | |
this.groups = groups; | |
} | |
@Override | |
public boolean onControllerScroll(ControllerMenuStage.MoveFocusDirection direction) { | |
Actor focusedActor = getFocusedActor(getFocusedGroup()); | |
Actor nextFocusableActor = getNextFocusableActor(direction); | |
if (focusedActor == nextFocusableActor) { | |
return true; | |
} else { | |
return stage.setFocusedActor(nextFocusableActor); | |
} | |
} | |
private Actor getNextFocusableActor(ControllerMenuStage.MoveFocusDirection direction) { | |
ControllerMenuStage.MoveFocusDirection opposite = opposite(direction); | |
if (direction == mainDirection || opposite == mainDirection) { | |
return getNextFocusableActor(direction == mainDirection); | |
} | |
return getNextFocusableActorInGroup(direction == crossDirection); | |
} | |
private Actor getNextFocusableActorInGroup(boolean next) { | |
FocusableGroup focusedGroup = getFocusedGroup(); | |
int groupIndex = groups.indexOf(focusedGroup); | |
if (next) { | |
if (groupIndex < groups.size() - 1) { | |
return groups.get(groupIndex + 1).actors.get(0); | |
} | |
} else { | |
if (groupIndex > 0) { | |
List<Actor> actors = groups.get(groupIndex - 1).actors; | |
return actors.get(actors.size() - 1); | |
} | |
} | |
return getFocusedActor(focusedGroup); | |
} | |
private Actor getNextFocusableActor(boolean next) { | |
FocusableGroup focusedGroup = getFocusedGroup(); | |
int groupIndex = groups.indexOf(focusedGroup); | |
Actor focusedActor = getFocusedActor(focusedGroup); | |
int focusIndex = focusedGroup.actors.indexOf(focusedActor); | |
if (next) { | |
if (focusIndex < focusedGroup.actors.size() - 1) { | |
return focusedGroup.actors.get(focusIndex + 1); | |
} else if (groupIndex < groups.size() - 1) { | |
return groups.get(groupIndex + 1).actors.get(0); | |
} | |
} else { | |
if (focusIndex > 0) { | |
return focusedGroup.actors.get(focusIndex - 1); | |
} else if (groupIndex > 0) { | |
List<Actor> actors = groups.get(groupIndex - 1).actors; | |
return actors.get(actors.size() - 1); | |
} | |
} | |
return focusedActor; | |
} | |
private FocusableGroup getFocusedGroup() { | |
return groups.stream() | |
.filter(it -> it.actors.stream().anyMatch(Actor::hasKeyboardFocus)) | |
.findFirst() | |
.orElseGet(() -> groups.get(0)); | |
} | |
private Actor getFocusedActor(FocusableGroup focusedGroup) { | |
return focusedGroup.actors.stream() | |
.filter(Actor::hasKeyboardFocus) | |
.findFirst() | |
.orElseGet(() -> focusedGroup.actors.get(0)); | |
} | |
private static ControllerMenuStage.MoveFocusDirection opposite(ControllerMenuStage.MoveFocusDirection direction) { | |
switch (direction) { | |
case west: | |
return ControllerMenuStage.MoveFocusDirection.east; | |
case north: | |
return ControllerMenuStage.MoveFocusDirection.south; | |
case east: | |
return ControllerMenuStage.MoveFocusDirection.west; | |
case south: | |
return ControllerMenuStage.MoveFocusDirection.north; | |
} | |
throw new IllegalArgumentException("Direction does not have an opposite" + direction); | |
} | |
private static class FocusableGroup { | |
private final List<Actor> actors; | |
private FocusableGroup(List<Actor> actors) { | |
this.actors = actors; | |
} | |
} | |
public static class Builder { | |
private final ControllerMenuStage stage; | |
private ControllerMenuStage.MoveFocusDirection mainDirection; | |
private ControllerMenuStage.MoveFocusDirection crossDirection; | |
private final List<FocusableGroup> groups = new ArrayList<>(); | |
public Builder(ControllerMenuStage stage) { | |
this.stage = stage; | |
} | |
public Builder mainDirection(ControllerMenuStage.MoveFocusDirection mainDirection) { | |
this.mainDirection = mainDirection; | |
return this; | |
} | |
public Builder crossDirection(ControllerMenuStage.MoveFocusDirection crossDirection) { | |
this.crossDirection = crossDirection; | |
return this; | |
} | |
public Builder group(Actor... actors) { | |
if (actors.length == 0) { | |
throw new IllegalArgumentException("You must supply at least one actor for a group"); | |
} | |
groups.add(new FocusableGroup(Arrays.asList(actors))); | |
return this; | |
} | |
public ControllerScrollableHelper build() { | |
if (mainDirection == null) { | |
throw new NullPointerException("mainDirection was null"); | |
} | |
if (crossDirection == null) { | |
throw new NullPointerException("crossDirection was null"); | |
} | |
if (groups.isEmpty()) { | |
throw new IllegalStateException("empty groups"); | |
} | |
return new ControllerScrollableHelper(stage, mainDirection, crossDirection, groups); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Usage extends Group implements IControllerScrollable { | |
/* | |
UI: | |
| one | five | |
| two | six | |
| three | seven | |
| four | eight | |
one + east = five | |
two + east = five | |
two + south = three | |
three + north = two | |
six + west = four | |
*/ | |
public Usage() { | |
helper = ControllerScrollableHelper.builder(stage) | |
// mainDirection goes through the actors in a group, then onto the next group | |
.mainDirection(ControllerMenuStage.MoveFocusDirection.south) | |
// crossDirection skips through groups | |
.crossDirection(ControllerMenuStage.MoveFocusDirection.east) | |
.group(one, two, three, four) | |
.group(five, six, seven, eighth) | |
.build(); | |
} | |
@Override | |
public boolean onControllerScroll(ControllerMenuStage.MoveFocusDirection direction) { | |
return helper.onControllerScroll(direction); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment