diff options
author | isXander <xandersmith2008@gmail.com> | 2022-11-27 18:17:36 +0000 |
---|---|---|
committer | isXander <xandersmith2008@gmail.com> | 2022-11-27 18:17:36 +0000 |
commit | d163b9128d760e53e34fd6c08dbf782fa3d50c51 (patch) | |
tree | b9ea79bb99bf52ea7de9d059cc05900270ff88d4 /src/main | |
parent | c26d3a89caae20f1a91898202d91de8dc90da5ad (diff) | |
download | YetAnotherConfigLib-d163b9128d760e53e34fd6c08dbf782fa3d50c51.tar.gz YetAnotherConfigLib-d163b9128d760e53e34fd6c08dbf782fa3d50c51.tar.bz2 YetAnotherConfigLib-d163b9128d760e53e34fd6c08dbf782fa3d50c51.zip |
split sourcesets
Diffstat (limited to 'src/main')
58 files changed, 4 insertions, 5112 deletions
diff --git a/src/main/java/dev/isxander/yacl/api/Binding.java b/src/main/java/dev/isxander/yacl/api/Binding.java deleted file mode 100644 index 395beb2..0000000 --- a/src/main/java/dev/isxander/yacl/api/Binding.java +++ /dev/null @@ -1,64 +0,0 @@ -package dev.isxander.yacl.api; - -import dev.isxander.yacl.impl.GenericBindingImpl; -import dev.isxander.yacl.mixin.SimpleOptionAccessor; -import net.minecraft.client.option.SimpleOption; -import org.apache.commons.lang3.Validate; - -import java.util.function.Consumer; -import java.util.function.Supplier; - -/** - * Controls modifying the bound option. - * Provides the default value, a setter and a getter. - */ -public interface Binding<T> { - void setValue(T value); - - T getValue(); - - T defaultValue(); - - /** - * Creates a generic binding. - * - * @param def default value of the option, used to reset - * @param getter should return the current value of the option - * @param setter should set the option to the supplied value - */ - static <T> Binding<T> generic(T def, Supplier<T> getter, Consumer<T> setter) { - Validate.notNull(def, "`def` must not be null"); - Validate.notNull(getter, "`getter` must not be null"); - Validate.notNull(setter, "`setter` must not be null"); - - return new GenericBindingImpl<>(def, getter, setter); - } - - /** - * Creates a {@link Binding} for Minecraft's {@link SimpleOption} - */ - static <T> Binding<T> minecraft(SimpleOption<T> minecraftOption) { - Validate.notNull(minecraftOption, "`minecraftOption` must not be null"); - - return new GenericBindingImpl<>( - ((SimpleOptionAccessor<T>) (Object) minecraftOption).getDefaultValue(), - minecraftOption::getValue, - minecraftOption::setValue - ); - } - - /** - * Creates an immutable binding that has no default and cannot be modified. - * - * @param value the value for the binding - */ - static <T> Binding<T> immutable(T value) { - Validate.notNull(value, "`value` must not be null"); - - return new GenericBindingImpl<>( - value, - () -> value, - changed -> {} - ); - } -} diff --git a/src/main/java/dev/isxander/yacl/api/ButtonOption.java b/src/main/java/dev/isxander/yacl/api/ButtonOption.java deleted file mode 100644 index 1124a9a..0000000 --- a/src/main/java/dev/isxander/yacl/api/ButtonOption.java +++ /dev/null @@ -1,123 +0,0 @@ -package dev.isxander.yacl.api; - -import dev.isxander.yacl.gui.YACLScreen; -import dev.isxander.yacl.impl.ButtonOptionImpl; -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.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; - -public interface ButtonOption extends Option<BiConsumer<YACLScreen, ButtonOption>> { - /** - * Action to be executed upon button press - */ - BiConsumer<YACLScreen, ButtonOption> action(); - - static Builder createBuilder() { - return new Builder(); - } - - class Builder { - private Text name; - private final List<Text> tooltipLines = new ArrayList<>(); - private boolean available = true; - private Function<ButtonOption, Controller<BiConsumer<YACLScreen, ButtonOption>>> controlGetter; - private BiConsumer<YACLScreen, ButtonOption> action; - - private Builder() { - - } - - /** - * Sets the name to be used by the option. - * - * @see Option#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 option. - * 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 Option.Builder#build()}. - */ - public Builder tooltip(@NotNull Text... tooltips) { - Validate.notNull(tooltips, "`tooltips` cannot be empty"); - - tooltipLines.addAll(List.of(tooltips)); - return this; - } - - public Builder action(@NotNull BiConsumer<YACLScreen, ButtonOption> action) { - Validate.notNull(action, "`action` cannot be null"); - - this.action = action; - return this; - } - - /** - * Action to be executed upon button press - * - * @see ButtonOption#action() - */ - @Deprecated - public Builder action(@NotNull Consumer<YACLScreen> action) { - Validate.notNull(action, "`action` cannot be null"); - - this.action = (screen, button) -> action.accept(screen); - return this; - } - - /** - * Sets if the option can be configured - * - * @see Option#available() - */ - public Builder available(boolean available) { - this.available = available; - return this; - } - - /** - * Sets the controller for the option. - * This is how you interact and change the options. - * - * @see dev.isxander.yacl.gui.controllers - */ - public Builder controller(@NotNull Function<ButtonOption, Controller<BiConsumer<YACLScreen, ButtonOption>>> control) { - Validate.notNull(control, "`control` cannot be null"); - - this.controlGetter = control; - return this; - } - - public ButtonOption build() { - Validate.notNull(name, "`name` must not be null when building `Option`"); - Validate.notNull(controlGetter, "`control` must not be null when building `Option`"); - Validate.notNull(action, "`action` 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; - - concatenatedTooltip.append(line); - } - - return new ButtonOptionImpl(name, concatenatedTooltip, action, available, controlGetter); - } - } -} diff --git a/src/main/java/dev/isxander/yacl/api/ConfigCategory.java b/src/main/java/dev/isxander/yacl/api/ConfigCategory.java deleted file mode 100644 index 27c3e95..0000000 --- a/src/main/java/dev/isxander/yacl/api/ConfigCategory.java +++ /dev/null @@ -1,158 +0,0 @@ -package dev.isxander.yacl.api; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.impl.ConfigCategoryImpl; -import dev.isxander.yacl.impl.OptionGroupImpl; -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.Collection; -import java.util.List; -import java.util.function.Function; - -/** - * Separates {@link Option}s or {@link OptionGroup}s into multiple distinct sections. - * Served to a user as a button in the left column, - * upon pressing, the options list is filled with options contained within this category. - */ -public interface ConfigCategory { - /** - * Name of category, displayed as a button on the left column. - */ - @NotNull Text name(); - - /** - * Gets every {@link OptionGroup} in this category. - */ - @NotNull ImmutableList<OptionGroup> groups(); - - /** - * Tooltip (or description) of the category. - * Rendered on hover. - */ - @NotNull Text tooltip(); - - /** - * Creates a builder to construct a {@link ConfigCategory} - */ - static Builder createBuilder() { - return new Builder(); - } - - class Builder { - private Text name; - - private final List<Option<?>> rootOptions = new ArrayList<>(); - private final List<OptionGroup> groups = new ArrayList<>(); - - private final List<Text> tooltipLines = new ArrayList<>(); - - 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; - } - - /** - * Adds an option to the root group of the category. - * To add to another group, use {@link Builder#group(OptionGroup)}. - * To construct an option, use {@link Option#createBuilder(Class)} - * - * @see ConfigCategory#groups() - * @see OptionGroup#isRoot() - */ - public Builder option(@NotNull Option<?> option) { - Validate.notNull(option, "`option` must not be null"); - - this.rootOptions.add(option); - return this; - } - - /** - * Adds multiple options to the root group of the category. - * To add to another group, use {@link Builder#groups(Collection)}. - * To construct an option, use {@link Option#createBuilder(Class)} - * - * @see ConfigCategory#groups() - * @see OptionGroup#isRoot() - */ - public Builder options(@NotNull Collection<Option<?>> options) { - Validate.notNull(options, "`options` must not be null"); - - this.rootOptions.addAll(options); - return this; - } - - /** - * Adds an option group. - * To add an option to the root group, use {@link Builder#option(Option)} - * To construct a group, use {@link OptionGroup#createBuilder()} - */ - public Builder group(@NotNull OptionGroup group) { - Validate.notNull(group, "`group` must not be null"); - - this.groups.add(group); - return this; - } - - /** - * Adds multiple option groups. - * To add multiple options to the root group, use {@link Builder#options(Collection)} - * To construct a group, use {@link OptionGroup#createBuilder()} - */ - public Builder groups(@NotNull Collection<OptionGroup> groups) { - Validate.notEmpty(groups, "`groups` must not be empty"); - - this.groups.addAll(groups); - 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; - } - - public ConfigCategory build() { - Validate.notNull(name, "`name` must not be null to build `ConfigCategory`"); - - List<OptionGroup> combinedGroups = new ArrayList<>(); - combinedGroups.add(new OptionGroupImpl(Text.empty(), Text.empty(), ImmutableList.copyOf(rootOptions), false, true)); - combinedGroups.addAll(groups); - - Validate.notEmpty(combinedGroups, "at least one option must be added 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 ConfigCategoryImpl(name, ImmutableList.copyOf(combinedGroups), concatenatedTooltip); - } - } -} diff --git a/src/main/java/dev/isxander/yacl/api/Controller.java b/src/main/java/dev/isxander/yacl/api/Controller.java deleted file mode 100644 index 7bf7e7f..0000000 --- a/src/main/java/dev/isxander/yacl/api/Controller.java +++ /dev/null @@ -1,28 +0,0 @@ -package dev.isxander.yacl.api; - -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.AbstractWidget; -import dev.isxander.yacl.gui.YACLScreen; -import net.minecraft.text.Text; - -/** - * Provides a widget to control the option. - */ -public interface Controller<T> { - /** - * Gets the dedicated {@link Option} for this controller - */ - Option<T> option(); - - /** - * Gets the formatted value based on {@link Option#pendingValue()} - */ - Text formatValue(); - - /** - * Provides a widget to display - * - * @param screen parent screen - */ - AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension); -} diff --git a/src/main/java/dev/isxander/yacl/api/NameableEnum.java b/src/main/java/dev/isxander/yacl/api/NameableEnum.java deleted file mode 100644 index 793b230..0000000 --- a/src/main/java/dev/isxander/yacl/api/NameableEnum.java +++ /dev/null @@ -1,10 +0,0 @@ -package dev.isxander.yacl.api; - -import net.minecraft.text.Text; - -/** - * Used for the default value formatter of {@link dev.isxander.yacl.gui.controllers.cycling.EnumController} - */ -public interface NameableEnum { - Text getDisplayName(); -} diff --git a/src/main/java/dev/isxander/yacl/api/Option.java b/src/main/java/dev/isxander/yacl/api/Option.java deleted file mode 100644 index 772c816..0000000 --- a/src/main/java/dev/isxander/yacl/api/Option.java +++ /dev/null @@ -1,336 +0,0 @@ -package dev.isxander.yacl.api; - -import com.google.common.collect.ImmutableSet; -import dev.isxander.yacl.impl.OptionImpl; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -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> { - /** - * Name of the option - */ - @NotNull Text name(); - - /** - * Tooltip (or description) of the option. - * Rendered on hover. - */ - @NotNull Text tooltip(); - - /** - * Widget provider for a type of option. - * - * @see dev.isxander.yacl.gui.controllers - */ - @NotNull Controller<T> controller(); - - /** - * Binding for the option. - * Controls setting, getting and default value. - * - * @see Binding - */ - @NotNull Binding<T> binding(); - - /** - * If the option can be configured - */ - boolean available(); - - /** - * Sets if the option can be configured after being built - * - * @see Option#available() - */ - void setAvailable(boolean available); - - /** - * Class of the option type. - * Used by some controllers. - */ - @NotNull Class<T> typeClass(); - - /** - * Tasks that needs to be executed upon applying changes. - */ - @NotNull ImmutableSet<OptionFlag> flags(); - - /** - * Checks if the pending value is not equal to the current set value - */ - boolean changed(); - - /** - * If true, modifying this option recommends a restart. - */ - @Deprecated - boolean requiresRestart(); - - /** - * Value in the GUI, ready to set the actual bound value or be undone. - */ - @NotNull T pendingValue(); - - /** - * Sets the pending value - */ - void requestSet(T value); - - /** - * Applies the pending value to the bound value. - * Cannot be undone. - * - * @return if there were changes to apply {@link Option#changed()} - */ - boolean applyValue(); - - /** - * Sets the pending value to the bound value. - */ - void forgetPendingValue(); - - /** - * Sets the pending value to the default bound value. - */ - void requestSetDefault(); - - /** - * Checks if the current pending value is equal to its default value - */ - boolean isPendingValueDefault(); - - /** - * Adds a listener for when the pending value changes - */ - void addListener(BiConsumer<Option<T>, T> changedListener); - - /** - * Creates a builder to construct an {@link Option} - * - * @param <T> type of the option's value - * @param typeClass used to capture the type - */ - static <T> Builder<T> createBuilder(Class<T> typeClass) { - return new Builder<>(typeClass); - } - - class Builder<T> { - private Text name = Text.literal("Name not specified!").formatted(Formatting.RED); - - private final List<Function<T, Text>> tooltipGetters = new ArrayList<>(); - - private Function<Option<T>, Controller<T>> controlGetter; - - private Binding<T> binding; - - private boolean available = true; - - private boolean instant = false; - - private final Set<OptionFlag> flags = new HashSet<>(); - - private final Class<T> typeClass; - - private final List<BiConsumer<Option<T>, T>> listeners = new ArrayList<>(); - - private Builder(Class<T> typeClass) { - this.typeClass = typeClass; - } - - /** - * Sets the name to be used by the option. - * - * @see Option#name() - */ - public Builder<T> name(@NotNull Text name) { - Validate.notNull(name, "`name` cannot be null"); - - this.name = name; - return this; - } - - /** - * 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. - * - * @param tooltips text lines - merged with a new-line on {@link Builder#build()}. - */ - public Builder<T> tooltip(@NotNull Text... tooltips) { - Validate.notNull(tooltips, "`tooltips` cannot be empty"); - - this.tooltipGetters.addAll(Stream.of(tooltips).map(text -> (Function<T, Text>) t -> text).toList()); - return this; - } - - /** - * Sets the controller for the option. - * This is how you interact and change the options. - * - * @see dev.isxander.yacl.gui.controllers - */ - public Builder<T> controller(@NotNull Function<Option<T>, Controller<T>> control) { - Validate.notNull(control, "`control` cannot be null"); - - this.controlGetter = control; - return this; - } - - /** - * Sets the binding for the option. - * Used for default, getter and setter. - * - * @see Binding - */ - public Builder<T> binding(@NotNull Binding<T> binding) { - Validate.notNull(binding, "`binding` cannot be null"); - - this.binding = binding; - return this; - } - - /** - * Sets the binding for the option. - * Shorthand of {@link Binding#generic(Object, Supplier, Consumer)} - * - * @param def default value of the option, used to reset - * @param getter should return the current value of the option - * @param setter should set the option to the supplied value - * @see Binding - */ - public Builder<T> binding(@NotNull T def, @NotNull Supplier<@NotNull T> getter, @NotNull Consumer<@NotNull T> setter) { - Validate.notNull(def, "`def` must not be null"); - Validate.notNull(getter, "`getter` must not be null"); - Validate.notNull(setter, "`setter` must not be null"); - - this.binding = Binding.generic(def, getter, setter); - return this; - } - - /** - * Sets if the option can be configured - * - * @see Option#available() - */ - public Builder<T> available(boolean available) { - this.available = available; - return this; - } - - /** - * Adds a flag to the option. - * Upon applying changes, all flags are executed. - * {@link Option#flags()} - */ - public Builder<T> flag(@NotNull OptionFlag... flag) { - Validate.notNull(flag, "`flag` must not be null"); - - this.flags.addAll(Arrays.asList(flag)); - return this; - } - - /** - * Adds a flag to the option. - * Upon applying changes, all flags are executed. - * {@link Option#flags()} - */ - public Builder<T> flags(@NotNull Collection<OptionFlag> flags) { - Validate.notNull(flags, "`flags` must not be null"); - - this.flags.addAll(flags); - return this; - } - - /** - * Instantly invokes the binder's setter when modified in the GUI. - * Prevents the user from undoing the change - * <p> - * Does not support {@link Option#flags()}! - */ - public Builder<T> instant(boolean instant) { - this.instant = instant; - return this; - } - - /** - * Adds a listener to the option. Invoked upon changing the pending value. - * - * @see Option#addListener(BiConsumer) - */ - public Builder<T> listener(@NotNull BiConsumer<Option<T>, T> listener) { - this.listeners.add(listener); - return this; - } - - /** - * Adds multiple listeners to the option. Invoked upon changing the pending value. - * - * @see Option#addListener(BiConsumer) - */ - public Builder<T> listeners(@NotNull Collection<BiConsumer<Option<T>, T>> listeners) { - this.listeners.addAll(listeners); - return this; - } - - /** - * Dictates whether the option should require a restart. - * {@link Option#requiresRestart()} - */ - @Deprecated - public Builder<T> requiresRestart(boolean requiresRestart) { - if (requiresRestart) flag(OptionFlag.GAME_RESTART); - else flags.remove(OptionFlag.GAME_RESTART); - - return this; - } - - public Option<T> build() { - Validate.notNull(controlGetter, "`control` must not be null when building `Option`"); - Validate.notNull(binding, "`binding` must not be null when building `Option`"); - Validate.isTrue(!instant || flags.isEmpty(), "instant application does not support option flags"); - - 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)); - } - - return concatenatedTooltip; - }; - - if (instant) { - listeners.add((opt, pendingValue) -> opt.applyValue()); - } - - return new OptionImpl<>(name, concatenatedTooltipGetter, controlGetter, binding, available, ImmutableSet.copyOf(flags), typeClass, listeners); - } - } -} diff --git a/src/main/java/dev/isxander/yacl/api/OptionFlag.java b/src/main/java/dev/isxander/yacl/api/OptionFlag.java deleted file mode 100644 index 203a674..0000000 --- a/src/main/java/dev/isxander/yacl/api/OptionFlag.java +++ /dev/null @@ -1,27 +0,0 @@ -package dev.isxander.yacl.api; - -import dev.isxander.yacl.gui.RequireRestartScreen; -import net.minecraft.client.MinecraftClient; - -import java.util.function.Consumer; - -/** - * Code that is executed upon certain options being applied. - * Each flag is executed only once per save, no matter the amount of options with the flag. - */ -@FunctionalInterface -public interface OptionFlag extends Consumer<MinecraftClient> { - /** - * Warns the user that a game restart is required for the changes to take effect - */ - OptionFlag GAME_RESTART = client -> client.setScreen(new RequireRestartScreen(client.currentScreen)); - - /** - * Reloads chunks upon applying (F3+A) - */ - OptionFlag RELOAD_CHUNKS = client -> client.worldRenderer.reload(); - - OptionFlag WORLD_RENDER_UPDATE = client -> client.worldRenderer.scheduleTerrainUpdate(); - - OptionFlag ASSET_RELOAD = MinecraftClient::reloadResourcesConcurrently; -} diff --git a/src/main/java/dev/isxander/yacl/api/OptionGroup.java b/src/main/java/dev/isxander/yacl/api/OptionGroup.java deleted file mode 100644 index 3364bdf..0000000 --- a/src/main/java/dev/isxander/yacl/api/OptionGroup.java +++ /dev/null @@ -1,141 +0,0 @@ -package dev.isxander.yacl.api; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.impl.OptionGroupImpl; -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.Collection; -import java.util.List; - -/** - * Serves as a separator between multiple chunks of options - * that may be too similar or too few to be placed in a separate {@link ConfigCategory}. - * Or maybe you just want your config to feel less dense. - */ -public interface OptionGroup { - /** - * Name of the option group, displayed as a separator in the option lists. - * Can be empty. - */ - Text name(); - - /** - * Tooltip displayed on hover. - */ - Text tooltip(); - - /** - * List of all options in the group - */ - @NotNull ImmutableList<Option<?>> options(); - - /** - * Dictates if the group should be collapsed by default. - */ - boolean collapsed(); - - /** - * Always false when using the {@link Builder} - * used to not render the separator if true - */ - boolean isRoot(); - - /** - * Creates a builder to construct a {@link OptionGroup} - */ - static Builder createBuilder() { - return new Builder(); - } - - class Builder { - private Text name = Text.empty(); - private final List<Text> tooltipLines = new ArrayList<>(); - private final List<Option<?>> options = new ArrayList<>(); - private boolean collapsed = false; - - private Builder() { - - } - - /** - * Sets name of the group, can be {@link Text#empty()} to just separate options, like sodium. - * - * @see OptionGroup#name() - */ - public Builder name(@NotNull Text name) { - Validate.notNull(name, "`name` must not be null"); - - this.name = name; - return this; - } - - /** - * Sets the tooltip to be used by the option group. - * 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; - } - - /** - * Adds an option to group. - * To construct an option, use {@link Option#createBuilder(Class)} - * - * @see OptionGroup#options() - */ - public Builder option(@NotNull Option<?> option) { - Validate.notNull(option, "`option` must not be null"); - - this.options.add(option); - return this; - } - - /** - * Adds multiple options to group. - * To construct an option, use {@link Option#createBuilder(Class)} - * - * @see OptionGroup#options() - */ - public Builder options(@NotNull Collection<? extends Option<?>> options) { - Validate.notEmpty(options, "`options` must not be empty"); - - this.options.addAll(options); - return this; - } - - /** - * Dictates if the group should be collapsed by default - * - * @see OptionGroup#collapsed() - */ - public Builder collapsed(boolean collapsible) { - this.collapsed = collapsible; - return this; - } - - public OptionGroup build() { - Validate.notEmpty(options, "`options` must not be empty to build `OptionGroup`"); - - MutableText concatenatedTooltip = Text.empty(); - boolean first = true; - for (Text line : tooltipLines) { - if (!first) concatenatedTooltip.append("\n"); - first = false; - - concatenatedTooltip.append(line); - } - - return new OptionGroupImpl(name, concatenatedTooltip, ImmutableList.copyOf(options), collapsed, false); - } - } -} diff --git a/src/main/java/dev/isxander/yacl/api/PlaceholderCategory.java b/src/main/java/dev/isxander/yacl/api/PlaceholderCategory.java deleted file mode 100644 index de7441c..0000000 --- a/src/main/java/dev/isxander/yacl/api/PlaceholderCategory.java +++ /dev/null @@ -1,94 +0,0 @@ -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/api/YetAnotherConfigLib.java b/src/main/java/dev/isxander/yacl/api/YetAnotherConfigLib.java deleted file mode 100644 index a69ae4e..0000000 --- a/src/main/java/dev/isxander/yacl/api/YetAnotherConfigLib.java +++ /dev/null @@ -1,136 +0,0 @@ -package dev.isxander.yacl.api; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.gui.YACLScreen; -import dev.isxander.yacl.impl.YetAnotherConfigLibImpl; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.text.Text; -import org.apache.commons.lang3.Validate; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.function.Consumer; - -/** - * Main class of the mod. - * Contains all data and used to provide a {@link Screen} - */ -public interface YetAnotherConfigLib { - /** - * Title of the GUI. Only used for Minecraft narration. - */ - Text title(); - - /** - * Gets all config categories. - */ - ImmutableList<ConfigCategory> categories(); - - /** - * Ran when changes are saved. Can be used to save config to a file etc. - */ - Runnable saveFunction(); - - /** - * Ran every time the YACL screen initialises. Can be paired with FAPI to add custom widgets. - */ - Consumer<YACLScreen> initConsumer(); - - /** - * Generates a Screen to display based on this instance. - * - * @param parent parent screen to open once closed - */ - Screen generateScreen(@Nullable Screen parent); - - /** - * Creates a builder to construct YACL - */ - static Builder createBuilder() { - return new Builder(); - } - - class Builder { - private Text title; - private final List<ConfigCategory> categories = new ArrayList<>(); - private Runnable saveFunction = () -> {}; - private Consumer<YACLScreen> initConsumer = screen -> {}; - - private Builder() { - - } - - /** - * Sets title of GUI for Minecraft narration - * - * @see YetAnotherConfigLib#title() - */ - public Builder title(@NotNull Text title) { - Validate.notNull(title, "`title` cannot be null"); - - this.title = title; - return this; - } - - /** - * Adds a new category. - * To create a category you need to use {@link ConfigCategory#createBuilder()} - * - * @see YetAnotherConfigLib#categories() - */ - public Builder category(@NotNull ConfigCategory category) { - Validate.notNull(category, "`category` cannot be null"); - - this.categories.add(category); - return this; - } - - /** - * Adds multiple categories at once. - * To create a category you need to use {@link ConfigCategory#createBuilder()} - * - * @see YetAnotherConfigLib#categories() - */ - public Builder categories(@NotNull Collection<? extends ConfigCategory> categories) { - Validate.notNull(categories, "`categories` cannot be null"); - - this.categories.addAll(categories); - return this; - } - - /** - * Used to define a save function for when user clicks the Save Changes button - * - * @see YetAnotherConfigLib#saveFunction() - */ - public Builder save(@NotNull Runnable saveFunction) { - Validate.notNull(saveFunction, "`saveFunction` cannot be null"); - - this.saveFunction = saveFunction; - return this; - } - - /** - * Defines a consumer that is accepted every time the YACL screen initialises - * - * @see YetAnotherConfigLib#initConsumer() - */ - public Builder screenInit(@NotNull Consumer<YACLScreen> initConsumer) { - Validate.notNull(initConsumer, "`initConsumer` cannot be null"); - - this.initConsumer = initConsumer; - return this; - } - - public YetAnotherConfigLib build() { - Validate.notNull(title, "`title must not be null to build `YetAnotherConfigLib`"); - Validate.notEmpty(categories, "`categories` must not be empty to build `YetAnotherConfigLib`"); - Validate.isTrue(!categories.stream().allMatch(category -> category instanceof PlaceholderCategory), "At least one regular category is required to build `YetAnotherConfigLib`"); - - return new YetAnotherConfigLibImpl(title, ImmutableList.copyOf(categories), saveFunction, initConsumer); - } - } -} diff --git a/src/main/java/dev/isxander/yacl/api/utils/Dimension.java b/src/main/java/dev/isxander/yacl/api/utils/Dimension.java deleted file mode 100644 index 0de0a58..0000000 --- a/src/main/java/dev/isxander/yacl/api/utils/Dimension.java +++ /dev/null @@ -1,33 +0,0 @@ -package dev.isxander.yacl.api.utils; - -import dev.isxander.yacl.impl.utils.DimensionIntegerImpl; - -public interface Dimension<T extends Number> { - T x(); - T y(); - - T width(); - T height(); - - T xLimit(); - T yLimit(); - - T centerX(); - T centerY(); - - boolean isPointInside(T x, T y); - - MutableDimension<T> clone(); - - Dimension<T> withX(T x); - Dimension<T> withY(T y); - Dimension<T> withWidth(T width); - Dimension<T> withHeight(T height); - - Dimension<T> moved(T x, T y); - Dimension<T> expanded(T width, T height); - - static MutableDimension<Integer> ofInt(int x, int y, int width, int height) { - return new DimensionIntegerImpl(x, y, width, height); - } -} diff --git a/src/main/java/dev/isxander/yacl/api/utils/MutableDimension.java b/src/main/java/dev/isxander/yacl/api/utils/MutableDimension.java deleted file mode 100644 index eff0186..0000000 --- a/src/main/java/dev/isxander/yacl/api/utils/MutableDimension.java +++ /dev/null @@ -1,11 +0,0 @@ -package dev.isxander.yacl.api.utils; - -public interface MutableDimension<T extends Number> extends Dimension<T> { - MutableDimension<T> setX(T x); - MutableDimension<T> setY(T y); - MutableDimension<T> setWidth(T width); - MutableDimension<T> setHeight(T height); - - MutableDimension<T> move(T x, T y); - MutableDimension<T> expand(T width, T height); -} diff --git a/src/main/java/dev/isxander/yacl/api/utils/OptionUtils.java b/src/main/java/dev/isxander/yacl/api/utils/OptionUtils.java deleted file mode 100644 index ab46b5b..0000000 --- a/src/main/java/dev/isxander/yacl/api/utils/OptionUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -package dev.isxander.yacl.api.utils; - -import dev.isxander.yacl.api.ConfigCategory; -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.api.OptionGroup; -import dev.isxander.yacl.api.YetAnotherConfigLib; - -import java.util.function.Consumer; -import java.util.function.Function; - -public class OptionUtils { - /** - * Consumes all options, ignoring groups and categories. - * When consumer returns true, this function stops iterating. - */ - public static void consumeOptions(YetAnotherConfigLib yacl, Function<Option<?>, Boolean> consumer) { - for (ConfigCategory category : yacl.categories()) { - for (OptionGroup group : category.groups()) { - for (Option<?> option : group.options()) { - if (consumer.apply(option)) return; - } - } - } - } - - /** - * Consumes all options, ignoring groups and categories. - * - * @see OptionUtils#consumeOptions(YetAnotherConfigLib, Function) - */ - public static void forEachOptions(YetAnotherConfigLib yacl, Consumer<Option<?>> consumer) { - consumeOptions(yacl, (opt) -> { - consumer.accept(opt); - return false; - }); - } -} diff --git a/src/main/java/dev/isxander/yacl/config/ConfigInstance.java b/src/main/java/dev/isxander/yacl/config/ConfigInstance.java index a7c013c..8795eb1 100644 --- a/src/main/java/dev/isxander/yacl/config/ConfigInstance.java +++ b/src/main/java/dev/isxander/yacl/config/ConfigInstance.java @@ -1,9 +1,6 @@ package dev.isxander.yacl.config; -import dev.isxander.yacl.api.YetAnotherConfigLib; - import java.lang.reflect.InvocationTargetException; -import java.util.function.BiFunction; /** * Responsible for handing the actual config data type. @@ -46,10 +43,6 @@ public abstract class ConfigInstance<T> { return this.configClass; } - public YetAnotherConfigLib buildConfig(BiFunction<ConfigInstance<T>, YetAnotherConfigLib.Builder, YetAnotherConfigLib.Builder> builder) { - return builder.apply(this, YetAnotherConfigLib.createBuilder().save(this::save)).build(); - } - public abstract void save(); public abstract void load(); } diff --git a/src/main/java/dev/isxander/yacl/gui/AbstractWidget.java b/src/main/java/dev/isxander/yacl/gui/AbstractWidget.java deleted file mode 100644 index bede0ae..0000000 --- a/src/main/java/dev/isxander/yacl/gui/AbstractWidget.java +++ /dev/null @@ -1,108 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.systems.RenderSystem; -import dev.isxander.yacl.api.utils.Dimension; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.Drawable; -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.client.gui.Element; -import net.minecraft.client.gui.Selectable; -import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; -import net.minecraft.client.gui.widget.ClickableWidget; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.sound.SoundEvents; - -import java.awt.*; - -public abstract class AbstractWidget implements Element, Drawable, Selectable { - protected final MinecraftClient client = MinecraftClient.getInstance(); - protected final TextRenderer textRenderer = client.textRenderer; - protected final int inactiveColor = 0xFFA0A0A0; - - private Dimension<Integer> dim; - - public AbstractWidget(Dimension<Integer> dim) { - this.dim = dim; - } - - public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) { - - } - - public boolean canReset() { - return false; - } - - @Override - public boolean isMouseOver(double mouseX, double mouseY) { - if (dim == null) return false; - return this.dim.isPointInside((int) mouseX, (int) mouseY); - } - - public void setDimension(Dimension<Integer> dim) { - this.dim = dim; - } - - public Dimension<Integer> getDimension() { - return dim; - } - - @Override - public SelectionType getType() { - return SelectionType.NONE; - } - - public void unfocus() { - - } - - public boolean matchesSearch(String query) { - return true; - } - - @Override - public void appendNarrations(NarrationMessageBuilder builder) { - - } - - protected void drawButtonRect(MatrixStack matrices, int x1, int y1, int x2, int y2, boolean hovered, boolean enabled) { - if (x1 > x2) { - int xx1 = x1; - x1 = x2; - x2 = xx1; - } - if (y1 > y2) { - int yy1 = y1; - y1 = y2; - y2 = yy1; - } - int width = x2 - x1; - int height = y2 - y1; - - RenderSystem.setShader(GameRenderer::getPositionTexProgram); - RenderSystem.setShaderTexture(0, ClickableWidget.WIDGETS_TEXTURE); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - int i = !enabled ? 0 : hovered ? 2 : 1; - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.enableDepthTest(); - DrawableHelper.drawTexture(matrices, x1, y1, 0, 0, 46 + i * 20, width / 2, height, 256, 256); - DrawableHelper.drawTexture(matrices, x1 + width / 2, y1, 0, 200 - width / 2f, 46 + i * 20, width / 2, height, 256, 256); - } - - protected int multiplyColor(int hex, float amount) { - Color color = new Color(hex, true); - - return new Color(Math.max((int)(color.getRed() *amount), 0), - Math.max((int)(color.getGreen()*amount), 0), - Math.max((int)(color.getBlue() *amount), 0), - color.getAlpha()).getRGB(); - } - - public void playDownSound() { - MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/CategoryListWidget.java b/src/main/java/dev/isxander/yacl/gui/CategoryListWidget.java deleted file mode 100644 index 46a9fdf..0000000 --- a/src/main/java/dev/isxander/yacl/gui/CategoryListWidget.java +++ /dev/null @@ -1,96 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.systems.RenderSystem; -import dev.isxander.yacl.api.ConfigCategory; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.Element; -import net.minecraft.client.gui.Selectable; -import net.minecraft.client.gui.widget.ElementListWidget; -import net.minecraft.client.util.math.MatrixStack; - -import java.util.List; - -public class CategoryListWidget extends ElementListWidget<CategoryListWidget.CategoryEntry> { - private final YACLScreen yaclScreen; - - public CategoryListWidget(MinecraftClient client, YACLScreen yaclScreen, int screenWidth, int screenHeight) { - super(client, screenWidth / 3, yaclScreen.searchFieldWidget.getY() - 5, 0, yaclScreen.searchFieldWidget.getY() - 5, 21); - this.yaclScreen = yaclScreen; - setRenderBackground(false); - setRenderHorizontalShadows(false); - - for (ConfigCategory category : yaclScreen.config.categories()) { - addEntry(new CategoryEntry(category)); - } - } - - @Override - protected void renderList(MatrixStack matrices, int mouseX, int mouseY, float delta) { - double d = this.client.getWindow().getScaleFactor(); - RenderSystem.enableScissor(0, (int)((yaclScreen.height - bottom) * d), (int)(width * d), (int)(height * d)); - super.renderList(matrices, mouseX, mouseY, delta); - RenderSystem.disableScissor(); - } - - public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) { - for (CategoryEntry entry : children()) { - entry.postRender(matrices, mouseX, mouseY, delta); - } - } - - @Override - public int getRowWidth() { - return Math.min(width - width / 10, 396); - } - - @Override - public int getRowLeft() { - return super.getRowLeft() - 2; - } - - @Override - protected int getScrollbarPositionX() { - return width - 2; - } - - public class CategoryEntry extends Entry<CategoryEntry> { - private final CategoryWidget categoryButton; - public final int categoryIndex; - - public CategoryEntry(ConfigCategory category) { - this.categoryIndex = yaclScreen.config.categories().indexOf(category); - categoryButton = new CategoryWidget( - yaclScreen, - category, - categoryIndex, - getRowLeft(), 0, - getRowWidth(), 20 - ); - } - - @Override - public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - if (mouseY > bottom) { - mouseY = -20; - } - - categoryButton.setY(y); - categoryButton.render(matrices, mouseX, mouseY, tickDelta); - } - - private void postRender(MatrixStack matrices, int mouseX, int mouseY, float tickDelta) { - categoryButton.renderHoveredTooltip(matrices); - } - - @Override - public List<? extends Element> children() { - return ImmutableList.of(categoryButton); - } - - @Override - public List<? extends Selectable> selectableChildren() { - return ImmutableList.of(categoryButton); - } - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/CategoryWidget.java b/src/main/java/dev/isxander/yacl/gui/CategoryWidget.java deleted file mode 100644 index 3c5d8d2..0000000 --- a/src/main/java/dev/isxander/yacl/gui/CategoryWidget.java +++ /dev/null @@ -1,31 +0,0 @@ -package dev.isxander.yacl.gui; - -import dev.isxander.yacl.api.ConfigCategory; -import net.minecraft.client.sound.SoundManager; - -public class CategoryWidget extends TooltipButtonWidget { - private final int categoryIndex; - - public CategoryWidget(YACLScreen screen, ConfigCategory category, int categoryIndex, int x, int y, int width, int height) { - super(screen, x, y, width, height, category.name(), category.tooltip(), btn -> { - screen.searchFieldWidget.setText(""); - screen.changeCategory(categoryIndex); - }); - this.categoryIndex = categoryIndex; - } - - private boolean isCurrentCategory() { - return ((YACLScreen) screen).getCurrentCategoryIdx() == categoryIndex; - } - - @Override - protected int getYImage(boolean hovered) { - return super.getYImage(hovered || isCurrentCategory()); - } - - @Override - public void playDownSound(SoundManager soundManager) { - if (!isCurrentCategory()) - super.playDownSound(soundManager); - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/LowProfileButtonWidget.java b/src/main/java/dev/isxander/yacl/gui/LowProfileButtonWidget.java deleted file mode 100644 index 4823428..0000000 --- a/src/main/java/dev/isxander/yacl/gui/LowProfileButtonWidget.java +++ /dev/null @@ -1,29 +0,0 @@ -package dev.isxander.yacl.gui; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.tooltip.Tooltip; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.Text; -import net.minecraft.util.math.MathHelper; - -public class LowProfileButtonWidget extends ButtonWidget { - public LowProfileButtonWidget(int x, int y, int width, int height, Text message, PressAction onPress) { - super(x, y, width, height, message, onPress, ButtonWidget.DEFAULT_NARRATION_SUPPLIER); - } - - public LowProfileButtonWidget(int x, int y, int width, int height, Text message, PressAction onPress, Tooltip tooltip) { - this(x, y, width, height, message, onPress); - setTooltip(tooltip); - } - - @Override - public void renderButton(MatrixStack matrices, int mouseX, int mouseY, float delta) { - if (!isHovered()) { - int j = this.active ? 0xFFFFFF : 0xA0A0A0; - drawCenteredText(matrices, MinecraftClient.getInstance().textRenderer, this.getMessage(), this.getX() + this.width / 2, this.getY() + (this.height - 8) / 2, j | MathHelper.ceil(this.alpha * 255.0F) << 24); - } else { - super.renderButton(matrices, mouseX, mouseY, delta); - } - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java b/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java deleted file mode 100644 index eed3aff..0000000 --- a/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java +++ /dev/null @@ -1,470 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.api.ConfigCategory; -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.api.OptionGroup; -import dev.isxander.yacl.api.utils.Dimension; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.MultilineText; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.Element; -import net.minecraft.client.gui.Selectable; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; -import net.minecraft.client.gui.screen.narration.NarrationPart; -import net.minecraft.client.gui.widget.ElementListWidget; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.Text; -import net.minecraft.util.math.MathHelper; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.function.Supplier; - -public class OptionListWidget extends ElementListWidget<OptionListWidget.Entry> { - private final YACLScreen yaclScreen; - private boolean singleCategory = false; - - private ImmutableList<Entry> viewableChildren; - - private double smoothScrollAmount = getScrollAmount(); - private boolean returnSmoothAmount = false; - - public OptionListWidget(YACLScreen screen, MinecraftClient client, int width, int height) { - super(client, width / 3 * 2, height, 0, height, 22); - this.yaclScreen = screen; - left = width - this.width; - right = width; - - refreshOptions(); - } - - public void refreshOptions() { - clearEntries(); - - List<ConfigCategory> categories = new ArrayList<>(); - if (yaclScreen.getCurrentCategoryIdx() == -1) { - categories.addAll(yaclScreen.config.categories()); - } else { - categories.add(yaclScreen.config.categories().get(yaclScreen.getCurrentCategoryIdx())); - } - singleCategory = categories.size() == 1; - - for (ConfigCategory category : categories) { - for (OptionGroup group : category.groups()) { - Supplier<Boolean> viewableSupplier; - GroupSeparatorEntry groupSeparatorEntry = null; - if (!group.isRoot()) { - groupSeparatorEntry = new GroupSeparatorEntry(group, yaclScreen); - viewableSupplier = groupSeparatorEntry::isExpanded; - addEntry(groupSeparatorEntry); - } else { - viewableSupplier = () -> true; - } - - List<OptionEntry> optionEntries = new ArrayList<>(); - for (Option<?> option : group.options()) { - OptionEntry entry = new OptionEntry(option, category, group, option.controller().provideWidget(yaclScreen, Dimension.ofInt(getRowLeft(), 0, getRowWidth(), 20)), viewableSupplier); - addEntry(entry); - optionEntries.add(entry); - } - - if (groupSeparatorEntry != null) { - groupSeparatorEntry.setOptionEntries(optionEntries); - } - } - } - - recacheViewableChildren(); - setScrollAmount(0); - } - - public void expandAllGroups() { - for (Entry entry : super.children()) { - if (entry instanceof GroupSeparatorEntry groupSeparatorEntry) { - groupSeparatorEntry.setExpanded(true); - } - } - } - - /* - below code is licensed from cloth-config under LGPL3 - modified to inherit vanilla's EntryListWidget and use yarn mappings - */ - - @Nullable - @Override - protected Entry getEntryAtPosition(double x, double y) { - int listMiddleX = this.left + this.width / 2; - int minX = listMiddleX - this.getRowWidth() / 2; - int maxX = listMiddleX + this.getRowWidth() / 2; - int currentY = MathHelper.floor(y - (double) this.top) - this.headerHeight + (int) this.getScrollAmount() - 4; - int itemY = 0; - int itemIndex = -1; - for (int i = 0; i < children().size(); i++) { - Entry item = children().get(i); - itemY += item.getItemHeight(); - if (itemY > currentY) { - itemIndex = i; - break; - } - } - return x < (double) this.getScrollbarPositionX() && x >= minX && y <= maxX && itemIndex >= 0 && currentY >= 0 && itemIndex < this.getEntryCount() ? this.children().get(itemIndex) : null; - } - - @Override - protected int getMaxPosition() { - return children().stream().map(Entry::getItemHeight).reduce(0, Integer::sum) + headerHeight; - } - - @Override - protected void centerScrollOn(Entry entry) { - double d = (this.bottom - this.top) / -2d; - for (int i = 0; i < this.children().indexOf(entry) && i < this.getEntryCount(); i++) - d += children().get(i).getItemHeight(); - this.setScrollAmount(d); - } - - @Override - protected int getRowTop(int index) { - int integer = top + 4 - (int) this.getScrollAmount() + headerHeight; - for (int i = 0; i < children().size() && i < index; i++) - integer += children().get(i).getItemHeight(); - return integer; - } - - @Override - protected void renderList(MatrixStack matrices, int mouseX, int mouseY, float delta) { - int left = this.getRowLeft(); - int right = this.getRowWidth(); - int count = this.getEntryCount(); - - for(int i = 0; i < count; ++i) { - Entry entry = children().get(i); - int top = this.getRowTop(i); - int bottom = top + entry.getItemHeight(); - int entryHeight = entry.getItemHeight() - 4; - if (bottom >= this.top && top <= this.bottom) { - this.renderEntry(matrices, mouseX, mouseY, delta, i, left, top, right, entryHeight); - } - } - } - - /* END cloth config code */ - - @Override - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - smoothScrollAmount = MathHelper.lerp(MinecraftClient.getInstance().getLastFrameDuration() * 0.5, smoothScrollAmount, getScrollAmount()); - returnSmoothAmount = true; - super.render(matrices, mouseX, mouseY, delta); - returnSmoothAmount = false; - } - - /** - * awful code to only use smooth scroll state when rendering, - * not other code that needs target scroll amount - */ - @Override - public double getScrollAmount() { - if (returnSmoothAmount) - return smoothScrollAmount; - - return super.getScrollAmount(); - } - - public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) { - for (Entry entry : children()) { - entry.postRender(matrices, mouseX, mouseY, delta); - } - } - - @Override - public int getRowWidth() { - return Math.min(396, (int)(width / 1.3f)); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - for (Entry child : children()) { - if (child != getEntryAtPosition(mouseX, mouseY) && child instanceof OptionEntry optionEntry) - optionEntry.widget.unfocus(); - } - - return super.mouseClicked(mouseX, mouseY, button); - } - - @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - for (Entry child : children()) { - if (child.mouseScrolled(mouseX, mouseY, amount)) - return true; - } - - this.setScrollAmount(this.getScrollAmount() - amount * 20 /* * (double) (getMaxScroll() / getEntryCount()) / 2.0D */); - return true; - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - for (Entry child : children()) { - if (child.keyPressed(keyCode, scanCode, modifiers)) - return true; - } - - return super.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - public boolean charTyped(char chr, int modifiers) { - for (Entry child : children()) { - if (child.charTyped(chr, modifiers)) - return true; - } - - return super.charTyped(chr, modifiers); - } - - @Override - protected int getScrollbarPositionX() { - return left + width - (int)(width * 0.05f); - } - - @Override - protected void renderBackground(MatrixStack matrices) { - setRenderBackground(client.world == null); - if (client.world != null) - fill(matrices, left, top, right, bottom, 0x6B000000); - } - - public void recacheViewableChildren() { - this.viewableChildren = ImmutableList.copyOf(super.children().stream().filter(Entry::isViewable).toList()); - - // update y positions before they need to be rendered are rendered - int i = 0; - for (Entry entry : viewableChildren) { - if (entry instanceof OptionEntry optionEntry) - optionEntry.widget.setDimension(optionEntry.widget.getDimension().withY(getRowTop(i))); - i++; - } - } - - @Override - public List<Entry> children() { - return viewableChildren; - } - - public abstract class Entry extends ElementListWidget.Entry<Entry> { - public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) { - - } - - public boolean isViewable() { - return true; - } - - public int getItemHeight() { - return 22; - } - - protected boolean isHovered() { - return Objects.equals(getHoveredEntry(), this); - } - } - - public class OptionEntry extends Entry { - public final Option<?> option; - public final ConfigCategory category; - public final OptionGroup group; - - public final AbstractWidget widget; - private final Supplier<Boolean> viewableSupplier; - - private final TextScaledButtonWidget resetButton; - - private final String categoryName; - private final String groupName; - - private OptionEntry(Option<?> option, ConfigCategory category, OptionGroup group, AbstractWidget widget, Supplier<Boolean> viewableSupplier) { - this.option = option; - this.category = category; - this.group = group; - this.widget = widget; - this.viewableSupplier = viewableSupplier; - this.categoryName = category.name().getString().toLowerCase(); - this.groupName = group.name().getString().toLowerCase(); - if (this.widget.canReset()) { - this.widget.setDimension(this.widget.getDimension().expanded(-21, 0)); - this.resetButton = new TextScaledButtonWidget(widget.getDimension().xLimit() + 1, -50, 20, 20, 2f, Text.of("\u21BB"), button -> { - option.requestSetDefault(); - }); - option.addListener((opt, val) -> this.resetButton.active = !opt.isPendingValueDefault() && opt.available()); - this.resetButton.active = !option.isPendingValueDefault() && option.available(); - } else { - this.resetButton = null; - } - } - - @Override - public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - widget.setDimension(widget.getDimension().withY(y)); - - widget.render(matrices, mouseX, mouseY, tickDelta); - - if (resetButton != null) { - resetButton.setY(y); - resetButton.render(matrices, mouseX, mouseY, tickDelta); - } - } - - @Override - public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) { - widget.postRender(matrices, mouseX, mouseY, delta); - } - - @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - return widget.mouseScrolled(mouseX, mouseY, amount); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - return widget.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - public boolean charTyped(char chr, int modifiers) { - return widget.charTyped(chr, modifiers); - } - - @Override - public boolean isViewable() { - String query = yaclScreen.searchFieldWidget.getText(); - return viewableSupplier.get() - && (yaclScreen.searchFieldWidget.isEmpty() - || (!singleCategory && categoryName.contains(query)) - || groupName.contains(query) - || widget.matchesSearch(query)); - } - - @Override - public int getItemHeight() { - return widget.getDimension().height() + 2; - } - - @Override - public List<? extends Selectable> selectableChildren() { - if (resetButton == null) - return ImmutableList.of(widget); - - return ImmutableList.of(widget, resetButton); - } - - @Override - public List<? extends Element> children() { - if (resetButton == null) - return ImmutableList.of(widget); - - return ImmutableList.of(widget, resetButton); - } - } - - public class GroupSeparatorEntry extends Entry { - private final OptionGroup group; - private final MultilineText wrappedName; - private final MultilineText wrappedTooltip; - - private final LowProfileButtonWidget expandMinimizeButton; - - private final Screen screen; - private final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; - - private boolean groupExpanded; - - private List<OptionEntry> optionEntries; - - private int y; - - private GroupSeparatorEntry(OptionGroup group, Screen screen) { - this.group = group; - this.screen = screen; - this.wrappedName = MultilineText.create(textRenderer, group.name(), getRowWidth() - 45); - this.wrappedTooltip = MultilineText.create(textRenderer, group.tooltip(), screen.width / 3 * 2 - 10); - this.groupExpanded = !group.collapsed(); - this.expandMinimizeButton = new LowProfileButtonWidget(0, 0, 20, 20, Text.empty(), btn -> { - setExpanded(!isExpanded()); - recacheViewableChildren(); - }); - updateExpandMinimizeText(); - } - - @Override - public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - this.y = y; - - expandMinimizeButton.setX(x); - expandMinimizeButton.setY(y + entryHeight / 2 - expandMinimizeButton.getHeight() / 2); - expandMinimizeButton.render(matrices, mouseX, mouseY, tickDelta); - - wrappedName.drawCenterWithShadow(matrices, x + entryWidth / 2, y + getYPadding()); - } - - @Override - public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) { - if (isHovered() && !expandMinimizeButton.isMouseOver(mouseX, mouseY)) { - YACLScreen.renderMultilineTooltip(matrices, textRenderer, wrappedTooltip, getRowLeft() + getRowWidth() / 2, y - 3, y + getItemHeight() + 3, screen.width, screen.height); - } - } - - public boolean isExpanded() { - return groupExpanded; - } - - public void setExpanded(boolean expanded) { - this.groupExpanded = expanded; - updateExpandMinimizeText(); - } - - private void updateExpandMinimizeText() { - expandMinimizeButton.setMessage(Text.of(isExpanded() ? "\u25BC" : "\u25B6")); - } - - public void setOptionEntries(List<OptionEntry> optionEntries) { - this.optionEntries = optionEntries; - } - - @Override - public boolean isViewable() { - return yaclScreen.searchFieldWidget.isEmpty() || optionEntries.stream().anyMatch(OptionEntry::isViewable); - } - - @Override - public int getItemHeight() { - return Math.max(wrappedName.count(), 1) * textRenderer.fontHeight + getYPadding() * 2; - } - - private int getYPadding() { - return 6; - } - - @Override - public List<? extends Selectable> selectableChildren() { - return ImmutableList.of(new Selectable() { - @Override - public Selectable.SelectionType getType() { - return Selectable.SelectionType.HOVERED; - } - - @Override - public void appendNarrations(NarrationMessageBuilder builder) { - builder.put(NarrationPart.TITLE, group.name()); - } - }); - } - - @Override - public List<? extends Element> children() { - return ImmutableList.of(expandMinimizeButton); - } - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/RequireRestartScreen.java b/src/main/java/dev/isxander/yacl/gui/RequireRestartScreen.java deleted file mode 100644 index 3c46738..0000000 --- a/src/main/java/dev/isxander/yacl/gui/RequireRestartScreen.java +++ /dev/null @@ -1,16 +0,0 @@ -package dev.isxander.yacl.gui; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.ConfirmScreen; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; - -public class RequireRestartScreen extends ConfirmScreen { - public RequireRestartScreen(Screen parent) { - super(option -> { - if (option) MinecraftClient.getInstance().scheduleStop(); - else MinecraftClient.getInstance().setScreen(parent); - }, Text.translatable("yacl.restart.title").formatted(Formatting.RED, Formatting.BOLD), Text.translatable("yacl.restart.message"), Text.translatable("yacl.restart.yes"), Text.translatable("yacl.restart.no")); - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/SearchFieldWidget.java b/src/main/java/dev/isxander/yacl/gui/SearchFieldWidget.java deleted file mode 100644 index 5b7c9dc..0000000 --- a/src/main/java/dev/isxander/yacl/gui/SearchFieldWidget.java +++ /dev/null @@ -1,62 +0,0 @@ -package dev.isxander.yacl.gui; - -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.widget.TextFieldWidget; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.Text; - -public class SearchFieldWidget extends TextFieldWidget { - private Text emptyText; - private final YACLScreen yaclScreen; - private final TextRenderer textRenderer; - - private boolean isEmpty = true; - - public SearchFieldWidget(YACLScreen yaclScreen, TextRenderer textRenderer, int x, int y, int width, int height, Text text, Text emptyText) { - super(textRenderer, x, y, width, height, text); - setChangedListener(string -> update()); - setTextPredicate(string -> !string.endsWith(" ") && !string.startsWith(" ")); - this.yaclScreen = yaclScreen; - this.textRenderer = textRenderer; - this.emptyText = emptyText; - } - - @Override - public void renderButton(MatrixStack matrices, int mouseX, int mouseY, float delta) { - super.renderButton(matrices, mouseX, mouseY, delta); - if (isVisible() && isEmpty()) { - textRenderer.drawWithShadow(matrices, emptyText, getX() + 4, this.getY() + (this.height - 8) / 2f, 0x707070); - } - } - - private void update() { - boolean wasEmpty = isEmpty; - isEmpty = getText().isEmpty(); - - if (isEmpty && wasEmpty) - return; - - if (!isEmpty && yaclScreen.getCurrentCategoryIdx() != -1) - yaclScreen.changeCategory(-1); - if (isEmpty && yaclScreen.getCurrentCategoryIdx() == -1) - yaclScreen.changeCategory(0); - - yaclScreen.optionList.expandAllGroups(); - yaclScreen.optionList.recacheViewableChildren(); - - yaclScreen.optionList.setScrollAmount(0); - yaclScreen.categoryList.setScrollAmount(0); - } - - public boolean isEmpty() { - return isEmpty; - } - - public Text getEmptyText() { - return emptyText; - } - - public void setEmptyText(Text emptyText) { - this.emptyText = emptyText; - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/TextScaledButtonWidget.java b/src/main/java/dev/isxander/yacl/gui/TextScaledButtonWidget.java deleted file mode 100644 index 9f153f6..0000000 --- a/src/main/java/dev/isxander/yacl/gui/TextScaledButtonWidget.java +++ /dev/null @@ -1,44 +0,0 @@ -package dev.isxander.yacl.gui; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.tooltip.Tooltip; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.OrderedText; -import net.minecraft.text.Text; -import net.minecraft.util.math.MathHelper; - -public class TextScaledButtonWidget extends ButtonWidget { - public float textScale; - - public TextScaledButtonWidget(int x, int y, int width, int height, float textScale, Text message, PressAction onPress) { - super(x, y, width, height, message, onPress, ButtonWidget.DEFAULT_NARRATION_SUPPLIER); - this.textScale = textScale; - } - - public TextScaledButtonWidget(int x, int y, int width, int height, float textScale, Text message, PressAction onPress, Tooltip tooltip) { - this(x, y, width, height, textScale, message, onPress); - setTooltip(tooltip); - } - - @Override - public void renderButton(MatrixStack matrices, int mouseX, int mouseY, float delta) { - // prevents super from rendering text - Text message = getMessage(); - setMessage(Text.empty()); - - super.renderButton(matrices, mouseX, mouseY, delta); - - setMessage(message); - int j = this.active ? 16777215 : 10526880; - OrderedText orderedText = getMessage().asOrderedText(); - TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; - - matrices.push(); - matrices.translate(((this.getX() + this.width / 2f) - textRenderer.getWidth(orderedText) * textScale / 2), (float)this.getY() + (this.height - 8 * textScale) / 2f / textScale, 0); - matrices.scale(textScale, textScale, 1); - textRenderer.drawWithShadow(matrices, orderedText, 0, 0, j | MathHelper.ceil(this.alpha * 255.0F) << 24); - matrices.pop(); - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/TooltipButtonWidget.java b/src/main/java/dev/isxander/yacl/gui/TooltipButtonWidget.java deleted file mode 100644 index 706765a..0000000 --- a/src/main/java/dev/isxander/yacl/gui/TooltipButtonWidget.java +++ /dev/null @@ -1,30 +0,0 @@ -package dev.isxander.yacl.gui; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.MultilineText; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.Text; - -public class TooltipButtonWidget extends ButtonWidget { - - protected final Screen screen; - protected MultilineText wrappedDescription; - - public TooltipButtonWidget(Screen screen, int x, int y, int width, int height, Text message, Text tooltip, PressAction onPress) { - super(x, y, width, height, message, onPress, ButtonWidget.DEFAULT_NARRATION_SUPPLIER); - this.screen = screen; - setTooltip(tooltip); - } - - public void renderHoveredTooltip(MatrixStack matrices) { - if (isHovered()) { - YACLScreen.renderMultilineTooltip(matrices, MinecraftClient.getInstance().textRenderer, wrappedDescription, getX() + width / 2, getY() - 4, getY() + height + 4, screen.width, screen.height); - } - } - - public void setTooltip(Text tooltip) { - wrappedDescription = MultilineText.create(MinecraftClient.getInstance().textRenderer, tooltip, screen.width / 3 - 5); - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/YACLScreen.java b/src/main/java/dev/isxander/yacl/gui/YACLScreen.java deleted file mode 100644 index e36c8e8..0000000 --- a/src/main/java/dev/isxander/yacl/gui/YACLScreen.java +++ /dev/null @@ -1,269 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.systems.RenderSystem; -import dev.isxander.yacl.api.*; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.api.utils.MutableDimension; -import dev.isxander.yacl.api.utils.OptionUtils; -import net.minecraft.client.font.MultilineText; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.Element; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.render.*; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import org.joml.Matrix4f; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; - -public class YACLScreen extends Screen { - public final YetAnotherConfigLib config; - private int currentCategoryIdx; - - private final Screen parent; - - public OptionListWidget optionList; - public CategoryListWidget categoryList; - public TooltipButtonWidget finishedSaveButton, cancelResetButton, undoButton; - public SearchFieldWidget searchFieldWidget; - - public Text saveButtonMessage, saveButtonTooltipMessage; - private int saveButtonMessageTime; - - - public YACLScreen(YetAnotherConfigLib config, Screen parent) { - super(config.title()); - this.config = config; - this.parent = parent; - this.currentCategoryIdx = 0; - } - - @Override - protected void init() { - int columnWidth = width / 3; - int padding = columnWidth / 20; - columnWidth = Math.min(columnWidth, 400); - int paddedWidth = columnWidth - padding * 2; - - MutableDimension<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) -> { - saveButtonMessage = null; - - if (pendingChanges()) { - Set<OptionFlag> flags = new HashSet<>(); - OptionUtils.forEachOptions(config, option -> { - if (option.applyValue()) { - flags.addAll(option.flags()); - } - }); - OptionUtils.forEachOptions(config, option -> { - if (option.changed()) { - option.forgetPendingValue(); - } - }); - config.saveFunction().run(); - - flags.forEach(flag -> flag.accept(client)); - } else close(); - }); - actionDim.expand(-actionDim.width() / 2 - 2, 0).move(-actionDim.width() / 2 - 2, -22); - cancelResetButton = new TooltipButtonWidget(this, actionDim.x() - actionDim.width() / 2, actionDim.y(), actionDim.width(), actionDim.height(), Text.empty(), Text.empty(), (btn) -> { - if (pendingChanges()) { - OptionUtils.forEachOptions(config, Option::forgetPendingValue); - close(); - } else { - OptionUtils.forEachOptions(config, Option::requestSetDefault); - } - - }); - actionDim.move(actionDim.width() + 4, 0); - undoButton = new TooltipButtonWidget(this, actionDim.x() - actionDim.width() / 2, actionDim.y(), actionDim.width(), actionDim.height(), Text.translatable("yacl.gui.undo"), Text.translatable("yacl.gui.undo.tooltip"), (btn) -> { - OptionUtils.forEachOptions(config, Option::forgetPendingValue); - }); - - searchFieldWidget = new SearchFieldWidget(this, textRenderer, width / 3 / 2 - paddedWidth / 2 + 1, undoButton.getY() - 22, paddedWidth - 2, 18, Text.translatable("gui.recipebook.search_hint"), Text.translatable("gui.recipebook.search_hint")); - - categoryList = new CategoryListWidget(client, this, width, height); - addSelectableChild(categoryList); - - updateActionAvailability(); - addDrawableChild(searchFieldWidget); - addDrawableChild(cancelResetButton); - addDrawableChild(undoButton); - addDrawableChild(finishedSaveButton); - - optionList = new OptionListWidget(this, client, width, height); - addSelectableChild(optionList); - - config.initConsumer().accept(this); - } - - @Override - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - renderBackground(matrices); - - super.render(matrices, mouseX, mouseY, delta); - categoryList.render(matrices, mouseX, mouseY, delta); - searchFieldWidget.render(matrices, mouseX, mouseY, delta); - optionList.render(matrices, mouseX, mouseY, delta); - - categoryList.postRender(matrices, mouseX, mouseY, delta); - optionList.postRender(matrices, mouseX, mouseY, delta); - - for (Element child : children()) { - if (child instanceof TooltipButtonWidget tooltipButtonWidget) { - tooltipButtonWidget.renderHoveredTooltip(matrices); - } - } - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (optionList.keyPressed(keyCode, scanCode, modifiers)) { - return true; - } - - return super.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - public boolean charTyped(char chr, int modifiers) { - if (optionList.charTyped(chr, modifiers)) { - return true; - } - - return super.charTyped(chr, modifiers); - } - - public void changeCategory(int idx) { - if (idx == currentCategoryIdx) - return; - - if (idx != -1 && config.categories().get(idx) instanceof PlaceholderCategory placeholderCategory) { - client.setScreen(placeholderCategory.screen().apply(client, this)); - } else { - currentCategoryIdx = idx; - optionList.refreshOptions(); - } - } - - public int getCurrentCategoryIdx() { - return currentCategoryIdx; - } - - private void updateActionAvailability() { - boolean pendingChanges = pendingChanges(); - - undoButton.active = pendingChanges; - finishedSaveButton.setMessage(pendingChanges ? Text.translatable("yacl.gui.save") : Text.translatable("gui.done")); - finishedSaveButton.setTooltip(pendingChanges ? Text.translatable("yacl.gui.save.tooltip") : Text.translatable("yacl.gui.finished.tooltip")); - cancelResetButton.setMessage(pendingChanges ? Text.translatable("gui.cancel") : Text.translatable("controls.reset")); - cancelResetButton.setTooltip(pendingChanges ? Text.translatable("yacl.gui.cancel.tooltip") : Text.translatable("yacl.gui.reset.tooltip")); - } - - @Override - public void tick() { - searchFieldWidget.tick(); - - updateActionAvailability(); - - if (saveButtonMessage != null) { - if (saveButtonMessageTime > 140) { - saveButtonMessage = null; - saveButtonTooltipMessage = null; - saveButtonMessageTime = 0; - } else { - saveButtonMessageTime++; - finishedSaveButton.setMessage(saveButtonMessage); - if (saveButtonTooltipMessage != null) { - finishedSaveButton.setTooltip(saveButtonTooltipMessage); - } - } - } - } - - private void setSaveButtonMessage(Text message, Text tooltip) { - saveButtonMessage = message; - saveButtonTooltipMessage = tooltip; - saveButtonMessageTime = 0; - } - - private boolean pendingChanges() { - AtomicBoolean pendingChanges = new AtomicBoolean(false); - OptionUtils.consumeOptions(config, (option) -> { - if (option.changed()) { - pendingChanges.set(true); - return true; - } - return false; - }); - - return pendingChanges.get(); - } - - @Override - public boolean shouldCloseOnEsc() { - if (pendingChanges()) { - setSaveButtonMessage(Text.translatable("yacl.gui.save_before_exit").formatted(Formatting.RED), Text.translatable("yacl.gui.save_before_exit.tooltip")); - return false; - } - return true; - } - - @Override - public void close() { - client.setScreen(parent); - } - - public static void renderMultilineTooltip(MatrixStack matrices, TextRenderer textRenderer, MultilineText text, int centerX, int yAbove, int yBelow, int screenWidth, int screenHeight) { - if (text.count() > 0) { - int maxWidth = text.getMaxWidth(); - int lineHeight = textRenderer.fontHeight + 1; - int height = text.count() * lineHeight - 1; - - int belowY = yBelow + 12; - int aboveY = yAbove - height + 12; - int maxBelow = screenHeight - (belowY + height); - int minAbove = aboveY - height; - int y = belowY; - if (maxBelow < -8) - y = maxBelow > minAbove ? belowY : aboveY; - - int x = Math.max(centerX - text.getMaxWidth() / 2 - 12, -6); - - int drawX = x + 12; - int drawY = y - 12; - - matrices.push(); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferBuilder = tessellator.getBuffer(); - RenderSystem.setShader(GameRenderer::getPositionColorProgram); - bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); - Matrix4f matrix4f = matrices.peek().getPositionMatrix(); - fillGradient(matrix4f, bufferBuilder, drawX - 3, drawY - 4, drawX + maxWidth + 3, drawY - 3, 400, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, drawX - 3, drawY + height + 3, drawX + maxWidth + 3, drawY + height + 4, 400, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, drawX - 3, drawY - 3, drawX + maxWidth + 3, drawY + height + 3, 400, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, drawX - 4, drawY - 3, drawX - 3, drawY + height + 3, 400, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, drawX + maxWidth + 3, drawY - 3, drawX + maxWidth + 4, drawY + height + 3, 400, -267386864, -267386864); - fillGradient(matrix4f, bufferBuilder, drawX - 3, drawY - 3 + 1, drawX - 3 + 1, drawY + height + 3 - 1, 400, 1347420415, 1344798847); - fillGradient(matrix4f, bufferBuilder, drawX + maxWidth + 2, drawY - 3 + 1, drawX + maxWidth + 3, drawY + height + 3 - 1, 400, 1347420415, 1344798847); - fillGradient(matrix4f, bufferBuilder, drawX - 3, drawY - 3, drawX + maxWidth + 3, drawY - 3 + 1, 400, 1347420415, 1347420415); - fillGradient(matrix4f, bufferBuilder, drawX - 3, drawY + height + 2, drawX + maxWidth + 3, drawY + height + 3, 400, 1344798847, 1344798847); - RenderSystem.enableDepthTest(); - RenderSystem.disableTexture(); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - BufferRenderer.drawWithGlobalProgram(bufferBuilder.end()); - RenderSystem.disableBlend(); - RenderSystem.enableTexture(); - matrices.translate(0.0, 0.0, 400.0); - - text.drawWithShadow(matrices, drawX, drawY, lineHeight, -1); - - matrices.pop(); - } - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/ActionController.java b/src/main/java/dev/isxander/yacl/gui/controllers/ActionController.java deleted file mode 100644 index b8e2cd1..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/ActionController.java +++ /dev/null @@ -1,120 +0,0 @@ -package dev.isxander.yacl.gui.controllers; - -import dev.isxander.yacl.api.ButtonOption; -import dev.isxander.yacl.api.Controller; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.AbstractWidget; -import dev.isxander.yacl.gui.YACLScreen; -import net.minecraft.text.Text; -import org.lwjgl.glfw.GLFW; - -import java.util.function.BiConsumer; - -/** - * Simple controller that simply runs the button action on press - * and renders a {@link} Text on the right. - */ -public class ActionController implements Controller<BiConsumer<YACLScreen, ButtonOption>> { - public static final Text DEFAULT_TEXT = Text.translatable("yacl.control.action.execute"); - - private final ButtonOption option; - private final Text text; - - /** - * Constructs an action controller - * with the default formatter of {@link ActionController#DEFAULT_TEXT} - * - * @param option bound option - */ - public ActionController(ButtonOption option) { - this(option, DEFAULT_TEXT); - } - - /** - * Constructs an action controller - * - * @param option bound option - * @param text text to display - */ - public ActionController(ButtonOption option, Text text) { - this.option = option; - this.text = text; - - } - - /** - * {@inheritDoc} - */ - @Override - public ButtonOption option() { - return option; - } - - /** - * {@inheritDoc} - */ - @Override - public Text formatValue() { - return text; - } - - /** - * {@inheritDoc} - */ - @Override - public AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) { - return new ActionControllerElement(this, screen, widgetDimension); - } - - public static class ActionControllerElement extends ControllerWidget<ActionController> { - private final String buttonString; - - public ActionControllerElement(ActionController control, YACLScreen screen, Dimension<Integer> dim) { - super(control, screen, dim); - buttonString = control.formatValue().getString().toLowerCase(); - } - - public void executeAction() { - playDownSound(); - control.option().action().accept(screen, control.option()); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (isMouseOver(mouseX, mouseY) && isAvailable()) { - executeAction(); - return true; - } - return false; - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (!focused) { - return false; - } - - if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_SPACE || keyCode == GLFW.GLFW_KEY_KP_ENTER) { - executeAction(); - return true; - } - - return false; - } - - @Override - protected int getHoveredControlWidth() { - return getUnhoveredControlWidth(); - } - - @Override - public boolean canReset() { - return false; - } - - @Override - public boolean matchesSearch(String query) { - return super.matchesSearch(query) || buttonString.contains(query); - } - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/BooleanController.java b/src/main/java/dev/isxander/yacl/gui/controllers/BooleanController.java deleted file mode 100644 index 7037ff5..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/BooleanController.java +++ /dev/null @@ -1,156 +0,0 @@ -package dev.isxander.yacl.gui.controllers; - -import dev.isxander.yacl.api.Controller; -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.AbstractWidget; -import dev.isxander.yacl.gui.YACLScreen; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import org.lwjgl.glfw.GLFW; - -import java.util.function.Function; - -/** - * This controller renders a simple formatted {@link Text} - */ -public class BooleanController implements Controller<Boolean> { - - public static final Function<Boolean, Text> ON_OFF_FORMATTER = (state) -> - state - ? Text.translatable("options.on") - : Text.translatable("options.off"); - - public static final Function<Boolean, Text> TRUE_FALSE_FORMATTER = (state) -> - state - ? Text.translatable("yacl.control.boolean.true") - : Text.translatable("yacl.control.boolean.false"); - - public static final Function<Boolean, Text> YES_NO_FORMATTER = (state) -> - state - ? Text.translatable("gui.yes") - : Text.translatable("gui.no"); - - private final Option<Boolean> option; - private final Function<Boolean, Text> valueFormatter; - private final boolean coloured; - - /** - * Constructs a tickbox controller - * with the default value formatter of {@link BooleanController#ON_OFF_FORMATTER} - * - * @param option bound option - */ - public BooleanController(Option<Boolean> option) { - this(option, ON_OFF_FORMATTER, false); - } - - /** - * Constructs a tickbox controller - * with the default value formatter of {@link BooleanController#ON_OFF_FORMATTER} - * - * @param option bound option - * @param coloured value format is green or red depending on the state - */ - public BooleanController(Option<Boolean> option, boolean coloured) { - this(option, ON_OFF_FORMATTER, coloured); - } - - /** - * Constructs a tickbox controller - * - * @param option bound option - * @param valueFormatter format value into any {@link Text} - * @param coloured value format is green or red depending on the state - */ - public BooleanController(Option<Boolean> option, Function<Boolean, Text> valueFormatter, boolean coloured) { - this.option = option; - this.valueFormatter = valueFormatter; - this.coloured = coloured; - } - - /** - * {@inheritDoc} - */ - @Override - public Option<Boolean> option() { - return option; - } - - /** - * {@inheritDoc} - */ - @Override - public Text formatValue() { - return valueFormatter.apply(option().pendingValue()); - } - - /** - * Value format is green or red depending on the state - */ - public boolean coloured() { - return coloured; - } - - /** - * {@inheritDoc} - */ - @Override - public AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) { - return new BooleanControllerElement(this, screen, widgetDimension); - } - - public static class BooleanControllerElement extends ControllerWidget<BooleanController> { - public BooleanControllerElement(BooleanController control, YACLScreen screen, Dimension<Integer> dim) { - super(control, screen, dim); - } - - @Override - protected void drawHoveredControl(MatrixStack matrices, int mouseX, int mouseY, float delta) { - - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (!isMouseOver(mouseX, mouseY) || !isAvailable()) - return false; - - toggleSetting(); - return true; - } - - @Override - protected int getHoveredControlWidth() { - return getUnhoveredControlWidth(); - } - - public void toggleSetting() { - control.option().requestSet(!control.option().pendingValue()); - playDownSound(); - } - - @Override - protected Text getValueText() { - if (control.coloured()) { - return super.getValueText().copy().formatted(control.option().pendingValue() ? Formatting.GREEN : Formatting.RED); - } - - return super.getValueText(); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (!focused) { - return false; - } - - if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_SPACE || keyCode == GLFW.GLFW_KEY_KP_ENTER) { - toggleSetting(); - return true; - } - - return false; - } - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/ColorController.java b/src/main/java/dev/isxander/yacl/gui/controllers/ColorController.java deleted file mode 100644 index 0a83fbe..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/ColorController.java +++ /dev/null @@ -1,203 +0,0 @@ -package dev.isxander.yacl.gui.controllers; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.api.utils.MutableDimension; -import dev.isxander.yacl.gui.AbstractWidget; -import dev.isxander.yacl.gui.YACLScreen; -import dev.isxander.yacl.gui.controllers.string.IStringController; -import dev.isxander.yacl.gui.controllers.string.StringControllerElement; -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; - -import java.awt.*; -import java.util.List; - -/** - * A color controller that uses a hex color field as input. - */ -public class ColorController implements IStringController<Color> { - private final Option<Color> option; - private final boolean allowAlpha; - - /** - * Constructs a color controller with {@link ColorController#allowAlpha()} defaulting to false - * - * @param option bound option - */ - public ColorController(Option<Color> option) { - this(option, false); - } - - /** - * Constructs a color controller - * - * @param option bound option - * @param allowAlpha allows the color input to accept alpha values - */ - public ColorController(Option<Color> option, boolean allowAlpha) { - this.option = option; - this.allowAlpha = allowAlpha; - } - - /** - * {@inheritDoc} - */ - @Override - public Option<Color> option() { - return option; - } - - public boolean allowAlpha() { - return allowAlpha; - } - - @Override - public String getString() { - return formatValue().getString(); - } - - @Override - public Text formatValue() { - MutableText text = Text.literal("#"); - text.append(Text.literal(toHex(option().pendingValue().getRed())).formatted(Formatting.RED)); - text.append(Text.literal(toHex(option().pendingValue().getGreen())).formatted(Formatting.GREEN)); - text.append(Text.literal(toHex(option().pendingValue().getBlue())).formatted(Formatting.BLUE)); - if (allowAlpha()) text.append(toHex(option().pendingValue().getAlpha())); - return text; - } - - private String toHex(int value) { - String hex = Integer.toString(value, 16).toUpperCase(); - if (hex.length() == 1) - hex = "0" + hex; - return hex; - } - - @Override - public void setFromString(String value) { - if (value.startsWith("#")) - value = value.substring(1); - - int red = Integer.parseInt(value.substring(0, 2), 16); - int green = Integer.parseInt(value.substring(2, 4), 16); - int blue = Integer.parseInt(value.substring(4, 6), 16); - - if (allowAlpha()) { - int alpha = Integer.parseInt(value.substring(6, 8), 16); - option().requestSet(new Color(red, green, blue, alpha)); - } else { - option().requestSet(new Color(red, green, blue)); - } - } - - @Override - public AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) { - return new ColorControllerElement(this, screen, widgetDimension); - } - - public static class ColorControllerElement extends StringControllerElement { - private final ColorController colorController; - - protected MutableDimension<Integer> colorPreviewDim; - - private final List<Character> allowedChars; - - public ColorControllerElement(ColorController control, YACLScreen screen, Dimension<Integer> dim) { - super(control, screen, dim); - this.colorController = control; - this.allowedChars = ImmutableList.of('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); - } - - @Override - protected void drawValueText(MatrixStack matrices, int mouseX, int mouseY, float delta) { - if (isHovered()) { - colorPreviewDim.move(-inputFieldBounds.width() - 5, 0); - super.drawValueText(matrices, mouseX, mouseY, delta); - } - - DrawableHelper.fill(matrices, colorPreviewDim.x(), colorPreviewDim.y(), colorPreviewDim.xLimit(), colorPreviewDim.yLimit(), colorController.option().pendingValue().getRGB()); - drawOutline(matrices, colorPreviewDim.x(), colorPreviewDim.y(), colorPreviewDim.xLimit(), colorPreviewDim.yLimit(), 1, 0xFF000000); - } - - @Override - public void write(String string) { - for (char chr : string.toCharArray()) { - if (!allowedChars.contains(Character.toLowerCase(chr))) { - return; - } - } - - if (caretPos == 0) - return; - - string = string.substring(0, Math.min(inputField.length() - caretPos, string.length())); - - inputField.replace(caretPos, caretPos + string.length(), string); - caretPos += string.length(); - setSelectionLength(); - - updateControl(); - } - - @Override - protected void doBackspace() { - if (caretPos > 1) { - inputField.setCharAt(caretPos - 1, '0'); - caretPos--; - updateControl(); - } - } - - @Override - protected void doDelete() { - - } - - @Override - protected boolean canUseShortcuts() { - return false; - } - - protected void setSelectionLength() { - selectionLength = caretPos < inputField.length() && caretPos > 0 ? 1 : 0; - } - - @Override - protected int getDefaultCarotPos() { - return colorController.allowAlpha() ? 3 : 1; - } - - @Override - public void setDimension(Dimension<Integer> dim) { - super.setDimension(dim); - - int previewSize = (dim.height() - getYPadding() * 2) / 2; - colorPreviewDim = Dimension.ofInt(dim.xLimit() - getXPadding() - previewSize, dim.centerY() - previewSize / 2, previewSize, previewSize); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (super.keyPressed(keyCode, scanCode, modifiers)) { - caretPos = Math.max(1, caretPos); - setSelectionLength(); - return true; - } - return false; - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (super.mouseClicked(mouseX, mouseY, button)) { - caretPos = Math.max(1, caretPos); - setSelectionLength(); - return true; - } - return false; - } - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java b/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java deleted file mode 100644 index c7f9e97..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java +++ /dev/null @@ -1,165 +0,0 @@ -package dev.isxander.yacl.gui.controllers; - -import dev.isxander.yacl.api.Controller; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.AbstractWidget; -import dev.isxander.yacl.gui.YACLScreen; -import net.minecraft.client.font.MultilineText; -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; - -public abstract class ControllerWidget<T extends Controller<?>> extends AbstractWidget { - protected final T control; - protected MultilineText wrappedTooltip; - protected final YACLScreen screen; - - protected boolean focused = false; - protected boolean hovered = false; - - protected final Text modifiedOptionName; - protected final String optionNameString; - - public ControllerWidget(T control, YACLScreen screen, Dimension<Integer> dim) { - super(dim); - this.control = control; - this.screen = screen; - control.option().addListener((opt, pending) -> updateTooltip()); - updateTooltip(); - this.modifiedOptionName = control.option().name().copy().formatted(Formatting.ITALIC); - this.optionNameString = control.option().name().getString().toLowerCase(); - } - - @Override - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - hovered = isMouseOver(mouseX, mouseY); - - Text name = control.option().changed() ? modifiedOptionName : control.option().name(); - String nameString = name.getString(); - - boolean firstIter = true; - while (textRenderer.getWidth(nameString) > getDimension().width() - getControlWidth() - getXPadding() - 7) { - nameString = nameString.substring(0, Math.max(nameString.length() - (firstIter ? 2 : 5), 0)).trim(); - nameString += "..."; - - firstIter = false; - } - - Text shortenedName = Text.literal(nameString).fillStyle(name.getStyle()); - - drawButtonRect(matrices, getDimension().x(), getDimension().y(), getDimension().xLimit(), getDimension().yLimit(), isHovered(), isAvailable()); - matrices.push(); - matrices.translate(getDimension().x() + getXPadding(), getTextY(), 0); - textRenderer.drawWithShadow(matrices, shortenedName, 0, 0, getValueColor()); - matrices.pop(); - - drawValueText(matrices, mouseX, mouseY, delta); - if (isHovered()) { - drawHoveredControl(matrices, mouseX, mouseY, delta); - } - } - - @Override - public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) { - if (hovered) { - YACLScreen.renderMultilineTooltip(matrices, textRenderer, wrappedTooltip, getDimension().centerX(), getDimension().y() - 5, getDimension().yLimit() + 5, screen.width, screen.height); - } - } - - protected void drawHoveredControl(MatrixStack matrices, int mouseX, int mouseY, float delta) { - - } - - protected void drawValueText(MatrixStack matrices, int mouseX, int mouseY, float delta) { - Text valueText = getValueText(); - matrices.push(); - matrices.translate(getDimension().xLimit() - textRenderer.getWidth(valueText) - getXPadding(), getTextY(), 0); - textRenderer.drawWithShadow(matrices, valueText, 0, 0, getValueColor()); - matrices.pop(); - } - - private void updateTooltip() { - this.wrappedTooltip = MultilineText.create(textRenderer, control.option().tooltip(), screen.width / 3 * 2 - 10); - } - - protected int getControlWidth() { - return isHovered() ? getHoveredControlWidth() : getUnhoveredControlWidth(); - } - - public boolean isHovered() { - return isAvailable() && (hovered || focused); - } - - protected abstract int getHoveredControlWidth(); - - protected int getUnhoveredControlWidth() { - return textRenderer.getWidth(getValueText()); - } - - protected int getXPadding() { - return 5; - } - - protected int getYPadding() { - return 2; - } - - protected Text getValueText() { - return control.formatValue(); - } - - protected boolean isAvailable() { - return control.option().available(); - } - - protected int getValueColor() { - return isAvailable() ? -1 : inactiveColor; - } - - @Override - public boolean canReset() { - return true; - } - - protected void drawOutline(MatrixStack matrices, int x1, int y1, int x2, int y2, int width, int color) { - DrawableHelper.fill(matrices, x1, y1, x2, y1 + width, color); - DrawableHelper.fill(matrices, x2, y1, x2 - width, y2, color); - DrawableHelper.fill(matrices, x1, y2, x2, y2 - width, color); - DrawableHelper.fill(matrices, x1, y1, x1 + width, y2, color); - } - - protected float getTextY() { - return getDimension().y() + getDimension().height() / 2f - textRenderer.fontHeight / 2f; - } - - @Override - public boolean changeFocus(boolean lookForwards) { - if (!isAvailable()) - return false; - - this.focused = !this.focused; - return this.focused; - } - - @Override - public void unfocus() { - this.focused = false; - } - - @Override - public boolean matchesSearch(String query) { - return optionNameString.contains(query.toLowerCase()); - } - - @Override - public SelectionType getType() { - return focused ? SelectionType.FOCUSED : isHovered() ? SelectionType.HOVERED : SelectionType.NONE; - } - - @Override - public void appendNarrations(NarrationMessageBuilder builder) { - - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java b/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java deleted file mode 100644 index ebad4ae..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java +++ /dev/null @@ -1,35 +0,0 @@ -package dev.isxander.yacl.gui.controllers; - -import dev.isxander.yacl.api.NameableEnum; -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.gui.controllers.cycling.CyclingListController; -import net.minecraft.text.Text; -import net.minecraft.util.TranslatableOption; - -import java.util.Arrays; -import java.util.function.Function; - -@Deprecated -public class EnumController<T extends Enum<T>> extends CyclingListController<T> { - public static <T extends Enum<T>> Function<T, Text> getDefaultFormatter() { - return value -> { - if (value instanceof NameableEnum nameableEnum) - return nameableEnum.getDisplayName(); - if (value instanceof TranslatableOption translatableOption) - return translatableOption.getText(); - return Text.of(value.toString()); - }; - } - - public EnumController(Option<T> option) { - this(option, getDefaultFormatter()); - } - - public EnumController(Option<T> option, Function<T, Text> valueFormatter) { - this(option, valueFormatter, option.typeClass().getEnumConstants()); - } - - public EnumController(Option<T> option, Function<T, Text> valueFormatter, T[] availableValues) { - super(option, Arrays.asList(availableValues), valueFormatter); - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/LabelController.java b/src/main/java/dev/isxander/yacl/gui/controllers/LabelController.java deleted file mode 100644 index 8369680..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/LabelController.java +++ /dev/null @@ -1,144 +0,0 @@ -package dev.isxander.yacl.gui.controllers; - -import dev.isxander.yacl.api.Controller; -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.AbstractWidget; -import dev.isxander.yacl.gui.YACLScreen; -import net.minecraft.client.font.MultilineText; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.item.ItemStack; -import net.minecraft.text.*; - -import java.util.List; - -/** - * Simply renders some text as a label. - */ -public class LabelController implements Controller<Text> { - private final Option<Text> option; - /** - * Constructs a label controller - * - * @param option bound option - */ - public LabelController(Option<Text> option) { - this.option = option; - } - - /** - * {@inheritDoc} - */ - @Override - public Option<Text> option() { - return option; - } - - @Override - public Text formatValue() { - return option().pendingValue(); - } - - @Override - public AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) { - return new LabelControllerElement(screen, widgetDimension); - } - - public class LabelControllerElement extends AbstractWidget { - private List<OrderedText> wrappedText; - protected MultilineText wrappedTooltip; - - protected final YACLScreen screen; - - public LabelControllerElement(YACLScreen screen, Dimension<Integer> dim) { - super(dim); - this.screen = screen; - option().addListener((opt, pending) -> updateTooltip()); - updateTooltip(); - updateText(); - } - - @Override - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - updateText(); - - float y = getDimension().y(); - for (OrderedText text : wrappedText) { - textRenderer.drawWithShadow(matrices, text, getDimension().x(), y + getYPadding(), option().available() ? -1 : 0xFFA0A0A0); - y += textRenderer.fontHeight; - } - } - - @Override - public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) { - if (isMouseOver(mouseX, mouseY)) { - YACLScreen.renderMultilineTooltip(matrices, textRenderer, wrappedTooltip, getDimension().centerX(), getDimension().y() - 5, getDimension().yLimit() + 5, screen.width, screen.height); - - Style style = getStyle(mouseX, mouseY); - if (style != null && style.getHoverEvent() != null) { - HoverEvent hoverEvent = style.getHoverEvent(); - HoverEvent.ItemStackContent itemStackContent = hoverEvent.getValue(HoverEvent.Action.SHOW_ITEM); - if (itemStackContent != null) { - ItemStack stack = itemStackContent.asStack(); - screen.renderTooltip(matrices, screen.getTooltipFromItem(stack), stack.getTooltipData(), mouseX, mouseY); - } else { - HoverEvent.EntityContent entityContent = hoverEvent.getValue(HoverEvent.Action.SHOW_ENTITY); - if (entityContent != null) { - if (this.client.options.advancedItemTooltips) { - screen.renderTooltip(matrices, entityContent.asTooltip(), mouseX, mouseY); - } - } else { - Text text = hoverEvent.getValue(HoverEvent.Action.SHOW_TEXT); - if (text != null) { - MultilineText multilineText = MultilineText.create(textRenderer, text, getDimension().width()); - YACLScreen.renderMultilineTooltip(matrices, textRenderer, multilineText, getDimension().centerX(), getDimension().y(), getDimension().yLimit(), screen.width, screen.height); - } - } - } - } - } - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (!isMouseOver(mouseX, mouseY)) - return false; - - Style style = getStyle((int) mouseX, (int) mouseY); - return screen.handleTextClick(style); - } - - protected Style getStyle(int mouseX, int mouseY) { - if (!getDimension().isPointInside(mouseX, mouseY)) - return null; - - int x = mouseX - getDimension().x(); - int y = mouseY - getDimension().y() - getYPadding(); - int line = y / textRenderer.fontHeight; - - if (x < 0 || x > getDimension().xLimit()) return null; - if (y < 0 || y > getDimension().yLimit()) return null; - if (line < 0 || line >= wrappedText.size()) return null; - - return textRenderer.getTextHandler().getStyleAt(wrappedText.get(line), x); - } - - private int getYPadding() { - return 3; - } - - private void updateText() { - wrappedText = textRenderer.wrapLines(formatValue(), getDimension().width()); - setDimension(getDimension().withHeight(wrappedText.size() * textRenderer.fontHeight + getYPadding() * 2)); - } - - private void updateTooltip() { - this.wrappedTooltip = MultilineText.create(textRenderer, option().tooltip(), screen.width / 3 * 2 - 10); - } - - @Override - public boolean matchesSearch(String query) { - return formatValue().getString().toLowerCase().contains(query.toLowerCase()); - } - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/TickBoxController.java b/src/main/java/dev/isxander/yacl/gui/controllers/TickBoxController.java deleted file mode 100644 index 340983d..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/TickBoxController.java +++ /dev/null @@ -1,120 +0,0 @@ -package dev.isxander.yacl.gui.controllers; - -import dev.isxander.yacl.api.Controller; -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.AbstractWidget; -import dev.isxander.yacl.gui.YACLScreen; -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.Text; -import org.lwjgl.glfw.GLFW; - -/** - * This controller renders a tickbox - */ -public class TickBoxController implements Controller<Boolean> { - private final Option<Boolean> option; - - /** - * Constructs a tickbox controller - * - * @param option bound option - */ - public TickBoxController(Option<Boolean> option) { - this.option = option; - } - - /** - * {@inheritDoc} - */ - @Override - public Option<Boolean> option() { - return option; - } - - /** - * {@inheritDoc} - */ - @Override - public Text formatValue() { - return Text.empty(); - } - - /** - * {@inheritDoc} - */ - @Override - public AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) { - return new TickBoxControllerElement(this, screen, widgetDimension); - } - - public static class TickBoxControllerElement extends ControllerWidget<TickBoxController> { - public TickBoxControllerElement(TickBoxController control, YACLScreen screen, Dimension<Integer> dim) { - super(control, screen, dim); - } - - @Override - protected void drawHoveredControl(MatrixStack matrices, int mouseX, int mouseY, float delta) { - int outlineSize = 10; - int outlineX1 = getDimension().xLimit() - getXPadding() - outlineSize; - int outlineY1 = getDimension().centerY() - outlineSize / 2; - int outlineX2 = getDimension().xLimit() - getXPadding(); - int outlineY2 = getDimension().centerY() + outlineSize / 2; - - int color = getValueColor(); - int shadowColor = multiplyColor(color, 0.25f); - - drawOutline(matrices, outlineX1 + 1, outlineY1 + 1, outlineX2 + 1, outlineY2 + 1, 1, shadowColor); - drawOutline(matrices, outlineX1, outlineY1, outlineX2, outlineY2, 1, color); - if (control.option().pendingValue()) { - DrawableHelper.fill(matrices, outlineX1 + 3, outlineY1 + 3, outlineX2 - 1, outlineY2 - 1, shadowColor); - DrawableHelper.fill(matrices, outlineX1 + 2, outlineY1 + 2, outlineX2 - 2, outlineY2 - 2, color); - } - } - - @Override - protected void drawValueText(MatrixStack matrices, int mouseX, int mouseY, float delta) { - if (!isHovered()) - drawHoveredControl(matrices, mouseX, mouseY, delta); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (!isMouseOver(mouseX, mouseY) || !isAvailable()) - return false; - - toggleSetting(); - return true; - } - - @Override - protected int getHoveredControlWidth() { - return 10; - } - - @Override - protected int getUnhoveredControlWidth() { - return 10; - } - - public void toggleSetting() { - control.option().requestSet(!control.option().pendingValue()); - playDownSound(); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (!focused) { - return false; - } - - if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_SPACE || keyCode == GLFW.GLFW_KEY_KP_ENTER) { - toggleSetting(); - return true; - } - - return false; - } - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java b/src/main/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java deleted file mode 100644 index ab0a9c3..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java +++ /dev/null @@ -1,60 +0,0 @@ -package dev.isxander.yacl.gui.controllers.cycling; - -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.YACLScreen; -import dev.isxander.yacl.gui.controllers.ControllerWidget; -import net.minecraft.client.gui.screen.Screen; -import org.lwjgl.glfw.GLFW; - -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 GLFW.GLFW_KEY_LEFT, GLFW.GLFW_KEY_DOWN -> - cycleValue(-1); - case GLFW.GLFW_KEY_RIGHT, GLFW.GLFW_KEY_UP -> - cycleValue(1); - case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_SPACE, GLFW.GLFW_KEY_KP_ENTER -> - 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/yacl/gui/controllers/cycling/CyclingListController.java b/src/main/java/dev/isxander/yacl/gui/controllers/cycling/CyclingListController.java deleted file mode 100644 index 3b14066..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/cycling/CyclingListController.java +++ /dev/null @@ -1,79 +0,0 @@ -package dev.isxander.yacl.gui.controllers.cycling; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.api.Option; -import net.minecraft.text.Text; - -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 Function<T, Text> 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<T> values) { - this(option, values, value -> Text.of(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<T> values, Function<T, Text> valueFormatter) { - this.option = option; - this.valueFormatter = valueFormatter; - this.values = ImmutableList.copyOf(values); - } - - /** - * {@inheritDoc} - */ - @Override - public Option<T> option() { - return option; - } - - /** - * {@inheritDoc} - */ - @Override - public Text formatValue() { - return valueFormatter.apply(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/yacl/gui/controllers/cycling/EnumController.java b/src/main/java/dev/isxander/yacl/gui/controllers/cycling/EnumController.java deleted file mode 100644 index bc9f46d..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/cycling/EnumController.java +++ /dev/null @@ -1,60 +0,0 @@ -package dev.isxander.yacl.gui.controllers.cycling; - -import dev.isxander.yacl.api.NameableEnum; -import dev.isxander.yacl.api.Option; -import net.minecraft.text.Text; -import net.minecraft.util.TranslatableOption; - -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, Text> getDefaultFormatter() { - return value -> { - if (value instanceof NameableEnum nameableEnum) - return nameableEnum.getDisplayName(); - if (value instanceof TranslatableOption translatableOption) - return translatableOption.getText(); - return Text.of(value.toString()); - }; - } - - /** - * Constructs a cycling enum controller with a default value formatter and all values being available. - * The default value formatter first searches if the - * enum is a {@link NameableEnum} or {@link TranslatableOption} else, just uses {@link Enum#toString()} - * - * @param option bound option - */ - public EnumController(Option<T> option) { - this(option, getDefaultFormatter()); - } - - /** - * Constructs a cycling enum controller with all values being available. - * - * @param option bound option - * @param valueFormatter format the enum into any {@link Text} - */ - public EnumController(Option<T> option, Function<T, Text> valueFormatter) { - this(option, valueFormatter, option.typeClass().getEnumConstants()); - } - - /** - * Constructs a cycling enum controller. - * - * @param option bound option - * @param valueFormatter format the enum into any {@link Text} - * @param availableValues all enum constants that can be cycled through - */ - public EnumController(Option<T> option, Function<T, Text> valueFormatter, T[] availableValues) { - super(option, Arrays.asList(availableValues), valueFormatter); - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/cycling/ICyclingController.java b/src/main/java/dev/isxander/yacl/gui/controllers/cycling/ICyclingController.java deleted file mode 100644 index 081b572..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/cycling/ICyclingController.java +++ /dev/null @@ -1,38 +0,0 @@ -package dev.isxander.yacl.gui.controllers.cycling; - -import dev.isxander.yacl.api.Controller; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.AbstractWidget; -import dev.isxander.yacl.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); - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/package-info.java b/src/main/java/dev/isxander/yacl/gui/controllers/package-info.java deleted file mode 100644 index 12ce86b..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/package-info.java +++ /dev/null @@ -1,12 +0,0 @@ -/** - * This package contains all {@link dev.isxander.yacl.api.Controller} implementations - * - * <ul> - * <li>For numbers: {@link dev.isxander.yacl.gui.controllers.slider}</li> - * <li>For booleans: {@link dev.isxander.yacl.gui.controllers.TickBoxController}</li> - * <li>For lists/enums: {@link dev.isxander.yacl.gui.controllers.cycling}</li> - * <li>For strings: {@link dev.isxander.yacl.gui.controllers.string.StringController}</li> - * <li>For {@link dev.isxander.yacl.api.ButtonOption}: {@link dev.isxander.yacl.gui.controllers.ActionController}</li> - * </ul> - */ -package dev.isxander.yacl.gui.controllers; diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/slider/DoubleSliderController.java b/src/main/java/dev/isxander/yacl/gui/controllers/slider/DoubleSliderController.java deleted file mode 100644 index b530e8c..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/slider/DoubleSliderController.java +++ /dev/null @@ -1,114 +0,0 @@ -package dev.isxander.yacl.gui.controllers.slider; - -import dev.isxander.yacl.api.Option; -import net.minecraft.text.Text; -import org.apache.commons.lang3.Validate; - -import java.util.function.Function; - -/** - * {@link ISliderController} for doubles. - */ -public class DoubleSliderController implements ISliderController<Double> { - /** - * Formats doubles to two decimal places - */ - public static final Function<Double, Text> DEFAULT_FORMATTER = value -> Text.of(String.format("%,.2f", value)); - - private final Option<Double> option; - - private final double min, max, interval; - - private final Function<Double, Text> valueFormatter; - - /** - * Constructs a {@link ISliderController} for doubles - * using the default value formatter {@link DoubleSliderController#DEFAULT_FORMATTER}. - * - * @param option bound option - * @param min minimum slider value - * @param max maximum slider value - * @param interval step size (or increments) for the slider - */ - public DoubleSliderController(Option<Double> option, double min, double max, double interval) { - this(option, min, max, interval, DEFAULT_FORMATTER); - } - - /** - * Constructs a {@link ISliderController} for doubles. - * - * @param option bound option - * @param min minimum slider value - * @param max maximum slider value - * @param interval step size (or increments) for the slider - * @param valueFormatter format the value into any {@link Text} - */ - public DoubleSliderController(Option<Double> option, double min, double max, double interval, Function<Double, Text> valueFormatter) { - Validate.isTrue(max > min, "`max` cannot be smaller than `min`"); - Validate.isTrue(interval > 0, "`interval` must be more than 0"); - Validate.notNull(valueFormatter, "`valueFormatter` must not be null"); - - this.option = option; - this.min = min; - this.max = max; - this.interval = interval; - this.valueFormatter = valueFormatter; - } - - /** - * {@inheritDoc} - */ - @Override - public Option<Double> option() { - return option; - } - - /** - * {@inheritDoc} - */ - @Override - public Text formatValue() { - return valueFormatter.apply(option().pendingValue()); - } - - /** - * {@inheritDoc} - */ - @Override - public double min() { - return min; - } - - /** - * {@inheritDoc} - */ - @Override - public double max() { - return max; - } - - /** - * {@inheritDoc} - */ - @Override - public double interval() { - return interval; - } - - /** - * {@inheritDoc} - */ - @Override - public void setPendingValue(double value) { - option().requestSet(value); - } - - /** - * {@inheritDoc} - */ - @Override - public double pendingValue() { - return option().pendingValue(); - } - -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/slider/FloatSliderController.java b/src/main/java/dev/isxander/yacl/gui/controllers/slider/FloatSliderController.java deleted file mode 100644 index d7c203e..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/slider/FloatSliderController.java +++ /dev/null @@ -1,114 +0,0 @@ -package dev.isxander.yacl.gui.controllers.slider; - -import dev.isxander.yacl.api.Option; -import net.minecraft.text.Text; -import org.apache.commons.lang3.Validate; - -import java.util.function.Function; - -/** - * {@link ISliderController} for floats. - */ -public class FloatSliderController implements ISliderController<Float> { - /** - * Formats floats to one decimal place - */ - public static final Function<Float, Text> DEFAULT_FORMATTER = value -> Text.of(String.format("%,.1f", value)); - - private final Option<Float> option; - - private final float min, max, interval; - - private final Function<Float, Text> valueFormatter; - - /** - * Constructs a {@link ISliderController} for floats - * using the default value formatter {@link FloatSliderController#DEFAULT_FORMATTER}. - * - * @param option bound option - * @param min minimum slider value - * @param max maximum slider value - * @param interval step size (or increments) for the slider - */ - public FloatSliderController(Option<Float> option, float min, float max, float interval) { - this(option, min, max, interval, DEFAULT_FORMATTER); - } - - /** - * Constructs a {@link ISliderController} for floats. - * - * @param option bound option - * @param min minimum slider value - * @param max maximum slider value - * @param interval step size (or increments) for the slider - * @param valueFormatter format the value into any {@link Text} - */ - public FloatSliderController(Option<Float> option, float min, float max, float interval, Function<Float, Text> valueFormatter) { - Validate.isTrue(max > min, "`max` cannot be smaller than `min`"); - Validate.isTrue(interval > 0, "`interval` must be more than 0"); - Validate.notNull(valueFormatter, "`valueFormatter` must not be null"); - - this.option = option; - this.min = min; - this.max = max; - this.interval = interval; - this.valueFormatter = valueFormatter; - } - - /** - * {@inheritDoc} - */ - @Override - public Option<Float> option() { - return option; - } - - /** - * {@inheritDoc} - */ - @Override - public Text formatValue() { - return valueFormatter.apply(option().pendingValue()); - } - - /** - * {@inheritDoc} - */ - @Override - public double min() { - return min; - } - - /** - * {@inheritDoc} - */ - @Override - public double max() { - return max; - } - - /** - * {@inheritDoc} - */ - @Override - public double interval() { - return interval; - } - - /** - * {@inheritDoc} - */ - @Override - public void setPendingValue(double value) { - option().requestSet((float) value); - } - - /** - * {@inheritDoc} - */ - @Override - public double pendingValue() { - return option().pendingValue(); - } - -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/slider/ISliderController.java b/src/main/java/dev/isxander/yacl/gui/controllers/slider/ISliderController.java deleted file mode 100644 index aa3c18f..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/slider/ISliderController.java +++ /dev/null @@ -1,54 +0,0 @@ -package dev.isxander.yacl.gui.controllers.slider; - -import dev.isxander.yacl.api.Controller; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.AbstractWidget; -import dev.isxander.yacl.gui.YACLScreen; - -/** - * Simple custom slider implementation that shifts the current value across when shown. - * <p> - * For simplicity, {@link SliderControllerElement} works in doubles so each - * {@link ISliderController} must cast to double. This is to get around re-writing the element for every type. - */ -public interface ISliderController<T extends Number> extends Controller<T> { - /** - * Gets the minimum value for the slider - */ - double min(); - - /** - * Gets the maximum value for the slider - */ - double max(); - - /** - * Gets the interval (or step size) for the slider. - */ - double interval(); - - /** - * Gets the range of the slider. - */ - default double range() { - return max() - min(); - } - - /** - * Sets the {@link dev.isxander.yacl.api.Option}'s pending value - */ - void setPendingValue(double value); - - /** - * Gets the {@link dev.isxander.yacl.api.Option}'s pending value - */ - double pendingValue(); - - /** - * {@inheritDoc} - */ - @Override - default AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) { - return new SliderControllerElement(this, screen, widgetDimension, min(), max(), interval()); - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/slider/IntegerSliderController.java b/src/main/java/dev/isxander/yacl/gui/controllers/slider/IntegerSliderController.java deleted file mode 100644 index a8bca7c..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/slider/IntegerSliderController.java +++ /dev/null @@ -1,111 +0,0 @@ -package dev.isxander.yacl.gui.controllers.slider; - -import dev.isxander.yacl.api.Option; -import net.minecraft.text.Text; -import org.apache.commons.lang3.Validate; - -import java.util.function.Function; - -/** - * {@link ISliderController} for integers. - */ -public class IntegerSliderController implements ISliderController<Integer> { - public static final Function<Integer, Text> DEFAULT_FORMATTER = value -> Text.of(String.format("%,d", value)); - - private final Option<Integer> option; - - private final int min, max, interval; - - private final Function<Integer, Text> valueFormatter; - - /** - * Constructs a {@link ISliderController} for integers - * using the default value formatter {@link IntegerSliderController#DEFAULT_FORMATTER}. - * - * @param option bound option - * @param min minimum slider value - * @param max maximum slider value - * @param interval step size (or increments) for the slider - */ - public IntegerSliderController(Option<Integer> option, int min, int max, int interval) { - this(option, min, max, interval, DEFAULT_FORMATTER); - } - - /** - * Constructs a {@link ISliderController} for integers. - * - * @param option bound option - * @param min minimum slider value - * @param max maximum slider value - * @param interval step size (or increments) for the slider - * @param valueFormatter format the value into any {@link Text} - */ - public IntegerSliderController(Option<Integer> option, int min, int max, int interval, Function<Integer, Text> valueFormatter) { - Validate.isTrue(max > min, "`max` cannot be smaller than `min`"); - Validate.isTrue(interval > 0, "`interval` must be more than 0"); - Validate.notNull(valueFormatter, "`valueFormatter` must not be null"); - - this.option = option; - this.min = min; - this.max = max; - this.interval = interval; - this.valueFormatter = valueFormatter; - } - - /** - * {@inheritDoc} - */ - @Override - public Option<Integer> option() { - return option; - } - - /** - * {@inheritDoc} - */ - @Override - public Text formatValue() { - return valueFormatter.apply(option().pendingValue()); - } - - /** - * {@inheritDoc} - */ - @Override - public double min() { - return min; - } - - /** - * {@inheritDoc} - */ - @Override - public double max() { - return max; - } - - /** - * {@inheritDoc} - */ - @Override - public double interval() { - return interval; - } - - /** - * {@inheritDoc} - */ - @Override - public void setPendingValue(double value) { - option().requestSet((int) value); - } - - /** - * {@inheritDoc} - */ - @Override - public double pendingValue() { - return option().pendingValue(); - } - -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/slider/LongSliderController.java b/src/main/java/dev/isxander/yacl/gui/controllers/slider/LongSliderController.java deleted file mode 100644 index 50559d5..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/slider/LongSliderController.java +++ /dev/null @@ -1,111 +0,0 @@ -package dev.isxander.yacl.gui.controllers.slider; - -import dev.isxander.yacl.api.Option; -import net.minecraft.text.Text; -import org.apache.commons.lang3.Validate; - -import java.util.function.Function; - -/** - * {@link ISliderController} for longs. - */ -public class LongSliderController implements ISliderController<Long> { - public static final Function<Long, Text> DEFAULT_FORMATTER = value -> Text.of(String.format("%,d", value)); - - private final Option<Long> option; - - private final long min, max, interval; - - private final Function<Long, Text> valueFormatter; - - /** - * Constructs a {@link ISliderController} for longs - * using the default value formatter {@link LongSliderController#DEFAULT_FORMATTER}. - * - * @param option bound option - * @param min minimum slider value - * @param max maximum slider value - * @param interval step size (or increments) for the slider - */ - public LongSliderController(Option<Long> option, long min, long max, long interval) { - this(option, min, max, interval, DEFAULT_FORMATTER); - } - - /** - * Constructs a {@link ISliderController} for longs. - * - * @param option bound option - * @param min minimum slider value - * @param max maximum slider value - * @param interval step size (or increments) for the slider - * @param valueFormatter format the value into any {@link Text} - */ - public LongSliderController(Option<Long> option, long min, long max, long interval, Function<Long, Text> valueFormatter) { - Validate.isTrue(max > min, "`max` cannot be smaller than `min`"); - Validate.isTrue(interval > 0, "`interval` must be more than 0"); - Validate.notNull(valueFormatter, "`valueFormatter` must not be null"); - - this.option = option; - this.min = min; - this.max = max; - this.interval = interval; - this.valueFormatter = valueFormatter; - } - - /** - * {@inheritDoc} - */ - @Override - public Option<Long> option() { - return option; - } - - /** - * {@inheritDoc} - */ - @Override - public Text formatValue() { - return valueFormatter.apply(option().pendingValue()); - } - - /** - * {@inheritDoc} - */ - @Override - public double min() { - return min; - } - - /** - * {@inheritDoc} - */ - @Override - public double max() { - return max; - } - - /** - * {@inheritDoc} - */ - @Override - public double interval() { - return interval; - } - - /** - * {@inheritDoc} - */ - @Override - public void setPendingValue(double value) { - option().requestSet((long) value); - } - - /** - * {@inheritDoc} - */ - @Override - public double pendingValue() { - return option().pendingValue(); - } - -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java b/src/main/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java deleted file mode 100644 index 913cc00..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java +++ /dev/null @@ -1,160 +0,0 @@ -package dev.isxander.yacl.gui.controllers.slider; - -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.YACLScreen; -import dev.isxander.yacl.gui.controllers.ControllerWidget; -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.MathHelper; -import org.lwjgl.glfw.GLFW; - -public class SliderControllerElement extends ControllerWidget<ISliderController<?>> { - private final double min, max, interval; - - private float interpolation; - - private Dimension<Integer> sliderBounds; - - private boolean mouseDown = false; - - public SliderControllerElement(ISliderController<?> option, YACLScreen screen, Dimension<Integer> dim, double min, double max, double interval) { - super(option, screen, dim); - this.min = min; - this.max = max; - this.interval = interval; - setDimension(dim); - } - - @Override - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - super.render(matrices, mouseX, mouseY, delta); - - calculateInterpolation(); - } - - @Override - protected void drawHoveredControl(MatrixStack matrices, int mouseX, int mouseY, float delta) { - // track - DrawableHelper.fill(matrices, sliderBounds.x(), sliderBounds.centerY() - 1, sliderBounds.xLimit(), sliderBounds.centerY(), -1); - // track shadow - DrawableHelper.fill(matrices, sliderBounds.x() + 1, sliderBounds.centerY(), sliderBounds.xLimit() + 1, sliderBounds.centerY() + 1, 0xFF404040); - - // thumb shadow - DrawableHelper.fill(matrices, getThumbX() - getThumbWidth() / 2 + 1, sliderBounds.y() + 1, getThumbX() + getThumbWidth() / 2 + 1, sliderBounds.yLimit() + 1, 0xFF404040); - // thumb - DrawableHelper.fill(matrices, getThumbX() - getThumbWidth() / 2, sliderBounds.y(), getThumbX() + getThumbWidth() / 2, sliderBounds.yLimit(), -1); - } - - @Override - protected void drawValueText(MatrixStack matrices, int mouseX, int mouseY, float delta) { - matrices.push(); - if (isHovered()) - matrices.translate(-(sliderBounds.width() + 6 + getThumbWidth() / 2f), 0, 0); - super.drawValueText(matrices, mouseX, mouseY, delta); - matrices.pop(); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (!isAvailable() || button != 0 || !sliderBounds.isPointInside((int) mouseX, (int) mouseY)) - return false; - - mouseDown = true; - - setValueFromMouse(mouseX); - return true; - } - - @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - if (!isAvailable() || button != 0 || !mouseDown) - return false; - - setValueFromMouse(mouseX); - return true; - } - - public void incrementValue(double amount) { - control.setPendingValue(MathHelper.clamp(control.pendingValue() + interval * amount, min, max)); - calculateInterpolation(); - } - - @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - if (!isAvailable() || (!isMouseOver(mouseX, mouseY)) || (!Screen.hasShiftDown() && !Screen.hasControlDown())) - return false; - - incrementValue(amount); - return true; - } - - @Override - public boolean mouseReleased(double mouseX, double mouseY, int button) { - if (isAvailable() && mouseDown) - playDownSound(); - mouseDown = false; - - return super.mouseReleased(mouseX, mouseY, button); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (!focused) - return false; - - switch (keyCode) { - case GLFW.GLFW_KEY_LEFT, GLFW.GLFW_KEY_DOWN -> incrementValue(-1); - case GLFW.GLFW_KEY_RIGHT, GLFW.GLFW_KEY_UP -> incrementValue(1); - default -> { - return false; - } - } - - return true; - } - - @Override - public boolean isMouseOver(double mouseX, double mouseY) { - return super.isMouseOver(mouseX, mouseY) || mouseDown; - } - - protected void setValueFromMouse(double mouseX) { - double value = (mouseX - sliderBounds.x()) / sliderBounds.width() * control.range(); - control.setPendingValue(roundToInterval(value)); - calculateInterpolation(); - } - - protected double roundToInterval(double value) { - return MathHelper.clamp(min + (interval * Math.round(value / interval)), min, max); // extremely imprecise, requires clamping - } - - @Override - protected int getHoveredControlWidth() { - return sliderBounds.width() + getUnhoveredControlWidth() + 6 + getThumbWidth() / 2; - } - - protected void calculateInterpolation() { - interpolation = MathHelper.clamp((float) ((control.pendingValue() - control.min()) * 1 / control.range()), 0f, 1f); - } - - @Override - public void setDimension(Dimension<Integer> dim) { - super.setDimension(dim); - sliderBounds = Dimension.ofInt(dim.xLimit() - getXPadding() - getThumbWidth() / 2 - dim.width() / 3, dim.centerY() - 5, dim.width() / 3, 10); - } - - protected int getThumbX() { - return (int) (sliderBounds.x() + sliderBounds.width() * interpolation); - } - - protected int getThumbWidth() { - return 4; - } - - @Override - public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) { - if (super.isMouseOver(mouseX, mouseY)) - super.postRender(matrices, mouseX, mouseY, delta); - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/slider/package-info.java b/src/main/java/dev/isxander/yacl/gui/controllers/slider/package-info.java deleted file mode 100644 index bff0d57..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/slider/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/** - * This package contains implementations of sliders for different number types - * <ul> - * <li>For doubles: {@link dev.isxander.yacl.gui.controllers.slider.DoubleSliderController}</li> - * <li>For floats: {@link dev.isxander.yacl.gui.controllers.slider.FloatSliderController}</li> - * <li>For integers: {@link dev.isxander.yacl.gui.controllers.slider.IntegerSliderController}</li> - * <li>For longs: {@link dev.isxander.yacl.gui.controllers.slider.LongSliderController}</li> - * </ul> - */ -package dev.isxander.yacl.gui.controllers.slider; diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/string/IStringController.java b/src/main/java/dev/isxander/yacl/gui/controllers/string/IStringController.java deleted file mode 100644 index 41843b8..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/string/IStringController.java +++ /dev/null @@ -1,32 +0,0 @@ -package dev.isxander.yacl.gui.controllers.string; - -import dev.isxander.yacl.api.Controller; -import dev.isxander.yacl.api.Option; -import net.minecraft.text.Text; - -/** - * A controller that can be any type but can input and output a string. - */ -public interface IStringController<T> extends Controller<T> { - /** - * Gets the option's pending value as a string. - * - * @see Option#pendingValue() - */ - String getString(); - - /** - * Sets the option's pending value from a string. - * - * @see Option#requestSet(Object) - */ - void setFromString(String value); - - /** - * {@inheritDoc} - */ - @Override - default Text formatValue() { - return Text.of(getString()); - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/string/StringController.java b/src/main/java/dev/isxander/yacl/gui/controllers/string/StringController.java deleted file mode 100644 index 0caaa93..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/string/StringController.java +++ /dev/null @@ -1,45 +0,0 @@ -package dev.isxander.yacl.gui.controllers.string; - -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.AbstractWidget; -import dev.isxander.yacl.gui.YACLScreen; - -/** - * A custom text field implementation for strings. - */ -public class StringController implements IStringController<String> { - private final Option<String> option; - - /** - * Constructs a string controller - * - * @param option bound option - */ - public StringController(Option<String> option) { - this.option = option; - } - - /** - * {@inheritDoc} - */ - @Override - public Option<String> option() { - return option; - } - - @Override - public String getString() { - return option().pendingValue(); - } - - @Override - public void setFromString(String value) { - option().requestSet(value); - } - - @Override - public AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) { - return new StringControllerElement(this, screen, widgetDimension); - } -} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java b/src/main/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java deleted file mode 100644 index 0c3b7c9..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java +++ /dev/null @@ -1,283 +0,0 @@ -package dev.isxander.yacl.gui.controllers.string; - -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.YACLScreen; -import dev.isxander.yacl.gui.controllers.ControllerWidget; -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import org.lwjgl.glfw.GLFW; - -public class StringControllerElement extends ControllerWidget<IStringController<?>> { - protected StringBuilder inputField; - protected Dimension<Integer> inputFieldBounds; - protected boolean inputFieldFocused; - - protected int caretPos; - protected int selectionLength; - - protected float ticks; - - private final Text emptyText; - - public StringControllerElement(IStringController<?> control, YACLScreen screen, Dimension<Integer> dim) { - super(control, screen, dim); - inputField = new StringBuilder(control.getString()); - inputFieldFocused = false; - selectionLength = 0; - emptyText = Text.literal("Click to type...").formatted(Formatting.GRAY); - setDimension(dim); - } - - @Override - protected void drawHoveredControl(MatrixStack matrices, int mouseX, int mouseY, float delta) { - ticks += delta; - - DrawableHelper.fill(matrices, inputFieldBounds.x(), inputFieldBounds.yLimit(), inputFieldBounds.xLimit(), inputFieldBounds.yLimit() + 1, -1); - DrawableHelper.fill(matrices, inputFieldBounds.x() + 1, inputFieldBounds.yLimit() + 1, inputFieldBounds.xLimit() + 1, inputFieldBounds.yLimit() + 2, 0xFF404040); - - if (inputFieldFocused || focused) { - int caretX = inputFieldBounds.x() + textRenderer.getWidth(control.getString().substring(0, caretPos)) - 1; - if (inputField.isEmpty()) - caretX += inputFieldBounds.width() / 2; - - if (ticks % 20 <= 10) { - DrawableHelper.fill(matrices, caretX, inputFieldBounds.y(), caretX + 1, inputFieldBounds.yLimit(), -1); - } - - if (selectionLength != 0) { - int selectionX = inputFieldBounds.x() + textRenderer.getWidth(control.getString().substring(0, caretPos + selectionLength)); - DrawableHelper.fill(matrices, caretX, inputFieldBounds.y() - 1, selectionX, inputFieldBounds.yLimit(), 0x803030FF); - } - } - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (isAvailable() && inputFieldBounds.isPointInside((int) mouseX, (int) mouseY)) { - if (!inputFieldFocused) { - inputFieldFocused = true; - caretPos = getDefaultCarotPos(); - } else { - int textWidth = (int) mouseX - inputFieldBounds.x(); - caretPos = textRenderer.trimToWidth(control.getString(), textWidth).length(); - selectionLength = 0; - } - return true; - } else { - inputFieldFocused = false; - } - - return false; - } - - protected int getDefaultCarotPos() { - return inputField.length(); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (!inputFieldFocused) - return false; - - switch (keyCode) { - case GLFW.GLFW_KEY_ESCAPE -> { - inputFieldFocused = false; - return true; - } - case GLFW.GLFW_KEY_LEFT -> { - if (Screen.hasShiftDown()) { - if (Screen.hasControlDown()) { - int spaceChar = findSpaceIndex(true); - selectionLength += caretPos - spaceChar; - caretPos = spaceChar; - } else if (caretPos > 0) { - caretPos--; - selectionLength += 1; - } - } else { - if (caretPos > 0) - caretPos--; - selectionLength = 0; - } - - return true; - } - case GLFW.GLFW_KEY_RIGHT -> { - if (Screen.hasShiftDown()) { - if (Screen.hasControlDown()) { - int spaceChar = findSpaceIndex(false); - selectionLength -= spaceChar - caretPos; - caretPos = spaceChar; - } else if (caretPos < inputField.length()) { - caretPos++; - selectionLength -= 1; - } - } else { - if (caretPos < inputField.length()) - caretPos++; - selectionLength = 0; - } - - return true; - } - case GLFW.GLFW_KEY_BACKSPACE -> { - doBackspace(); - return true; - } - case GLFW.GLFW_KEY_DELETE -> { - doDelete(); - return true; - } - } - - if (canUseShortcuts()) { - if (Screen.isPaste(keyCode)) { - this.write(client.keyboard.getClipboard()); - return true; - } else if (Screen.isCopy(keyCode) && selectionLength != 0) { - client.keyboard.setClipboard(getSelection()); - return true; - } else if (Screen.isCut(keyCode) && selectionLength != 0) { - client.keyboard.setClipboard(getSelection()); - this.write(""); - return true; - } else if (Screen.isSelectAll(keyCode)) { - caretPos = inputField.length(); - selectionLength = -caretPos; - return true; - } - } - - return false; - } - - @Override - public boolean charTyped(char chr, int modifiers) { - if (!inputFieldFocused) - return false; - - write(Character.toString(chr)); - - return true; - } - - protected boolean canUseShortcuts() { - return true; - } - - protected void doBackspace() { - if (selectionLength != 0) { - write(""); - } else if (caretPos > 0) { - inputField.deleteCharAt(caretPos - 1); - caretPos--; - updateControl(); - } - } - - protected void doDelete() { - if (caretPos < inputField.length()) { - inputField.deleteCharAt(caretPos); - updateControl(); - } - } - - public void write(String string) { - if (selectionLength == 0) { - string = textRenderer.trimToWidth(string, getMaxLength() - textRenderer.getWidth(inputField.toString())); - - inputField.insert(caretPos, string); - caretPos += string.length(); - } else { - int start = getSelectionStart(); - int end = getSelectionEnd(); - - string = textRenderer.trimToWidth(string, getMaxLength() - textRenderer.getWidth(inputField.toString()) + textRenderer.getWidth(inputField.substring(start, end))); - - inputField.replace(start, end, string); - caretPos = start + string.length(); - selectionLength = 0; - } - updateControl(); - } - - public int getMaxLength() { - return getDimension().width() / 8 * 7; - } - - public int getSelectionStart() { - return Math.min(caretPos, caretPos + selectionLength); - } - - public int getSelectionEnd() { - return Math.max(caretPos, caretPos + selectionLength); - } - - protected String getSelection() { - return inputField.substring(getSelectionStart(), getSelectionEnd()); - } - - protected int findSpaceIndex(boolean reverse) { - int i; - int fromIndex = caretPos; - if (reverse) { - if (caretPos > 0) - fromIndex -= 1; - i = this.inputField.lastIndexOf(" ", fromIndex); - - if (i == -1) i = 0; - } else { - if (caretPos < inputField.length()) - fromIndex += 1; - i = this.inputField.indexOf(" ", fromIndex); - - if (i == -1) i = inputField.length(); - } - - return i; - } - - @Override - public boolean changeFocus(boolean lookForwards) { - return inputFieldFocused = super.changeFocus(lookForwards); - } - - @Override - public void unfocus() { - super.unfocus(); - inputFieldFocused = false; - } - - @Override - public void setDimension(Dimension<Integer> dim) { - super.setDimension(dim); - - int width = Math.max(6, textRenderer.getWidth(getValueText())); - inputFieldBounds = Dimension.ofInt(dim.xLimit() - getXPadding() - width, dim.centerY() - textRenderer.fontHeight / 2, width, textRenderer.fontHeight); - } - - @Override - public boolean isHovered() { - return super.isHovered() || inputFieldFocused; - } - - protected void updateControl() { - control.setFromString(inputField.toString()); - } - - @Override - protected int getHoveredControlWidth() { - return getUnhoveredControlWidth(); - } - - @Override - protected Text getValueText() { - if (!inputFieldFocused && inputField.isEmpty()) - return emptyText; - - return super.getValueText(); - } -} diff --git a/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java b/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java deleted file mode 100644 index dcb9c7a..0000000 --- a/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java +++ /dev/null @@ -1,142 +0,0 @@ -package dev.isxander.yacl.impl; - -import com.google.common.collect.ImmutableSet; -import dev.isxander.yacl.api.*; -import dev.isxander.yacl.gui.YACLScreen; -import net.minecraft.text.Text; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.BiConsumer; -import java.util.function.Function; - -public class ButtonOptionImpl implements ButtonOption { - private final Text name; - private final Text tooltip; - private final BiConsumer<YACLScreen, ButtonOption> action; - private boolean available; - private final Controller<BiConsumer<YACLScreen, ButtonOption>> controller; - private final Binding<BiConsumer<YACLScreen, ButtonOption>> binding; - - public ButtonOptionImpl( - @NotNull Text name, - @Nullable Text tooltip, - @NotNull BiConsumer<YACLScreen, ButtonOption> action, - boolean available, - @NotNull Function<ButtonOption, Controller<BiConsumer<YACLScreen, ButtonOption>>> controlGetter - ) { - this.name = name; - this.tooltip = tooltip; - this.action = action; - this.available = available; - this.controller = controlGetter.apply(this); - this.binding = new EmptyBinderImpl(); - } - - @Override - public @NotNull Text name() { - return name; - } - - @Override - public @NotNull Text tooltip() { - return tooltip; - } - - @Override - public BiConsumer<YACLScreen, ButtonOption> action() { - return action; - } - - @Override - public boolean available() { - return available; - } - - @Override - public void setAvailable(boolean available) { - this.available = available; - } - - @Override - public @NotNull Controller<BiConsumer<YACLScreen, ButtonOption>> controller() { - return controller; - } - - @Override - public @NotNull Binding<BiConsumer<YACLScreen, ButtonOption>> binding() { - return binding; - } - - @Override - public @NotNull Class<BiConsumer<YACLScreen, ButtonOption>> typeClass() { - throw new UnsupportedOperationException(); - } - - @Override - public @NotNull ImmutableSet<OptionFlag> flags() { - return ImmutableSet.of(); - } - - @Override - public boolean requiresRestart() { - return false; - } - - @Override - public boolean changed() { - return false; - } - - @Override - public @NotNull BiConsumer<YACLScreen, ButtonOption> pendingValue() { - throw new UnsupportedOperationException(); - } - - @Override - public void requestSet(BiConsumer<YACLScreen, ButtonOption> value) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean applyValue() { - return false; - } - - @Override - public void forgetPendingValue() { - - } - - @Override - public void requestSetDefault() { - - } - - @Override - public boolean isPendingValueDefault() { - throw new UnsupportedOperationException(); - } - - @Override - public void addListener(BiConsumer<Option<BiConsumer<YACLScreen, ButtonOption>>, BiConsumer<YACLScreen, ButtonOption>> changedListener) { - - } - - private static class EmptyBinderImpl implements Binding<BiConsumer<YACLScreen, ButtonOption>> { - @Override - public void setValue(BiConsumer<YACLScreen, ButtonOption> value) { - - } - - @Override - public BiConsumer<YACLScreen, ButtonOption> getValue() { - throw new UnsupportedOperationException(); - } - - @Override - public BiConsumer<YACLScreen, ButtonOption> defaultValue() { - throw new UnsupportedOperationException(); - } - } -} diff --git a/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java b/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java deleted file mode 100644 index 971fecf..0000000 --- a/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java +++ /dev/null @@ -1,10 +0,0 @@ -package dev.isxander.yacl.impl; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.api.ConfigCategory; -import dev.isxander.yacl.api.OptionGroup; -import net.minecraft.text.Text; - -public record ConfigCategoryImpl(Text name, ImmutableList<OptionGroup> groups, Text tooltip) implements ConfigCategory { - -} diff --git a/src/main/java/dev/isxander/yacl/impl/GenericBindingImpl.java b/src/main/java/dev/isxander/yacl/impl/GenericBindingImpl.java deleted file mode 100644 index 1867bb6..0000000 --- a/src/main/java/dev/isxander/yacl/impl/GenericBindingImpl.java +++ /dev/null @@ -1,35 +0,0 @@ -package dev.isxander.yacl.impl; - -import dev.isxander.yacl.api.Binding; - -import java.util.function.Consumer; -import java.util.function.Supplier; - -public class GenericBindingImpl<T> implements Binding<T> { - private final T def; - private final Supplier<T> getter; - private final Consumer<T> setter; - - public GenericBindingImpl(T def, Supplier<T> getter, Consumer<T> setting) { - this.def = def; - this.getter = getter; - this.setter = setting; - } - - - @Override - public void setValue(T value) { - setter.accept(value); - } - - @Override - public T getValue() { - return getter.get(); - } - - @Override - public T defaultValue() { - return def; - } - -} diff --git a/src/main/java/dev/isxander/yacl/impl/OptionGroupImpl.java b/src/main/java/dev/isxander/yacl/impl/OptionGroupImpl.java deleted file mode 100644 index 58bc96b..0000000 --- a/src/main/java/dev/isxander/yacl/impl/OptionGroupImpl.java +++ /dev/null @@ -1,10 +0,0 @@ -package dev.isxander.yacl.impl; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.api.OptionGroup; -import net.minecraft.text.Text; -import org.jetbrains.annotations.NotNull; - -public record OptionGroupImpl(@NotNull Text name, @NotNull Text tooltip, ImmutableList<Option<?>> options, boolean collapsed, boolean isRoot) implements OptionGroup { -} diff --git a/src/main/java/dev/isxander/yacl/impl/OptionImpl.java b/src/main/java/dev/isxander/yacl/impl/OptionImpl.java deleted file mode 100644 index c76f115..0000000 --- a/src/main/java/dev/isxander/yacl/impl/OptionImpl.java +++ /dev/null @@ -1,145 +0,0 @@ -package dev.isxander.yacl.impl; - -import com.google.common.collect.ImmutableSet; -import dev.isxander.yacl.api.Binding; -import dev.isxander.yacl.api.Controller; -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.api.OptionFlag; -import net.minecraft.text.Text; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.function.BiConsumer; -import java.util.function.Function; - -public class OptionImpl<T> implements Option<T> { - private final Text name; - private Text tooltip; - private final Controller<T> controller; - private final Binding<T> binding; - private boolean available; - - private final ImmutableSet<OptionFlag> flags; - - private final Class<T> typeClass; - - private T pendingValue; - - private final List<BiConsumer<Option<T>, T>> listeners; - - public OptionImpl( - @NotNull Text name, - @Nullable Function<T, Text> tooltipGetter, - @NotNull Function<Option<T>, Controller<T>> controlGetter, - @NotNull Binding<T> binding, - boolean available, - ImmutableSet<OptionFlag> flags, - @NotNull Class<T> typeClass, - @NotNull Collection<BiConsumer<Option<T>, T>> listeners - ) { - this.name = name; - this.binding = binding; - this.available = available; - this.flags = flags; - this.typeClass = typeClass; - this.listeners = new ArrayList<>(listeners); - this.controller = controlGetter.apply(this); - - addListener((opt, pending) -> tooltip = tooltipGetter.apply(pending)); - requestSet(binding().getValue()); - } - - @Override - public @NotNull Text name() { - return name; - } - - @Override - public @NotNull Text tooltip() { - return tooltip; - } - - @Override - public @NotNull Controller<T> controller() { - return controller; - } - - @Override - public @NotNull Binding<T> binding() { - return binding; - } - - @Override - public boolean available() { - return available; - } - - @Override - public void setAvailable(boolean available) { - this.available = available; - } - - @Override - public @NotNull Class<T> typeClass() { - return typeClass; - } - - @Override - public @NotNull ImmutableSet<OptionFlag> flags() { - return flags; - } - - @Override - public boolean requiresRestart() { - return flags.contains(OptionFlag.GAME_RESTART); - } - - @Override - public boolean changed() { - return !binding().getValue().equals(pendingValue); - } - - @Override - public @NotNull T pendingValue() { - return pendingValue; - } - - @Override - public void requestSet(T value) { - pendingValue = value; - listeners.forEach(listener -> listener.accept(this, pendingValue)); - } - - @Override - public boolean applyValue() { - if (changed()) { - binding().setValue(pendingValue); - return true; - } - return false; - } - - @Override - public void forgetPendingValue() { - requestSet(binding().getValue()); - } - - @Override - public void requestSetDefault() { - requestSet(binding().defaultValue()); - } - - @Override - public boolean isPendingValueDefault() { - return binding().defaultValue().equals(pendingValue()); - } - - @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 deleted file mode 100644 index a5180ad..0000000 --- a/src/main/java/dev/isxander/yacl/impl/PlaceholderCategoryImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -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(); - } -} diff --git a/src/main/java/dev/isxander/yacl/impl/YetAnotherConfigLibImpl.java b/src/main/java/dev/isxander/yacl/impl/YetAnotherConfigLibImpl.java deleted file mode 100644 index eb23eac..0000000 --- a/src/main/java/dev/isxander/yacl/impl/YetAnotherConfigLibImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package dev.isxander.yacl.impl; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.api.ConfigCategory; -import dev.isxander.yacl.api.YetAnotherConfigLib; -import dev.isxander.yacl.gui.YACLScreen; -import dev.isxander.yacl.impl.utils.YACLConstants; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.text.Text; - -import java.util.function.Consumer; - -public record YetAnotherConfigLibImpl(Text title, ImmutableList<ConfigCategory> categories, Runnable saveFunction, Consumer<YACLScreen> initConsumer) implements YetAnotherConfigLib { - @Override - public Screen generateScreen(Screen parent) { - YACLConstants.LOGGER.info("Generating YACL screen"); - return new YACLScreen(this, parent); - } -} diff --git a/src/main/java/dev/isxander/yacl/impl/utils/DimensionIntegerImpl.java b/src/main/java/dev/isxander/yacl/impl/utils/DimensionIntegerImpl.java deleted file mode 100644 index 6c7508d..0000000 --- a/src/main/java/dev/isxander/yacl/impl/utils/DimensionIntegerImpl.java +++ /dev/null @@ -1,115 +0,0 @@ -package dev.isxander.yacl.impl.utils; - -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.api.utils.MutableDimension; - -public class DimensionIntegerImpl implements MutableDimension<Integer> { - private int x, y; - private int width, height; - - public DimensionIntegerImpl(int x, int y, int width, int height) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - } - - @Override - public Integer x() { - return x; - } - - @Override - public Integer y() { - return y; - } - - @Override - public Integer width() { - return width; - } - - @Override - public Integer height() { - return height; - } - - @Override - public Integer xLimit() { - return x + width; - } - - @Override - public Integer yLimit() { - return y + height; - } - - @Override - public Integer centerX() { - return x + width / 2; - } - - @Override - public Integer centerY() { - return y + height / 2; - } - - @Override - public boolean isPointInside(Integer x, Integer y) { - return x >= x() && x <= xLimit() && y >= y() && y <= yLimit(); - } - - @Override - public MutableDimension<Integer> clone() { - return new DimensionIntegerImpl(x, y, width, height); - } - - @Override public MutableDimension<Integer> setX(Integer x) { this.x = x; return this; } - @Override public MutableDimension<Integer> setY(Integer y) { this.y = y; return this; } - @Override public MutableDimension<Integer> setWidth(Integer width) { this.width = width; return this; } - @Override public MutableDimension<Integer> setHeight(Integer height) { this.height = height; return this; } - - @Override - public Dimension<Integer> withX(Integer x) { - return clone().setX(x); - } - - @Override - public Dimension<Integer> withY(Integer y) { - return clone().setY(y); - } - - @Override - public Dimension<Integer> withWidth(Integer width) { - return clone().setWidth(width); - } - - @Override - public Dimension<Integer> withHeight(Integer height) { - return clone().setHeight(height); - } - - @Override - public MutableDimension<Integer> move(Integer x, Integer y) { - this.x += x; - this.y += y; - return this; - } - - @Override - public MutableDimension<Integer> expand(Integer width, Integer height) { - this.width += width; - this.height += height; - return this; - } - - @Override - public Dimension<Integer> moved(Integer x, Integer y) { - return clone().move(x, y); - } - - @Override - public Dimension<Integer> expanded(Integer width, Integer height) { - return clone().expand(width, height); - } -} diff --git a/src/main/java/dev/isxander/yacl/impl/utils/YACLConstants.java b/src/main/java/dev/isxander/yacl/impl/utils/YACLConstants.java deleted file mode 100644 index 3d382d4..0000000 --- a/src/main/java/dev/isxander/yacl/impl/utils/YACLConstants.java +++ /dev/null @@ -1,8 +0,0 @@ -package dev.isxander.yacl.impl.utils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class YACLConstants { - public static final Logger LOGGER = LoggerFactory.getLogger("YetAnotherConfigLib"); -} diff --git a/src/main/java/dev/isxander/yacl/mixin/SimpleOptionAccessor.java b/src/main/java/dev/isxander/yacl/mixin/SimpleOptionAccessor.java deleted file mode 100644 index 9207225..0000000 --- a/src/main/java/dev/isxander/yacl/mixin/SimpleOptionAccessor.java +++ /dev/null @@ -1,11 +0,0 @@ -package dev.isxander.yacl.mixin; - -import net.minecraft.client.option.SimpleOption; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(SimpleOption.class) -public interface SimpleOptionAccessor<T> { - @Accessor - T getDefaultValue(); -} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 234a281..0bd51c5 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -25,7 +25,10 @@ "fabric-resource-loader-v0": "*" }, "mixins": [ - "yet-another-config-lib.mixins.json" + { + "config": "yet-another-config-lib.client.mixins.json", + "environment": "client" + } ], "accessWidener": "yacl.accesswidener", "custom": { diff --git a/src/main/resources/yet-another-config-lib.mixins.json b/src/main/resources/yet-another-config-lib.mixins.json deleted file mode 100644 index cb96c48..0000000 --- a/src/main/resources/yet-another-config-lib.mixins.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "required": true, - "package": "dev.isxander.yacl.mixin", - "compatibilityLevel": "JAVA_17", - "injectors": { - "defaultRequire": 1 - }, - "client": [ - "SimpleOptionAccessor" - ] -} |