diff options
| author | isXander <isxander@users.noreply.github.com> | 2022-09-18 19:14:58 +0100 | 
|---|---|---|
| committer | isXander <isxander@users.noreply.github.com> | 2022-09-18 19:15:09 +0100 | 
| commit | 33e98c7edc1404e099f9c9bcc586fd5c55cb8bdd (patch) | |
| tree | a964082d62c3b13f5628c036fe49f9ea19d32315 /src/main/java/dev/isxander/yacl | |
| parent | 564a028eed25cfce0e0486f1a1a21affb499a311 (diff) | |
| download | YetAnotherConfigLib-33e98c7edc1404e099f9c9bcc586fd5c55cb8bdd.tar.gz YetAnotherConfigLib-33e98c7edc1404e099f9c9bcc586fd5c55cb8bdd.tar.bz2 YetAnotherConfigLib-33e98c7edc1404e099f9c9bcc586fd5c55cb8bdd.zip | |
1.3.0
option tooltips now consume the pending value
PlaceholderCategory: a category that when selected, just opens a screen
Diffstat (limited to 'src/main/java/dev/isxander/yacl')
8 files changed, 188 insertions, 50 deletions
| diff --git a/src/main/java/dev/isxander/yacl/api/ConfigCategory.java b/src/main/java/dev/isxander/yacl/api/ConfigCategory.java index 1b2a2bc..27c3e95 100644 --- a/src/main/java/dev/isxander/yacl/api/ConfigCategory.java +++ b/src/main/java/dev/isxander/yacl/api/ConfigCategory.java @@ -90,7 +90,7 @@ public interface ConfigCategory {           * @see OptionGroup#isRoot()           */          public Builder options(@NotNull Collection<Option<?>> options) { -            Validate.notEmpty(options, "`options` must not be empty"); +            Validate.notNull(options, "`options` must not be null");              this.rootOptions.addAll(options);              return this; diff --git a/src/main/java/dev/isxander/yacl/api/Option.java b/src/main/java/dev/isxander/yacl/api/Option.java index ff72c4c..1c3b006 100644 --- a/src/main/java/dev/isxander/yacl/api/Option.java +++ b/src/main/java/dev/isxander/yacl/api/Option.java @@ -9,9 +9,11 @@ import org.apache.commons.lang3.Validate;  import org.jetbrains.annotations.NotNull;  import java.util.*; +import java.util.function.BiConsumer;  import java.util.function.Consumer;  import java.util.function.Function;  import java.util.function.Supplier; +import java.util.stream.Stream;  public interface Option<T> {      /** @@ -95,6 +97,8 @@ public interface Option<T> {       */      void requestSetDefault(); +    void addListener(BiConsumer<Option<T>, T> changedListener); +      /**       * Creates a builder to construct an {@link Option}       * @@ -108,7 +112,7 @@ public interface Option<T> {      class Builder<T> {          private Text name = Text.literal("Name not specified!").formatted(Formatting.RED); -        private final List<Text> tooltipLines = new ArrayList<>(); +        private final List<Function<T, Text>> tooltipGetters = new ArrayList<>();          private Function<Option<T>, Controller<T>> controlGetter; @@ -138,6 +142,20 @@ public interface Option<T> {          /**           * Sets the tooltip to be used by the option. +         * No need to wrap the text yourself, the gui does this itself. +         * +         * @param tooltipGetter function to get tooltip depending on value {@link Builder#build()}. +         */ +        @SafeVarargs +        public final Builder<T> tooltip(@NotNull Function<T, Text>... tooltipGetter) { +            Validate.notNull(tooltipGetter, "`tooltipGetter` cannot be null"); + +            this.tooltipGetters.addAll(List.of(tooltipGetter)); +            return this; +        } + +        /** +         * Sets the tooltip to be used by the option.           * Can be invoked twice to append more lines.           * No need to wrap the text yourself, the gui does this itself.           * @@ -146,7 +164,7 @@ public interface Option<T> {          public Builder<T> tooltip(@NotNull Text... tooltips) {              Validate.notNull(tooltips, "`tooltips` cannot be empty"); -            tooltipLines.addAll(List.of(tooltips)); +            this.tooltipGetters.addAll(Stream.of(tooltips).map(text -> (Function<T, Text>) t -> text).toList());              return this;          } @@ -244,16 +262,20 @@ public interface Option<T> {              Validate.notNull(controlGetter, "`control` must not be null when building `Option`");              Validate.notNull(binding, "`binding` must not be null when building `Option`"); -            MutableText concatenatedTooltip = Text.empty(); -            boolean first = true; -            for (Text line : tooltipLines) { -                if (!first) concatenatedTooltip.append("\n"); -                first = false; +            Function<T, Text> concatenatedTooltipGetter = value -> { +                MutableText concatenatedTooltip = Text.empty(); +                boolean first = true; +                for (Function<T, Text> line : tooltipGetters) { +                    if (!first) concatenatedTooltip.append("\n"); +                    first = false; + +                    concatenatedTooltip.append(line.apply(value)); +                } -                concatenatedTooltip.append(line); -            } +                return concatenatedTooltip; +            }; -            return new OptionImpl<>(name, concatenatedTooltip, controlGetter, binding, available, ImmutableSet.copyOf(flags), typeClass); +            return new OptionImpl<>(name, concatenatedTooltipGetter, controlGetter, binding, available, ImmutableSet.copyOf(flags), typeClass);          }      }  } diff --git a/src/main/java/dev/isxander/yacl/api/PlaceholderCategory.java b/src/main/java/dev/isxander/yacl/api/PlaceholderCategory.java new file mode 100644 index 0000000..de7441c --- /dev/null +++ b/src/main/java/dev/isxander/yacl/api/PlaceholderCategory.java @@ -0,0 +1,94 @@ +package dev.isxander.yacl.api; + +import dev.isxander.yacl.gui.YACLScreen; +import dev.isxander.yacl.impl.PlaceholderCategoryImpl; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import org.apache.commons.lang3.Validate; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; + +/** + * A placeholder category that actually just opens another screen, + * instead of displaying options + */ +public interface PlaceholderCategory extends ConfigCategory { +    /** +     * Function to create a screen to open upon changing to this category +     */ +    BiFunction<MinecraftClient, YACLScreen, Screen> screen(); + +    static Builder createBuilder() { +        return new Builder(); +    } + +    class Builder { +        private Text name; + +        private final List<Text> tooltipLines = new ArrayList<>(); + +        private BiFunction<MinecraftClient, YACLScreen, Screen> screenFunction; + +        private Builder() { + +        } + +        /** +         * Sets name of the category +         * +         * @see ConfigCategory#name() +         */ +        public Builder name(@NotNull Text name) { +            Validate.notNull(name, "`name` cannot be null"); + +            this.name = name; +            return this; +        } + +        /** +         * Sets the tooltip to be used by the category. +         * Can be invoked twice to append more lines. +         * No need to wrap the text yourself, the gui does this itself. +         * +         * @param tooltips text lines - merged with a new-line on {@link Builder#build()}. +         */ +        public Builder tooltip(@NotNull Text... tooltips) { +            Validate.notEmpty(tooltips, "`tooltips` cannot be empty"); + +            tooltipLines.addAll(List.of(tooltips)); +            return this; +        } + +        /** +         * Screen to open upon selecting this category +         * +         * @see PlaceholderCategory#screen() +         */ +        public Builder screen(@NotNull BiFunction<MinecraftClient, YACLScreen, Screen> screenFunction) { +            Validate.notNull(screenFunction, "`screenFunction` cannot be null"); + +            this.screenFunction = screenFunction; +            return this; +        } + +        public PlaceholderCategory build() { +            Validate.notNull(name, "`name` must not be null to build `ConfigCategory`"); + +            MutableText concatenatedTooltip = Text.empty(); +            boolean first = true; +            for (Text line : tooltipLines) { +                if (!first) concatenatedTooltip.append("\n"); +                first = false; + +                concatenatedTooltip.append(line); +            } + +            return new PlaceholderCategoryImpl(name, screenFunction, concatenatedTooltip); +        } +    } +} diff --git a/src/main/java/dev/isxander/yacl/gui/YACLScreen.java b/src/main/java/dev/isxander/yacl/gui/YACLScreen.java index 26f4ad5..80ffb0e 100644 --- a/src/main/java/dev/isxander/yacl/gui/YACLScreen.java +++ b/src/main/java/dev/isxander/yacl/gui/YACLScreen.java @@ -1,10 +1,7 @@  package dev.isxander.yacl.gui;  import com.mojang.blaze3d.systems.RenderSystem; -import dev.isxander.yacl.api.ConfigCategory; -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.api.OptionFlag; -import dev.isxander.yacl.api.YetAnotherConfigLib; +import dev.isxander.yacl.api.*;  import dev.isxander.yacl.api.utils.Dimension;  import dev.isxander.yacl.api.utils.OptionUtils;  import dev.isxander.yacl.impl.YACLConstants; @@ -32,13 +29,11 @@ public class YACLScreen extends Screen {      private final Screen parent;      public OptionListWidget optionList; -//    public final List<CategoryWidget> categoryButtons;      public CategoryListWidget categoryList;      public TooltipButtonWidget finishedSaveButton, cancelResetButton, undoButton;      public SearchFieldWidget searchFieldWidget; -    public Text saveButtonMessage; -    public Text saveButtonTooltipMessage; +    public Text saveButtonMessage, saveButtonTooltipMessage;      private int saveButtonMessageTime; @@ -46,34 +41,15 @@ public class YACLScreen extends Screen {          super(config.title());          this.config = config;          this.parent = parent; -//        this.categoryButtons = new ArrayList<>();          this.currentCategoryIdx = 0;      }      @Override      protected void init() { -//        categoryButtons.clear();          int columnWidth = width / 3;          int padding = columnWidth / 20;          columnWidth = Math.min(columnWidth, 400);          int paddedWidth = columnWidth - padding * 2; -//        Dimension<Integer> categoryDim = Dimension.ofInt(width / 3 / 2, padding, paddedWidth, 20); -//        int idx = 0; -//        for (ConfigCategory category : config.categories()) { -//            CategoryWidget categoryWidget = new CategoryWidget( -//                    this, -//                    category, -//                    idx, -//                    categoryDim.x() - categoryDim.width() / 2, categoryDim.y(), -//                    categoryDim.width(), categoryDim.height() -//            ); -// -//            categoryButtons.add(categoryWidget); -//            addDrawableChild(categoryWidget); -// -//            idx++; -//            categoryDim.move(0, 21); -//        }          Dimension<Integer> actionDim = Dimension.ofInt(width / 3 / 2, height - padding - 20, paddedWidth, 20);          finishedSaveButton = new TooltipButtonWidget(this, actionDim.x() - actionDim.width() / 2, actionDim.y(), actionDim.width(), actionDim.height(), Text.empty(), Text.empty(), (btn) -> { @@ -167,8 +143,12 @@ public class YACLScreen extends Screen {      }      public void changeCategory(int idx) { -        currentCategoryIdx = idx; -        optionList.refreshOptions(); +        if (currentCategoryIdx != -1 && config.categories().get(idx) instanceof PlaceholderCategory placeholderCategory) { +            client.setScreen(placeholderCategory.screen().apply(client, this)); +        } else { +            currentCategoryIdx = idx; +            optionList.refreshOptions(); +        }      }      private void updateActionAvailability() { diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java b/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java index 1c986e4..cd70872 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java @@ -16,7 +16,7 @@ import java.util.List;  public abstract class ControllerWidget<T extends Controller<?>> extends AbstractWidget {      protected final T control; -    protected final MultilineText wrappedTooltip; +    protected MultilineText wrappedTooltip;      protected final YACLScreen screen;      protected boolean focused = false; @@ -29,7 +29,8 @@ public abstract class ControllerWidget<T extends Controller<?>> extends Abstract          super(dim);          this.control = control;          this.screen = screen; -        this.wrappedTooltip = MultilineText.create(textRenderer, control.option().tooltip(), screen.width / 2); +        control.option().addListener((opt, pending) -> updateTooltip()); +        updateTooltip();      }      @Override @@ -71,7 +72,7 @@ public abstract class ControllerWidget<T extends Controller<?>> extends Abstract      @Override      public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) { -        if (hoveredTicks > YACLConstants.HOVER_TICKS) { +        if (hoveredTicks >= YACLConstants.HOVER_TICKS) {              YACLScreen.renderMultilineTooltip(matrices, textRenderer, wrappedTooltip, mouseX, mouseY, screen.width, screen.height);          }      } @@ -94,6 +95,10 @@ public abstract class ControllerWidget<T extends Controller<?>> extends Abstract          return this.dim.isPointInside((int) mouseX, (int) mouseY);      } +    private void updateTooltip() { +        this.wrappedTooltip = MultilineText.create(textRenderer, control.option().tooltip(), screen.width / 2); +    } +      protected int getControlWidth() {          return isHovered() ? getHoveredControlWidth() : getUnhoveredControlWidth();      } diff --git a/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java b/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java index a600bc3..51c94b0 100644 --- a/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java +++ b/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java @@ -1,16 +1,14 @@  package dev.isxander.yacl.impl;  import com.google.common.collect.ImmutableSet; -import dev.isxander.yacl.api.Binding; -import dev.isxander.yacl.api.ButtonOption; -import dev.isxander.yacl.api.Controller; -import dev.isxander.yacl.api.OptionFlag; +import dev.isxander.yacl.api.*;  import dev.isxander.yacl.gui.YACLScreen;  import net.minecraft.text.Text;  import org.jetbrains.annotations.ApiStatus;  import org.jetbrains.annotations.NotNull;  import org.jetbrains.annotations.Nullable; +import java.util.function.BiConsumer;  import java.util.function.Consumer;  import java.util.function.Function; @@ -113,6 +111,11 @@ public class ButtonOptionImpl implements ButtonOption {      } +    @Override +    public void addListener(BiConsumer<Option<Consumer<YACLScreen>>, Consumer<YACLScreen>> changedListener) { + +    } +      private static class EmptyBinderImpl implements Binding<Consumer<YACLScreen>> {          @Override          public void setValue(Consumer<YACLScreen> value) { diff --git a/src/main/java/dev/isxander/yacl/impl/OptionImpl.java b/src/main/java/dev/isxander/yacl/impl/OptionImpl.java index 5a31a70..1cf2a79 100644 --- a/src/main/java/dev/isxander/yacl/impl/OptionImpl.java +++ b/src/main/java/dev/isxander/yacl/impl/OptionImpl.java @@ -10,12 +10,16 @@ import org.jetbrains.annotations.ApiStatus;  import org.jetbrains.annotations.NotNull;  import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer;  import java.util.function.Function;  @ApiStatus.Internal  public class OptionImpl<T> implements Option<T> {      private final Text name; -    private final Text tooltip; +    private Text tooltip; +    private final Function<T, Text> tooltipGetter;      private final Controller<T> controller;      private final Binding<T> binding;      private final boolean available; @@ -26,9 +30,11 @@ public class OptionImpl<T> implements Option<T> {      private T pendingValue; +    private final List<BiConsumer<Option<T>, T>> listeners; +      public OptionImpl(              @NotNull Text name, -            @Nullable Text tooltip, +            @Nullable Function<T, Text> tooltipGetter,              @NotNull Function<Option<T>, Controller<T>> controlGetter,              @NotNull Binding<T> binding,              boolean available, @@ -36,13 +42,16 @@ public class OptionImpl<T> implements Option<T> {              @NotNull Class<T> typeClass      ) {          this.name = name; -        this.tooltip = tooltip; +        this.tooltipGetter = tooltipGetter;          this.controller = controlGetter.apply(this);          this.binding = binding;          this.available = available;          this.flags = flags;          this.typeClass = typeClass; -        this.pendingValue = binding().getValue(); +        this.listeners = new ArrayList<>(); + +        addListener((opt, pending) -> tooltip = tooltipGetter.apply(pending)); +        requestSet(binding().getValue());      }      @Override @@ -98,6 +107,7 @@ public class OptionImpl<T> implements Option<T> {      @Override      public void requestSet(T value) {          pendingValue = value; +        listeners.forEach(listener -> listener.accept(this, pendingValue));      }      @Override @@ -118,4 +128,9 @@ public class OptionImpl<T> implements Option<T> {      public void requestSetDefault() {          pendingValue = binding().defaultValue();      } + +    @Override +    public void addListener(BiConsumer<Option<T>, T> changedListener) { +        this.listeners.add(changedListener); +    }  } diff --git a/src/main/java/dev/isxander/yacl/impl/PlaceholderCategoryImpl.java b/src/main/java/dev/isxander/yacl/impl/PlaceholderCategoryImpl.java new file mode 100644 index 0000000..a5180ad --- /dev/null +++ b/src/main/java/dev/isxander/yacl/impl/PlaceholderCategoryImpl.java @@ -0,0 +1,19 @@ +package dev.isxander.yacl.impl; + +import com.google.common.collect.ImmutableList; +import dev.isxander.yacl.api.OptionGroup; +import dev.isxander.yacl.api.PlaceholderCategory; +import dev.isxander.yacl.gui.YACLScreen; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; + +import java.util.function.BiFunction; + +public record PlaceholderCategoryImpl(Text name, BiFunction<MinecraftClient, YACLScreen, Screen> screen, Text tooltip) implements PlaceholderCategory { +    @Override +    public @NotNull ImmutableList<OptionGroup> groups() { +        return ImmutableList.of(); +    } +} | 
