aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin <92656833+kevinthegreat1@users.noreply.github.com>2023-11-18 04:07:39 -0500
committerGitHub <noreply@github.com>2023-11-18 09:07:39 +0000
commit442f48a6e28196910e92f460d3d677e3e47cbfc0 (patch)
tree3e34b77b7bf9707f8553a07abe629aab837a6130
parent953645023c829735663493511390948bf69714f8 (diff)
downloadYetAnotherConfigLib-442f48a6e28196910e92f460d3d677e3e47cbfc0.tar.gz
YetAnotherConfigLib-442f48a6e28196910e92f460d3d677e3e47cbfc0.tar.bz2
YetAnotherConfigLib-442f48a6e28196910e92f460d3d677e3e47cbfc0.zip
Add Enum Dropdown Controller (#117)
-rw-r--r--common/src/main/java/dev/isxander/yacl3/api/NameableEnum.java2
-rw-r--r--common/src/main/java/dev/isxander/yacl3/api/controller/EnumDropdownControllerBuilder.java10
-rw-r--r--common/src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/AbstractDropdownController.java6
-rw-r--r--common/src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/EnumDropdownController.java92
-rw-r--r--common/src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/EnumDropdownControllerElement.java25
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/EnumDropdownControllerBuilderImpl.java27
-rw-r--r--test-common/src/main/java/dev/isxander/yacl3/test/ConfigTest.java3
-rw-r--r--test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java11
8 files changed, 174 insertions, 2 deletions
diff --git a/common/src/main/java/dev/isxander/yacl3/api/NameableEnum.java b/common/src/main/java/dev/isxander/yacl3/api/NameableEnum.java
index 5a50207..425623f 100644
--- a/common/src/main/java/dev/isxander/yacl3/api/NameableEnum.java
+++ b/common/src/main/java/dev/isxander/yacl3/api/NameableEnum.java
@@ -3,7 +3,7 @@ package dev.isxander.yacl3.api;
import net.minecraft.network.chat.Component;
/**
- * Used for the default value formatter of {@link dev.isxander.yacl3.gui.controllers.cycling.EnumController}
+ * Used for the default value formatter of {@link dev.isxander.yacl3.gui.controllers.cycling.EnumController} and {@link dev.isxander.yacl3.gui.controllers.dropdown.EnumDropdownController}
*/
public interface NameableEnum {
Component getDisplayName();
diff --git a/common/src/main/java/dev/isxander/yacl3/api/controller/EnumDropdownControllerBuilder.java b/common/src/main/java/dev/isxander/yacl3/api/controller/EnumDropdownControllerBuilder.java
new file mode 100644
index 0000000..0814cc6
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/api/controller/EnumDropdownControllerBuilder.java
@@ -0,0 +1,10 @@
+package dev.isxander.yacl3.api.controller;
+
+import dev.isxander.yacl3.api.Option;
+import dev.isxander.yacl3.impl.controller.EnumDropdownControllerBuilderImpl;
+
+public interface EnumDropdownControllerBuilder<E extends Enum<E>> extends ValueFormattableController<E, EnumDropdownControllerBuilder<E>> {
+ static <E extends Enum<E>> EnumDropdownControllerBuilder<E> create(Option<E> option) {
+ return new EnumDropdownControllerBuilderImpl<>(option);
+ }
+}
diff --git a/common/src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/AbstractDropdownController.java b/common/src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/AbstractDropdownController.java
index b4e4304..b913d15 100644
--- a/common/src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/AbstractDropdownController.java
+++ b/common/src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/AbstractDropdownController.java
@@ -26,8 +26,12 @@ public abstract class AbstractDropdownController<T> implements IStringController
this.allowAnyValue = allowAnyValue;
}
+ protected AbstractDropdownController(Option<T> option, List<String> allowedValues) {
+ this(option, allowedValues, false, false);
+ }
+
protected AbstractDropdownController(Option<T> option) {
- this(option, Collections.emptyList(), false, false);
+ this(option, Collections.emptyList());
}
/**
diff --git a/common/src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/EnumDropdownController.java b/common/src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/EnumDropdownController.java
new file mode 100644
index 0000000..8e6e0e6
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/EnumDropdownController.java
@@ -0,0 +1,92 @@
+package dev.isxander.yacl3.gui.controllers.dropdown;
+
+import dev.isxander.yacl3.api.Option;
+import dev.isxander.yacl3.api.controller.ValueFormatter;
+import dev.isxander.yacl3.api.utils.Dimension;
+import dev.isxander.yacl3.gui.AbstractWidget;
+import dev.isxander.yacl3.gui.YACLScreen;
+import net.minecraft.network.chat.Component;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+public class EnumDropdownController<E extends Enum<E>> extends AbstractDropdownController<E> {
+ /**
+ * The function used to convert enum constants to strings used for display, suggestion, and validation. Defaults to {@link Enum#toString}.
+ */
+ protected final ValueFormatter<E> formatter;
+
+ public EnumDropdownController(Option<E> option, ValueFormatter<E> formatter) {
+ super(option, Arrays.stream(option.pendingValue().getDeclaringClass().getEnumConstants()).map(formatter::format).map(Component::getString).toList());
+ this.formatter = formatter;
+ }
+
+ @Override
+ public String getString() {
+ return formatter.format(option().pendingValue()).getString();
+ }
+
+ @Override
+ public void setFromString(String value) {
+ option().requestSet(getEnumFromString(value));
+ }
+
+ /**
+ * Searches through enum constants for one whose {@link #formatter} result equals {@code value}
+ *
+ * @return The enum constant associated with the {@code value} or the pending value if none are found
+ * @implNote The return value of {@link #formatter} on each enum constant should be unique in order to ensure accuracy
+ */
+ private E getEnumFromString(String value) {
+ value = value.toLowerCase();
+ for (E constant : option().pendingValue().getDeclaringClass().getEnumConstants()) {
+ if (formatter.format(constant).getString().toLowerCase().equals(value)) return constant;
+ }
+
+ return option().pendingValue();
+ }
+
+ @Override
+ public boolean isValueValid(String value) {
+ value = value.toLowerCase();
+ for (String constant : getAllowedValues()) {
+ if (constant.equals(value)) return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ protected String getValidValue(String value, int offset) {
+ return getValidEnumConstants(value)
+ .skip(offset)
+ .findFirst()
+ .orElseGet(this::getString);
+ }
+
+ /**
+ * Filters and sorts through enum constants for those whose {@link #formatter} result equals {@code value}
+ *
+ * @return a sorted stream containing enum constants associated with the {@code value}
+ * @implNote The return value of {@link #formatter} on each enum constant should be unique in order to ensure accuracy
+ */
+ @NotNull
+ protected Stream<String> getValidEnumConstants(String value) {
+ String valueLowerCase = value.toLowerCase();
+ return getAllowedValues().stream()
+ .filter(constant -> constant.toLowerCase().contains(valueLowerCase))
+ .sorted((s1, s2) -> {
+ String s1LowerCase = s1.toLowerCase();
+ String s2LowerCase = s2.toLowerCase();
+ if (s1LowerCase.startsWith(valueLowerCase) && !s2LowerCase.startsWith(valueLowerCase)) return -1;
+ if (!s1LowerCase.startsWith(valueLowerCase) && s2LowerCase.startsWith(valueLowerCase)) return 1;
+ return s1.compareTo(s2);
+ });
+ }
+
+ @Override
+ public AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) {
+ return new EnumDropdownControllerElement<>(this, screen, widgetDimension);
+ }
+}
diff --git a/common/src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/EnumDropdownControllerElement.java b/common/src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/EnumDropdownControllerElement.java
new file mode 100644
index 0000000..2df6f6b
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/EnumDropdownControllerElement.java
@@ -0,0 +1,25 @@
+package dev.isxander.yacl3.gui.controllers.dropdown;
+
+import dev.isxander.yacl3.api.utils.Dimension;
+import dev.isxander.yacl3.gui.YACLScreen;
+
+import java.util.List;
+
+public class EnumDropdownControllerElement<E extends Enum<E>> extends AbstractDropdownControllerElement<E, String> {
+ private final EnumDropdownController<E> controller;
+
+ public EnumDropdownControllerElement(EnumDropdownController<E> control, YACLScreen screen, Dimension<Integer> dim) {
+ super(control, screen, dim);
+ this.controller = control;
+ }
+
+ @Override
+ public List<String> computeMatchingValues() {
+ return controller.getValidEnumConstants(inputField).toList();
+ }
+
+ @Override
+ public String getString(String object) {
+ return object;
+ }
+}
diff --git a/common/src/main/java/dev/isxander/yacl3/impl/controller/EnumDropdownControllerBuilderImpl.java b/common/src/main/java/dev/isxander/yacl3/impl/controller/EnumDropdownControllerBuilderImpl.java
new file mode 100644
index 0000000..4ac063f
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/impl/controller/EnumDropdownControllerBuilderImpl.java
@@ -0,0 +1,27 @@
+package dev.isxander.yacl3.impl.controller;
+
+import dev.isxander.yacl3.api.Controller;
+import dev.isxander.yacl3.api.Option;
+import dev.isxander.yacl3.api.controller.EnumDropdownControllerBuilder;
+import dev.isxander.yacl3.api.controller.ValueFormatter;
+import dev.isxander.yacl3.gui.controllers.cycling.EnumController;
+import dev.isxander.yacl3.gui.controllers.dropdown.EnumDropdownController;
+
+public class EnumDropdownControllerBuilderImpl<E extends Enum<E>> extends AbstractControllerBuilderImpl<E> implements EnumDropdownControllerBuilder<E> {
+ private ValueFormatter<E> formatter = EnumController.<E>getDefaultFormatter()::apply;
+
+ public EnumDropdownControllerBuilderImpl(Option<E> option) {
+ super(option);
+ }
+
+ @Override
+ public EnumDropdownControllerBuilder<E> formatValue(ValueFormatter<E> formatter) {
+ this.formatter = formatter;
+ return this;
+ }
+
+ @Override
+ public Controller<E> build() {
+ return new EnumDropdownController<>(option, formatter);
+ }
+}
diff --git a/test-common/src/main/java/dev/isxander/yacl3/test/ConfigTest.java b/test-common/src/main/java/dev/isxander/yacl3/test/ConfigTest.java
index a61a112..a8f49b0 100644
--- a/test-common/src/main/java/dev/isxander/yacl3/test/ConfigTest.java
+++ b/test-common/src/main/java/dev/isxander/yacl3/test/ConfigTest.java
@@ -4,6 +4,7 @@ import dev.isxander.yacl3.config.v2.api.ConfigClassHandler;
import dev.isxander.yacl3.config.v2.api.SerialEntry;
import dev.isxander.yacl3.config.v2.api.serializer.GsonConfigSerializerBuilder;
import dev.isxander.yacl3.platform.YACLPlatform;
+import net.minecraft.ChatFormatting;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
@@ -51,6 +52,8 @@ public class ConfigTest {
public String stringSuggestions = "";
@SerialEntry
public Item item = Items.OAK_LOG;
+ @SerialEntry
+ public ChatFormatting formattingOption = ChatFormatting.RED;
@SerialEntry
public List<String> stringList = List.of("This is quite cool.", "You can add multiple items!", "And it is integrated so well into Option groups!");
diff --git a/test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java b/test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java
index a20312e..ec16e2e 100644
--- a/test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java
+++ b/test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java
@@ -14,6 +14,7 @@ import dev.isxander.yacl3.gui.controllers.string.number.DoubleFieldController;
import dev.isxander.yacl3.gui.controllers.string.number.FloatFieldController;
import dev.isxander.yacl3.gui.controllers.string.number.IntegerFieldController;
import dev.isxander.yacl3.gui.controllers.string.number.LongFieldController;
+import net.minecraft.ChatFormatting;
import net.minecraft.Util;
import net.minecraft.client.GraphicsStatus;
import net.minecraft.client.Minecraft;
@@ -24,6 +25,7 @@ import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.HoverEvent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
+import org.apache.commons.lang3.StringUtils;
import java.awt.Color;
import java.nio.file.Path;
@@ -268,6 +270,15 @@ public class GuiTest {
)
.controller(ItemControllerBuilder::create)
.build())
+ .option(Option.<ChatFormatting>createBuilder()
+ .name(Component.literal("Enum Dropdown"))
+ .binding(
+ defaults.formattingOption,
+ () -> config.formattingOption,
+ (value) -> config.formattingOption = value
+ )
+ .controller(option -> EnumDropdownControllerBuilder.create(option).formatValue(formatting -> Component.literal(StringUtils.capitalize(formatting.getName()).replaceAll("_", " "))))
+ .build())
.build())
.group(OptionGroup.createBuilder()
.name(Component.literal("Options that aren't really options"))