diff options
| author | isxander <xander@isxander.dev> | 2024-04-11 18:43:06 +0100 |
|---|---|---|
| committer | isxander <xander@isxander.dev> | 2024-04-11 18:43:06 +0100 |
| commit | 04fe933f4c24817100f3101f088accf55a621f8a (patch) | |
| tree | feff94ca3ab4484160e69a24f4ee38522381950e /src/main/java/dev/isxander/yacl3/gui/controllers/cycling | |
| parent | 831b894fdb7fe3e173d81387c8f6a2402b8ccfa9 (diff) | |
| download | YetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.tar.gz YetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.tar.bz2 YetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.zip | |
Extremely fragile and broken multiversion build with stonecutter
Diffstat (limited to 'src/main/java/dev/isxander/yacl3/gui/controllers/cycling')
4 files changed, 232 insertions, 0 deletions
diff --git a/src/main/java/dev/isxander/yacl3/gui/controllers/cycling/CyclingControllerElement.java b/src/main/java/dev/isxander/yacl3/gui/controllers/cycling/CyclingControllerElement.java new file mode 100644 index 0000000..3d85afe --- /dev/null +++ b/src/main/java/dev/isxander/yacl3/gui/controllers/cycling/CyclingControllerElement.java @@ -0,0 +1,60 @@ +package dev.isxander.yacl3.gui.controllers.cycling; + +import com.mojang.blaze3d.platform.InputConstants; +import dev.isxander.yacl3.api.utils.Dimension; +import dev.isxander.yacl3.gui.YACLScreen; +import dev.isxander.yacl3.gui.controllers.ControllerWidget; +import net.minecraft.client.gui.screens.Screen; + +public class CyclingControllerElement extends ControllerWidget<ICyclingController<?>> { + + public CyclingControllerElement(ICyclingController<?> control, YACLScreen screen, Dimension<Integer> 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 InputConstants.KEY_LEFT -> + cycleValue(-1); + case InputConstants.KEY_RIGHT -> + cycleValue(1); + case InputConstants.KEY_RETURN, InputConstants.KEY_SPACE, InputConstants.KEY_NUMPADENTER -> + 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/yacl3/gui/controllers/cycling/CyclingListController.java b/src/main/java/dev/isxander/yacl3/gui/controllers/cycling/CyclingListController.java new file mode 100644 index 0000000..3fce3cf --- /dev/null +++ b/src/main/java/dev/isxander/yacl3/gui/controllers/cycling/CyclingListController.java @@ -0,0 +1,86 @@ +package dev.isxander.yacl3.gui.controllers.cycling; + +import com.google.common.collect.ImmutableList; +import dev.isxander.yacl3.api.Option; +import dev.isxander.yacl3.api.controller.ValueFormatter; +import net.minecraft.network.chat.Component; +import org.jetbrains.annotations.ApiStatus; + +import java.util.function.Function; + +/** + * A controller where once clicked, cycles through elements + * in the provided list. + */ +public class CyclingListController<T> implements ICyclingController<T> { + private final Option<T> option; + private final ValueFormatter<T> valueFormatter; + private final ImmutableList<T> values; + + /** + * Constructs a {@link CyclingListController}, with a default + * value formatter of {@link Object#toString()}. + * @param option option of which to bind the controller to + * @param values the values to cycle through + */ + public CyclingListController(Option<T> option, Iterable<? extends T> values) { + this(option, values, value -> Component.literal(value.toString())); + } + + /** + * Constructs a {@link CyclingListController} + * @param option option of which to bind the controller to + * @param values the values to cycle through + * @param valueFormatter function of how to convert each value to a string to display + */ + public CyclingListController(Option<T> option, Iterable<? extends T> values, Function<T, Component> valueFormatter) { + this.option = option; + this.valueFormatter = valueFormatter::apply; + this.values = ImmutableList.copyOf(values); + } + + @ApiStatus.Internal + public static <T> CyclingListController<T> createInternal(Option<T> option, Iterable<? extends T> values, ValueFormatter<T> formatter) { + return new CyclingListController<>(option, values, formatter::format); + } + + /** + * {@inheritDoc} + */ + @Override + public Option<T> option() { + return option; + } + + /** + * {@inheritDoc} + */ + @Override + public Component formatValue() { + return valueFormatter.format(option().pendingValue()); + } + + /** + * {@inheritDoc} + */ + @Override + public void setPendingValue(int ordinal) { + option().requestSet(values.get(ordinal)); + } + + /** + * {@inheritDoc} + */ + @Override + public int getPendingValue() { + return values.indexOf(option().pendingValue()); + } + + /** + * {@inheritDoc} + */ + @Override + public int getCycleLength() { + return values.size(); + } +} diff --git a/src/main/java/dev/isxander/yacl3/gui/controllers/cycling/EnumController.java b/src/main/java/dev/isxander/yacl3/gui/controllers/cycling/EnumController.java new file mode 100644 index 0000000..5a6a912 --- /dev/null +++ b/src/main/java/dev/isxander/yacl3/gui/controllers/cycling/EnumController.java @@ -0,0 +1,48 @@ +package dev.isxander.yacl3.gui.controllers.cycling; + +import dev.isxander.yacl3.api.NameableEnum; +import dev.isxander.yacl3.api.Option; +import dev.isxander.yacl3.api.controller.ValueFormatter; +import net.minecraft.network.chat.Component; +import net.minecraft.util.OptionEnum; + +import java.util.Arrays; +import java.util.function.Function; + +/** + * Simple controller type that displays the enum on the right. + * <p> + * Cycles forward with left click, cycles backward with right click or when shift is held + * + * @param <T> enum type + */ +public class EnumController<T extends Enum<T>> extends CyclingListController<T> { + public static <T extends Enum<T>> Function<T, Component> getDefaultFormatter() { + return value -> { + if (value instanceof NameableEnum nameableEnum) + return nameableEnum.getDisplayName(); + if (value instanceof OptionEnum translatableOption) + return translatableOption.getCaption(); + return Component.literal(value.toString()); + }; + } + + public EnumController(Option<T> option, Class<T> enumClass) { + this(option, getDefaultFormatter(), enumClass.getEnumConstants()); + } + + /** + * Constructs a cycling enum controller. + * + * @param option bound option + * @param valueFormatter format the enum into any {@link Component} + * @param availableValues all enum constants that can be cycled through + */ + public EnumController(Option<T> option, Function<T, Component> valueFormatter, T[] availableValues) { + super(option, Arrays.asList(availableValues), valueFormatter); + } + + public static <T extends Enum<T>> EnumController<T> createInternal(Option<T> option, ValueFormatter<T> formatter, T[] values) { + return new EnumController<>(option, formatter::format, values); + } +} diff --git a/src/main/java/dev/isxander/yacl3/gui/controllers/cycling/ICyclingController.java b/src/main/java/dev/isxander/yacl3/gui/controllers/cycling/ICyclingController.java new file mode 100644 index 0000000..cfddefa --- /dev/null +++ b/src/main/java/dev/isxander/yacl3/gui/controllers/cycling/ICyclingController.java @@ -0,0 +1,38 @@ +package dev.isxander.yacl3.gui.controllers.cycling; + +import dev.isxander.yacl3.api.Controller; +import dev.isxander.yacl3.api.utils.Dimension; +import dev.isxander.yacl3.gui.AbstractWidget; +import dev.isxander.yacl3.gui.YACLScreen; + +/** + * This interface simply generifies setting and getting of + * the pending value, using an ordinal so elements can cycle through + * without knowing the content. + */ +public interface ICyclingController<T> extends Controller<T> { + /** + * Sets the pending value to whatever corresponds to the ordinal + * @param ordinal index of element to set + */ + void setPendingValue(int ordinal); + + /** + * Gets the pending ordinal that corresponds to the actual value + * @return ordinal + */ + int getPendingValue(); + + /** + * Allows the element when it should wrap-around back to zeroth ordinal + */ + int getCycleLength(); + + /** + * {@inheritDoc} + */ + @Override + default AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) { + return new CyclingControllerElement(this, screen, widgetDimension); + } +} |
