diff options
6 files changed, 165 insertions, 49 deletions
diff --git a/src/main/java/me/xmrvizzy/skyblocker/config/ConfigUtils.java b/src/main/java/me/xmrvizzy/skyblocker/config/ConfigUtils.java index 651f7aa9..28ed704b 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/config/ConfigUtils.java +++ b/src/main/java/me/xmrvizzy/skyblocker/config/ConfigUtils.java @@ -1,44 +1,21 @@ package me.xmrvizzy.skyblocker.config; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - import dev.isxander.yacl3.api.Option; import dev.isxander.yacl3.api.controller.BooleanControllerBuilder; -import dev.isxander.yacl3.api.controller.DropdownStringControllerBuilder; import dev.isxander.yacl3.api.controller.EnumControllerBuilder; +import me.xmrvizzy.skyblocker.config.controllers.EnumDropdownControllerBuilder; public class ConfigUtils { - @SuppressWarnings("unchecked") - public static <E extends Enum<E>> EnumControllerBuilder<E> createEnumCyclingListController(Option<E> opt) { - return EnumControllerBuilder.create(opt).enumClass((Class<E>) opt.binding().defaultValue().getClass()); - } - public static BooleanControllerBuilder createBooleanController(Option<Boolean> opt) { return BooleanControllerBuilder.create(opt).yesNoFormatter().coloured(true); } - /** - * Searches through enum constants in {@code enumClass} for one whose {@link Enum#toString()} result equals {@code expectedValue} - * - * @return The enum constant associated with the {@code expectedValue} - * @throws IllegalStateException Thrown when a constant couldn't be found - * - * @implNote The return value of {@link Enum#toString()} on each enum constant should be unique in order to ensure accuracy - */ - public static <E extends Enum<E>> E enumConstantFromToString(Class<E> enumClass, String expectedValue) { - for (E constant : enumClass.getEnumConstants()) { - if (constant.toString().equals(expectedValue)) - return constant; - } - - throw new IllegalStateException("Didn't find an enum constant matching: " + expectedValue); + @SuppressWarnings("unchecked") + public static <E extends Enum<E>> EnumControllerBuilder<E> createEnumCyclingListController(Option<E> opt) { + return EnumControllerBuilder.create(opt).enumClass((Class<E>) opt.binding().defaultValue().getClass()); } - public static <E extends Enum<E>> DropdownStringControllerBuilder createDropdownControllerFromEnum(Option<String> opt, Class<E> enumClass) { - List<String> stringifiedConstants = Arrays.stream(enumClass.getEnumConstants()).map(Enum::toString).collect(Collectors.toList()); - - return DropdownStringControllerBuilder.create(opt).allowAnyValue(false).allowEmptyValue(false).values(stringifiedConstants); + public static <E extends Enum<E>> EnumDropdownControllerBuilder<E> createEnumDropdownController(Option<E> opt) { + return EnumDropdownControllerBuilder.create(opt); } } diff --git a/src/main/java/me/xmrvizzy/skyblocker/config/categories/DungeonsCategory.java b/src/main/java/me/xmrvizzy/skyblocker/config/categories/DungeonsCategory.java index 1478500b..16439cb5 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/config/categories/DungeonsCategory.java +++ b/src/main/java/me/xmrvizzy/skyblocker/config/categories/DungeonsCategory.java @@ -150,34 +150,34 @@ public class DungeonsCategory { newValue -> config.locations.dungeons.dungeonChestProfit.neutralThreshold = newValue) .controller(IntegerFieldControllerBuilder::create) .build()) - .option(Option.<String>createBuilder() + .option(Option.<FormattingOption>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.neutralColor")) - .binding(defaults.locations.dungeons.dungeonChestProfit.neutralColor.toString(), - () -> config.locations.dungeons.dungeonChestProfit.neutralColor.toString(), - newValue -> config.locations.dungeons.dungeonChestProfit.neutralColor = ConfigUtils.enumConstantFromToString(FormattingOption.class, newValue)) - .controller(opt -> ConfigUtils.createDropdownControllerFromEnum(opt, FormattingOption.class)) + .binding(defaults.locations.dungeons.dungeonChestProfit.neutralColor, + () -> config.locations.dungeons.dungeonChestProfit.neutralColor, + newValue -> config.locations.dungeons.dungeonChestProfit.neutralColor = newValue) + .controller(ConfigUtils::createEnumDropdownController) .build()) - .option(Option.<String>createBuilder() + .option(Option.<FormattingOption>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.profitColor")) - .binding(defaults.locations.dungeons.dungeonChestProfit.profitColor.toString(), - () -> config.locations.dungeons.dungeonChestProfit.profitColor.toString(), - newValue -> config.locations.dungeons.dungeonChestProfit.profitColor = ConfigUtils.enumConstantFromToString(FormattingOption.class, newValue)) - .controller(opt -> ConfigUtils.createDropdownControllerFromEnum(opt, FormattingOption.class)) + .binding(defaults.locations.dungeons.dungeonChestProfit.profitColor, + () -> config.locations.dungeons.dungeonChestProfit.profitColor, + newValue -> config.locations.dungeons.dungeonChestProfit.profitColor = newValue) + .controller(ConfigUtils::createEnumDropdownController) .build()) - .option(Option.<String>createBuilder() + .option(Option.<FormattingOption>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.lossColor")) - .binding(defaults.locations.dungeons.dungeonChestProfit.lossColor.toString(), - () -> config.locations.dungeons.dungeonChestProfit.lossColor.toString(), - newValue -> config.locations.dungeons.dungeonChestProfit.lossColor = ConfigUtils.enumConstantFromToString(FormattingOption.class, newValue)) - .controller(opt -> ConfigUtils.createDropdownControllerFromEnum(opt, FormattingOption.class)) + .binding(defaults.locations.dungeons.dungeonChestProfit.lossColor, + () -> config.locations.dungeons.dungeonChestProfit.lossColor, + newValue -> config.locations.dungeons.dungeonChestProfit.lossColor = newValue) + .controller(ConfigUtils::createEnumDropdownController) .build()) - .option(Option.<String>createBuilder() + .option(Option.<FormattingOption>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.incompleteColor")) .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.incompleteColor.@Tooltip"))) - .binding(defaults.locations.dungeons.dungeonChestProfit.incompleteColor.toString(), - () -> config.locations.dungeons.dungeonChestProfit.incompleteColor.toString(), - newValue -> config.locations.dungeons.dungeonChestProfit.incompleteColor = ConfigUtils.enumConstantFromToString(FormattingOption.class, newValue)) - .controller(opt -> ConfigUtils.createDropdownControllerFromEnum(opt, FormattingOption.class)) + .binding(defaults.locations.dungeons.dungeonChestProfit.incompleteColor, + () -> config.locations.dungeons.dungeonChestProfit.incompleteColor, + newValue -> config.locations.dungeons.dungeonChestProfit.incompleteColor = newValue) + .controller(ConfigUtils::createEnumDropdownController) .build()) .build()) diff --git a/src/main/java/me/xmrvizzy/skyblocker/config/controllers/EnumDropdownController.java b/src/main/java/me/xmrvizzy/skyblocker/config/controllers/EnumDropdownController.java new file mode 100644 index 00000000..cf40c7d5 --- /dev/null +++ b/src/main/java/me/xmrvizzy/skyblocker/config/controllers/EnumDropdownController.java @@ -0,0 +1,86 @@ +package me.xmrvizzy.skyblocker.config.controllers; + +import dev.isxander.yacl3.api.Option; +import dev.isxander.yacl3.api.utils.Dimension; +import dev.isxander.yacl3.gui.AbstractWidget; +import dev.isxander.yacl3.gui.YACLScreen; +import dev.isxander.yacl3.gui.controllers.dropdown.AbstractDropdownController; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.stream.Stream; + +public class EnumDropdownController<E extends Enum<E>> extends AbstractDropdownController<E> { + protected EnumDropdownController(Option<E> option) { + super(option); + } + + @Override + public String getString() { + return option().pendingValue().toString(); + } + + @Override + public void setFromString(String value) { + option().requestSet(getEnumFromString(value)); + } + + /** + * Searches through enum constants for one whose {@link Enum#toString()} 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 Enum#toString()} 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 (constant.toString().toLowerCase().equals(value)) return constant; + } + + return option().pendingValue(); + } + + @Override + public boolean isValueValid(String value) { + value = value.toLowerCase(); + for (E constant : option().pendingValue().getDeclaringClass().getEnumConstants()) { + if (constant.toString().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 Enum#toString()} result equals {@code value} + * + * @return a sorted stream containing enum constants associated with the {@code value} + * @implNote The return value of {@link Enum#toString()} on each enum constant should be unique in order to ensure accuracy + */ + @NotNull + protected Stream<String> getValidEnumConstants(String value) { + String valueLowerCase = value.toLowerCase(); + return Arrays.stream(option().pendingValue().getDeclaringClass().getEnumConstants()) + .map(Enum::toString) + .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/src/main/java/me/xmrvizzy/skyblocker/config/controllers/EnumDropdownControllerBuilder.java b/src/main/java/me/xmrvizzy/skyblocker/config/controllers/EnumDropdownControllerBuilder.java new file mode 100644 index 00000000..baadb8b3 --- /dev/null +++ b/src/main/java/me/xmrvizzy/skyblocker/config/controllers/EnumDropdownControllerBuilder.java @@ -0,0 +1,10 @@ +package me.xmrvizzy.skyblocker.config.controllers; + +import dev.isxander.yacl3.api.Option; +import dev.isxander.yacl3.api.controller.ControllerBuilder; + +public interface EnumDropdownControllerBuilder<E extends Enum<E>> extends ControllerBuilder<E> { + static <E extends Enum<E>> EnumDropdownControllerBuilder<E> create(Option<E> option) { + return new EnumDropdownControllerBuilderImpl<>(option); + } +} diff --git a/src/main/java/me/xmrvizzy/skyblocker/config/controllers/EnumDropdownControllerBuilderImpl.java b/src/main/java/me/xmrvizzy/skyblocker/config/controllers/EnumDropdownControllerBuilderImpl.java new file mode 100644 index 00000000..ea30d1da --- /dev/null +++ b/src/main/java/me/xmrvizzy/skyblocker/config/controllers/EnumDropdownControllerBuilderImpl.java @@ -0,0 +1,17 @@ +package me.xmrvizzy.skyblocker.config.controllers; + +import dev.isxander.yacl3.api.Controller; +import dev.isxander.yacl3.api.Option; +import dev.isxander.yacl3.impl.controller.AbstractControllerBuilderImpl; + +public class EnumDropdownControllerBuilderImpl<E extends Enum<E>> extends AbstractControllerBuilderImpl<E> implements EnumDropdownControllerBuilder<E> { + public EnumDropdownControllerBuilderImpl(Option<E> option) { + super(option); + } + + @SuppressWarnings("UnstableApiUsage") + @Override + public Controller<E> build() { + return new EnumDropdownController<>(option); + } +} diff --git a/src/main/java/me/xmrvizzy/skyblocker/config/controllers/EnumDropdownControllerElement.java b/src/main/java/me/xmrvizzy/skyblocker/config/controllers/EnumDropdownControllerElement.java new file mode 100644 index 00000000..6c5a0097 --- /dev/null +++ b/src/main/java/me/xmrvizzy/skyblocker/config/controllers/EnumDropdownControllerElement.java @@ -0,0 +1,26 @@ +package me.xmrvizzy.skyblocker.config.controllers; + +import dev.isxander.yacl3.api.utils.Dimension; +import dev.isxander.yacl3.gui.YACLScreen; +import dev.isxander.yacl3.gui.controllers.dropdown.AbstractDropdownControllerElement; + +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; + } +} |