diff --git a/src/main/java/me/melontini/flightpanel/api/builders/elements/collections/ListBasedBuilder.java b/src/main/java/me/melontini/flightpanel/api/builders/elements/collections/ListBasedBuilder.java new file mode 100644 index 0000000..90ba3f4 --- /dev/null +++ b/src/main/java/me/melontini/flightpanel/api/builders/elements/collections/ListBasedBuilder.java @@ -0,0 +1,28 @@ +package me.melontini.flightpanel.api.builders.elements.collections; + +import me.melontini.flightpanel.api.builders.elements.ValuedElementBuilder; +import me.melontini.flightpanel.api.elements.AbstractValuedElement; +import me.melontini.flightpanel.api.util.DataType; +import net.minecraft.text.Text; + +import java.util.List; +import java.util.function.Function; + +public abstract class ListBasedBuilder, S extends ListBasedBuilder> extends ValuedElementBuilder { + + public static final DataType> VALUES = DataType.of(); + public static final DataType> TEXTIFIER = DataType.of(); + + public DataType> valuesType() { + return (DataType>) (Object) VALUES; + } + public DataType> textifierType() { + return (DataType>) (Object) TEXTIFIER; + } + + protected ListBasedBuilder(Text elementName, T value, List values, Function textifier) { + super(elementName, value); + this.data(valuesType(), values); + this.data(textifierType(), textifier); + } +} diff --git a/src/main/java/me/melontini/flightpanel/api/builders/elements/collections/ListButtonBuilder.java b/src/main/java/me/melontini/flightpanel/api/builders/elements/collections/ListButtonBuilder.java new file mode 100644 index 0000000..4706b4b --- /dev/null +++ b/src/main/java/me/melontini/flightpanel/api/builders/elements/collections/ListButtonBuilder.java @@ -0,0 +1,23 @@ +package me.melontini.flightpanel.api.builders.elements.collections; + +import me.melontini.flightpanel.impl.elements.collections.ListButtonElement; +import net.minecraft.text.Text; + +import java.util.List; +import java.util.function.Function; + +public class ListButtonBuilder extends ListBasedBuilder, ListButtonBuilder> { + + public static ListButtonBuilder create(Text elementName, T value, List values, Function textifier) { + return new ListButtonBuilder<>(elementName, value, values, textifier); + } + + protected ListButtonBuilder(Text elementName, T value, List values, Function textifier) { + super(elementName, value, values, textifier); + } + + @Override + public ListButtonElement build() { + return new ListButtonElement<>(this); + } +} diff --git a/src/main/java/me/melontini/flightpanel/api/builders/elements/collections/ListSliderBuilder.java b/src/main/java/me/melontini/flightpanel/api/builders/elements/collections/ListSliderBuilder.java new file mode 100644 index 0000000..12292f0 --- /dev/null +++ b/src/main/java/me/melontini/flightpanel/api/builders/elements/collections/ListSliderBuilder.java @@ -0,0 +1,23 @@ +package me.melontini.flightpanel.api.builders.elements.collections; + +import me.melontini.flightpanel.impl.elements.collections.ListSliderElement; +import net.minecraft.text.Text; + +import java.util.List; +import java.util.function.Function; + +public class ListSliderBuilder extends ListBasedBuilder, ListSliderBuilder> { + + public static ListSliderBuilder create(Text elementName, T value, List values, Function textifier) { + return new ListSliderBuilder<>(elementName, value, values, textifier); + } + + protected ListSliderBuilder(Text elementName, T value, List values, Function textifier) { + super(elementName, value, values, textifier); + } + + @Override + public ListSliderElement build() { + return new ListSliderElement<>(this); + } +} diff --git a/src/main/java/me/melontini/flightpanel/api/builders/elements/NestedListBuilder.java b/src/main/java/me/melontini/flightpanel/api/builders/elements/collections/NestedListBuilder.java similarity index 88% rename from src/main/java/me/melontini/flightpanel/api/builders/elements/NestedListBuilder.java rename to src/main/java/me/melontini/flightpanel/api/builders/elements/collections/NestedListBuilder.java index e3f16f7..bd9eeeb 100644 --- a/src/main/java/me/melontini/flightpanel/api/builders/elements/NestedListBuilder.java +++ b/src/main/java/me/melontini/flightpanel/api/builders/elements/collections/NestedListBuilder.java @@ -1,8 +1,10 @@ -package me.melontini.flightpanel.api.builders.elements; +package me.melontini.flightpanel.api.builders.elements.collections; +import me.melontini.flightpanel.api.builders.elements.CollapsibleObjectBuilder; +import me.melontini.flightpanel.api.builders.elements.ValuedElementBuilder; import me.melontini.flightpanel.api.elements.AbstractValuedElement; import me.melontini.flightpanel.api.util.DataType; -import me.melontini.flightpanel.impl.elements.NestedListElement; +import me.melontini.flightpanel.impl.elements.collections.NestedListElement; import net.minecraft.text.Text; import java.util.List; diff --git a/src/main/java/me/melontini/flightpanel/api/generators/GuiRegistry.java b/src/main/java/me/melontini/flightpanel/api/generators/GuiRegistry.java index 7fb6d2d..c786187 100644 --- a/src/main/java/me/melontini/flightpanel/api/generators/GuiRegistry.java +++ b/src/main/java/me/melontini/flightpanel/api/generators/GuiRegistry.java @@ -6,10 +6,7 @@ import me.melontini.flightpanel.api.elements.AbstractConfigElement; import me.melontini.flightpanel.api.generators.context.FactoryContext; import me.melontini.flightpanel.api.generators.context.ProviderContext; import me.melontini.flightpanel.api.util.Result; -import me.melontini.flightpanel.impl.generators.CollapsibleObjectProviderFactory; -import me.melontini.flightpanel.impl.generators.ListProviderFactory; -import me.melontini.flightpanel.impl.generators.PrimitiveProviderFactory; -import me.melontini.flightpanel.impl.generators.StringProviderFactory; +import me.melontini.flightpanel.impl.generators.*; import org.jetbrains.annotations.NotNull; import java.lang.reflect.Field; @@ -33,6 +30,7 @@ public class GuiRegistry implements GuiProviderFactory, GuiFieldTransformer { registry.registerProviderFactory(new PrimitiveProviderFactory()); registry.registerProviderFactory(new StringProviderFactory()); registry.registerProviderFactory(new ListProviderFactory()); + registry.registerProviderFactory(new EnumProviderFactory()); registry.registerProviderFactory(new CollapsibleObjectProviderFactory()); } diff --git a/src/main/java/me/melontini/flightpanel/impl/TestInit.java b/src/main/java/me/melontini/flightpanel/impl/TestInit.java index 7b5a892..a88db8e 100644 --- a/src/main/java/me/melontini/flightpanel/impl/TestInit.java +++ b/src/main/java/me/melontini/flightpanel/impl/TestInit.java @@ -29,7 +29,7 @@ public class TestInit implements ClientModInitializer { .title(Text.literal("NEVER GONNA GIVE YOU UP")) .saveFunction(() -> System.out.println(CONFIG)); - List>> partition = Lists.partition(ElementGenerator.generateForObject("test.flight-panel.config.", CONFIG, RealConfig::new, Optional.empty()), 3); + List>> partition = Lists.partition(ElementGenerator.generateForObject("test.flight-panel.config.", CONFIG, RealConfig::new, Optional.empty()), 5); for (int i = 0; i < partition.size(); i++) { List> builders = partition.get(i); sb.category(Text.literal("default " + i)).addAll(builders); @@ -51,10 +51,17 @@ public class TestInit implements ClientModInitializer { public List integers = List.of(12, 34, 56, 78); public boolean aBoolean = true; public String aString = "Hello World!"; + public @Slider @Range(to = 1) int tinySlider = 0; + public @Slider SliderEnum sliderEnum = SliderEnum.TWO; + public SliderEnum buttonEnum = SliderEnum.TWO; public List<@Collapsible InnerObj> innerObjs = Lists.newArrayList(); } + public enum SliderEnum { + ONE, TWO, THREE + } + @EqualsAndHashCode @ToString public static class InnerObj { diff --git a/src/main/java/me/melontini/flightpanel/impl/elements/collections/ListButtonElement.java b/src/main/java/me/melontini/flightpanel/impl/elements/collections/ListButtonElement.java new file mode 100644 index 0000000..c3c096a --- /dev/null +++ b/src/main/java/me/melontini/flightpanel/impl/elements/collections/ListButtonElement.java @@ -0,0 +1,59 @@ +package me.melontini.flightpanel.impl.elements.collections; + +import me.melontini.flightpanel.api.builders.elements.collections.ListButtonBuilder; +import me.melontini.flightpanel.api.elements.AbstractValuedElement; +import me.melontini.flightpanel.api.util.SquareData; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.text.Text; + +import java.util.List; +import java.util.function.Function; + +public class ListButtonElement extends AbstractValuedElement> { + + private final List values; + private final Function textifier; + private final ButtonWidget widget; + + public ListButtonElement(ListButtonBuilder builder) { + super(builder); + this.values = builder.dataOrThrow(builder.valuesType()); + this.textifier = builder.dataOrThrow(builder.textifierType()); + + this.widget = ButtonWidget.builder(this.textifier.apply(this.value()), button -> { + int index = this.values.indexOf(value()); + index = index >= this.values.size() - 1 ? 0 : index + 1; + this.value(this.values.get(index)); + }).size(86,20).build(); + + this.listenToChange((oldValue, newValue) -> this.widget.setMessage(this.textifier.apply(newValue))); + } + + @Override + public void rebuildPositions(SquareData self, SquareData parent) { + super.rebuildPositions(self, parent); + + this.widget.setX(self.endX() - (resetButton.visible ? 108 : 87)); + this.widget.setY(self.y() + 1); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + + context.drawTextWithShadow(client.textRenderer, displayName(mouseX, mouseY), pos.x(), pos.y() + 7, -1); + this.widget.render(context, mouseX, mouseY, delta); + } + + @Override + protected void resetToDefault(T def) { + this.value(def); + } + + @Override + public List children() { + return List.of(widget, resetButton); + } +} diff --git a/src/main/java/me/melontini/flightpanel/impl/elements/collections/ListSliderElement.java b/src/main/java/me/melontini/flightpanel/impl/elements/collections/ListSliderElement.java new file mode 100644 index 0000000..56164d9 --- /dev/null +++ b/src/main/java/me/melontini/flightpanel/impl/elements/collections/ListSliderElement.java @@ -0,0 +1,36 @@ +package me.melontini.flightpanel.impl.elements.collections; + +import me.melontini.flightpanel.api.builders.elements.collections.ListSliderBuilder; +import me.melontini.flightpanel.api.elements.AbstractSliderElement; +import net.minecraft.text.Text; + +import java.util.List; +import java.util.function.Function; + +public class ListSliderElement extends AbstractSliderElement> { + + private final List values; + private final Function textifier; + + public ListSliderElement(ListSliderBuilder builder) { + super(builder); + this.values = builder.dataOrThrow(builder.valuesType()); + this.textifier = builder.dataOrThrow(builder.textifierType()); + this.applyDefaults(); + } + + @Override + protected Text getMessage(T value) { + return this.textifier.apply(value); + } + + @Override + protected T convertFromRange(double value) { + return values.get((int) Math.round((values.size() - 1) * value)); + } + + @Override + protected double convertToRange(T value) { + return (double) values.indexOf(value) / (values.size() - 1); + } +} diff --git a/src/main/java/me/melontini/flightpanel/impl/elements/NestedListElement.java b/src/main/java/me/melontini/flightpanel/impl/elements/collections/NestedListElement.java similarity index 98% rename from src/main/java/me/melontini/flightpanel/impl/elements/NestedListElement.java rename to src/main/java/me/melontini/flightpanel/impl/elements/collections/NestedListElement.java index 70a5d4c..bb83290 100644 --- a/src/main/java/me/melontini/flightpanel/impl/elements/NestedListElement.java +++ b/src/main/java/me/melontini/flightpanel/impl/elements/collections/NestedListElement.java @@ -1,7 +1,7 @@ -package me.melontini.flightpanel.impl.elements; +package me.melontini.flightpanel.impl.elements.collections; import me.melontini.flightpanel.api.builders.elements.CollapsibleObjectBuilder; -import me.melontini.flightpanel.api.builders.elements.NestedListBuilder; +import me.melontini.flightpanel.api.builders.elements.collections.NestedListBuilder; import me.melontini.flightpanel.api.elements.AbstractConfigElement; import me.melontini.flightpanel.api.elements.AbstractValuedElement; import me.melontini.flightpanel.api.util.SquareData; @@ -42,7 +42,7 @@ public class NestedListElement extends AbstractValuedElement, NestedL this.defaultElementValue = builder.dataOrThrow(builder.defaultElementType()); this.collapsed = builder.dataOrElse(CollapsibleObjectBuilder.COLLAPSED, true); - this.newElementButton = ButtonWidget.builder(Text.literal("+").formatted(Formatting.YELLOW), button -> { + this.newElementButton = ButtonWidget.builder(Text.literal("+"), button -> { var list = new ArrayList<>(NestedListElement.this.value()); var cell = new NestedCell(this.cellFactory.apply(this.defaultElementValue.get(), this), list.size()); this.children.add(cell); diff --git a/src/main/java/me/melontini/flightpanel/impl/generators/EnumProviderFactory.java b/src/main/java/me/melontini/flightpanel/impl/generators/EnumProviderFactory.java new file mode 100644 index 0000000..0b20b5a --- /dev/null +++ b/src/main/java/me/melontini/flightpanel/impl/generators/EnumProviderFactory.java @@ -0,0 +1,63 @@ +package me.melontini.flightpanel.impl.generators; + +import me.melontini.flightpanel.api.builders.elements.BaseElementBuilder; +import me.melontini.flightpanel.api.builders.elements.collections.ListButtonBuilder; +import me.melontini.flightpanel.api.builders.elements.collections.ListSliderBuilder; +import me.melontini.flightpanel.api.elements.AbstractConfigElement; +import me.melontini.flightpanel.api.generators.GuiProvider; +import me.melontini.flightpanel.api.generators.GuiProviderFactory; +import me.melontini.flightpanel.api.generators.GuiRegistry; +import me.melontini.flightpanel.api.generators.Transformations; +import me.melontini.flightpanel.api.generators.context.FactoryContext; +import me.melontini.flightpanel.api.generators.context.ProviderContext; +import me.melontini.flightpanel.api.util.Result; +import me.melontini.flightpanel.impl.elements.collections.ListButtonElement; +import me.melontini.flightpanel.impl.elements.collections.ListSliderElement; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +public class EnumProviderFactory implements GuiProviderFactory { + + @Override + public @NotNull , S extends BaseElementBuilder> Result, ? extends RuntimeException> createGuiProvider(GuiRegistry registry, FactoryContext context) { + if (!context.types().raw().isEnum()) return Result.success(null); + List> values = Arrays.asList(((Class>)context.types().raw()).getEnumConstants()); + + Transformations.Slider slider = context.accessor().fromType(Transformations.Slider.class); + if (slider != null) { + return Result.success((GuiProvider) new EnumSliderProvider<>(slider, values)); + } + return Result.success((GuiProvider) new EnumButtonProvider<>(values)); + } + + public static > Function nameProvider(String i18n, Class type) { + return t -> { + String remainingKey = i18n.contains(".option") ? i18n.substring(0, i18n.indexOf(".option") + ".option".length()) : i18n; + String classKey = String.format("%s.%s.%s", remainingKey, type.getSimpleName(), t.name()); + return I18n.hasTranslation(classKey) ? Text.translatable(classKey) : Text.literal(t.name()); + }; + } + + public record EnumButtonProvider>(List> values) implements GuiProvider, ListButtonBuilder> { + @Override + public @NotNull ListButtonBuilder provideGui(@Nullable T obj, @Nullable Supplier<@NotNull T> def, ProviderContext context) { + return ListButtonBuilder.create(context.i18nOrEmpty(), value(obj, def).orElse((T) values.get(0)), (List) values, nameProvider(context.i18n(), values.get(0).getDeclaringClass())) + .defaultValue(def); + } + } + + public record EnumSliderProvider>(Transformations.Slider slider, List> values) implements GuiProvider, ListSliderBuilder> { + @Override + public @NotNull ListSliderBuilder provideGui(@Nullable T obj, @Nullable Supplier<@NotNull T> def, ProviderContext context) { + return ListSliderBuilder.create(context.i18nOrEmpty(), value(obj, def).orElse((T) values.get(0)), (List) values, nameProvider(context.i18n(), values.get(0).getDeclaringClass())) + .defaultValue(def); + } + } +} diff --git a/src/main/java/me/melontini/flightpanel/impl/generators/ListProviderFactory.java b/src/main/java/me/melontini/flightpanel/impl/generators/ListProviderFactory.java index b3cf50d..39dd720 100644 --- a/src/main/java/me/melontini/flightpanel/impl/generators/ListProviderFactory.java +++ b/src/main/java/me/melontini/flightpanel/impl/generators/ListProviderFactory.java @@ -1,7 +1,7 @@ package me.melontini.flightpanel.impl.generators; import me.melontini.flightpanel.api.builders.elements.BaseElementBuilder; -import me.melontini.flightpanel.api.builders.elements.NestedListBuilder; +import me.melontini.flightpanel.api.builders.elements.collections.NestedListBuilder; import me.melontini.flightpanel.api.elements.AbstractConfigElement; import me.melontini.flightpanel.api.elements.AbstractValuedElement; import me.melontini.flightpanel.api.generators.GuiProvider; @@ -11,7 +11,7 @@ import me.melontini.flightpanel.api.generators.context.FactoryContext; import me.melontini.flightpanel.api.generators.context.ProviderContext; import me.melontini.flightpanel.api.generators.context.TypeContext; import me.melontini.flightpanel.api.util.Result; -import me.melontini.flightpanel.impl.elements.NestedListElement; +import me.melontini.flightpanel.impl.elements.collections.NestedListElement; import org.jetbrains.annotations.NotNull; import java.lang.reflect.AnnotatedParameterizedType; diff --git a/src/main/resources/assets/flight-panel/lang/en_us.json b/src/main/resources/assets/flight-panel/lang/en_us.json index 6c5bb0b..39b1a2a 100644 --- a/src/main/resources/assets/flight-panel/lang/en_us.json +++ b/src/main/resources/assets/flight-panel/lang/en_us.json @@ -29,9 +29,17 @@ "test.flight-panel.config.option.aBoolean": "Boolean Toggle", "test.flight-panel.config.option.aString": "A String Text Box With a Longer Name", "test.flight-panel.config.option.aString.@Tooltip": "Wow, the name really is long!", + "test.flight-panel.config.option.tinySlider": "Tiny Slider", + "test.flight-panel.config.option.sliderEnum": "Enum Slider", + "test.flight-panel.config.option.sliderEnum.@Tooltip": "A simple enum slider", + "test.flight-panel.config.option.buttonEnum": "Enum Button", "test.flight-panel.config.option.innerObjs": "A list of collapsible objects.", "test.flight-panel.config.option.InnerObj": "Inner Object", "test.flight-panel.config.option.InnerObj.value": "An inner value.", "test.flight-panel.config.option.InnerObj.value.option.value": "Nested Nested Object", - "test.flight-panel.config.option.InnerObj.value.option.value.option.value": "Nested Int Value" + "test.flight-panel.config.option.InnerObj.value.option.value.option.value": "Nested Int Value", + + "test.flight-panel.config.option.SliderEnum.ONE": "One", + "test.flight-panel.config.option.SliderEnum.TWO": "Two", + "test.flight-panel.config.option.SliderEnum.THREE": "Three" } \ No newline at end of file