From 575faeaf25256e02cbca39501c3ec97655959cea Mon Sep 17 00:00:00 2001 From: isXander Date: Wed, 28 Sep 2022 22:01:25 +0100 Subject: generified cycling controller --- .../yacl/gui/controllers/EnumController.java | 126 +-------------------- .../cycling/CyclingControllerElement.java | 60 ++++++++++ .../controllers/cycling/CyclingListController.java | 48 ++++++++ .../gui/controllers/cycling/EnumController.java | 60 ++++++++++ .../controllers/cycling/ICyclingController.java | 19 ++++ 5 files changed, 192 insertions(+), 121 deletions(-) create mode 100644 src/main/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java create mode 100644 src/main/java/dev/isxander/yacl/gui/controllers/cycling/CyclingListController.java create mode 100644 src/main/java/dev/isxander/yacl/gui/controllers/cycling/EnumController.java create mode 100644 src/main/java/dev/isxander/yacl/gui/controllers/cycling/ICyclingController.java (limited to 'src/main/java/dev/isxander/yacl/gui/controllers') diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java b/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java index 9989981..ebad4ae 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java @@ -1,31 +1,16 @@ package dev.isxander.yacl.gui.controllers; -import dev.isxander.yacl.api.Controller; import dev.isxander.yacl.api.NameableEnum; import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.AbstractWidget; -import dev.isxander.yacl.gui.YACLScreen; -import net.minecraft.client.gui.screen.Screen; +import dev.isxander.yacl.gui.controllers.cycling.CyclingListController; import net.minecraft.text.Text; import net.minecraft.util.TranslatableOption; -import org.jetbrains.annotations.ApiStatus; -import org.lwjgl.glfw.GLFW; +import java.util.Arrays; import java.util.function.Function; -/** - * Simple controller type that displays the enum on the right. - *

- * Cycles forward with left click, cycles backward with right click or when shift is held - * - * @param enum type - */ -public class EnumController> implements Controller { - private final Option option; - private final Function valueFormatter; - private final T[] availableValues; - +@Deprecated +public class EnumController> extends CyclingListController { public static > Function getDefaultFormatter() { return value -> { if (value instanceof NameableEnum nameableEnum) @@ -36,116 +21,15 @@ public class EnumController> implements Controller { }; } - /** - * Constructs a cycling enum controller with a default value formatter and all values being available. - * The default value formatter first searches if the - * enum is a {@link NameableEnum} else, just uses {@link Enum#toString()} - * - * @param option bound option - */ public EnumController(Option option) { this(option, getDefaultFormatter()); } - /** - * Constructs a cycling enum controller with all values being available. - * - * @param option bound option - * @param valueFormatter format the enum into any {@link Text} - */ public EnumController(Option option, Function valueFormatter) { this(option, valueFormatter, option.typeClass().getEnumConstants()); } - /** - * Constructs a cycling enum controller. - * - * @param option bound option - * @param valueFormatter format the enum into any {@link Text} - * @param availableValues all enum constants that can be cycled through - */ public EnumController(Option option, Function valueFormatter, T[] availableValues) { - this.option = option; - this.valueFormatter = valueFormatter; - this.availableValues = availableValues; - } - - /** - * {@inheritDoc} - */ - @Override - public Option option() { - return option; - } - - /** - * {@inheritDoc} - */ - @Override - public Text formatValue() { - return valueFormatter.apply(option().pendingValue()); - } - - /** - * {@inheritDoc} - */ - @Override - public AbstractWidget provideWidget(YACLScreen screen, Dimension widgetDimension) { - return new EnumControllerElement<>(this, screen, widgetDimension, availableValues); - } - - public static class EnumControllerElement> extends ControllerWidget> { - private final T[] values; - - public EnumControllerElement(EnumController control, YACLScreen screen, Dimension dim, T[] values) { - super(control, screen, dim); - this.values = values; - } - - public void cycleValue(int increment) { - int targetIdx = control.option().pendingValue().ordinal() + increment; - if (targetIdx >= values.length) { - targetIdx -= values.length; - } else if (targetIdx < 0) { - targetIdx += values.length; - } - control.option().requestSet(values[targetIdx]); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (!isMouseOver(mouseX, mouseY) || (button != 0 && button != 1) || !isAvailable()) - return false; - - playDownSound(); - cycleValue(button == 1 || Screen.hasShiftDown() || Screen.hasControlDown() ? -1 : 1); - - return true; - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (!focused) - return false; - - switch (keyCode) { - case GLFW.GLFW_KEY_LEFT, GLFW.GLFW_KEY_DOWN -> - cycleValue(-1); - case GLFW.GLFW_KEY_RIGHT, GLFW.GLFW_KEY_UP -> - cycleValue(1); - case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_SPACE, GLFW.GLFW_KEY_KP_ENTER -> - cycleValue(Screen.hasControlDown() || Screen.hasShiftDown() ? -1 : 1); - default -> { - return false; - } - } - - return true; - } - - @Override - protected int getHoveredControlWidth() { - return getUnhoveredControlWidth(); - } + super(option, Arrays.asList(availableValues), valueFormatter); } } diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java b/src/main/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java new file mode 100644 index 0000000..ab0a9c3 --- /dev/null +++ b/src/main/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java @@ -0,0 +1,60 @@ +package dev.isxander.yacl.gui.controllers.cycling; + +import dev.isxander.yacl.api.utils.Dimension; +import dev.isxander.yacl.gui.YACLScreen; +import dev.isxander.yacl.gui.controllers.ControllerWidget; +import net.minecraft.client.gui.screen.Screen; +import org.lwjgl.glfw.GLFW; + +public class CyclingControllerElement extends ControllerWidget> { + + public CyclingControllerElement(ICyclingController control, YACLScreen screen, Dimension dim) { + super(control, screen, dim); + } + + public void cycleValue(int increment) { + int targetIdx = control.getPendingValue() + increment; + if (targetIdx >= control.getCycleLength()) { + targetIdx -= control.getCycleLength(); + } else if (targetIdx < 0) { + targetIdx += control.getCycleLength(); + } + control.setPendingValue(targetIdx); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (!isMouseOver(mouseX, mouseY) || (button != 0 && button != 1) || !isAvailable()) + return false; + + playDownSound(); + cycleValue(button == 1 || Screen.hasShiftDown() || Screen.hasControlDown() ? -1 : 1); + + return true; + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (!focused) + return false; + + switch (keyCode) { + case GLFW.GLFW_KEY_LEFT, GLFW.GLFW_KEY_DOWN -> + cycleValue(-1); + case GLFW.GLFW_KEY_RIGHT, GLFW.GLFW_KEY_UP -> + cycleValue(1); + case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_SPACE, GLFW.GLFW_KEY_KP_ENTER -> + cycleValue(Screen.hasControlDown() || Screen.hasShiftDown() ? -1 : 1); + default -> { + return false; + } + } + + return true; + } + + @Override + protected int getHoveredControlWidth() { + return getUnhoveredControlWidth(); + } +} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/cycling/CyclingListController.java b/src/main/java/dev/isxander/yacl/gui/controllers/cycling/CyclingListController.java new file mode 100644 index 0000000..a894eff --- /dev/null +++ b/src/main/java/dev/isxander/yacl/gui/controllers/cycling/CyclingListController.java @@ -0,0 +1,48 @@ +package dev.isxander.yacl.gui.controllers.cycling; + +import com.google.common.collect.ImmutableList; +import dev.isxander.yacl.api.Option; +import net.minecraft.text.Text; + +import java.util.function.Function; + +public class CyclingListController implements ICyclingController { + private final Option option; + private final Function valueFormatter; + private final ImmutableList values; + + public CyclingListController(Option option, Iterable values) { + this(option, values, value -> Text.of(value.toString())); + } + + public CyclingListController(Option option, Iterable values, Function valueFormatter) { + this.option = option; + this.valueFormatter = valueFormatter; + this.values = ImmutableList.copyOf(values); + } + + @Override + public Option option() { + return option; + } + + @Override + public Text formatValue() { + return valueFormatter.apply(option().pendingValue()); + } + + @Override + public void setPendingValue(int ordinal) { + option().requestSet(values.get(ordinal)); + } + + @Override + public int getPendingValue() { + return values.indexOf(option().pendingValue()); + } + + @Override + public int getCycleLength() { + return values.size(); + } +} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/cycling/EnumController.java b/src/main/java/dev/isxander/yacl/gui/controllers/cycling/EnumController.java new file mode 100644 index 0000000..291863c --- /dev/null +++ b/src/main/java/dev/isxander/yacl/gui/controllers/cycling/EnumController.java @@ -0,0 +1,60 @@ +package dev.isxander.yacl.gui.controllers.cycling; + +import dev.isxander.yacl.api.NameableEnum; +import dev.isxander.yacl.api.Option; +import net.minecraft.text.Text; +import net.minecraft.util.TranslatableOption; + +import java.util.Arrays; +import java.util.function.Function; + +/** + * Simple controller type that displays the enum on the right. + *

+ * Cycles forward with left click, cycles backward with right click or when shift is held + * + * @param enum type + */ +public class EnumController> extends CyclingListController { + public static > Function getDefaultFormatter() { + return value -> { + if (value instanceof NameableEnum nameableEnum) + return nameableEnum.getDisplayName(); + if (value instanceof TranslatableOption translatableOption) + return translatableOption.getText(); + return Text.of(value.toString()); + }; + } + + /** + * Constructs a cycling enum controller with a default value formatter and all values being available. + * The default value formatter first searches if the + * enum is a {@link NameableEnum} else, just uses {@link Enum#toString()} + * + * @param option bound option + */ + public EnumController(Option option) { + this(option, getDefaultFormatter()); + } + + /** + * Constructs a cycling enum controller with all values being available. + * + * @param option bound option + * @param valueFormatter format the enum into any {@link Text} + */ + public EnumController(Option option, Function valueFormatter) { + this(option, valueFormatter, option.typeClass().getEnumConstants()); + } + + /** + * Constructs a cycling enum controller. + * + * @param option bound option + * @param valueFormatter format the enum into any {@link Text} + * @param availableValues all enum constants that can be cycled through + */ + public EnumController(Option option, Function valueFormatter, T[] availableValues) { + super(option, Arrays.asList(availableValues), valueFormatter); + } +} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/cycling/ICyclingController.java b/src/main/java/dev/isxander/yacl/gui/controllers/cycling/ICyclingController.java new file mode 100644 index 0000000..39f0b35 --- /dev/null +++ b/src/main/java/dev/isxander/yacl/gui/controllers/cycling/ICyclingController.java @@ -0,0 +1,19 @@ +package dev.isxander.yacl.gui.controllers.cycling; + +import dev.isxander.yacl.api.Controller; +import dev.isxander.yacl.api.utils.Dimension; +import dev.isxander.yacl.gui.AbstractWidget; +import dev.isxander.yacl.gui.YACLScreen; + +public interface ICyclingController extends Controller { + void setPendingValue(int ordinal); + + int getPendingValue(); + + int getCycleLength(); + + @Override + default AbstractWidget provideWidget(YACLScreen screen, Dimension widgetDimension) { + return new CyclingControllerElement(this, screen, widgetDimension); + } +} -- cgit