aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java12
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java9
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java12
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/impl/FocusHandler.java41
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/impl/package-info.java6
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java79
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;
+ }
}