diff options
author | Juuxel <6596629+Juuxel@users.noreply.github.com> | 2020-05-21 00:10:10 +0300 |
---|---|---|
committer | Juuxel <6596629+Juuxel@users.noreply.github.com> | 2020-05-21 00:10:10 +0300 |
commit | cf9323b4df45937f7e96fbe25151ee7f7ac6da36 (patch) | |
tree | 1f19260264d3565d21c922714c32ef76d0a6317a | |
parent | 6bbe55ce7c6dab51e801399177152e228a391b37 (diff) | |
download | LibGui-cf9323b4df45937f7e96fbe25151ee7f7ac6da36.tar.gz LibGui-cf9323b4df45937f7e96fbe25151ee7f7ac6da36.tar.bz2 LibGui-cf9323b4df45937f7e96fbe25151ee7f7ac6da36.zip |
Add focus cycling to panels
Closes #37. Closes #54.
6 files changed, 151 insertions, 8 deletions
diff --git a/src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java b/src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java index fec799b..815b179 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java @@ -2,6 +2,7 @@ package io.github.cottonmc.cotton.gui; import javax.annotation.Nullable; +import io.github.cottonmc.cotton.gui.impl.FocusHandler; import io.github.cottonmc.cotton.gui.widget.WPanel; import io.github.cottonmc.cotton.gui.widget.WWidget; import net.fabricmc.api.EnvType; @@ -50,5 +51,14 @@ public interface GuiDescription { /** Notifies this gui that the widget wants to give up its hold over focus. */ public void releaseFocus(WWidget widget); - + + /** + * Cycles the focused widget in the GUI. + * + * @param lookForwards whether this should cycle forwards (true) or backwards (false) + * @since 2.0.0 + */ + default void cycleFocus(boolean lookForwards) { + FocusHandler.cycleFocus(this, lookForwards); + } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java index b5ac34e..96546fa 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java @@ -224,4 +224,13 @@ public class CottonClientScreen extends Screen implements TextHoverRendererScree public void renderTextHover(MatrixStack matrices, Text text, int x, int y) { renderTextHoverEffect(matrices, text, x, y); } + + @Override + public boolean changeFocus(boolean lookForwards) { + if (description != null) { + description.cycleFocus(lookForwards); + } + + return true; + } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java index ea24abf..fb73dd2 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java @@ -87,6 +87,9 @@ public class CottonInventoryScreen<T extends CottonInventoryController> extends if (ch==GLFW.GLFW_KEY_ESCAPE) { this.client.player.closeHandledScreen(); return true; + } else if (ch==GLFW.GLFW_KEY_TAB) { + changeFocus(!hasShiftDown()); + return true; } else { //if (super.keyPressed(ch, keyCode, modifiers)) return true; if (description.getFocus()==null) { @@ -236,4 +239,13 @@ public class CottonInventoryScreen<T extends CottonInventoryController> extends public void renderTextHover(MatrixStack matrices, Text text, int x, int y) { renderTextHoverEffect(matrices, text, x, y); } + + @Override + public boolean changeFocus(boolean lookForwards) { + if (description != null) { + description.cycleFocus(lookForwards); + } + + return true; + } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/FocusHandler.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/FocusHandler.java new file mode 100644 index 0000000..df0ef32 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/FocusHandler.java @@ -0,0 +1,41 @@ +package io.github.cottonmc.cotton.gui.impl; + +import io.github.cottonmc.cotton.gui.GuiDescription; +import io.github.cottonmc.cotton.gui.widget.WPanel; +import io.github.cottonmc.cotton.gui.widget.WWidget; + +/** + * The implementation for focus cycling. + */ +public final class FocusHandler { + public static void cycleFocus(GuiDescription host, boolean lookForwards) { + boolean result; + WWidget focus = host.getFocus(); + if (focus == null) { + result = cycleFocus(host, lookForwards, host.getRootPanel(), null); + } else { + WPanel parent = focus.getParent(); + result = cycleFocus(host, lookForwards, parent != null ? parent : host.getRootPanel(), focus); + } + + if (!result) { + // Try again from the beginning + cycleFocus(host, lookForwards, host.getRootPanel(), null); + } + } + + private static boolean cycleFocus(GuiDescription host, boolean lookForwards, WPanel panel, WWidget pivot) { + WWidget next = panel.cycleFocus(lookForwards, pivot); + if (next != null) { + host.requestFocus(next); + return true; + } else { + WPanel parent = panel.getParent(); + if (parent != null) { + return cycleFocus(host, lookForwards, parent, panel); + } + } + + return false; + } +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/package-info.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/package-info.java new file mode 100644 index 0000000..678ba6f --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/package-info.java @@ -0,0 +1,6 @@ +/** + * Internal implementation classes. + * + * @since 2.0.0 + */ +package io.github.cottonmc.cotton.gui.impl; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java index d1f0f4a..987248f 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java @@ -9,6 +9,8 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.util.math.MatrixStack; +import javax.annotation.Nullable; + /** * Panels are widgets that contain other widgets. */ @@ -21,7 +23,7 @@ public abstract class WPanel extends WWidget { protected final List<WWidget> children = new ArrayList<>(); @Environment(EnvType.CLIENT) private BackgroundPainter backgroundPainter = null; - + @Override public void createPeers(GuiDescription c) { super.createPeers(c); @@ -38,7 +40,7 @@ public abstract class WPanel extends WWidget { public void remove(WWidget w) { children.remove(w); } - + @Override public boolean canResize() { return true; @@ -65,7 +67,7 @@ public abstract class WPanel extends WWidget { public BackgroundPainter getBackgroundPainter() { return this.backgroundPainter; } - + /** * Uses this Panel's layout rules to reposition and resize components to fit nicely in the panel. */ @@ -150,7 +152,7 @@ public abstract class WPanel extends WWidget { } } }*/ - + /** * Finds the most specific child node at this location. */ @@ -168,7 +170,7 @@ public abstract class WPanel extends WWidget { } return this; } - + @Override public void validate(GuiDescription c) { layout(); @@ -177,12 +179,12 @@ public abstract class WPanel extends WWidget { } if (c!=null) createPeers(c); } - + @Environment(EnvType.CLIENT) @Override public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { if (backgroundPainter!=null) backgroundPainter.paintBackground(x, y, this); - + for(WWidget child : children) { child.paint(matrices, x + child.getX(), y + child.getY(), mouseX-child.getX(), mouseY-child.getY()); } @@ -196,4 +198,67 @@ public abstract class WPanel extends WWidget { public void tick() { for(WWidget child : children) child.tick(); } + + /** + * Cycles the focus inside this panel. + * + * @param lookForwards whether this should cycle forwards (true) or backwards (false) + * @param pivot the widget that should be cycled around (can be null for beginning / end) + * @return the next focused widget, or null if should exit to the parent panel + * @since 2.0.0 + */ + @Nullable + public WWidget cycleFocus(boolean lookForwards, @Nullable WWidget pivot) { + if (pivot == null) { + if (lookForwards) { + for (WWidget child : children) { + WWidget result = checkFocusCycling(lookForwards, child); + if (result != null) return result; + } + } else if (!children.isEmpty()) { + for (int i = children.size() - 1; i >= 0; i--) { + WWidget child = children.get(i); + WWidget result = checkFocusCycling(lookForwards, child); + if (result != null) return result; + } + } + } else { + int currentIndex = children.indexOf(pivot); + + if (currentIndex == -1) { // outside widget + currentIndex = lookForwards ? 0 : children.size() - 1; + } + + if (lookForwards) { + if (currentIndex < children.size() - 1) { + for (int i = currentIndex + 1; i < children.size(); i++) { + WWidget child = children.get(i); + WWidget result = checkFocusCycling(lookForwards, child); + if (result != null) return result; + } + } + } else { // look forwards = false + if (currentIndex > 0) { + for (int i = currentIndex - 1; i >= 0; i--) { + WWidget child = children.get(i); + WWidget result = checkFocusCycling(lookForwards, child); + if (result != null) return result; + } + } + } + } + + return null; + } + + @Nullable + private WWidget checkFocusCycling(boolean lookForwards, WWidget child) { + if (child.canFocus()) { + return child; + } else if (child instanceof WPanel) { + return ((WPanel) child).cycleFocus(lookForwards, null); + } + + return null; + } } |