aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GuiTest/src/main/java/io/github/cottonmc/test/LibGuiTest.java6
-rw-r--r--gradle.properties14
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java11
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java4
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java51
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java51
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/impl/FocusHandler.java43
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/impl/client/FocusElements.java156
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/impl/mixin/client/ScreenAccessor.java15
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/impl/mixin/client/package-info.java4
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java9
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java5
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WItem.java4
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WItemSlot.java65
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java68
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WScrollBar.java6
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WTabPanel.java5
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java22
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WToggleButton.java5
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java29
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/data/InputResult.java2
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/data/Rect2i.java13
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/focus/Focus.java27
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/focus/FocusHandler.java50
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/focus/SimpleFocusHandler.java23
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/focus/package-info.java4
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/icon/ItemIcon.java15
-rw-r--r--src/main/resources/fabric.mod.json9
-rw-r--r--src/main/resources/mixins.libgui.json14
29 files changed, 489 insertions, 241 deletions
diff --git a/GuiTest/src/main/java/io/github/cottonmc/test/LibGuiTest.java b/GuiTest/src/main/java/io/github/cottonmc/test/LibGuiTest.java
index 009ea23..3c11004 100644
--- a/GuiTest/src/main/java/io/github/cottonmc/test/LibGuiTest.java
+++ b/GuiTest/src/main/java/io/github/cottonmc/test/LibGuiTest.java
@@ -13,6 +13,8 @@ import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
+import net.minecraft.resource.featuretoggle.FeatureFlags;
+import net.minecraft.resource.featuretoggle.FeatureSet;
import net.minecraft.screen.ScreenHandlerContext;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.util.Identifier;
@@ -48,10 +50,10 @@ public class LibGuiTest implements ModInitializer {
GUI_SCREEN_HANDLER_TYPE = new ScreenHandlerType<>((int syncId, PlayerInventory inventory) -> {
return new TestDescription(GUI_SCREEN_HANDLER_TYPE, syncId, inventory, ScreenHandlerContext.EMPTY);
- });
+ }, FeatureSet.of(FeatureFlags.VANILLA));
Registry.register(Registries.SCREEN_HANDLER, new Identifier(MODID, "gui"), GUI_SCREEN_HANDLER_TYPE);
- REALLY_SIMPLE_SCREEN_HANDLER_TYPE = new ScreenHandlerType<>(ReallySimpleDescription::new);
+ REALLY_SIMPLE_SCREEN_HANDLER_TYPE = new ScreenHandlerType<>(ReallySimpleDescription::new, FeatureSet.of(FeatureFlags.VANILLA));
Registry.register(Registries.SCREEN_HANDLER, new Identifier(MODID, "really_simple"), REALLY_SIMPLE_SCREEN_HANDLER_TYPE);
Optional<ModContainer> containerOpt = FabricLoader.getInstance().getModContainer("jankson");
diff --git a/gradle.properties b/gradle.properties
index 1fe8e59..7476692 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -4,17 +4,17 @@ fabric.loom.multiProjectOptimisation = true
# Fabric Properties
# check these on https://fabricmc.net/use
- minecraft_version=1.19.3
- yarn_mappings=1.19.3+build.2
- loader_version=0.14.11
+ minecraft_version=1.19.4
+ yarn_mappings=1.19.4+build.1
+ loader_version=0.14.17
# Mod Properties
- mod_version = 6.5.3
+ mod_version = 7.0.0-beta.1
maven_group = io.github.cottonmc
archives_base_name = LibGui
# Dependencies
- fabric_version=0.76.0+1.19.3
- jankson_version=5.0.0+j1.2.1
- modmenu_version=5.0.2
+ fabric_version=0.76.0+1.19.4
+ jankson_version=5.0.1+j1.2.2
+ modmenu_version=6.1.0-rc.4
libninepatch_version=1.2.0
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 5962e69..6435651 100644
--- a/src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java
+++ b/src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java
@@ -4,7 +4,6 @@ import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.screen.PropertyDelegate;
-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 io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment;
@@ -77,16 +76,6 @@ public interface GuiDescription {
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);
- }
-
- /**
* Gets whether this GUI is fullscreen.
*
* <p>Fullscreen GUIs have no default background painter and
diff --git a/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java b/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java
index 15917ff..4a92003 100644
--- a/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java
+++ b/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java
@@ -475,8 +475,8 @@ public class SyncedGuiDescription extends ScreenHandler implements GuiDescriptio
}
@Override
- public void close(PlayerEntity player) {
- super.close(player);
+ public void onClosed(PlayerEntity player) {
+ super.onClosed(player);
if (blockInventory != null) blockInventory.onClose(player);
}
//}
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 524e73d..81d7646 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
@@ -1,5 +1,6 @@
package io.github.cottonmc.cotton.gui.client;
+import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
import net.minecraft.client.util.math.MatrixStack;
@@ -10,15 +11,18 @@ import net.minecraft.text.Text;
import io.github.cottonmc.cotton.gui.GuiDescription;
import io.github.cottonmc.cotton.gui.impl.VisualLogger;
import io.github.cottonmc.cotton.gui.impl.client.CottonScreenImpl;
+import io.github.cottonmc.cotton.gui.impl.client.FocusElements;
import io.github.cottonmc.cotton.gui.impl.client.MouseInputHandler;
import io.github.cottonmc.cotton.gui.impl.client.NarrationHelper;
+import io.github.cottonmc.cotton.gui.impl.mixin.client.ScreenAccessor;
import io.github.cottonmc.cotton.gui.widget.WPanel;
import io.github.cottonmc.cotton.gui.widget.WWidget;
+import io.github.cottonmc.cotton.gui.widget.data.InputResult;
import org.jetbrains.annotations.Nullable;
-import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL11;
public class CottonClientScreen extends Screen implements CottonScreenImpl {
+ private static final VisualLogger LOGGER = new VisualLogger(CottonInventoryScreen.class);
protected GuiDescription description;
protected int left = 0;
protected int top = 0;
@@ -67,6 +71,14 @@ public class CottonClientScreen extends Screen implements CottonScreenImpl {
if (root != null) root.addPainters();
description.addPainters();
reposition(width, height);
+
+ if (root != null) {
+ Element rootPanelElement = FocusElements.ofPanel(root);
+ ((ScreenAccessor) this).libgui$getChildren().add(rootPanelElement);
+ setInitialFocus(rootPanelElement);
+ } else {
+ LOGGER.warn("No root panel found, keyboard navigation disabled");
+ }
}
@Override
@@ -217,28 +229,32 @@ public class CottonClientScreen extends Screen implements CottonScreenImpl {
@Override
public boolean charTyped(char ch, int keyCode) {
- if (description.getFocus()==null) return super.charTyped(ch, keyCode);
- description.getFocus().onCharTyped(ch);
- return true;
+ WWidget focus = description.getFocus();
+ if (focus != null && focus.onCharTyped(ch) == InputResult.PROCESSED) {
+ return true;
+ }
+
+ return super.charTyped(ch, keyCode);
}
@Override
public boolean keyPressed(int ch, int keyCode, int modifiers) {
- if (ch == GLFW.GLFW_KEY_ESCAPE || ch == GLFW.GLFW_KEY_TAB) {
- // special hardcoded keys, these will never be delivered to widgets
- return super.keyPressed(ch, keyCode, modifiers);
- } else {
- if (description.getFocus() == null) return super.keyPressed(ch, keyCode, modifiers);
- description.getFocus().onKeyPressed(ch, keyCode, modifiers);
+ WWidget focus = description.getFocus();
+ if (focus != null && focus.onKeyPressed(ch, keyCode, modifiers) == InputResult.PROCESSED) {
return true;
}
+
+ return super.keyPressed(ch, keyCode, modifiers);
}
@Override
public boolean keyReleased(int ch, int keyCode, int modifiers) {
- if (description.getFocus()==null) return super.keyReleased(ch, keyCode, modifiers);
- description.getFocus().onKeyReleased(ch, keyCode, modifiers);
- return true;
+ WWidget focus = description.getFocus();
+ if (focus != null && focus.onKeyReleased(ch, keyCode, modifiers) == InputResult.PROCESSED) {
+ return true;
+ }
+
+ return super.keyReleased(ch, keyCode, modifiers);
}
@Override
@@ -247,15 +263,6 @@ public class CottonClientScreen extends Screen implements CottonScreenImpl {
}
@Override
- public boolean changeFocus(boolean lookForwards) {
- if (description != null) {
- description.cycleFocus(lookForwards);
- }
-
- return true;
- }
-
- @Override
protected void addElementNarrations(NarrationMessageBuilder builder) {
if (description != null) NarrationHelper.addNarrations(description.getRootPanel(), builder);
}
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 6406619..61fc287 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
@@ -1,5 +1,6 @@
package io.github.cottonmc.cotton.gui.client;
+import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
import net.minecraft.client.render.DiffuseLighting;
@@ -14,13 +15,15 @@ import io.github.cottonmc.cotton.gui.GuiDescription;
import io.github.cottonmc.cotton.gui.SyncedGuiDescription;
import io.github.cottonmc.cotton.gui.impl.VisualLogger;
import io.github.cottonmc.cotton.gui.impl.client.CottonScreenImpl;
+import io.github.cottonmc.cotton.gui.impl.client.FocusElements;
import io.github.cottonmc.cotton.gui.impl.client.MouseInputHandler;
import io.github.cottonmc.cotton.gui.impl.client.NarrationHelper;
+import io.github.cottonmc.cotton.gui.impl.mixin.client.ScreenAccessor;
import io.github.cottonmc.cotton.gui.widget.WPanel;
import io.github.cottonmc.cotton.gui.widget.WWidget;
+import io.github.cottonmc.cotton.gui.widget.data.InputResult;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
-import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL11;
/**
@@ -29,6 +32,7 @@ import org.lwjgl.opengl.GL11;
* @param <T> the description type
*/
public class CottonInventoryScreen<T extends SyncedGuiDescription> extends HandledScreen<T> implements CottonScreenImpl {
+ private static final VisualLogger LOGGER = new VisualLogger(CottonInventoryScreen.class);
protected SyncedGuiDescription description;
@Nullable protected WWidget lastResponder = null;
private final MouseInputHandler<CottonInventoryScreen<T>> mouseInputHandler = new MouseInputHandler<>(this);
@@ -102,6 +106,14 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl
description.addPainters();
reposition(width, height);
+
+ if (root != null) {
+ Element rootPanelElement = FocusElements.ofPanel(root);
+ ((ScreenAccessor) this).libgui$getChildren().add(rootPanelElement);
+ setInitialFocus(rootPanelElement);
+ } else {
+ LOGGER.warn("No root panel found, keyboard navigation disabled");
+ }
}
@Override
@@ -233,28 +245,32 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl
@Override
public boolean charTyped(char ch, int keyCode) {
- if (description.getFocus()==null) return super.charTyped(ch, keyCode);
- description.getFocus().onCharTyped(ch);
- return true;
+ WWidget focus = description.getFocus();
+ if (focus != null && focus.onCharTyped(ch) == InputResult.PROCESSED) {
+ return true;
+ }
+
+ return super.charTyped(ch, keyCode);
}
@Override
public boolean keyPressed(int ch, int keyCode, int modifiers) {
- if (ch == GLFW.GLFW_KEY_ESCAPE || ch == GLFW.GLFW_KEY_TAB) {
- // special hardcoded keys, these will never be delivered to widgets
- return super.keyPressed(ch, keyCode, modifiers);
- } else {
- if (description.getFocus() == null) return super.keyPressed(ch, keyCode, modifiers);
- description.getFocus().onKeyPressed(ch, keyCode, modifiers);
+ WWidget focus = description.getFocus();
+ if (focus != null && focus.onKeyPressed(ch, keyCode, modifiers) == InputResult.PROCESSED) {
return true;
}
+
+ return super.keyPressed(ch, keyCode, modifiers);
}
@Override
public boolean keyReleased(int ch, int keyCode, int modifiers) {
- if (description.getFocus()==null) return super.keyReleased(ch, keyCode, modifiers);
- description.getFocus().onKeyReleased(ch, keyCode, modifiers);
- return true;
+ WWidget focus = description.getFocus();
+ if (focus != null && focus.onKeyReleased(ch, keyCode, modifiers) == InputResult.PROCESSED) {
+ return true;
+ }
+
+ return super.keyReleased(ch, keyCode, modifiers);
}
@Override
@@ -321,15 +337,6 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl
}
@Override
- public boolean changeFocus(boolean lookForwards) {
- if (description != null) {
- description.cycleFocus(lookForwards);
- }
-
- return true;
- }
-
- @Override
protected void addElementNarrations(NarrationMessageBuilder builder) {
if (description != null) NarrationHelper.addNarrations(description.getRootPanel(), builder);
}
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
deleted file mode 100644
index 61cffa6..0000000
--- a/src/main/java/io/github/cottonmc/cotton/gui/impl/FocusHandler.java
+++ /dev/null
@@ -1,43 +0,0 @@
-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 {
- result = cycleFocus(host, lookForwards, focus, null);
- }
-
- if (!result) {
- // Try again from the beginning
- cycleFocus(host, lookForwards, host.getRootPanel(), null);
- }
- }
-
- private static boolean cycleFocus(GuiDescription host, boolean lookForwards, WWidget widget, WWidget pivot) {
- WWidget next = widget instanceof WPanel
- ? ((WPanel) widget).cycleFocus(lookForwards, pivot)
- : widget.cycleFocus(lookForwards);
-
- if (next != null) {
- host.requestFocus(next);
- return true;
- } else {
- WPanel parent = widget.getParent();
- if (parent != null) {
- return cycleFocus(host, lookForwards, parent, widget);
- }
- }
-
- return false;
- }
-}
diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/client/FocusElements.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/FocusElements.java
new file mode 100644
index 0000000..fc2fa42
--- /dev/null
+++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/FocusElements.java
@@ -0,0 +1,156 @@
+package io.github.cottonmc.cotton.gui.impl.client;
+
+import net.minecraft.client.gui.AbstractParentElement;
+import net.minecraft.client.gui.Element;
+import net.minecraft.client.gui.ScreenRect;
+import net.minecraft.client.gui.navigation.GuiNavigation;
+import net.minecraft.client.gui.navigation.GuiNavigationPath;
+
+import io.github.cottonmc.cotton.gui.widget.WPanel;
+import io.github.cottonmc.cotton.gui.widget.WWidget;
+import io.github.cottonmc.cotton.gui.widget.data.Rect2i;
+import io.github.cottonmc.cotton.gui.widget.focus.Focus;
+import io.github.cottonmc.cotton.gui.widget.focus.FocusHandler;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+public final class FocusElements {
+ public static PanelFocusElement ofPanel(WPanel panel) {
+ PanelFocusElement result = new PanelFocusElement(panel);
+ result.refreshChildren();
+ return result;
+ }
+
+ public static Stream<FocusElement<?>> toElements(WWidget widget) {
+ if (widget instanceof WPanel panel) {
+ return Stream.of(ofPanel(panel));
+ } else {
+ return fromFoci(widget);
+ }
+ }
+
+ private static Stream<FocusElement<?>> fromFoci(WWidget widget) {
+ @Nullable FocusHandler<?> focusHandler = widget.getFocusHandler();
+ if (focusHandler == null) return Stream.empty();
+
+ return focusHandler.foci().map(focus -> new LeafFocusElement(widget, focus));
+ }
+
+ public sealed interface FocusElement<W extends WWidget> extends Element {
+ W widget();
+ }
+
+ private record LeafFocusElement(WWidget widget, Focus<?> focus) implements FocusElement<WWidget> {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void setFocused(boolean focused) {
+ if (focused) {
+ Focus<?> focus = focus();
+
+ if (focus != null) {
+ widget.requestFocus();
+ ((FocusHandler<Object>) widget.getFocusHandler()).setFocused((Focus<Object>) focus);
+ }
+ } else {
+ widget.releaseFocus();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean isFocused() {
+ if (widget.isFocused()) {
+ FocusHandler<Object> focusHandler = (FocusHandler<Object>) widget.getFocusHandler();
+ if (focusHandler != null) {
+ return focusHandler.isFocused((Focus<Object>) focus);
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public ScreenRect getNavigationFocus() {
+ Rect2i area = focus.area();
+ return new ScreenRect(
+ widget.getAbsoluteX() + area.x(),
+ widget.getAbsoluteY() + area.y(),
+ area.width(), area.height()
+ );
+ }
+
+ @Override
+ public @Nullable GuiNavigationPath getNavigationPath(GuiNavigation navigation) {
+ return widget.canFocus() && !isFocused() ? GuiNavigationPath.of(this) : null;
+ }
+ }
+
+ private static final class PanelFocusElement extends AbstractParentElement implements FocusElement<WPanel> {
+ private final List<FocusElement<?>> children = new ArrayList<>();
+ private final WPanel widget;
+ private List<WWidget> childWidgets;
+
+ private PanelFocusElement(WPanel widget) {
+ this.widget = widget;
+ }
+
+ private void refreshChildren() {
+ boolean shouldRefresh = false;
+ if (childWidgets == null) {
+ childWidgets = widget.streamChildren().toList();
+ shouldRefresh = true;
+ } else {
+ List<WWidget> currentChildren = widget.streamChildren().toList();
+ if (!childWidgets.equals(currentChildren)) {
+ childWidgets = currentChildren;
+ shouldRefresh = true;
+ }
+ }
+
+ if (shouldRefresh) {
+ children.clear();
+ fromFoci(widget).forEach(children::add);
+ childWidgets.stream()
+ .flatMap(FocusElements::toElements)
+ .forEach(children::add);
+ refreshFocus();
+ }
+ }
+
+ @Override
+ public List<FocusElement<?>> children() {
+ refreshChildren();
+ return children;
+ }
+
+ @Override
+ public WPanel widget() {
+ return widget;
+ }
+
+ @Override
+ public @Nullable Element getFocused() {
+ refreshFocus();
+ return super.getFocused();
+ }
+
+ public void refreshFocus() {
+ if (children.isEmpty()) return;
+
+ boolean foundFocus = false;
+ for (FocusElement<?> child : children) {
+ if (child instanceof PanelFocusElement panel) {
+ panel.refreshFocus();
+ }
+
+ if (!foundFocus && child.isFocused()) {
+ setFocused(child);
+ foundFocus = true;
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/mixin/client/ScreenAccessor.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/mixin/client/ScreenAccessor.java
new file mode 100644
index 0000000..f2703ed
--- /dev/null
+++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/mixin/client/ScreenAccessor.java
@@ -0,0 +1,15 @@
+package io.github.cottonmc.cotton.gui.impl.mixin.client;
+
+import net.minecraft.client.gui.Element;
+import net.minecraft.client.gui.screen.Screen;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+import java.util.List;
+
+@Mixin(Screen.class)
+public interface ScreenAccessor {
+ @Accessor("children")
+ List<Element> libgui$getChildren();
+}
diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/mixin/client/package-info.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/mixin/client/package-info.java
new file mode 100644
index 0000000..ce1472f
--- /dev/null
+++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/mixin/client/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Internal implementation classes.
+ */
+package io.github.cottonmc.cotton.gui.impl.mixin.client;
diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java
index 83ad651..945c121 100644
--- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java
+++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java
@@ -319,7 +319,7 @@ public abstract class WAbstractSlider extends WWidget {
@Environment(EnvType.CLIENT)
@Override
- public void onKeyPressed(int ch, int key, int modifiers) {
+ public InputResult onKeyPressed(int ch, int key, int modifiers) {
boolean valueChanged = false;
if (modifiers == 0) {
if (isDecreasingKey(ch, direction) && value > min) {
@@ -343,15 +343,20 @@ public abstract class WAbstractSlider extends WWidget {
onValueChanged(value);
pendingDraggingFinishedFromKeyboard = true;
}
+
+ return InputResult.of(valueChanged);
}
@Environment(EnvType.CLIENT)
@Override
- public void onKeyReleased(int ch, int key, int modifiers) {
+ public InputResult onKeyReleased(int ch, int key, int modifiers) {
if (pendingDraggingFinishedFromKeyboard && (isDecreasingKey(ch, direction) || isIncreasingKey(ch, direction))) {
if (draggingFinishedListener != null) draggingFinishedListener.accept(value);
pendingDraggingFinishedFromKeyboard = false;
+ return InputResult.PROCESSED;
}
+
+ return InputResult.IGNORED;
}
/**
diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java
index 78874b6..de212fb 100644
--- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java
+++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java
@@ -151,10 +151,13 @@ public class WButton extends WWidget {
@Environment(EnvType.CLIENT)
@Override
- public void onKeyPressed(int ch, int key, int modifiers) {
+ public InputResult onKeyPressed(int ch, int key, int modifiers) {
if (isActivationKey(ch)) {
onClick(0, 0, 0);
+ return InputResult.PROCESSED;
}
+
+ return InputResult.IGNORED;
}
/**
diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WItem.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WItem.java
index 89b973a..32770c3 100644
--- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WItem.java
+++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WItem.java
@@ -64,9 +64,7 @@ public class WItem extends WWidget {
MinecraftClient mc = MinecraftClient.getInstance();
ItemRenderer renderer = mc.getItemRenderer();
- renderer.zOffset = 100f;
- renderer.renderInGui(items.get(current), x + getWidth() / 2 - 8, y + getHeight() / 2 - 8);
- renderer.zOffset = 0f;
+ renderer.renderInGui(matrices, items.get(current), x + getWidth() / 2 - 8, y + getHeight() / 2 - 8);
}
/**
diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WItemSlot.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WItemSlot.java
index a85b08a..ff7548c 100644
--- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WItemSlot.java
+++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WItemSlot.java
@@ -21,6 +21,9 @@ import io.github.cottonmc.cotton.gui.impl.LibGuiCommon;
import io.github.cottonmc.cotton.gui.impl.VisualLogger;
import io.github.cottonmc.cotton.gui.impl.client.NarrationMessages;
import io.github.cottonmc.cotton.gui.widget.data.InputResult;
+import io.github.cottonmc.cotton.gui.widget.data.Rect2i;
+import io.github.cottonmc.cotton.gui.widget.focus.Focus;
+import io.github.cottonmc.cotton.gui.widget.focus.FocusHandler;
import io.github.cottonmc.cotton.gui.widget.icon.Icon;
import org.jetbrains.annotations.Nullable;
@@ -30,6 +33,7 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
+import java.util.stream.Stream;
/**
* A widget that displays an item that can be interacted with.
@@ -92,6 +96,42 @@ public class WItemSlot extends WWidget {
private int hoveredSlot = -1;
private Predicate<ItemStack> filter = ValidatedSlot.DEFAULT_ITEM_FILTER;
private final Set<ChangeListener> listeners = new HashSet<>();
+ private final FocusHandler<Integer> focusHandler = new FocusHandler<>() {
+ @Override
+ public boolean isFocused(Focus<Integer> focus) {
+ return focusedSlot == focus.key();
+ }
+
+ @Override
+ public void setFocused(Focus<Integer> focus) {
+ focusedSlot = focus.key();
+ }
+
+ @Override
+ public Stream<Focus<Integer>> foci() {
+ Stream.Builder<Focus<Integer>> builder = Stream.builder();
+ int index = 0;
+
+ for (int y = 0; y < slotsHigh; y++) {
+ for (int x = 0; x < slotsWide; x++) {
+ int slotX = x * 18;
+ int slotY = y * 18;
+ int size = 18;
+
+ if (big) {
+ slotX -= 4;
+ slotY -= 4;
+ size = 26;
+ }
+
+ builder.add(new Focus<>(index, new Rect2i(slotX, slotY, size, size)));
+ index++;
+ }
+ }
+
+ return builder.build();
+ }
+ };
public WItemSlot(Inventory inventory, int startIndex, int slotsWide, int slotsHigh, boolean big) {
this();
@@ -311,14 +351,17 @@ public class WItemSlot extends WWidget {
@Environment(EnvType.CLIENT)
@Override
- public void onKeyPressed(int ch, int key, int modifiers) {
+ public InputResult onKeyPressed(int ch, int key, int modifiers) {
if (isActivationKey(ch) && host instanceof ScreenHandler && focusedSlot >= 0) {
ScreenHandler handler = (ScreenHandler) host;
MinecraftClient client = MinecraftClient.getInstance();
ValidatedSlot peer = peers.get(focusedSlot);
client.interactionManager.clickSlot(handler.syncId, peer.id, 0, SlotActionType.PICKUP, client.player);
+ return InputResult.PROCESSED;
}
+
+ return InputResult.IGNORED;
}
/**
@@ -396,24 +439,8 @@ public class WItemSlot extends WWidget {
<