diff options
author | Xander <xander@isxander.dev> | 2023-04-25 16:28:41 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-25 16:28:41 +0100 |
commit | 13c7ba45ff201423eb8dba8a40cfb66ebb531439 (patch) | |
tree | 1e799aa9da11fbc0833bc6b7c6e6799633c2ec50 /src | |
parent | 8ba7196ae990fe9aa98680aba1b387e385fff99c (diff) | |
download | YetAnotherConfigLib-13c7ba45ff201423eb8dba8a40cfb66ebb531439.tar.gz YetAnotherConfigLib-13c7ba45ff201423eb8dba8a40cfb66ebb531439.tar.bz2 YetAnotherConfigLib-13c7ba45ff201423eb8dba8a40cfb66ebb531439.zip |
Architectury! (#61)
Diffstat (limited to 'src')
94 files changed, 0 insertions, 8635 deletions
diff --git a/src/client/java/dev/isxander/yacl/api/Binding.java b/src/client/java/dev/isxander/yacl/api/Binding.java deleted file mode 100644 index ba5a2c0..0000000 --- a/src/client/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.client.OptionInstanceAccessor; -import net.minecraft.client.OptionInstance; -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 OptionInstance} - */ - static <T> Binding<T> minecraft(OptionInstance<T> minecraftOption) { - Validate.notNull(minecraftOption, "`minecraftOption` must not be null"); - - return new GenericBindingImpl<>( - ((OptionInstanceAccessor<T>) (Object) minecraftOption).getInitialValue(), - minecraftOption::get, - minecraftOption::set - ); - } - - /** - * 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/client/java/dev/isxander/yacl/api/ButtonOption.java b/src/client/java/dev/isxander/yacl/api/ButtonOption.java deleted file mode 100644 index 88e1c4b..0000000 --- a/src/client/java/dev/isxander/yacl/api/ButtonOption.java +++ /dev/null @@ -1,66 +0,0 @@ -package dev.isxander.yacl.api; - -import dev.isxander.yacl.gui.YACLScreen; -import dev.isxander.yacl.impl.ButtonOptionImpl; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.NotNull; - -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 dev.isxander.yacl.api.ButtonOption.Builder createBuilder() { - return new ButtonOptionImpl.BuilderImpl(); - } - - interface Builder { - /** - * Sets the name to be used by the option. - * - * @see Option#name() - */ - dev.isxander.yacl.api.ButtonOption.Builder name(@NotNull Component name); - - /** - * 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()}. - */ - dev.isxander.yacl.api.ButtonOption.Builder tooltip(@NotNull Component... tooltips); - - dev.isxander.yacl.api.ButtonOption.Builder action(@NotNull BiConsumer<YACLScreen, ButtonOption> action); - - /** - * Action to be executed upon button press - * - * @see ButtonOption#action() - */ - @Deprecated - dev.isxander.yacl.api.ButtonOption.Builder action(@NotNull Consumer<YACLScreen> action); - - /** - * Sets if the option can be configured - * - * @see Option#available() - */ - dev.isxander.yacl.api.ButtonOption.Builder available(boolean available); - - /** - * Sets the controller for the option. - * This is how you interact and change the options. - * - * @see dev.isxander.yacl.gui.controllers - */ - dev.isxander.yacl.api.ButtonOption.Builder controller(@NotNull Function<ButtonOption, Controller<BiConsumer<YACLScreen, ButtonOption>>> control); - - ButtonOption build(); - } -} diff --git a/src/client/java/dev/isxander/yacl/api/ConfigCategory.java b/src/client/java/dev/isxander/yacl/api/ConfigCategory.java deleted file mode 100644 index 7764479..0000000 --- a/src/client/java/dev/isxander/yacl/api/ConfigCategory.java +++ /dev/null @@ -1,94 +0,0 @@ -package dev.isxander.yacl.api; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.impl.ConfigCategoryImpl; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; - -/** - * 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 Component name(); - - /** - * Gets every {@link OptionGroup} in this category. - */ - @NotNull ImmutableList<OptionGroup> groups(); - - /** - * Tooltip (or description) of the category. - * Rendered on hover. - */ - @NotNull Component tooltip(); - - /** - * Creates a builder to construct a {@link ConfigCategory} - */ - static Builder createBuilder() { - return new ConfigCategoryImpl.BuilderImpl(); - } - - interface Builder extends OptionAddable { - /** - * Sets name of the category - * - * @see ConfigCategory#name() - */ - Builder name(@NotNull Component name); - - /** - * 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() - */ - @Override - Builder option(@NotNull Option<?> option); - - /** - * 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() - */ - @Override - Builder options(@NotNull Collection<? extends Option<?>> options); - - /** - * 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()} - */ - Builder group(@NotNull OptionGroup group); - - /** - * 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()} - */ - Builder groups(@NotNull Collection<OptionGroup> groups); - - /** - * 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()}. - */ - Builder tooltip(@NotNull Component... tooltips); - - ConfigCategory build(); - } -} diff --git a/src/client/java/dev/isxander/yacl/api/Controller.java b/src/client/java/dev/isxander/yacl/api/Controller.java deleted file mode 100644 index 0b8e2ed..0000000 --- a/src/client/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.network.chat.Component; - -/** - * 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()} - */ - Component formatValue(); - - /** - * Provides a widget to display - * - * @param screen parent screen - */ - AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension); -} diff --git a/src/client/java/dev/isxander/yacl/api/LabelOption.java b/src/client/java/dev/isxander/yacl/api/LabelOption.java deleted file mode 100644 index 05c7214..0000000 --- a/src/client/java/dev/isxander/yacl/api/LabelOption.java +++ /dev/null @@ -1,41 +0,0 @@ -package dev.isxander.yacl.api; - -import dev.isxander.yacl.impl.LabelOptionImpl; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; - -/** - * A label option is an easier way of creating a label with a {@link dev.isxander.yacl.gui.controllers.LabelController}. - * This option is immutable and cannot be disabled. Tooltips are supported through - * {@link Component} styling. - */ -public interface LabelOption extends Option<Component> { - @NotNull Component label(); - - /** - * Creates a new label option with the given label, skipping a builder for ease. - */ - static LabelOption create(@NotNull Component label) { - return new LabelOptionImpl(label); - } - - static dev.isxander.yacl.api.LabelOption.Builder createBuilder() { - return new LabelOptionImpl.BuilderImpl(); - } - - interface Builder { - /** - * Appends a line to the label - */ - dev.isxander.yacl.api.LabelOption.Builder line(@NotNull Component line); - - /** - * Appends multiple lines to the label - */ - dev.isxander.yacl.api.LabelOption.Builder lines(@NotNull Collection<? extends Component> lines); - - LabelOption build(); - } -} diff --git a/src/client/java/dev/isxander/yacl/api/ListOption.java b/src/client/java/dev/isxander/yacl/api/ListOption.java deleted file mode 100644 index afba8ee..0000000 --- a/src/client/java/dev/isxander/yacl/api/ListOption.java +++ /dev/null @@ -1,152 +0,0 @@ -package dev.isxander.yacl.api; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.impl.ListOptionImpl; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.ApiStatus; -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; - -/** - * A list option that takes form as an option group for UX. - * You add this option through {@link ConfigCategory.Builder#group(OptionGroup)}. Do NOT add as an option. - * Users can add remove and reshuffle a list type. You can use any controller you wish, there are no dedicated - * controllers for list types. List options do not manipulate your list but get and set the list with a - * regular binding for simplicity. - * - * You may apply option flags like a normal option and collapse like a normal group, it is a merge of them both. - * Methods in this interface marked with {@link ApiStatus.Internal} should not be used, and could be subject to - * change at any time - * @param <T> - */ -public interface ListOption<T> extends OptionGroup, Option<List<T>> { - @Override - @NotNull ImmutableList<ListOptionEntry<T>> options(); - - /** - * Class of the entry type - */ - @NotNull Class<T> elementTypeClass(); - - @ApiStatus.Internal - ListOptionEntry<T> insertNewEntryToTop(); - - @ApiStatus.Internal - void insertEntry(int index, ListOptionEntry<?> entry); - - @ApiStatus.Internal - int indexOf(ListOptionEntry<?> entry); - - @ApiStatus.Internal - void removeEntry(ListOptionEntry<?> entry); - - @ApiStatus.Internal - void addRefreshListener(Runnable changedListener); - - static <T> Builder<T> createBuilder(Class<T> typeClass) { - return new ListOptionImpl.BuilderImpl<>(typeClass); - } - - interface Builder<T> { - /** - * Sets name of the list, for UX purposes, a name should always be given, - * but isn't enforced. - * - * @see ListOption#name() - */ - Builder<T> name(@NotNull Component name); - - /** - * Sets the tooltip to be used by the list. It is displayed like a normal - * group when you hover over the name. Entries do not allow a tooltip. - * <p> - * 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 dev.isxander.yacl.api.ListOption.Builder#build()}. - */ - Builder<T> tooltip(@NotNull Component... tooltips); - - /** - * Sets the value that is used when creating new entries - */ - Builder<T> initial(@NotNull T initialValue); - - /** - * Sets the controller for the option. - * This is how you interact and change the options. - * - * @see dev.isxander.yacl.gui.controllers - */ - Builder<T> controller(@NotNull Function<ListOptionEntry<T>, Controller<T>> control); - - /** - * Sets the binding for the option. - * Used for default, getter and setter. - * - * @see Binding - */ - Builder<T> binding(@NotNull Binding<List<T>> binding); - - /** - * 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 - */ - Builder<T> binding(@NotNull List<T> def, @NotNull Supplier<@NotNull List<T>> getter, @NotNull Consumer<@NotNull List<T>> setter); - - /** - * Sets if the option can be configured - * - * @see Option#available() - */ - Builder<T> available(boolean available); - - /** - * Adds a flag to the option. - * Upon applying changes, all flags are executed. - * {@link Option#flags()} - */ - Builder<T> flag(@NotNull OptionFlag... flag); - - /** - * Adds a flag to the option. - * Upon applying changes, all flags are executed. - * {@link Option#flags()} - */ - Builder<T> flags(@NotNull Collection<OptionFlag> flags); - - /** - * Dictates if the group should be collapsed by default. - * If not set, it will not be collapsed by default. - * - * @see OptionGroup#collapsed() - */ - Builder<T> collapsed(boolean collapsible); - - /** - * Adds a listener to the option. Invoked upon changing any of the list's entries. - * - * @see Option#addListener(BiConsumer) - */ - ListOption.Builder<T> listener(@NotNull BiConsumer<Option<List<T>>, List<T>> listener); - - /** - * Adds multiple listeners to the option. Invoked upon changing of any of the list's entries. - * - * @see Option#addListener(BiConsumer) - */ - ListOption.Builder<T> listeners(@NotNull Collection<BiConsumer<Option<List<T>>, List<T>>> listeners); - - ListOption<T> build(); - } -} diff --git a/src/client/java/dev/isxander/yacl/api/ListOptionEntry.java b/src/client/java/dev/isxander/yacl/api/ListOptionEntry.java deleted file mode 100644 index e0a3424..0000000 --- a/src/client/java/dev/isxander/yacl/api/ListOptionEntry.java +++ /dev/null @@ -1,23 +0,0 @@ -package dev.isxander.yacl.api; - -import com.google.common.collect.ImmutableSet; -import org.jetbrains.annotations.NotNull; - -public interface ListOptionEntry<T> extends Option<T> { - ListOption<T> parentGroup(); - - @Override - default @NotNull Class<T> typeClass() { - return parentGroup().elementTypeClass(); - } - - @Override - default @NotNull ImmutableSet<OptionFlag> flags() { - return parentGroup().flags(); - } - - @Override - default boolean available() { - return parentGroup().available(); - } -} diff --git a/src/client/java/dev/isxander/yacl/api/NameableEnum.java b/src/client/java/dev/isxander/yacl/api/NameableEnum.java deleted file mode 100644 index 4b04057..0000000 --- a/src/client/java/dev/isxander/yacl/api/NameableEnum.java +++ /dev/null @@ -1,10 +0,0 @@ -package dev.isxander.yacl.api; - -import net.minecraft.network.chat.Component; - -/** - * Used for the default value formatter of {@link dev.isxander.yacl.gui.controllers.cycling.EnumController} - */ -public interface NameableEnum { - Component getDisplayName(); -} diff --git a/src/client/java/dev/isxander/yacl/api/Option.java b/src/client/java/dev/isxander/yacl/api/Option.java deleted file mode 100644 index a6c0311..0000000 --- a/src/client/java/dev/isxander/yacl/api/Option.java +++ /dev/null @@ -1,227 +0,0 @@ -package dev.isxander.yacl.api; - -import com.google.common.collect.ImmutableSet; -import dev.isxander.yacl.impl.OptionImpl; -import net.minecraft.network.chat.Component; -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; - -public interface Option<T> { - /** - * Name of the option - */ - @NotNull Component name(); - - /** - * Tooltip (or description) of the option. - * Rendered on hover. - */ - @NotNull Component 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(); - - /** - * 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(); - - default boolean canResetToDefault() { - return true; - } - - /** - * 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 OptionImpl.BuilderImpl<>(typeClass); - } - - interface Builder<T> { - /** - * Sets the name to be used by the option. - * - * @see Option#name() - */ - Builder<T> name(@NotNull Component name); - - /** - * 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()}. - */ - Builder<T> tooltip(@NotNull Function<T, Component> tooltipGetter); - - /** - * 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()}. - */ - @Deprecated - Builder<T> tooltip(@NotNull Function<T, Component>... tooltipGetter); - - /** - * 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()}. - */ - Builder<T> tooltip(@NotNull Component... tooltips); - - /** - * Sets the controller for the option. - * This is how you interact and change the options. - * - * @see dev.isxander.yacl.gui.controllers - */ - Builder<T> controller(@NotNull Function<Option<T>, Controller<T>> control); - - /** - * Sets the binding for the option. - * Used for default, getter and setter. - * - * @see Binding - */ - Builder<T> binding(@NotNull Binding<T> binding); - - /** - * 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 - */ - Builder<T> binding(@NotNull T def, @NotNull Supplier<@NotNull T> getter, @NotNull Consumer<@NotNull T> setter); - - /** - * Sets if the option can be configured - * - * @see Option#available() - */ - Builder<T> available(boolean available); - - /** - * Adds a flag to the option. - * Upon applying changes, all flags are executed. - * {@link Option#flags()} - */ - Builder<T> flag(@NotNull OptionFlag... flag); - - /** - * Adds a flag to the option. - * Upon applying changes, all flags are executed. - * {@link Option#flags()} - */ - Builder<T> flags(@NotNull Collection<OptionFlag> flags); - - /** - * 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()}! - */ - Builder<T> instant(boolean instant); - - /** - * Adds a listener to the option. Invoked upon changing the pending value. - * - * @see Option#addListener(BiConsumer) - */ - Builder<T> listener(@NotNull BiConsumer<Option<T>, T> listener); - - /** - * Adds multiple listeners to the option. Invoked upon changing the pending value. - * - * @see Option#addListener(BiConsumer) - */ - Builder<T> listeners(@NotNull Collection<BiConsumer<Option<T>, T>> listeners); - - Option<T> build(); - } -} diff --git a/src/client/java/dev/isxander/yacl/api/OptionAddable.java b/src/client/java/dev/isxander/yacl/api/OptionAddable.java deleted file mode 100644 index 57be06c..0000000 --- a/src/client/java/dev/isxander/yacl/api/OptionAddable.java +++ /dev/null @@ -1,19 +0,0 @@ -package dev.isxander.yacl.api; - -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; - -public interface OptionAddable { - /** - * Adds an option to an abstract builder. - * To construct an option, use {@link Option#createBuilder(Class)} - */ - OptionAddable option(@NotNull Option<?> option); - - /** - * Adds multiple options to an abstract builder. - * To construct an option, use {@link Option#createBuilder(Class)} - */ - OptionAddable options(@NotNull Collection<? extends Option<?>> options); -} diff --git a/src/client/java/dev/isxander/yacl/api/OptionFlag.java b/src/client/java/dev/isxander/yacl/api/OptionFlag.java deleted file mode 100644 index 51d57e4..0000000 --- a/src/client/java/dev/isxander/yacl/api/OptionFlag.java +++ /dev/null @@ -1,23 +0,0 @@ -package dev.isxander.yacl.api; - -import dev.isxander.yacl.gui.RequireRestartScreen; -import net.minecraft.client.Minecraft; - -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<Minecraft> { - /** Warns the user that a game restart is required for the changes to take effect */ - OptionFlag GAME_RESTART = client -> client.setScreen(new RequireRestartScreen(client.screen)); - - /** Reloads chunks upon applying (F3+A) */ - OptionFlag RELOAD_CHUNKS = client -> client.levelRenderer.allChanged(); - - OptionFlag WORLD_RENDER_UPDATE = client -> client.levelRenderer.needsUpdate(); - - OptionFlag ASSET_RELOAD = Minecraft::delayTextureReload; -} diff --git a/src/client/java/dev/isxander/yacl/api/OptionGroup.java b/src/client/java/dev/isxander/yacl/api/OptionGroup.java deleted file mode 100644 index 4fe43c7..0000000 --- a/src/client/java/dev/isxander/yacl/api/OptionGroup.java +++ /dev/null @@ -1,94 +0,0 @@ -package dev.isxander.yacl.api; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.impl.OptionGroupImpl; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; - -/** - * 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. - */ - Component name(); - - /** - * Tooltip displayed on hover. - */ - Component tooltip(); - - /** - * List of all options in the group - */ - @NotNull ImmutableList<? extends 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 OptionGroupImpl.BuilderImpl(); - } - - interface Builder extends OptionAddable { - /** - * Sets name of the group, can be {@link Component#empty()} to just separate options, like sodium. - * - * @see OptionGroup#name() - */ - Builder name(@NotNull Component name); - - /** - * Sets the tooltip to be used by the option group. - * Can be invoked twice to append more lines. - * No need to wrap the Component yourself, the gui does this itself. - * - * @param tooltips Component lines - merged with a new-line on {@link Builder#build()}. - */ - Builder tooltip(@NotNull Component... tooltips); - - /** - * Adds an option to group. - * To construct an option, use {@link Option#createBuilder(Class)} - * - * @see OptionGroup#options() - */ - @Override - Builder option(@NotNull Option<?> option); - - /** - * Adds multiple options to group. - * To construct an option, use {@link Option#createBuilder(Class)} - * - * @see OptionGroup#options() - */ - @Override - Builder options(@NotNull Collection<? extends Option<?>> options); - - /** - * Dictates if the group should be collapsed by default - * - * @see OptionGroup#collapsed() - */ - Builder collapsed(boolean collapsible); - - OptionGroup build(); - } -} diff --git a/src/client/java/dev/isxander/yacl/api/PlaceholderCategory.java b/src/client/java/dev/isxander/yacl/api/PlaceholderCategory.java deleted file mode 100644 index 3641fad..0000000 --- a/src/client/java/dev/isxander/yacl/api/PlaceholderCategory.java +++ /dev/null @@ -1,52 +0,0 @@ -package dev.isxander.yacl.api; - -import dev.isxander.yacl.gui.YACLScreen; -import dev.isxander.yacl.impl.PlaceholderCategoryImpl; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.NotNull; - -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<Minecraft, YACLScreen, Screen> screen(); - - static Builder createBuilder() { - return new PlaceholderCategoryImpl.BuilderImpl(); - } - - interface Builder { - /** - * Sets name of the category - * - * @see ConfigCategory#name() - */ - Builder name(@NotNull Component name); - - /** - * Sets the tooltip to be used by the category. - * Can be invoked twice to append more lines. - * No need to wrap the Component yourself, the gui does this itself. - * - * @param tooltips Component lines - merged with a new-line on {@link dev.isxander.yacl.api.PlaceholderCategory.Builder#build()}. - */ - Builder tooltip(@NotNull Component... tooltips); - - /** - * Screen to open upon selecting this category - * - * @see PlaceholderCategory#screen() - */ - Builder screen(@NotNull BiFunction<Minecraft, YACLScreen, Screen> screenFunction); - - PlaceholderCategory build(); - } -} diff --git a/src/client/java/dev/isxander/yacl/api/YetAnotherConfigLib.java b/src/client/java/dev/isxander/yacl/api/YetAnotherConfigLib.java deleted file mode 100644 index c6da1d1..0000000 --- a/src/client/java/dev/isxander/yacl/api/YetAnotherConfigLib.java +++ /dev/null @@ -1,107 +0,0 @@ -package dev.isxander.yacl.api; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.config.ConfigInstance; -import dev.isxander.yacl.gui.YACLScreen; -import dev.isxander.yacl.impl.YetAnotherConfigLibImpl; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; -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. - */ - Component 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 YetAnotherConfigLibImpl.BuilderImpl(); - } - - /** - * Creates an instance using a {@link ConfigInstance} which autofills the save() builder method. - * This also takes an easy functional interface that provides defaults and config to help build YACL bindings. - */ - static <T> YetAnotherConfigLib create(ConfigInstance<T> configInstance, ConfigBackedBuilder<T> builder) { - return builder.build(configInstance.getDefaults(), configInstance.getConfig(), createBuilder().save(configInstance::save)).build(); - } - - interface Builder { - /** - * Sets title of GUI for Minecraft narration - * - * @see YetAnotherConfigLib#title() - */ - Builder title(@NotNull Component title); - - /** - * Adds a new category. - * To create a category you need to use {@link ConfigCategory#createBuilder()} - * - * @see YetAnotherConfigLib#categories() - */ - Builder category(@NotNull ConfigCategory category); - - /** - * Adds multiple categories at once. - * To create a category you need to use {@link ConfigCategory#createBuilder()} - * - * @see YetAnotherConfigLib#categories() - */ - Builder categories(@NotNull Collection<? extends ConfigCategory> categories); - - /** - * Used to define a save function for when user clicks the Save Changes button - * - * @see YetAnotherConfigLib#saveFunction() - */ - Builder save(@NotNull Runnable saveFunction); - - /** - * Defines a consumer that is accepted every time the YACL screen initialises - * - * @see YetAnotherConfigLib#initConsumer() - */ - Builder screenInit(@NotNull Consumer<YACLScreen> initConsumer); - - YetAnotherConfigLib build(); - } - - @FunctionalInterface - interface ConfigBackedBuilder<T> { - YetAnotherConfigLib.Builder build(T defaults, T config, YetAnotherConfigLib.Builder builder); - } -} diff --git a/src/client/java/dev/isxander/yacl/api/utils/OptionUtils.java b/src/client/java/dev/isxander/yacl/api/utils/OptionUtils.java deleted file mode 100644 index 22032bd..0000000 --- a/src/client/java/dev/isxander/yacl/api/utils/OptionUtils.java +++ /dev/null @@ -1,39 +0,0 @@ -package dev.isxander.yacl.api.utils; - -import dev.isxander.yacl.api.*; - -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()) { - if (group instanceof ListOption<?> list) { - if (consumer.apply(list)) return; - } else { - 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/client/java/dev/isxander/yacl/gui/AbstractWidget.java b/src/client/java/dev/isxander/yacl/gui/AbstractWidget.java deleted file mode 100644 index c6d2b09..0000000 --- a/src/client/java/dev/isxander/yacl/gui/AbstractWidget.java +++ /dev/null @@ -1,107 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import dev.isxander.yacl.api.utils.Dimension; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.GuiComponent; -import net.minecraft.client.gui.components.Renderable; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.narration.NarratableEntry; -import net.minecraft.client.gui.narration.NarrationElementOutput; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.resources.sounds.SimpleSoundInstance; -import net.minecraft.sounds.SoundEvents; - -import java.awt.Color; - -public abstract class AbstractWidget implements GuiEventListener, Renderable, NarratableEntry { - protected final Minecraft client = Minecraft.getInstance(); - protected final Font textRenderer = client.font; - protected final int inactiveColor = 0xFFA0A0A0; - - private Dimension<Integer> dim; - - public AbstractWidget(Dimension<Integer> dim) { - this.dim = dim; - } - - public void postRender(PoseStack 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 NarrationPriority narrationPriority() { - return NarrationPriority.NONE; - } - - public void unfocus() { - - } - - public boolean matchesSearch(String query) { - return true; - } - - @Override - public void updateNarration(NarrationElementOutput builder) { - - } - - protected void drawButtonRect(PoseStack 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::getPositionTexShader); - RenderSystem.setShaderTexture(0, net.minecraft.client.gui.components.AbstractWidget.WIDGETS_LOCATION); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - int i = !enabled ? 0 : hovered ? 2 : 1; - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.enableDepthTest(); - GuiComponent.blit(matrices, x1, y1, 0, 0, 46 + i * 20, width / 2, height, 256, 256); - GuiComponent.blit(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() { - Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/CategoryListWidget.java b/src/client/java/dev/isxander/yacl/gui/CategoryListWidget.java deleted file mode 100644 index 41286ff..0000000 --- a/src/client/java/dev/isxander/yacl/gui/CategoryListWidget.java +++ /dev/null @@ -1,99 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import dev.isxander.yacl.api.ConfigCategory; -import dev.isxander.yacl.gui.utils.GuiUtils; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.narration.NarratableEntry; - -import java.util.List; - -public class CategoryListWidget extends ElementListWidgetExt<CategoryListWidget.CategoryEntry> { - private final YACLScreen yaclScreen; - - public CategoryListWidget(Minecraft client, YACLScreen yaclScreen, int screenWidth, int screenHeight) { - super(client, 0, 0, screenWidth / 3, yaclScreen.searchFieldWidget.getY() - 5, true); - this.yaclScreen = yaclScreen; - setRenderBackground(false); - setRenderTopAndBottom(false); - - for (ConfigCategory category : yaclScreen.config.categories()) { - addEntry(new CategoryEntry(category)); - } - } - - @Override - public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - GuiUtils.enableScissor(0, 0, width, height); - super.render(matrices, mouseX, mouseY, delta); - RenderSystem.disableScissor(); - } - - @Override - public int getRowWidth() { - return Math.min(width - width / 10, 396); - } - - @Override - public int getRowLeft() { - return super.getRowLeft() - 2; - } - - @Override - protected int getScrollbarPosition() { - return width - 2; - } - - @Override - protected void renderBackground(PoseStack matrices) { - - } - - 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(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - if (mouseY > y1) { - mouseY = -20; - } - - categoryButton.setY(y); - categoryButton.render(matrices, mouseX, mouseY, tickDelta); - } - - public void postRender(PoseStack matrices, int mouseX, int mouseY, float tickDelta) { - categoryButton.renderHoveredTooltip(matrices); - } - - @Override - public int getItemHeight() { - return 21; - } - - @Override - public List<? extends GuiEventListener> children() { - return ImmutableList.of(categoryButton); - } - - @Override - public List<? extends NarratableEntry> narratables() { - return ImmutableList.of(categoryButton); - } - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/CategoryWidget.java b/src/client/java/dev/isxander/yacl/gui/CategoryWidget.java deleted file mode 100644 index 60817a2..0000000 --- a/src/client/java/dev/isxander/yacl/gui/CategoryWidget.java +++ /dev/null @@ -1,38 +0,0 @@ -package dev.isxander.yacl.gui; - -import dev.isxander.yacl.api.ConfigCategory; -import net.minecraft.client.sounds.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.setValue(""); - screen.changeCategory(categoryIndex); - }); - this.categoryIndex = categoryIndex; - } - - private boolean isCurrentCategory() { - return ((YACLScreen) screen).getCurrentCategoryIdx() == categoryIndex; - } - - @Override - protected int getTextureY() { - int i = 1; - if (!this.active) { - i = 0; - } else if (this.isHoveredOrFocused() || isCurrentCategory()) { - i = 2; - } - - return 46 + i * 20; - } - - @Override - public void playDownSound(SoundManager soundManager) { - if (!isCurrentCategory()) - super.playDownSound(soundManager); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/ElementListWidgetExt.java b/src/client/java/dev/isxander/yacl/gui/ElementListWidgetExt.java deleted file mode 100644 index 46503a6..0000000 --- a/src/client/java/dev/isxander/yacl/gui/ElementListWidgetExt.java +++ /dev/null @@ -1,179 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.platform.InputConstants; -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.ContainerObjectSelectionList; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.util.Mth; -import org.jetbrains.annotations.Nullable; - -import java.util.Iterator; - -public class ElementListWidgetExt<E extends ElementListWidgetExt.Entry<E>> extends ContainerObjectSelectionList<E> { - protected final int x, y; - - private double smoothScrollAmount = getScrollAmount(); - private boolean returnSmoothAmount = false; - private final boolean doSmoothScrolling; - - public ElementListWidgetExt(Minecraft client, int x, int y, int width, int height, boolean smoothScrolling) { - super(client, width, height, y, y + height, 22); - this.x = this.x0 = x; - this.y = y; - this.x1 = this.x0 + width; - this.doSmoothScrolling = smoothScrolling; - } - - @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - // default implementation bases scroll step from total height of entries, this is constant - this.setScrollAmount(this.getScrollAmount() - amount * 20); - return true; - } - - @Override - protected void renderBackground(PoseStack matrices) { - // render transparent background if in-game. - setRenderBackground(minecraft.level == null); - if (minecraft.level != null) - fill(matrices, x0, y0, x1, y1, 0x6B000000); - } - - @Override - protected int getScrollbarPosition() { - // default implementation does not respect left/right - return this.x1 - 2; - } - - @Override - public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - smoothScrollAmount = Mth.lerp(Minecraft.getInstance().getDeltaFrameTime() * 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 && doSmoothScrolling) - return smoothScrollAmount; - - return super.getScrollAmount(); - } - - protected void resetSmoothScrolling() { - this.smoothScrollAmount = getScrollAmount(); - } - - public void postRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - for (E entry : children()) { - entry.postRender(matrices, mouseX, mouseY, delta); - } - } - - @Nullable - @Override - protected E getEntryAtPosition(double x, double y) { - y += getScrollAmount(); - - if (x < this.x0 || x > this.x1) - return null; - - int currentY = this.y0 - headerHeight + 4; - for (E entry : children()) { - if (y >= currentY && y <= currentY + entry.getItemHeight()) { - return entry; - } - - currentY += entry.getItemHeight(); - } - - return null; - } - - /* - below code is licensed from cloth-config under LGPL3 - modified to inherit vanilla's EntryListWidget and use yarn mappings - - code is responsible for having dynamic item heights - */ - - @Override - protected int getMaxPosition() { - return children().stream().map(E::getItemHeight).reduce(0, Integer::sum) + headerHeight; - } - - @Override - protected void centerScrollOn(E entry) { - double d = (this.height) / -2d; - for (int i = 0; i < this.children().indexOf(entry) && i < this.getItemCount(); i++) - d += children().get(i).getItemHeight(); - this.setScrollAmount(d); - } - - @Override - protected int getRowTop(int index) { - int integer = y0 + 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(PoseStack matrices, int mouseX, int mouseY, float delta) { - int left = this.getRowLeft(); - int right = this.getRowWidth(); - int count = this.getItemCount(); - - for(int i = 0; i < count; ++i) { - E entry = children().get(i); - int top = this.getRowTop(i); - int bottom = top + entry.getItemHeight(); - int entryHeight = entry.getItemHeight() - 4; - if (bottom >= this.y0 && top <= this.y1) { - this.renderItem(matrices, mouseX, mouseY, delta, i, left, top, right, entryHeight); - } - } - } - - /* END cloth config code */ - - public abstract static class Entry<E extends ElementListWidgetExt.Entry<E>> extends ContainerObjectSelectionList.Entry<E> { - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - for (GuiEventListener child : this.children()) { - if (child.mouseClicked(mouseX, mouseY, button)) { - if (button == InputConstants.MOUSE_BUTTON_LEFT) - this.setDragging(true); - return true; - } - } - - return false; - } - - @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - if (isDragging() && button == InputConstants.MOUSE_BUTTON_LEFT) { - for (GuiEventListener child : this.children()) { - if (child.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) - return true; - } - } - return false; - } - - public void postRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - - } - - public int getItemHeight() { - return 22; - } - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/LowProfileButtonWidget.java b/src/client/java/dev/isxander/yacl/gui/LowProfileButtonWidget.java deleted file mode 100644 index 7e17aac..0000000 --- a/src/client/java/dev/isxander/yacl/gui/LowProfileButtonWidget.java +++ /dev/null @@ -1,29 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.Tooltip; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; - -public class LowProfileButtonWidget extends Button { - public LowProfileButtonWidget(int x, int y, int width, int height, Component message, OnPress onPress) { - super(x, y, width, height, message, onPress, DEFAULT_NARRATION); - } - - public LowProfileButtonWidget(int x, int y, int width, int height, Component message, OnPress onPress, Tooltip tooltip) { - this(x, y, width, height, message, onPress); - setTooltip(tooltip); - } - - @Override - public void renderWidget(PoseStack matrices, int mouseX, int mouseY, float deltaTicks) { - if (!isHoveredOrFocused() || !active) { - int j = this.active ? 0xFFFFFF : 0xA0A0A0; - this.renderString(matrices, Minecraft.getInstance().font, j); - } else { - super.renderWidget(matrices, mouseX, mouseY, deltaTicks); - } - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/OptionListWidget.java b/src/client/java/dev/isxander/yacl/gui/OptionListWidget.java deleted file mode 100644 index 8f96ddf..0000000 --- a/src/client/java/dev/isxander/yacl/gui/OptionListWidget.java +++ /dev/null @@ -1,568 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.vertex.PoseStack; -import dev.isxander.yacl.api.*; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.impl.utils.YACLConstants; -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.components.MultiLineLabel; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.narration.NarratableEntry; -import net.minecraft.client.gui.narration.NarratedElementType; -import net.minecraft.client.gui.narration.NarrationElementOutput; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -public class OptionListWidget extends ElementListWidgetExt<OptionListWidget.Entry> { - private final YACLScreen yaclScreen; - private boolean singleCategory = false; - - private ImmutableList<dev.isxander.yacl.gui.OptionListWidget.Entry> viewableChildren; - - public OptionListWidget(YACLScreen screen, Minecraft client, int width, int height) { - super(client, width / 3, 0, width / 3 * 2 + 1, height, true); - this.yaclScreen = screen; - - refreshOptions(); - - for (ConfigCategory category : screen.config.categories()) { - for (OptionGroup group : category.groups()) { - if (group instanceof ListOption<?> listOption) { - listOption.addRefreshListener(() -> refreshListEntries(listOption, category)); - } - } - } - } - - public void refreshOptions() { - clearEntries(); - - List<ConfigCategory> categories = new ArrayList<>(); - if (yaclScreen.getCurrentCategoryIdx() == -1) { - // -1 = no category, search in progress, so use all categories for search - 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()) { - GroupSeparatorEntry groupSeparatorEntry; - if (!group.isRoot()) { - groupSeparatorEntry = group instanceof ListOption<?> listOption - ? new ListGroupSeparatorEntry(listOption, yaclScreen) - : new GroupSeparatorEntry(group, yaclScreen); - addEntry(groupSeparatorEntry); - } else { - groupSeparatorEntry = null; - } - - List<dev.isxander.yacl.gui.OptionListWidget.Entry> optionEntries = new ArrayList<>(); - - // add empty entry to make sure users know it's empty not just bugging out - if (groupSeparatorEntry instanceof ListGroupSeparatorEntry listGroupSeparatorEntry) { - if (listGroupSeparatorEntry.listOption.options().isEmpty()) { - EmptyListLabel emptyListLabel = new EmptyListLabel(listGroupSeparatorEntry, category); - addEntry(emptyListLabel); - optionEntries.add(emptyListLabel); - } - } - - for (Option<?> option : group.options()) { - OptionEntry entry = new OptionEntry(option, category, group, groupSeparatorEntry, option.controller().provideWidget(yaclScreen, getDefaultEntryDimension())); - addEntry(entry); - optionEntries.add(entry); - } - - if (groupSeparatorEntry != null) { - groupSeparatorEntry.setChildEntries(optionEntries); - } - } - } - - recacheViewableChildren(); - setScrollAmount(0); - resetSmoothScrolling(); - } - - private void refreshListEntries(ListOption<?> listOption, ConfigCategory category) { - // find group separator for group - ListGroupSeparatorEntry groupSeparator = super.children().stream().filter(e -> e instanceof ListGroupSeparatorEntry gs && gs.group == listOption).map(ListGroupSeparatorEntry.class::cast).findAny().orElse(null); - - if (groupSeparator == null) { - YACLConstants.LOGGER.warn("Can't find group seperator to refresh list option entries for list option " + listOption.name()); - return; - } - - for (dev.isxander.yacl.gui.OptionListWidget.Entry entry : groupSeparator.childEntries) - super.removeEntry(entry); - groupSeparator.childEntries.clear(); - - // if no entries, below loop won't run where addEntryBelow() recaches viewable children - if (listOption.options().isEmpty()) { - EmptyListLabel emptyListLabel; - addEntryBelow(groupSeparator, emptyListLabel = new EmptyListLabel(groupSeparator, category)); - groupSeparator.childEntries.add(emptyListLabel); - return; - } - - dev.isxander.yacl.gui.OptionListWidget.Entry lastEntry = groupSeparator; - for (ListOptionEntry<?> listOptionEntry : listOption.options()) { - OptionEntry optionEntry = new OptionEntry(listOptionEntry, category, listOption, groupSeparator, listOptionEntry.controller().provideWidget(yaclScreen, getDefaultEntryDimension())); - addEntryBelow(lastEntry, optionEntry); - groupSeparator.childEntries.add(optionEntry); - lastEntry = optionEntry; - } - } - - public Dimension<Integer> getDefaultEntryDimension() { - return Dimension.ofInt(getRowLeft(), 0, getRowWidth(), 20); - } - - public void expandAllGroups() { - for (dev.isxander.yacl.gui.OptionListWidget.Entry entry : super.children()) { - if (entry instanceof GroupSeparatorEntry groupSeparatorEntry) { - groupSeparatorEntry.setExpanded(true); - } - } - } - - @Override - public int getRowWidth() { - return Math.min(396, (int)(width / 1.3f)); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - for (dev.isxander.yacl.gui.OptionListWidget.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) { - super.mouseScrolled(mouseX, mouseY, amount); - - for (dev.isxander.yacl.gui.OptionListWidget.Entry child : children()) { - if (child.mouseScrolled(mouseX, mouseY, amount)) - break; - } - - return true; - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - for (dev.isxander.yacl.gui.OptionListWidget.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 (dev.isxander.yacl.gui.OptionListWidget.Entry child : children()) { - if (child.charTyped(chr, modifiers)) - return true; - } - - return super.charTyped(chr, modifiers); - } - - @Override - protected int getScrollbarPosition() { - return x1 - (int)(width * 0.05f); - } - - public void recacheViewableChildren() { - this.viewableChildren = ImmutableList.copyOf(super.children().stream().filter(dev.isxander.yacl.gui.OptionListWidget.Entry::isViewable).toList()); - - // update y positions before they need to be rendered are rendered - int i = 0; - for (dev.isxander.yacl.gui.OptionListWidget.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 void addEntry(int index, Entry entry) { - super.children().add(index, entry); - recacheViewableChildren(); - } - - public void addEntryBelow(Entry below, Entry entry) { - int idx = super.children().indexOf(below) + 1; - - if (idx == 0) - throw new IllegalStateException("The entry to insert below does not exist!"); - - addEntry(idx, entry); - } - - public void addEntryBelowWithoutScroll(Entry below, Entry entry) { - double d = (double)this.getMaxScroll() - this.getScrollAmount(); - addEntryBelow(below, entry); - setScrollAmount(getMaxScroll() - d); - } - - @Override - public boolean removeEntryFromTop(Entry entry) { - boolean ret = super.removeEntryFromTop(entry); - recacheViewableChildren(); - return ret; - } - - @Override - public boolean removeEntry(Entry entry) { - boolean ret = super.removeEntry(entry); - recacheViewableChildren(); - return ret; - } - - public abstract class Entry extends ElementListWidgetExt.Entry<Entry> { - public boolean isViewable() { - return true; - } - - protected boolean isHovered() { - return Objects.equals(getHovered(), this); - } - } - - public class OptionEntry extends Entry { - public final Option<?> option; - public final ConfigCategory category; - public final OptionGroup group; - - public final @Nullable GroupSeparatorEntry groupSeparatorEntry; - - public final AbstractWidget widget; - - private final TextScaledButtonWidget resetButton; - - private final String categoryName; - private final String groupName; - - public OptionEntry(Option<?> option, ConfigCategory category, OptionGroup group, @Nullable GroupSeparatorEntry groupSeparatorEntry, AbstractWidget widget) { - this.option = option; - this.category = category; - this.group = group; - this.groupSeparatorEntry = groupSeparatorEntry; - this.widget = widget; - this.categoryName = category.name().getString().toLowerCase(); - this.groupName = group.name().getString().toLowerCase(); - if (option.canResetToDefault() && this.widget.canReset()) { - this.widget.setDimension(this.widget.getDimension().expanded(-20, 0)); - this.resetButton = new TextScaledButtonWidget(widget.getDimension().xLimit(), -50, 20, 20, 2f, Component.literal("\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(PoseStack 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(PoseStack 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.getQuery(); - return (groupSeparatorEntry == null || groupSeparatorEntry.isExpanded()) - && (yaclScreen.searchFieldWidget.isEmpty() - || (!singleCategory && categoryName.contains(query)) - || groupName.contains(query) - || widget.matchesSearch(query)); - } - - @Override - public int getItemHeight() { - return Math.max(widget.getDimension().height(), resetButton != null ? resetButton.getHeight() : 0) + 2; - } - - @Override - public void setFocused(boolean focused) { - super.setFocused(focused); - } - - @Override - public List<? extends NarratableEntry> narratables() { - if (resetButton == null) - return ImmutableList.of(widget); - - return ImmutableList.of(widget, resetButton); - } - - @Override - public List<? extends GuiEventListener> children() { - if (resetButton == null) - return ImmutableList.of(widget); - - return ImmutableList.of(widget, resetButton); - } - } - - public class GroupSeparatorEntry extends Entry { - protected final OptionGroup group; - protected final MultiLineLabel wrappedName; - protected final MultiLineLabel wrappedTooltip; - - protected final LowProfileButtonWidget expandMinimizeButton; - - protected final Screen screen; - protected final Font font = Minecraft.getInstance().font; - - protected boolean groupExpanded; - - protected List<Entry> childEntries = new ArrayList<>(); - - private int y; - - private GroupSeparatorEntry(OptionGroup group, Screen screen) { - this.group = group; - this.screen = screen; - this.wrappedName = MultiLineLabel.create(font, group.name(), getRowWidth() - 45); - this.wrappedTooltip = MultiLineLabel.create(font, group.tooltip(), screen.width / 3 * 2 - 10); - this.groupExpanded = !group.collapsed(); - this.expandMinimizeButton = new LowProfileButtonWidget(0, 0, 20, 20, Component.empty(), btn -> onExpandButtonPress()); - updateExpandMinimizeText(); - } - - @Override - public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - this.y = y; - - int buttonY = y + entryHeight / 2 - expandMinimizeButton.getHeight() / 2 + 1; - - expandMinimizeButton.setY(buttonY); - expandMinimizeButton.setX(x); - expandMinimizeButton.render(matrices, mouseX, mouseY, tickDelta); - - wrappedName.renderCentered(matrices, x + entryWidth / 2, y + getYPadding()); - } - - @Override - public void postRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - if ((isHovered() && !expandMinimizeButton.isMouseOver(mouseX, mouseY)) || expandMinimizeButton.isFocused()) { - YACLScreen.renderMultilineTooltip(matrices, font, wrappedTooltip, getRowLeft() + getRowWidth() / 2, y - 3, y + getItemHeight() + 3, screen.width, screen.height); - } - } - - public boolean isExpanded() { - return groupExpanded; - } - - public void setExpanded(boolean expanded) { - if (this.groupExpanded == expanded) - return; - - this.groupExpanded = expanded; - updateExpandMinimizeText(); - recacheViewableChildren(); - } - - protected void onExpandButtonPress() { - setExpanded(!isExpanded()); - } - - protected void updateExpandMinimizeText() { - expandMinimizeButton.setMessage(Component.literal(isExpanded() ? "▼" : "▶")); - } - - public void setChildEntries(List<? extends Entry> childEntries) { - this.childEntries.clear(); - this.childEntries.addAll(childEntries); - } - - @Override - public boolean isViewable() { - return yaclScreen.searchFieldWidget.isEmpty() || childEntries.stream().anyMatch(Entry::isViewable); - } - - @Override - public int getItemHeight() { - return Math.max(wrappedName.getLineCount(), 1) * font.lineHeight + getYPadding() * 2; - } - - private int getYPadding() { - return 6; - } - - @Override - public List<? extends NarratableEntry> narratables() { - return ImmutableList.of(new NarratableEntry() { - @Override - public NarratableEntry.NarrationPriority narrationPriority() { - return NarrationPriority.HOVERED; - } - - @Override - public void updateNarration(NarrationElementOutput builder) { - builder.add(NarratedElementType.TITLE, group.name()); - builder.add(NarratedElementType.HINT, group.tooltip()); - } - }); - } - - @Override - public List<? extends GuiEventListener> children() { - return ImmutableList.of(expandMinimizeButton); - } - } - - public class ListGroupSeparatorEntry extends GroupSeparatorEntry { - private final ListOption<?> listOption; - private final TextScaledButtonWidget resetListButton; - private final TooltipButtonWidget addListButton; - - private ListGroupSeparatorEntry(ListOption<?> group, Screen screen) { - super(group, screen); - this.listOption = group; - - this.resetListButton = new TextScaledButtonWidget(getRowRight() - 20, -50, 20, 20, 2f, Component.literal("\u21BB"), button -> { - group.requestSetDefault(); - }); - group.addListener((opt, val) -> this.resetListButton.active = !opt.isPendingValueDefault() && opt.available()); - this.resetListButton.active = !group.isPendingValueDefault() && group.available(); - - this.addListButton = new TooltipButtonWidget(yaclScreen, resetListButton.getX() - 20, -50, 20, 20, Component.literal("+"), Component.translatable("yacl.list.add_top"), btn -> { - group.insertNewEntryToTop(); - setExpanded(true); - }); - - updateExpandMinimizeText(); - minimizeIfUnavailable(); - } - - @Override - public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - updateExpandMinimizeText(); // update every render because option could become available/unavailable at any time - - super.render(matrices, index, y, x, entryWidth, entryHeight, mouseX, mouseY, hovered, tickDelta); - - int buttonY = expandMinimizeButton.getY(); - - resetListButton.setY(buttonY); - addListButton.setY(buttonY); - - resetListButton.render(matrices, mouseX, mouseY, tickDelta); - addListButton.render(matrices, mouseX, mouseY, tickDelta); - } - - @Override - public void postRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - minimizeIfUnavailable(); // cannot run in render because it *should* cause a ConcurrentModificationException (but doesn't) - - super.postRender(matrices, mouseX, mouseY, delta); - - addListButton.renderHoveredTooltip(matrices); - } - - private void minimizeIfUnavailable() { - if (!listOption.available() && isExpanded()) { - setExpanded(false); - } - } - - @Override - protected void updateExpandMinimizeText() { - super.updateExpandMinimizeText(); - expandMinimizeButton.active = listOption == null || listOption.available(); - if (addListButton != null) - addListButton.active = expandMinimizeButton.active; - } - - @Override - public List<? extends GuiEventListener> children() { - return ImmutableList.of(expandMinimizeButton, addListButton, resetListButton); - } - } - - public class EmptyListLabel extends Entry { - private final ListGroupSeparatorEntry parent; - private final String groupName; - private final String categoryName; - - public EmptyListLabel(ListGroupSeparatorEntry parent, ConfigCategory category) { - this.parent = parent; - this.groupName = parent.group.name().getString().toLowerCase(); - this.categoryName = category.name().getString().toLowerCase(); - } - - @Override - public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - drawCenteredString(matrices, Minecraft.getInstance().font, Component.translatable("yacl.list.empty").withStyle(ChatFormatting.DARK_GRAY, ChatFormatting.ITALIC), x + entryWidth / 2, y, -1); - } - - @Override - public boolean isViewable() { - String query = yaclScreen.searchFieldWidget.getQuery(); - return parent.isExpanded() && (yaclScreen.searchFieldWidget.isEmpty() - || (!singleCategory && categoryName.contains(query)) - || groupName.contains(query)); - } - - @Override - public int getItemHeight() { - return 11; - } - - @Override - public List<? extends GuiEventListener> children() { - return ImmutableList.of(); - } - - @Override - public List<? extends NarratableEntry> narratables() { - return ImmutableList.of(); - } - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/RequireRestartScreen.java b/src/client/java/dev/isxander/yacl/gui/RequireRestartScreen.java deleted file mode 100644 index 18b6033..0000000 --- a/src/client/java/dev/isxander/yacl/gui/RequireRestartScreen.java +++ /dev/null @@ -1,21 +0,0 @@ -package dev.isxander.yacl.gui; - -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.ConfirmScreen; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; - -public class RequireRestartScreen extends ConfirmScreen { - public RequireRestartScreen(Screen parent) { - super(option -> { - if (option) Minecraft.getInstance().stop(); - else Minecraft.getInstance().setScreen(parent); - }, - Component.translatable("yacl.restart.title").withStyle(ChatFormatting.RED, ChatFormatting.BOLD), - Component.translatable("yacl.restart.message"), - Component.translatable("yacl.restart.yes"), - Component.translatable("yacl.restart.no") - ); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/SearchFieldWidget.java b/src/client/java/dev/isxander/yacl/gui/SearchFieldWidget.java deleted file mode 100644 index 5cf38e0..0000000 --- a/src/client/java/dev/isxander/yacl/gui/SearchFieldWidget.java +++ /dev/null @@ -1,66 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.components.EditBox; -import net.minecraft.network.chat.Component; - -public class SearchFieldWidget extends EditBox { - private Component emptyText; - private final YACLScreen yaclScreen; - private final Font font; - - private boolean isEmpty = true; - - public SearchFieldWidget(YACLScreen yaclScreen, Font font, int x, int y, int width, int height, Component text, Component emptyText) { - super(font, x, y, width, height, text); - setResponder(string -> update()); - setFilter(string -> !string.endsWith(" ") && !string.startsWith(" ")); - this.yaclScreen = yaclScreen; - this.font = font; - this.emptyText = emptyText; - } - - @Override - public void renderWidget(PoseStack matrices, int mouseX, int mouseY, float delta) { - super.renderWidget(matrices, mouseX, mouseY, delta); - if (isVisible() && isEmpty()) { - font.drawShadow(matrices, emptyText, getX() + 4, this.getY() + (this.height - 8) / 2f, 0x707070); - } - } - - private void update() { - boolean wasEmpty = isEmpty; - isEmpty = getValue().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 String getQuery() { - return getValue().toLowerCase(); - } - - public boolean isEmpty() { - return isEmpty; - } - - public Component getEmptyText() { - return emptyText; - } - - public void setEmptyText(Component emptyText) { - this.emptyText = emptyText; - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/TextScaledButtonWidget.java b/src/client/java/dev/isxander/yacl/gui/TextScaledButtonWidget.java deleted file mode 100644 index b955912..0000000 --- a/src/client/java/dev/isxander/yacl/gui/TextScaledButtonWidget.java +++ /dev/null @@ -1,34 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.Tooltip; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; - -public class TextScaledButtonWidget extends Button { - public float textScale; - - public TextScaledButtonWidget(int x, int y, int width, int height, float textScale, Component message, OnPress onPress) { - super(x, y, width, height, message, onPress, DEFAULT_NARRATION); - this.textScale = textScale; - } - - public TextScaledButtonWidget(int x, int y, int width, int height, float textScale, Component message, OnPress onPress, Tooltip tooltip) { - this(x, y, width, height, textScale, message, onPress); - setTooltip(tooltip); - } - - @Override - public void renderString(PoseStack matrices, Font textRenderer, int color) { - Font font = Minecraft.getInstance().font; - - matrices.pushPose(); - matrices.translate(((this.getX() + this.width / 2f) - font.width(getMessage()) * textScale / 2), (float)this.getY() + (this.height - 8 * textScale) / 2f / textScale, 0); - matrices.scale(textScale, textScale, 1); - font.drawShadow(matrices, getMessage(), 0, 0, color | Mth.ceil(this.alpha * 255.0F) << 24); - matrices.popPose(); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/TooltipButtonWidget.java b/src/client/java/dev/isxander/yacl/gui/TooltipButtonWidget.java deleted file mode 100644 index 1395a3f..0000000 --- a/src/client/java/dev/isxander/yacl/gui/TooltipButtonWidget.java +++ /dev/null @@ -1,34 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.MultiLineLabel; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; - -public class TooltipButtonWidget extends TextScaledButtonWidget { - - protected final Screen screen; - protected MultiLineLabel wrappedDescription; - - public TooltipButtonWidget(Screen screen, int x, int y, int width, int height, Component message, float textScale, Component tooltip, Button.OnPress onPress) { - super(x, y, width, height, textScale, message, onPress); - this.screen = screen; - setTooltip(tooltip); - } - - public TooltipButtonWidget(Screen screen, int x, int y, int width, int height, Component message, Component tooltip, Button.OnPress onPress) { - this(screen, x, y, width, height, message, 1, tooltip, onPress); - } - - public void renderHoveredTooltip(PoseStack matrices) { - if (isHoveredOrFocused()) { - YACLScreen.renderMultilineTooltip(matrices, Minecraft.getInstance().font, wrappedDescription, getX() + width / 2, getY() - 4, getY() + height + 4, screen.width, screen.height); - } - } - - public void setTooltip(Component tooltip) { - wrappedDescription = MultiLineLabel.create(Minecraft.getInstance().font, tooltip, screen.width / 3 - 5); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/YACLScreen.java b/src/client/java/dev/isxander/yacl/gui/YACLScreen.java deleted file mode 100644 index d653d8c..0000000 --- a/src/client/java/dev/isxander/yacl/gui/YACLScreen.java +++ /dev/null @@ -1,316 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.*; -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 dev.isxander.yacl.gui.utils.GuiUtils; -import dev.isxander.yacl.impl.utils.YACLConstants; -import net.minecraft.ChatFormatting; -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.GuiComponent; -import net.minecraft.client.gui.components.MultiLineLabel; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.gui.screens.inventory.tooltip.TooltipRenderUtil; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.network.chat.CommonComponents; -import net.minecraft.network.chat.Component; -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 Component 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(), - Component.empty(), - Component.empty(), - btn -> finishOrSave() - ); - 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(), - Component.empty(), - Component.empty(), - btn -> cancelOrReset() - ); - actionDim.move(actionDim.width() + 4, 0); - undoButton = new TooltipButtonWidget( - this, - actionDim.x() - actionDim.width() / 2, - actionDim.y(), - actionDim.width(), - actionDim.height(), - Component.translatable("yacl.gui.undo"), - Component.translatable("yacl.gui.undo.tooltip"), - btn -> undo() - ); - - searchFieldWidget = new SearchFieldWidget( - this, - font, - width / 3 / 2 - paddedWidth / 2 + 1, - undoButton.getY() - 22, - paddedWidth - 2, 18, - Component.translatable("gui.recipebook.search_hint"), - Component.translatable("gui.recipebook.search_hint") - ); - - categoryList = new CategoryListWidget(minecraft, this, width, height); - addWidget(categoryList); - - updateActionAvailability(); - addRenderableWidget(searchFieldWidget); - addRenderableWidget(cancelResetButton); - addRenderableWidget(undoButton); - addRenderableWidget(finishedSaveButton); - - optionList = new OptionListWidget(this, minecraft, width, height); - addWidget(optionList); - - config.initConsumer().accept(this); - } - - @Override - public void render(PoseStack 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 (GuiEventListener child : children()) { - if (child instanceof TooltipButtonWidget tooltipButtonWidget) { - tooltipButtonWidget.renderHoveredTooltip(matrices); - } - } - } - - protected void finishOrSave() { - 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()) { - // if still changed after applying, reset to the current value from binding - // as something has gone wrong. - option.forgetPendingValue(); - YACLConstants.LOGGER.error("Option '{}' value mismatch after applying! Reset to binding's getter.", option.name().getString()); - } - }); - config.saveFunction().run(); - - flags.forEach(flag -> flag.accept(minecraft)); - } else onClose(); - } - - protected void cancelOrReset() { - if (pendingChanges()) { // if pending changes, button acts as a cancel button - OptionUtils.forEachOptions(config, Option::forgetPendingValue); - onClose(); - } else { // if not, button acts as a reset button - OptionUtils.forEachOptions(config, Option::requestSetDefault); - } - } - - protected void undo() { - OptionUtils.forEachOptions(config, Option::forgetPendingValue); - } - - @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) { - minecraft.setScreen(placeholderCategory.screen().apply(minecraft, this)); - } else { - currentCategoryIdx = idx; - optionList.refreshOptions(); - } - } - - public int getCurrentCategoryIdx() { - return currentCategoryIdx; - } - - private void updateActionAvailability() { - boolean pendingChanges = pendingChanges(); - - undoButton.active = pendingChanges; - finishedSaveButton.setMessage(pendingChanges ? Component.translatable("yacl.gui.save") : GuiUtils.translatableFallback("yacl.gui.done", CommonComponents.GUI_DONE)); - finishedSaveButton.setTooltip(pendingChanges ? Component.translatable("yacl.gui.save.tooltip") : Component.translatable("yacl.gui.finished.tooltip")); - cancelResetButton.setMessage(pendingChanges ? GuiUtils.translatableFallback("yacl.gui.cancel", CommonComponents.GUI_CANCEL) : Component.translatable("controls.reset")); - cancelResetButton.setTooltip(pendingChanges ? Component.translatable("yacl.gui.cancel.tooltip") : Component.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(Component message, Component 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(Component.translatable("yacl.gui.save_before_exit").withStyle(ChatFormatting.RED), Component.translatable("yacl.gui.save_before_exit.tooltip")); - return false; - } - return true; - } - - @Override - public void onClose() { - minecraft.setScreen(parent); - } - - public static void renderMultilineTooltip(PoseStack matrices, Font font, MultiLineLabel text, int centerX, int yAbove, int yBelow, int screenWidth, int screenHeight) { - if (text.getLineCount() > 0) { - int maxWidth = text.getWidth(); - int lineHeight = font.lineHeight + 1; - int height = text.getLineCount() * lineHeight - 1; - - int belowY = yBelow + 12; - int aboveY = yAbove - height + 12; - int maxBelow = screenHeight - (belowY + height); - int minAbove = aboveY - height; - int y = aboveY; - if (minAbove < 8) - y = maxBelow > minAbove ? belowY : aboveY; - - int x = Math.max(centerX - text.getWidth() / 2 - 12, -6); - - int drawX = x + 12; - int drawY = y - 12; - - matrices.pushPose(); - Tesselator tesselator = Tesselator.getInstance(); - BufferBuilder bufferBuilder = tesselator.getBuilder(); - RenderSystem.setShader(GameRenderer::getPositionColorShader); - bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); - Matrix4f matrix4f = matrices.last().pose(); - TooltipRenderUtil.renderTooltipBackground( - GuiComponent::fillGradient, - matrix4f, - bufferBuilder, - drawX, - drawY, - maxWidth, - height, - 400 - ); - RenderSystem.enableDepthTest(); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - BufferUploader.drawWithShader(bufferBuilder.end()); - RenderSystem.disableBlend(); - matrices.translate(0.0, 0.0, 400.0); - - text.renderLeftAligned(matrices, drawX, drawY, lineHeight, -1); - - matrices.popPose(); - } - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/ActionController.java b/src/client/java/dev/isxander/yacl/gui/controllers/ActionController.java deleted file mode 100644 index e57cdd2..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/ActionController.java +++ /dev/null @@ -1,120 +0,0 @@ -package dev.isxander.yacl.gui.controllers; - -import com.mojang.blaze3d.platform.InputConstants; -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.network.chat.Component; - -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 Component DEFAULT_TEXT = Component.translatable("yacl.control.action.execute"); - - private final ButtonOption option; - private final Component 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, Component text) { - this.option = option; - this.text = text; - - } - - /** - * {@inheritDoc} - */ - @Override - public ButtonOption option() { - return option; - } - - /** - * {@inheritDoc} - */ - @Override - public Component 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 == InputConstants.KEY_RETURN || keyCode == InputConstants.KEY_SPACE || keyCode == InputConstants.KEY_NUMPADENTER) { - 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/client/java/dev/isxander/yacl/gui/controllers/BooleanController.java b/src/client/java/dev/isxander/yacl/gui/controllers/BooleanController.java deleted file mode 100644 index d7d17d5..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/BooleanController.java +++ /dev/null @@ -1,157 +0,0 @@ -package dev.isxander.yacl.gui.controllers; - -import com.mojang.blaze3d.platform.InputConstants; -import com.mojang.blaze3d.vertex.PoseStack; -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.ChatFormatting; -import net.minecraft.network.chat.CommonComponents; -import net.minecraft.network.chat.Component; - -import java.util.function.Function; - -/** - * This controller renders a simple formatted {@link Component} - */ -public class BooleanController implements Controller<Boolean> { - - public static final Function<Boolean, Component> ON_OFF_FORMATTER = (state) -> - state - ? CommonComponents.OPTION_ON - : CommonComponents.OPTION_OFF; - - public static final Function<Boolean, Component> TRUE_FALSE_FORMATTER = (state) -> - state - ? Component.translatable("yacl.control.boolean.true") - : Component.translatable("yacl.control.boolean.false"); - - public static final Function<Boolean, Component> YES_NO_FORMATTER = (state) -> - state - ? CommonComponents.GUI_YES - : CommonComponents.GUI_NO; - - private final Option<Boolean> option; - private final Function<Boolean, Component> 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 Component} - * @param coloured value format is green or red depending on the state - */ - public BooleanController(Option<Boolean> option, Function<Boolean, Component> valueFormatter, boolean coloured) { - this.option = option; - this.valueFormatter = valueFormatter; - this.coloured = coloured; - } - - /** - * {@inheritDoc} - */ - @Override - public Option<Boolean> option() { - return option; - } - - /** - * {@inheritDoc} - */ - @Override - public Component 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(PoseStack 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 Component getValueText() { - if (control.coloured()) { - return super.getValueText().copy().withStyle(control.option().pendingValue() ? ChatFormatting.GREEN : ChatFormatting.RED); - } - - return super.getValueText(); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (!isFocused()) { - return false; - } - - if (keyCode == InputConstants.KEY_RETURN || keyCode == InputConstants.KEY_SPACE || keyCode == InputConstants.KEY_NUMPADENTER) { - toggleSetting(); - return true; - } - - return false; - } - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/ColorController.java b/src/client/java/dev/isxander/yacl/gui/controllers/ColorController.java deleted file mode 100644 index 473407b..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/ColorController.java +++ /dev/null @@ -1,221 +0,0 @@ -package dev.isxander.yacl.gui.controllers; - -import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.vertex.PoseStack; -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.ChatFormatting; -import net.minecraft.client.gui.GuiComponent; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; - -import java.awt.Color; -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 Component formatValue() { - MutableComponent text = Component.literal("#"); - text.append(Component.literal(toHex(option().pendingValue().getRed())).withStyle(ChatFormatting.RED)); - text.append(Component.literal(toHex(option().pendingValue().getGreen())).withStyle(ChatFormatting.GREEN)); - text.append(Component.literal(toHex(option().pendingValue().getBlue())).withStyle(ChatFormatting.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, true); - 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(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (isHovered()) { - colorPreviewDim.move(-inputFieldBounds.width() - 5, 0); - super.drawValueText(matrices, mouseX, mouseY, delta); - } - - GuiComponent.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) { - if (string.startsWith("0x")) string = string.substring(2); - for (char chr : string.toCharArray()) { - if (!allowedChars.contains(Character.toLowerCase(chr))) { - return; - } - } - - if (caretPos == 0) - return; - - String trimmed = string.substring(0, Math.min(inputField.length() - caretPos, string.length())); - - if (modifyInput(builder -> builder.replace(caretPos, caretPos + trimmed.length(), trimmed))) { - caretPos += trimmed.length(); - setSelectionLength(); - updateControl(); - } - } - - @Override - protected void doBackspace() { - if (caretPos > 1) { - if (modifyInput(builder -> builder.setCharAt(caretPos - 1, '0'))) { - caretPos--; - updateControl(); - } - } - } - - @Override - protected void doDelete() { - if (caretPos >= 1) { - if (modifyInput(builder -> builder.setCharAt(caretPos, '0'))) { - updateControl(); - } - } - } - - @Override - protected boolean doCut() { - return false; - } - - @Override - protected boolean doCopy() { - return false; - } - - @Override - protected boolean doSelectAll() { - return false; - } - - protected void setSelectionLength() { - selectionLength = caretPos < inputField.length() && caretPos > 0 ? 1 : 0; - } - - @Override - protected int getDefaultCaretPos() { - 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) { - int prevSelectionLength = selectionLength; - selectionLength = 0; - if (super.keyPressed(keyCode, scanCode, modifiers)) { - caretPos = Math.max(1, caretPos); - setSelectionLength(); - return true; - } else selectionLength = prevSelectionLength; - 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/client/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java b/src/client/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java deleted file mode 100644 index 22c469d..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java +++ /dev/null @@ -1,170 +0,0 @@ -package dev.isxander.yacl.gui.controllers; - -import com.mojang.blaze3d.vertex.PoseStack; -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 dev.isxander.yacl.gui.utils.GuiUtils; -import net.minecraft.ChatFormatting; -import net.minecraft.client.gui.ComponentPath; -import net.minecraft.client.gui.GuiComponent; -import net.minecraft.client.gui.components.MultiLineLabel; -import net.minecraft.client.gui.narration.NarratedElementType; -import net.minecraft.client.gui.narration.NarrationElementOutput; -import net.minecraft.client.gui.navigation.FocusNavigationEvent; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.Nullable; - -public abstract class ControllerWidget<T extends Controller<?>> extends AbstractWidget { - protected final T control; - protected MultiLineLabel wrappedTooltip; - protected final YACLScreen screen; - - protected boolean focused = false; - protected boolean hovered = false; - - protected final Component 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().withStyle(ChatFormatting.ITALIC); - this.optionNameString = control.option().name().getString().toLowerCase(); - } - - @Override - public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - hovered = isMouseOver(mouseX, mouseY); - - Component name = control.option().changed() ? modifiedOptionName : control.option().name(); - Component shortenedName = Component.literal(GuiUtils.shortenString(name.getString(), textRenderer, getDimension().width() - getControlWidth() - getXPadding() - 7, "...")).setStyle(name.getStyle()); - - drawButtonRect(matrices, getDimension().x(), getDimension().y(), getDimension().xLimit(), getDimension().yLimit(), isHovered(), isAvailable()); - matrices.pushPose(); - matrices.translate(getDimension().x() + getXPadding(), getTextY(), 0); - textRenderer.drawShadow(matrices, shortenedName, 0, 0, getValueColor()); - matrices.popPose(); - - drawValueText(matrices, mouseX, mouseY, delta); - if (isHovered()) { - drawHoveredControl(matrices, mouseX, mouseY, delta); - } - } - - @Override - public void postRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (hovered || focused) { - YACLScreen.renderMultilineTooltip(matrices, textRenderer, wrappedTooltip, getDimension().centerX(), getDimension().y() - 5, getDimension().yLimit() + 5, screen.width, screen.height); - } - } - - protected void drawHoveredControl(PoseStack matrices, int mouseX, int mouseY, float delta) { - - } - - protected void drawValueText(PoseStack matrices, int mouseX, int mouseY, float delta) { - Component valueText = getValueText(); - matrices.pushPose(); - matrices.translate(getDimension().xLimit() - textRenderer.width(valueText) - getXPadding(), getTextY(), 0); - textRenderer.drawShadow(matrices, valueText, 0, 0, getValueColor()); - matrices.popPose(); - } - - private void updateTooltip() { - this.wrappedTooltip = MultiLineLabel.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.width(getValueText()); - } - - protected int getXPadding() { - return 5; - } - - protected int getYPadding() { - return 2; - } - - protected Component 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(PoseStack matrices, int x1, int y1, int x2, int y2, int width, int color) { - GuiComponent.fill(matrices, x1, y1, x2, y1 + width, color); - GuiComponent.fill(matrices, x2, y1, x2 - width, y2, color); - GuiComponent.fill(matrices, x1, y2, x2, y2 - width, color); - GuiComponent.fill(matrices, x1, y1, x1 + width, y2, color); - } - - protected float getTextY() { - return getDimension().y() + getDimension().height() / 2f - textRenderer.lineHeight / 2f; - } - - @Nullable - @Override - public ComponentPath nextFocusPath(FocusNavigationEvent focusNavigationEvent) { - if (!this.isAvailable()) - return null; - return !this.isFocused() ? ComponentPath.leaf(this) : null; - } - - @Override - public boolean isFocused() { - return focused; - } - - @Override - public void setFocused(boolean focused) { - this.focused = focused; - } - - @Override - public void unfocus() { - this.focused = false; - } - - @Override - public boolean matchesSearch(String query) { - return optionNameString.contains(query.toLowerCase()); - } - - @Override - public NarrationPriority narrationPriority() { - return focused ? NarrationPriority.FOCUSED : isHovered() ? NarrationPriority.HOVERED : NarrationPriority.NONE; - } - - @Override - public void updateNarration(NarrationElementOutput builder) { - builder.add(NarratedElementType.TITLE, control.option().name()); - builder.add(NarratedElementType.HINT, control.option().tooltip()); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/LabelController.java b/src/client/java/dev/isxander/yacl/gui/controllers/LabelController.java deleted file mode 100644 index 1dfae0b..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/LabelController.java +++ /dev/null @@ -1,193 +0,0 @@ -package dev.isxander.yacl.gui.controllers; - -import com.mojang.blaze3d.vertex.PoseStack; -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.ComponentPath; -import net.minecraft.client.gui.GuiComponent; -import net.minecraft.client.gui.components.MultiLineLabel; -import net.minecraft.client.gui.narration.NarratedElementType; -import net.minecraft.client.gui.narration.NarrationElementOutput; -import net.minecraft.client.gui.navigation.FocusNavigationEvent; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.HoverEvent; -import net.minecraft.network.chat.Style; -import net.minecraft.util.FormattedCharSequence; -import net.minecraft.world.item.ItemStack; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -/** - * Simply renders some text as a label. - */ -public class LabelController implements Controller<Component> { - private final Option<Component> option; - /** - * Constructs a label controller - * - * @param option bound option - */ - public LabelController(Option<Component> option) { - this.option = option; - } - - /** - * {@inheritDoc} - */ - @Override - public Option<Component> option() { - return option; - } - - @Override - public Component 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<FormattedCharSequence> wrappedText; - protected MultiLineLabel wrappedTooltip; - protected boolean focused; - - 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(PoseStack matrices, int mouseX, int mouseY, float delta) { - updateText(); - - float y = getDimension().y(); - for (FormattedCharSequence text : wrappedText) { - textRenderer.drawShadow(matrices, text, getDimension().x() + getXPadding(), y + getYPadding(), option().available() ? -1 : 0xFFA0A0A0); - y += textRenderer.lineHeight; - } - - if (isFocused()) { - GuiComponent.fill(matrices, getDimension().x() - 1, getDimension().y() - 1, getDimension().xLimit() + 1, getDimension().y(), -1); - GuiComponent.fill(matrices, getDimension().x() - 1, getDimension().y() - 1, getDimension().x(), getDimension().yLimit() + 1, -1); - GuiComponent.fill(matrices, getDimension().x() - 1, getDimension().yLimit(), getDimension().xLimit() + 1, getDimension().yLimit() + 1, -1); - GuiComponent.fill(matrices, getDimension().xLimit(), getDimension().y() - 1, getDimension().xLimit() + 1, getDimension().yLimit() + 1, -1); - } - } - - @Override - public void postRender(PoseStack 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.ItemStackInfo itemStackContent = hoverEvent.getValue(HoverEvent.Action.SHOW_ITEM); - if (itemStackContent != null) { - ItemStack stack = itemStackContent.getItemStack(); - screen.renderTooltip(matrices, screen.getTooltipFromItem(stack), stack.getTooltipImage(), mouseX, mouseY); - } else { - HoverEvent.EntityTooltipInfo entityContent = hoverEvent.getValue(HoverEvent.Action.SHOW_ENTITY); - if (entityContent != null) { - if (this.client.options.advancedItemTooltips) { - screen.renderComponentTooltip(matrices, entityContent.getTooltipLines(), mouseX, mouseY); - } - } else { - Component text = hoverEvent.getValue(HoverEvent.Action.SHOW_TEXT); - if (text != null) { - MultiLineLabel multilineText = MultiLineLabel.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.handleComponentClicked(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.lineHeight; - - 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.getSplitter().componentStyleAtWidth(wrappedText.get(line), x); - } - - private int getXPadding() { - return 4; - } - - private int getYPadding() { - return 3; - } - - private void updateText() { - wrappedText = textRenderer.split(formatValue(), getDimension().width() - getXPadding() * 2); - setDimension(getDimension().withHeight(wrappedText.size() * textRenderer.lineHeight + getYPadding() * 2)); - } - - private void updateTooltip() { - this.wrappedTooltip = MultiLineLabel.create(textRenderer, option().tooltip(), screen.width / 3 * 2 - 10); - } - - @Override - public boolean matchesSearch(String query) { - return formatValue().getString().toLowerCase().contains(query.toLowerCase()); - } - - @Nullable - @Override - public ComponentPath nextFocusPath(FocusNavigationEvent focusNavigationEvent) { - if (!option().available()) - return null; - return !this.isFocused() ? ComponentPath.leaf(this) : null; - } - - @Override - public boolean isFocused() { - return focused; - } - - @Override - public void setFocused(boolean focused) { - this.focused = focused; - } - - @Override - public void updateNarration(NarrationElementOutput builder) { - builder.add(NarratedElementType.TITLE, formatValue()); - } - - @Override - public NarrationPriority narrationPriority() { - return NarrationPriority.FOCUSED; - } - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/ListEntryWidget.java b/src/client/java/dev/isxander/yacl/gui/controllers/ListEntryWidget.java deleted file mode 100644 index 1acccf1..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/ListEntryWidget.java +++ /dev/null @@ -1,133 +0,0 @@ -package dev.isxander.yacl.gui.controllers; - -import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.vertex.PoseStack; -import dev.isxander.yacl.api.ListOption; -import dev.isxander.yacl.api.ListOptionEntry; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.*; -import net.minecraft.client.gui.components.events.ContainerEventHandler; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.narration.NarrationElementOutput; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -public class ListEntryWidget extends AbstractWidget implements ContainerEventHandler { - private final TooltipButtonWidget removeButton, moveUpButton, moveDownButton; - private final AbstractWidget entryWidget; - - private final ListOption<?> listOption; - private final ListOptionEntry<?> listOptionEntry; - - private final String optionNameString; - - private GuiEventListener focused; - private boolean dragging; - - public ListEntryWidget(YACLScreen screen, ListOptionEntry<?> listOptionEntry, AbstractWidget entryWidget) { - super(entryWidget.getDimension().withHeight(Math.max(entryWidget.getDimension().height(), 20) - ((listOptionEntry.parentGroup().indexOf(listOptionEntry) == listOptionEntry.parentGroup().options().size() - 1) ? 0 : 2))); // -2 to remove the padding - this.listOptionEntry = listOptionEntry; - this.listOption = listOptionEntry.parentGroup(); - this.optionNameString = listOptionEntry.name().getString().toLowerCase(); - this.entryWidget = entryWidget; - - Dimension<Integer> dim = entryWidget.getDimension(); - entryWidget.setDimension(dim.clone().move(20 * 2, 0).expand(-20 * 3, 0)); - - removeButton = new TooltipButtonWidget(screen, dim.xLimit() - 20, dim.y(), 20, 20, Component.literal("\u274c"), Component.translatable("yacl.list.remove"), btn -> { - listOption.removeEntry(listOptionEntry); - updateButtonStates(); - }); - - moveUpButton = new TooltipButtonWidget(screen, dim.x(), dim.y(), 20, 20, Component.literal("\u2191"), Component.translatable("yacl.list.move_up"), btn -> { - int index = listOption.indexOf(listOptionEntry) - 1; - if (index >= 0) { - listOption.removeEntry(listOptionEntry); - listOption.insertEntry(index, listOptionEntry); - updateButtonStates(); - } - }); - - moveDownButton = new TooltipButtonWidget(screen, dim.x() + 20, dim.y(), 20, 20, Component.literal("\u2193"), Component.translatable("yacl.list.move_down"), btn -> { - int index = listOption.indexOf(listOptionEntry) + 1; - if (index < listOption.options().size()) { - listOption.removeEntry(listOptionEntry); - listOption.insertEntry(index, listOptionEntry); - updateButtonStates(); - } - }); - - updateButtonStates(); - } - - @Override - public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - updateButtonStates(); // update every render in case option becomes available/unavailable - - removeButton.setY(getDimension().y()); - moveUpButton.setY(getDimension().y()); - moveDownButton.setY(getDimension().y()); - entryWidget.setDimension(entryWidget.getDimension().withY(getDimension().y())); - - removeButton.render(matrices, mouseX, mouseY, delta); - moveUpButton.render(matrices, mouseX, mouseY, delta); - moveDownButton.render(matrices, mouseX, mouseY, delta); - entryWidget.render(matrices, mouseX, mouseY, delta); - } - - @Override - public void postRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - removeButton.renderHoveredTooltip(matrices); - moveUpButton.renderHoveredTooltip(matrices); - moveDownButton.renderHoveredTooltip(matrices); - } - - protected void updateButtonStates() { - removeButton.active = listOption.available(); - moveUpButton.active = listOption.indexOf(listOptionEntry) > 0 && listOption.available(); - moveDownButton.active = listOption.indexOf(listOptionEntry) < listOption.options().size() - 1 && listOption.available(); - } - - @Override - public void unfocus() { - entryWidget.unfocus(); - } - - @Override - public void updateNarration(NarrationElementOutput builder) { - entryWidget.updateNarration(builder); - } - - @Override - public boolean matchesSearch(String query) { - return optionNameString.contains(query.toLowerCase()); - } - - @Override - public List<? extends GuiEventListener> children() { - return ImmutableList.of(moveUpButton, moveDownButton, entryWidget, removeButton); - } - - @Override - public boolean isDragging() { - return dragging; - } - - @Override - public void setDragging(boolean dragging) { - this.dragging = dragging; - } - - @Nullable - @Override - public GuiEventListener getFocused() { - return focused; - } - - @Override - public void setFocused(@Nullable GuiEventListener focused) { - this.focused = focused; - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/TickBoxController.java b/src/client/java/dev/isxander/yacl/gui/controllers/TickBoxController.java deleted file mode 100644 index 3f615db..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/TickBoxController.java +++ /dev/null @@ -1,120 +0,0 @@ -package dev.isxander.yacl.gui.controllers; - -import com.mojang.blaze3d.platform.InputConstants; -import com.mojang.blaze3d.vertex.PoseStack; -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.GuiComponent; -import net.minecraft.network.chat.Component; - -/** - * 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 Component formatValue() { - return Component.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(PoseStack 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()) { - GuiComponent.fill(matrices, outlineX1 + 3, outlineY1 + 3, outlineX2 - 1, outlineY2 - 1, shadowColor); - GuiComponent.fill(matrices, outlineX1 + 2, outlineY1 + 2, outlineX2 - 2, outlineY2 - 2, color); - } - } - - @Override - protected void drawValueText(PoseStack 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 == InputConstants.KEY_RETURN || keyCode == InputConstants.KEY_SPACE || keyCode == InputConstants.KEY_NUMPADENTER) { - toggleSetting(); - return true; - } - - return false; - } - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java b/src/client/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java deleted file mode 100644 index ff20039..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java +++ /dev/null @@ -1,60 +0,0 @@ -package dev.isxander.yacl.gui.controllers.cycling; - -import com.mojang.blaze3d.platform.InputConstants; -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.screens.Screen; - -public class CyclingControllerElement extends ControllerWidget<ICyclingController<?>> { - - public CyclingControllerElement(ICyclingController<?> control, YACLScreen screen, Dimension<Integer> dim) { - super(control, screen, dim); - } - - public void cycleValue(int increment) { - int targetIdx = control.getPendingValue() + increment; - if (targetIdx >= control.getCycleLength()) { - targetIdx -= control.getCycleLength(); - } else if (targetIdx < 0) { - targetIdx += control.getCycleLength(); - } - control.setPendingValue(targetIdx); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (!isMouseOver(mouseX, mouseY) || (button != 0 && button != 1) || !isAvailable()) - return false; - - playDownSound(); - cycleValue(button == 1 || Screen.hasShiftDown() || Screen.hasControlDown() ? -1 : 1); - - return true; - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (!focused) - return false; - - switch (keyCode) { - case InputConstants.KEY_LEFT -> - cycleValue(-1); - case InputConstants.KEY_RIGHT -> - cycleValue(1); - case InputConstants.KEY_RETURN, InputConstants.KEY_SPACE, InputConstants.KEY_NUMPADENTER -> - cycleValue(Screen.hasControlDown() || Screen.hasShiftDown() ? -1 : 1); - default -> { - return false; - } - } - - return true; - } - - @Override - protected int getHoveredControlWidth() { - return getUnhoveredControlWidth(); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/cycling/CyclingListController.java b/src/client/java/dev/isxander/yacl/gui/controllers/cycling/CyclingListController.java deleted file mode 100644 index 34f2cc9..0000000 --- a/src/client/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.network.chat.Component; - -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, Component> 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 -> Component.literal(value.toString())); - } - - /** - * Constructs a {@link CyclingListController} - * @param option option of which to bind the controller to - * @param values the values to cycle through - * @param valueFormatter function of how to convert each value to a string to display - */ - public CyclingListController(Option<T> option, Iterable<T> values, Function<T, Component> valueFormatter) { - this.option = option; - this.valueFormatter = valueFormatter; - this.values = ImmutableList.copyOf(values); - } - - /** - * {@inheritDoc} - */ - @Override - public Option<T> option() { - return option; - } - - /** - * {@inheritDoc} - */ - @Override - public Component 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/client/java/dev/isxander/yacl/gui/controllers/cycling/EnumController.java b/src/client/java/dev/isxander/yacl/gui/controllers/cycling/EnumController.java deleted file mode 100644 index ebd2cb6..0000000 --- a/src/client/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.network.chat.Component; -import net.minecraft.util.OptionEnum; - -import java.util.Arrays; -import java.util.function.Function; - -/** - * Simple controller type that displays the enum on the right. - * <p> - * Cycles forward with left click, cycles backward with right click or when shift is held - * - * @param <T> enum type - */ -public class EnumController<T extends Enum<T>> extends CyclingListController<T> { - public static <T extends Enum<T>> Function<T, Component> getDefaultFormatter() { - return value -> { - if (value instanceof NameableEnum nameableEnum) - return nameableEnum.getDisplayName(); - if (value instanceof OptionEnum translatableOption) - return translatableOption.getCaption(); - return Component.literal(value.toString()); - }; - } - - /** - * 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 OptionEnum} 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 Component} - */ - public EnumController(Option<T> option, Function<T, Component> valueFormatter) { - this(option, valueFormatter, option.typeClass().getEnumConstants()); - } - - /** - * Constructs a cycling enum controller. - * - * @param option bound option - * @param valueFormatter format the enum into any {@link Component} - * @param availableValues all enum constants that can be cycled through - */ - public EnumController(Option<T> option, Function<T, Component> valueFormatter, T[] availableValues) { - super(option, Arrays.asList(availableValues), valueFormatter); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/cycling/ICyclingController.java b/src/client/java/dev/isxander/yacl/gui/controllers/cycling/ICyclingController.java deleted file mode 100644 index 081b572..0000000 --- a/src/client/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/client/java/dev/isxander/yacl/gui/controllers/package-info.java b/src/client/java/dev/isxander/yacl/gui/controllers/package-info.java deleted file mode 100644 index 12ce86b..0000000 --- a/src/client/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/client/java/dev/isxander/yacl/gui/controllers/slider/DoubleSliderController.java b/src/client/java/dev/isxander/yacl/gui/controllers/slider/DoubleSliderController.java deleted file mode 100644 index 8e044b1..0000000 --- a/src/client/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.network.chat.Component; -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, Component> DEFAULT_FORMATTER = value -> Component.literal(String.format("%,.2f", value).replaceAll("[\u00a0\u202F]", " ")); - - private final Option<Double> option; - - private final double min, max, interval; - - private final Function<Double, Component> 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 Component} - */ - public DoubleSliderController(Option<Double> option, double min, double max, double interval, Function<Double, Component> 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 Component 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/client/java/dev/isxander/yacl/gui/controllers/slider/FloatSliderController.java b/src/client/java/dev/isxander/yacl/gui/controllers/slider/FloatSliderController.java deleted file mode 100644 index 25f2206..0000000 --- a/src/client/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.network.chat.Component; -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, Component> DEFAULT_FORMATTER = value -> Component.literal(String.format("%,.1f", value).replaceAll("[\u00a0\u202F]", " ")); - - private final Option<Float> option; - - private final float min, max, interval; - - private final Function<Float, Component> 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 Component} - */ - public FloatSliderController(Option<Float> option, float min, float max, float interval, Function<Float, Component> 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 Component 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/client/java/dev/isxander/yacl/gui/controllers/slider/ISliderController.java b/src/client/java/dev/isxander/yacl/gui/controllers/slider/ISliderController.java deleted file mode 100644 index aa3c18f..0000000 --- a/src/client/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/client/java/dev/isxander/yacl/gui/controllers/slider/IntegerSliderController.java b/src/client/java/dev/isxander/yacl/gui/controllers/slider/IntegerSliderController.java deleted file mode 100644 index 4a68497..0000000 --- a/src/client/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.network.chat.Component; -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, Component> DEFAULT_FORMATTER = value -> Component.literal(String.format("%,d", value).replaceAll("[\u00a0\u202F]", " ")); - - private final Option<Integer> option; - - private final int min, max, interval; - - private final Function<Integer, Component> 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 Component} - */ - public IntegerSliderController(Option<Integer> option, int min, int max, int interval, Function<Integer, Component> 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 Component 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/client/java/dev/isxander/yacl/gui/controllers/slider/LongSliderController.java b/src/client/java/dev/isxander/yacl/gui/controllers/slider/LongSliderController.java deleted file mode 100644 index 681e7cf..0000000 --- a/src/client/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.network.chat.Component; -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, Component> DEFAULT_FORMATTER = value -> Component.literal(String.format("%,d", value).replaceAll("[\u00a0\u202F]", " ")); - - private final Option<Long> option; - - private final long min, max, interval; - - private final Function<Long, Component> 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 Component} - */ - public LongSliderController(Option<Long> option, long min, long max, long interval, Function<Long, Component> 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 Component 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/client/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java b/src/client/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java deleted file mode 100644 index d00f3d7..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java +++ /dev/null @@ -1,164 +0,0 @@ -package dev.isxander.yacl.gui.controllers.slider; - -import com.mojang.blaze3d.platform.InputConstants; -import com.mojang.blaze3d.vertex.PoseStack; -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.GuiComponent; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.util.Mth; - -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(PoseStack matrices, int mouseX, int mouseY, float delta) { - super.render(matrices, mouseX, mouseY, delta); - - calculateInterpolation(); - } - - @Override - protected void drawHoveredControl(PoseStack matrices, int mouseX, int mouseY, float delta) { - // track - GuiComponent.fill(matrices, sliderBounds.x(), sliderBounds.centerY() - 1, sliderBounds.xLimit(), sliderBounds.centerY(), -1); - // track shadow - GuiComponent.fill(matrices, sliderBounds.x() + 1, sliderBounds.centerY(), sliderBounds.xLimit() + 1, sliderBounds.centerY() + 1, 0xFF404040); - - // thumb shadow - GuiComponent.fill(matrices, getThumbX() - getThumbWidth() / 2 + 1, sliderBounds.y() + 1, getThumbX() + getThumbWidth() / 2 + 1, sliderBounds.yLimit() + 1, 0xFF404040); - // thumb - GuiComponent.fill(matrices, getThumbX() - getThumbWidth() / 2, sliderBounds.y(), getThumbX() + getThumbWidth() / 2, sliderBounds.yLimit(), -1); - } - - @Override - protected void drawValueText(PoseStack matrices, int mouseX, int mouseY, float delta) { - matrices.pushPose(); - if (isHovered()) - matrices.translate(-(sliderBounds.width() + 6 + getThumbWidth() / 2f), 0, 0); - super.drawValueText(matrices, mouseX, mouseY, delta); - matrices.popPose(); - } - - @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(Mth.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 InputConstants.KEY_LEFT -> incrementValue(-1); - case InputConstants.KEY_RIGHT -> 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 Mth.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 = Mth.clamp((float) ((control.pendingValue() - control.min()) * 1 / control.range()), 0f, 1f); - } - - @Override - public void setDimension(Dimension<Integer> dim) { - super.setDimension(dim); - int trackWidth = dim.width() / 3; - if (optionNameString.isEmpty()) - trackWidth = dim.width() / 2; - - sliderBounds = Dimension.ofInt(dim.xLimit() - getXPadding() - getThumbWidth() / 2 - trackWidth, dim.centerY() - 5, trackWidth, 10); - } - - protected int getThumbX() { - return (int) (sliderBounds.x() + sliderBounds.width() * interpolation); - } - - protected int getThumbWidth() { - return 4; - } - - @Override - public void postRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (super.isMouseOver(mouseX, mouseY) || focused) - super.postRender(matrices, mouseX, mouseY, delta); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/slider/package-info.java b/src/client/java/dev/isxander/yacl/gui/controllers/slider/package-info.java deleted file mode 100644 index bff0d57..0000000 --- a/src/client/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/client/java/dev/isxander/yacl/gui/controllers/string/IStringController.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/IStringController.java deleted file mode 100644 index 6a603d2..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/string/IStringController.java +++ /dev/null @@ -1,44 +0,0 @@ -package dev.isxander.yacl.gui.controllers.string; - -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.network.chat.Component; - -/** - * 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 Component formatValue() { - return Component.literal(getString()); - } - - default boolean isInputValid(String input) { - return true; - } - - @Override - default AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) { - return new StringControllerElement(this, screen, widgetDimension, true); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/StringController.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/StringController.java deleted file mode 100644 index 3a07641..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/string/StringController.java +++ /dev/null @@ -1,40 +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); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java deleted file mode 100644 index cb2ad4e..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java +++ /dev/null @@ -1,408 +0,0 @@ -package dev.isxander.yacl.gui.controllers.string; - -import com.mojang.blaze3d.platform.InputConstants; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.YACLScreen; -import dev.isxander.yacl.gui.controllers.ControllerWidget; -import dev.isxander.yacl.gui.utils.GuiUtils; -import net.minecraft.ChatFormatting; -import net.minecraft.client.gui.GuiComponent; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; - -import java.util.function.Consumer; - -public class StringControllerElement extends ControllerWidget<IStringController<?>> { - protected final boolean instantApply; - - protected String inputField; - protected Dimension<Integer> inputFieldBounds; - protected boolean inputFieldFocused; - - protected int caretPos; - protected int selectionLength; - - protected int renderOffset; - - protected float ticks; - - private final Component emptyText; - - public StringControllerElement(IStringController<?> control, YACLScreen screen, Dimension<Integer> dim, boolean instantApply) { - super(control, screen, dim); - this.instantApply = instantApply; - inputField = control.getString(); - inputFieldFocused = false; - selectionLength = 0; - emptyText = Component.literal("Click to type...").withStyle(ChatFormatting.GRAY); - control.option().addListener((opt, val) -> inputField = control.getString()); - setDimension(dim); - } - - @Override - protected void drawHoveredControl(PoseStack matrices, int mouseX, int mouseY, float delta) { - - } - - @Override - protected void drawValueText(PoseStack matrices, int mouseX, int mouseY, float delta) { - Component valueText = getValueText(); - if (!isHovered()) valueText = Component.literal(GuiUtils.shortenString(valueText.getString(), textRenderer, getMaxUnwrapLength(), "...")).setStyle(valueText.getStyle()); - - matrices.pushPose(); - int textX = getDimension().xLimit() - textRenderer.width(valueText) + renderOffset - getXPadding(); - matrices.translate(textX, getTextY(), 0); - GuiUtils.enableScissor(inputFieldBounds.x(), inputFieldBounds.y() - 2, inputFieldBounds.width() + 1, inputFieldBounds.height() + 4); - textRenderer.drawShadow(matrices, valueText, 0, 0, getValueColor()); - matrices.popPose(); - - if (isHovered()) { - ticks += delta; - - String text = getValueText().getString(); - - GuiComponent.fill(matrices, inputFieldBounds.x(), inputFieldBounds.yLimit(), inputFieldBounds.xLimit(), inputFieldBounds.yLimit() + 1, -1); - GuiComponent.fill(matrices, inputFieldBounds.x() + 1, inputFieldBounds.yLimit() + 1, inputFieldBounds.xLimit() + 1, inputFieldBounds.yLimit() + 2, 0xFF404040); - - if (inputFieldFocused || focused) { - if (caretPos > text.length()) - caretPos = text.length(); - - int caretX = textX + textRenderer.width(text.substring(0, caretPos)) - 1; - if (text.isEmpty()) - caretX = inputFieldBounds.x() + inputFieldBounds.width() / 2; - - if (ticks % 20 <= 10) { - GuiComponent.fill(matrices, caretX, inputFieldBounds.y(), caretX + 1, inputFieldBounds.yLimit(), -1); - } - - if (selectionLength != 0) { - int selectionX = textX + textRenderer.width(text.substring(0, caretPos + selectionLength)); - GuiComponent.fill(matrices, caretX, inputFieldBounds.y() - 1, selectionX, inputFieldBounds.yLimit(), 0x803030FF); - } - } - } - RenderSystem.disableScissor(); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (isAvailable() && getDimension().isPointInside((int) mouseX, (int) mouseY)) { - inputFieldFocused = true; - - if (!inputFieldBounds.isPointInside((int) mouseX, (int) mouseY)) { - caretPos = getDefaultCaretPos(); - } else { - // gets the appropriate caret position for where you click - int textX = (int) mouseX - (inputFieldBounds.xLimit() - textRenderer.width(getValueText())); - int pos = -1; - int currentWidth = 0; - for (char ch : inputField.toCharArray()) { - pos++; - int charLength = textRenderer.width(String.valueOf(ch)); - if (currentWidth + charLength / 2 > textX) { // if more than halfway past the characters select in front of that char - caretPos = pos; - break; - } else if (pos == inputField.length() - 1) { - // if we have reached the end and no matches, it must be the second half of the char so the last position - caretPos = pos + 1; - } - currentWidth += charLength; - } - - selectionLength = 0; - } - return true; - } else { - inputFieldFocused = false; - } - - return false; - } - - protected int getDefaultCaretPos() { - return inputField.length(); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (!inputFieldFocused) - return false; - - switch (keyCode) { - case InputConstants.KEY_ESCAPE, InputConstants.KEY_RETURN -> { - unfocus(); - return true; - } - case InputConstants.KEY_LEFT -> { - if (Screen.hasShiftDown()) { - if (Screen.hasControlDown()) { - int spaceChar = findSpaceIndex(true); - selectionLength += caretPos - spaceChar; - caretPos = spaceChar; - } else if (caretPos > 0) { - caretPos--; - selectionLength += 1; - } - checkRenderOffset(); - } else { - if (caretPos > 0) { - if (selectionLength != 0) - caretPos += Math.min(selectionLength, 0); - else - caretPos--; - } - checkRenderOffset(); - selectionLength = 0; - } - - return true; - } - case InputConstants.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; - } - checkRenderOffset(); - } else { - if (caretPos < inputField.length()) { - if (selectionLength != 0) - caretPos += Math.max(selectionLength, 0); - else - caretPos++; - checkRenderOffset(); - } - selectionLength = 0; - } - - return true; - } - case InputConstants.KEY_BACKSPACE -> { - doBackspace(); - return true; - } - case InputConstants.KEY_DELETE -> { - doDelete(); - return true; - } - } - - if (Screen.isPaste(keyCode)) { - return doPaste(); - } else if (Screen.isCopy(keyCode)) { - return doCopy(); - } else if (Screen.isCut(keyCode)) { - return doCut(); - } else if (Screen.isSelectAll(keyCode)) { - return doSelectAll(); - } - - return false; - } - - protected boolean doPaste() { - this.write(client.keyboardHandler.getClipboard()); - return true; - } - - protected boolean doCopy() { - if (selectionLength != 0) { - client.keyboardHandler.setClipboard(getSelection()); - return true; - } - return false; - } - - protected boolean doCut() { - if (selectionLength != 0) { - client.keyboardHandler.setClipboard(getSelection()); - this.write(""); - return true; - } - return false; - } - - protected boolean doSelectAll() { - caretPos = inputField.length(); - checkRenderOffset(); - selectionLength = -caretPos; - return true; - } - - protected void checkRenderOffset() { - if (textRenderer.width(inputField) < getUnshiftedLength()) { - renderOffset = 0; - return; - } - - int textX = getDimension().xLimit() - textRenderer.width(inputField) - getXPadding(); - int caretX = textX + textRenderer.width(inputField.substring(0, caretPos)) - 1; - - int minX = getDimension().xLimit() - getXPadding() - getUnshiftedLength(); - int maxX = minX + getUnshiftedLength(); - - if (caretX + renderOffset < minX) { - renderOffset = minX - caretX; - } else if (caretX + renderOffset > maxX) { - renderOffset = maxX - caretX; - } - } - - @Override - public boolean charTyped(char chr, int modifiers) { - if (!inputFieldFocused) - return false; - - write(Character.toString(chr)); - - return true; - } - - protected void doBackspace() { - if (selectionLength != 0) { - write(""); - } else if (caretPos > 0) { - if (modifyInput(builder -> builder.deleteCharAt(caretPos - 1))) { - caretPos--; - checkRenderOffset(); - } - } - } - - protected void doDelete() { - if (selectionLength != 0) { - write(""); - } else if (caretPos < inputField.length()) { - modifyInput(builder -> builder.deleteCharAt(caretPos)); - } - } - - public void write(String string) { - if (selectionLength == 0) { - if (modifyInput(builder -> builder.insert(caretPos, string))) { - caretPos += string.length(); - checkRenderOffset(); - } - } else { - int start = getSelectionStart(); - int end = getSelectionEnd(); - - if (modifyInput(builder -> builder.replace(start, end, string))) { - caretPos = start + string.length(); - selectionLength = 0; - checkRenderOffset(); - } - } - } - - public boolean modifyInput(Consumer<StringBuilder> consumer) { - StringBuilder temp = new StringBuilder(inputField); - consumer.accept(temp); - if (!control.isInputValid(temp.toString())) - return false; - inputField = temp.toString(); - if (instantApply) - updateControl(); - return true; - } - - public int getUnshiftedLength() { - if (optionNameString.isEmpty()) - return getDimension().width() - getXPadding() * 2; - return getDimension().width() / 8 * 5; - } - - public int getMaxUnwrapLength() { - if (optionNameString.isEmpty()) - return getDimension().width() - getXPadding() * 2; - return getDimension().width() / 2; - } - - 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 void setFocused(boolean focused) { - super.setFocused(focused); - inputFieldFocused = focused; - } - - @Override - public void unfocus() { - super.unfocus(); - inputFieldFocused = false; - renderOffset = 0; - if (!instantApply) updateControl(); - } - - @Override - public void setDimension(Dimension<Integer> dim) { - super.setDimension(dim); - - int width = Math.max(6, Math.min(textRenderer.width(getValueText()), getUnshiftedLength())); - inputFieldBounds = Dimension.ofInt(dim.xLimit() - getXPadding() - width, dim.centerY() - textRenderer.lineHeight / 2, width, textRenderer.lineHeight); - } - - @Override - public boolean isHovered() { - return super.isHovered() || inputFieldFocused; - } - - protected void updateControl() { - control.setFromString(inputField); - } - - @Override - protected int getUnhoveredControlWidth() { - return !isHovered() ? Math.min(getHoveredControlWidth(), getMaxUnwrapLength()) : getHoveredControlWidth(); - } - - @Override - protected int getHoveredControlWidth() { - return Math.min(textRenderer.width(getValueText()), getUnshiftedLength()); - } - - @Override - protected Component getValueText() { - if (!inputFieldFocused && inputField.isEmpty()) - return emptyText; - - return instantApply || !inputFieldFocused ? control.formatValue() : Component.literal(inputField); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/DoubleFieldController.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/DoubleFieldController.java deleted file mode 100644 index df28241..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/DoubleFieldController.java +++ /dev/null @@ -1,104 +0,0 @@ -package dev.isxander.yacl.gui.controllers.string.number; - -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.gui.controllers.slider.DoubleSliderController; -import net.minecraft.network.chat.Component; - -import java.util.function.Function; - -/** - * {@inheritDoc} - */ -public class DoubleFieldController extends NumberFieldController<Double> { - private final double min, max; - - /** - * Constructs a double field controller - * - * @param option option to bind controller to - * @param min minimum allowed value (clamped on apply) - * @param max maximum allowed value (clamped on apply) - * @param formatter display text, not used whilst editing - */ - public DoubleFieldController(Option<Double> option, double min, double max, Function<Double, Component> formatter) { - super(option, formatter); - this.min = min; - this.max = max; - } - - /** - * Constructs a double field controller. - * Uses {@link DoubleSliderController#DEFAULT_FORMATTER} as display text, - * not used whilst editing. - * - * @param option option to bind controller to - * @param min minimum allowed value (clamped on apply) - * @param max maximum allowed value (clamped on apply) - */ - public DoubleFieldController(Option<Double> option, double min, double max) { - this(option, min, max, DoubleSliderController.DEFAULT_FORMATTER); - } - - /** - * Constructs a double field controller. - * Does not have a minimum or a maximum range. - * - * @param option option to bind controller to - * @param formatter display text, not used whilst editing - */ - public DoubleFieldController(Option<Double> option, Function<Double, Component> formatter) { - this(option, -Double.MAX_VALUE, Double.MAX_VALUE, formatter); - } - - /** - * Constructs a double field controller. - * Uses {@link DoubleSliderController#DEFAULT_FORMATTER} as display text, - * not used whilst editing. - * Does not have a minimum or a maximum range. - * - * @param option option to bind controller to - */ - public DoubleFieldController(Option<Double> option) { - this(option, -Double.MAX_VALUE, Double.MAX_VALUE, DoubleSliderController.DEFAULT_FORMATTER); - } - - /** - * {@inheritDoc} - */ - @Override - public double min() { - return this.min; - } - - /** - * {@inheritDoc} - */ - @Override - public double max() { - return this.max; - } - - /** - * {@inheritDoc} - */ - @Override - public String getString() { - return String.valueOf(option().pendingValue()); - } - - /** - * {@inheritDoc} - */ - @Override - public void setPendingValue(double value) { - option().requestSet(value); - } - - /** - * {@inheritDoc} - */ - @Override - public double pendingValue() { - return option().pendingValue(); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/FloatFieldController.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/FloatFieldController.java deleted file mode 100644 index 957100a..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/FloatFieldController.java +++ /dev/null @@ -1,104 +0,0 @@ -package dev.isxander.yacl.gui.controllers.string.number; - -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.gui.controllers.slider.FloatSliderController; -import net.minecraft.network.chat.Component; - -import java.util.function.Function; - -/** - * {@inheritDoc} - */ -public class FloatFieldController extends NumberFieldController<Float> { - private final float min, max; - - /** - * Constructs a double field controller - * - * @param option option to bind controller to - * @param min minimum allowed value (clamped on apply) - * @param max maximum allowed value (clamped on apply) - * @param formatter display text, not used whilst editing - */ - public FloatFieldController(Option<Float> option, float min, float max, Function<Float, Component> formatter) { - super(option, formatter); - this.min = min; - this.max = max; - } - - /** - * Constructs a double field controller. - * Uses {@link FloatSliderController#DEFAULT_FORMATTER} as display text, - * not used whilst editing. - * - * @param option option to bind controller to - * @param min minimum allowed value (clamped on apply) - * @param max maximum allowed value (clamped on apply) - */ - public FloatFieldController(Option<Float> option, float min, float max) { - this(option, min, max, FloatSliderController.DEFAULT_FORMATTER); - } - - /** - * Constructs a double field controller. - * Does not have a minimum or a maximum range. - * - * @param option option to bind controller to - * @param formatter display text, not used whilst editing - */ - public FloatFieldController(Option<Float> option, Function<Float, Component> formatter) { - this(option, -Float.MAX_VALUE, Float.MAX_VALUE, formatter); - } - - /** - * Constructs a double field controller. - * Uses {@link FloatSliderController#DEFAULT_FORMATTER} as display text, - * not used whilst editing. - * Does not have a minimum or a maximum range. - * - * @param option option to bind controller to - */ - public FloatFieldController(Option<Float> option) { - this(option, -Float.MAX_VALUE, Float.MAX_VALUE, FloatSliderController.DEFAULT_FORMATTER); - } - - /** - * {@inheritDoc} - */ - @Override - public double min() { - return this.min; - } - - /** - * {@inheritDoc} - */ - @Override - public double max() { - return this.max; - } - - /** - * {@inheritDoc} - */ - @Override - public String getString() { - return String.valueOf(option().pendingValue()); - } - - /** - * {@inheritDoc} - */ - @Override - public void setPendingValue(double value) { - option().requestSet((float) value); - } - - /** - * {@inheritDoc} - */ - @Override - public double pendingValue() { - return option().pendingValue(); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/IntegerFieldController.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/IntegerFieldController.java deleted file mode 100644 index 2d64a3a..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/IntegerFieldController.java +++ /dev/null @@ -1,109 +0,0 @@ -package dev.isxander.yacl.gui.controllers.string.number; - -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.gui.controllers.slider.IntegerSliderController; -import net.minecraft.network.chat.Component; - -import java.util.function.Function; - -/** - * {@inheritDoc} - */ -public class IntegerFieldController extends NumberFieldController<Integer> { - private final int min, max; - - /** - * Constructs a double field controller - * - * @param option option to bind controller to - * @param min minimum allowed value (clamped on apply) - * @param max maximum allowed value (clamped on apply) - * @param formatter display text, not used whilst editing - */ - public IntegerFieldController(Option<Integer> option, int min, int max, Function<Integer, Component> formatter) { - super(option, formatter); - this.min = min; - this.max = max; - } - - /** - * Constructs a double field controller. - * Uses {@link IntegerSliderController#DEFAULT_FORMATTER} as display text, - * not used whilst editing. - * - * @param option option to bind controller to - * @param min minimum allowed value (clamped on apply) - * @param max maximum allowed value (clamped on apply) - */ - public IntegerFieldController(Option<Integer> option, int min, int max) { - this(option, min, max, IntegerSliderController.DEFAULT_FORMATTER); - } - - /** - * Constructs a double field controller. - * Does not have a minimum or a maximum range. - * - * @param option option to bind controller to - * @param formatter display text, not used whilst editing - */ - public IntegerFieldController(Option<Integer> option, Function<Integer, Component> formatter) { - this(option, -Integer.MAX_VALUE, Integer.MAX_VALUE, formatter); - } - - /** - * Constructs a double field controller. - * Uses {@link IntegerSliderController#DEFAULT_FORMATTER} as display text, - * not used whilst editing. - * Does not have a minimum or a maximum range. - * - * @param option option to bind controller to - */ - public IntegerFieldController(Option<Integer> option) { - this(option, -Integer.MAX_VALUE, Integer.MAX_VALUE, IntegerSliderController.DEFAULT_FORMATTER); - } - - @Override - public boolean isInputValid(String input) { - return input.matches("\\d+|-|"); - } - - /** - * {@inheritDoc} - */ - @Override - public double min() { - return this.min; - } - - /** - * {@inheritDoc} - */ - @Override - public double max() { - return this.max; - } - - /** - * {@inheritDoc} - */ - @Override - public String getString() { - return String.valueOf(option().pendingValue()); - } - - /** - * {@inheritDoc} - */ - @Override - public void setPendingValue(double value) { - option().requestSet((int) value); - } - - /** - * {@inheritDoc} - */ - @Override - public double pendingValue() { - return option().pendingValue(); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/LongFieldController.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/LongFieldController.java deleted file mode 100644 index a640621..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/LongFieldController.java +++ /dev/null @@ -1,109 +0,0 @@ -package dev.isxander.yacl.gui.controllers.string.number; - -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.gui.controllers.slider.LongSliderController; -import net.minecraft.network.chat.Component; - -import java.util.function.Function; - -/** - * {@inheritDoc} - */ -public class LongFieldController extends NumberFieldController<Long> { - private final long min, max; - - /** - * Constructs a double field controller - * - * @param option option to bind controller to - * @param min minimum allowed value (clamped on apply) - * @param max maximum allowed value (clamped on apply) - * @param formatter display text, not used whilst editing - */ - public LongFieldController(Option<Long> option, long min, long max, Function<Long, Component> formatter) { - super(option, formatter); - this.min = min; - this.max = max; - } - - /** - * Constructs a double field controller. - * Uses {@link LongSliderController#DEFAULT_FORMATTER} as display text, - * not used whilst editing. - * - * @param option option to bind controller to - * @param min minimum allowed value (clamped on apply) - * @param max maximum allowed value (clamped on apply) - */ - public LongFieldController(Option<Long> option, long min, long max) { - this(option, min, max, LongSliderController.DEFAULT_FORMATTER); - } - - /** - * Constructs a double field controller. - * Does not have a minimum or a maximum range. - * - * @param option option to bind controller to - * @param formatter display text, not used whilst editing - */ - public LongFieldController(Option<Long> option, Function<Long, Component> formatter) { - this(option, -Long.MAX_VALUE, Long.MAX_VALUE, formatter); - } - - /** - * Constructs a double field controller. - * Uses {@link LongSliderController#DEFAULT_FORMATTER} as display text, - * not used whilst editing. - * Does not have a minimum or a maximum range. - * - * @param option option to bind controller to - */ - public LongFieldController(Option<Long> option) { - this(option, -Long.MAX_VALUE, Long.MAX_VALUE, LongSliderController.DEFAULT_FORMATTER); - } - - @Override - public boolean isInputValid(String input) { - return input.matches("\\d+|-|"); - } - - /** - * {@inheritDoc} - */ - @Override - public double min() { - return this.min; - } - - /** - * {@inheritDoc} - */ - @Override - public double max() { - return this.max; - } - - /** - * {@inheritDoc} - */ - @Override - public String getString() { - return String.valueOf(option().pendingValue()); - } - - /** - * {@inheritDoc} - */ - @Override - public void setPendingValue(double value) { - option().requestSet((long) value); - } - - /** - * {@inheritDoc} - */ - @Override - public double pendingValue() { - return option().pendingValue(); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/NumberFieldController.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/NumberFieldController.java deleted file mode 100644 index 4240849..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/NumberFieldController.java +++ /dev/null @@ -1,69 +0,0 @@ -package dev.isxander.yacl.gui.controllers.string.number; - -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 dev.isxander.yacl.gui.controllers.slider.ISliderController; -import dev.isxander.yacl.gui.controllers.string.IStringController; -import dev.isxander.yacl.gui.controllers.string.StringControllerElement; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; - -import java.text.DecimalFormatSymbols; -import java.util.function.Function; - -/** - * Controller that allows you to enter in numbers using a text field. - * - * @param <T> number type - */ -public abstract class NumberFieldController<T extends Number> implements ISliderController<T>, IStringController<T> { - private final Option<T> option; - private final Function<T, Component> displayFormatter; - - public NumberFieldController(Option<T> option, Function<T, Component> displayFormatter) { - this.option = option; - this.displayFormatter = displayFormatter; - } - - @Override - public Option<T> option() { - return this.option; - } - - @Override - public void setFromString(String value) { - if (value.isEmpty() || value.equals(".") || value.equals("-")) value = "0"; - setPendingValue(Mth.clamp(Double.parseDouble(cleanupNumberString(value)), min(), max())); - } - - @Override - public double pendingValue() { - return option().pendingValue().doubleValue(); - } - - @Override - public boolean isInputValid(String input) { - return input.matches("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)|[.]||-"); - } - - @Override - public Component formatValue() { - return displayFormatter.apply(option().pendingValue()); - } - - @Override - public AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) { - return new StringControllerElement(this, screen, widgetDimension, false); - } - - protected String cleanupNumberString(String number) { - return number.replace(String.valueOf(DecimalFormatSymbols.getInstance().getGroupingSeparator()), ""); - } - - @Override - public double interval() { - return -1; - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/package-info.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/package-info.java deleted file mode 100644 index 86b9314..0000000 --- a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/** - * This package contains implementations of input fields for different number types - * <ul> - * <li>For doubles: {@link dev.isxander.yacl.gui.controllers.string.number.DoubleFieldController}</li> - * <li>For floats: {@link dev.isxander.yacl.gui.controllers.string.number.FloatFieldController}</li> - * <li>For integers: {@link dev.isxander.yacl.gui.controllers.string.number.IntegerFieldController}</li> - * <li>For longs: {@link dev.isxander.yacl.gui.controllers.string.number.LongFieldController}</li> - * </ul> - */ -package dev.isxander.yacl.gui.controllers.string.number; diff --git a/src/client/java/dev/isxander/yacl/gui/utils/GuiUtils.java b/src/client/java/dev/isxander/yacl/gui/utils/GuiUtils.java deleted file mode 100644 index aa8bbaa..0000000 --- a/src/client/java/dev/isxander/yacl/gui/utils/GuiUtils.java +++ /dev/null @@ -1,41 +0,0 @@ -package dev.isxander.yacl.gui.utils; - -import com.mojang.blaze3d.platform.Window; -import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; - -public class GuiUtils { - public static MutableComponent translatableFallback(String key, Component fallback) { - if (Language.getInstance().has(key)) - return Component.translatable(key); - return fallback.copy(); - } - - public static void enableScissor(int x, int y, int width, int height) { - Window window = Minecraft.getInstance().getWindow(); - double d = window.getGuiScale(); - RenderSystem.enableScissor((int)(x * d), (int)((window.getGuiScaledHeight() - y - height) * d), (int)(width * d), (int)(height * d)); - } - - public static String shortenString(String string, Font font, int maxWidth, String suffix) { - if (string.isEmpty()) - return string; - - boolean firstIter = true; - while (font.width(string) > maxWidth) { - string = string.substring(0, Math.max(string.length() - 1 - (firstIter ? 1 : suffix.length() + 1), 0)).trim(); - string += suffix; - - if (string.equals(suffix)) - break; - - firstIter = false; - } - - return string; - } -} diff --git a/src/client/java/dev/isxander/yacl/impl/ButtonOptionImpl.java b/src/client/java/dev/isxander/yacl/impl/ButtonOptionImpl.java deleted file mode 100644 index 33cb474..0000000 --- a/src/client/java/dev/isxander/yacl/impl/ButtonOptionImpl.java +++ /dev/null @@ -1,218 +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.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import org.apache.commons.lang3.Validate; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; - -@ApiStatus.Internal -public final class ButtonOptionImpl implements ButtonOption { - private final Component name; - private final Component 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 Component name, - @Nullable Component 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 Component name() { - return name; - } - - @Override - public @NotNull Component 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 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(); - } - } - - @ApiStatus.Internal - public static final class BuilderImpl implements ButtonOption.Builder { - private Component name; - private final List<Component> tooltipLines = new ArrayList<>(); - private boolean available = true; - private Function<ButtonOption, Controller<BiConsumer<YACLScreen, ButtonOption>>> controlGetter; - private BiConsumer<YACLScreen, ButtonOption> action; - - @Override - public ButtonOption.Builder name(@NotNull Component name) { - Validate.notNull(name, "`name` cannot be null"); - - this.name = name; - return this; - } - - @Override - public ButtonOption.Builder tooltip(@NotNull Component... tooltips) { - Validate.notNull(tooltips, "`tooltips` cannot be empty"); - - tooltipLines.addAll(List.of(tooltips)); - return this; - } - - @Override - public ButtonOption.Builder action(@NotNull BiConsumer<YACLScreen, ButtonOption> action) { - Validate.notNull(action, "`action` cannot be null"); - - this.action = action; - return this; - } - - @Override - @Deprecated - public ButtonOption.Builder action(@NotNull Consumer<YACLScreen> action) { - Validate.notNull(action, "`action` cannot be null"); - - this.action = (screen, button) -> action.accept(screen); - return this; - } - - @Override - public ButtonOption.Builder available(boolean available) { - this.available = available; - return this; - } - - @Override - public ButtonOption.Builder controller(@NotNull Function<ButtonOption, Controller<BiConsumer<YACLScreen, ButtonOption>>> control) { - Validate.notNull(control, "`control` cannot be null"); - - this.controlGetter = control; - return this; - } - - @Override - 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`"); - - MutableComponent concatenatedTooltip = Component.empty(); - boolean first = true; - for (Component line : tooltipLines) { - if (!first) concatenatedTooltip.append("\n"); - first = false; - - concatenatedTooltip.append(line); - } - - return new ButtonOptionImpl(name, concatenatedTooltip, action, available, controlGetter); - } - } -} diff --git a/src/client/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java b/src/client/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java deleted file mode 100644 index 2d39eb9..0000000 --- a/src/client/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java +++ /dev/null @@ -1,137 +0,0 @@ -package dev.isxander.yacl.impl; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.api.ConfigCategory; -import dev.isxander.yacl.api.ListOption; -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.api.OptionGroup; -import dev.isxander.yacl.impl.utils.YACLConstants; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.ComponentContents; -import net.minecraft.network.chat.MutableComponent; -import org.apache.commons.lang3.Validate; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -@ApiStatus.Internal -public final class ConfigCategoryImpl implements ConfigCategory { - private final Component name; - private final ImmutableList<OptionGroup> groups; - private final Component tooltip; - - public ConfigCategoryImpl(Component name, ImmutableList<OptionGroup> groups, Component tooltip) { - this.name = name; - this.groups = groups; - this.tooltip = tooltip; - } - - @Override - public @NotNull Component name() { - return name; - } - - @Override - public @NotNull ImmutableList<OptionGroup> groups() { - return groups; - } - - @Override - public @NotNull Component tooltip() { - return tooltip; - } - - @ApiStatus.Internal - public static final class BuilderImpl implements Builder { - private Component name; - - private final List<Option<?>> rootOptions = new ArrayList<>(); - private final List<OptionGroup> groups = new ArrayList<>(); - - private final List<Component> tooltipLines = new ArrayList<>(); - - @Override - public Builder name(@NotNull Component name) { - Validate.notNull(name, "`name` cannot be null"); - - this.name = name; - return this; - } - - @Override - public Builder option(@NotNull Option<?> option) { - Validate.notNull(option, "`option` must not be null"); - - if (option instanceof ListOption<?> listOption) { - YACLConstants.LOGGER.warn("Adding list option as an option is not supported! Rerouting to group!"); - return group(listOption); - } - - this.rootOptions.add(option); - return this; - } - - @Override - public Builder options(@NotNull Collection<? extends Option<?>> options) { - Validate.notNull(options, "`options` must not be null"); - - if (options.stream().anyMatch(ListOption.class::isInstance)) - throw new UnsupportedOperationException("List options must not be added as an option but a group!"); - - this.rootOptions.addAll(options); - return this; - } - - @Override - public Builder group(@NotNull OptionGroup group) { - Validate.notNull(group, "`group` must not be null"); - - this.groups.add(group); - return this; - } - - @Override - public Builder groups(@NotNull Collection<OptionGroup> groups) { - Validate.notEmpty(groups, "`groups` must not be empty"); - - this.groups.addAll(groups); - return this; - } - - @Override - public Builder tooltip(@NotNull Component... tooltips) { - Validate.notEmpty(tooltips, "`tooltips` cannot be empty"); - - tooltipLines.addAll(List.of(tooltips)); - return this; - } - - @Override - public ConfigCategory build() { - Validate.notNull(name, "`name` must not be null to build `ConfigCategory`"); - - List<OptionGroup> combinedGroups = new ArrayList<>(); - combinedGroups.add(new OptionGroupImpl(Component.empty(), Component.empty(), ImmutableList.copyOf(rootOptions), false, true)); - combinedGroups.addAll(groups); - - Validate.notEmpty(combinedGroups, "at least one option must be added to build `ConfigCategory`"); - - MutableComponent concatenatedTooltip = Component.empty(); - boolean first = true; - for (Component line : tooltipLines) { - if (line.getContents() == ComponentContents.EMPTY) - continue; - - if (!first) concatenatedTooltip.append("\n"); - first = false; - - concatenatedTooltip.append(line); - } - - return new ConfigCategoryImpl(name, ImmutableList.copyOf(combinedGroups), concatenatedTooltip); - } - } -} diff --git a/src/client/java/dev/isxander/yacl/impl/GenericBindingImpl.java b/src/client/java/dev/isxander/yacl/impl/GenericBindingImpl.java deleted file mode 100644 index 0d668c6..0000000 --- a/src/client/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 final 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/client/java/dev/isxander/yacl/impl/LabelOptionImpl.java b/src/client/java/dev/isxander/yacl/impl/LabelOptionImpl.java deleted file mode 100644 index b6c3c09..0000000 --- a/src/client/java/dev/isxander/yacl/impl/LabelOptionImpl.java +++ /dev/null @@ -1,154 +0,0 @@ -package dev.isxander.yacl.impl; - -import com.google.common.collect.ImmutableSet; -import dev.isxander.yacl.api.*; -import dev.isxander.yacl.gui.controllers.LabelController; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import org.apache.commons.lang3.Validate; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.function.BiConsumer; - -@ApiStatus.Internal -public final class LabelOptionImpl implements LabelOption { - private final Component label; - private final Component name = Component.literal("Label Option"); - private final Component tooltip = Component.empty(); - private final LabelController labelController; - private final Binding<Component> binding; - - public LabelOptionImpl(Component label) { - this.label = label; - this.labelController = new LabelController(this); - this.binding = Binding.immutable(label); - } - - @Override - public @NotNull Component label() { - return label; - } - - @Override - public @NotNull Component name() { - return name; - } - - @Override - public @NotNull Component tooltip() { - return tooltip; - } - - @Override - public @NotNull Controller<Component> controller() { - return labelController; - } - - @Override - public @NotNull Binding<Component> binding() { - return binding; - } - - @Override - public boolean available() { - return true; - } - - @Override - public void setAvailable(boolean available) { - throw new UnsupportedOperationException("Label options cannot be disabled."); - } - - @Override - public @NotNull Class<Component> typeClass() { - return Component.class; - } - - @Override - public @NotNull ImmutableSet<OptionFlag> flags() { - return ImmutableSet.of(); - } - - @Override - public boolean changed() { - return false; - } - - @Override - public @NotNull Component pendingValue() { - return label; - } - - @Override - public void requestSet(Component value) { - - } - - @Override - public boolean applyValue() { - return false; - } - - @Override - public void forgetPendingValue() { - - } - - @Override - public void requestSetDefault() { - - } - - @Override - public boolean isPendingValueDefault() { - return true; - } - - @Override - public boolean canResetToDefault() { - return false; - } - - @Override - public void addListener(BiConsumer<Option<Component>, Component> changedListener) { - - } - - @ApiStatus.Internal - public static final class BuilderImpl implements LabelOption.Builder { - private final List<Component> lines = new ArrayList<>(); - - @Override - public dev.isxander.yacl.api.LabelOption.Builder line(@NotNull Component line) { - Validate.notNull(line, "`line` must not be null"); - - this.lines.add(line); - return this; - } - - @Override - public dev.isxander.yacl.api.LabelOption.Builder lines(@NotNull Collection<? extends Component> lines) { - this.lines.addAll(lines); - return this; - } - - @Override - public LabelOption build() { - MutableComponent text = Component.empty(); - Iterator<Component> iterator = lines.iterator(); - while (iterator.hasNext()) { - text.append(iterator.next()); - - if (iterator.hasNext()) - text.append("\n"); - } - - return new LabelOptionImpl(text); - } - } -} diff --git a/src/client/java/dev/isxander/yacl/impl/ListOptionEntryImpl.java b/src/client/java/dev/isxander/yacl/impl/ListOptionEntryImpl.java deleted file mode 100644 index c15efe6..0000000 --- a/src/client/java/dev/isxander/yacl/impl/ListOptionEntryImpl.java +++ /dev/null @@ -1,149 +0,0 @@ -package dev.isxander.yacl.impl; - -import dev.isxander.yacl.api.*; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.gui.AbstractWidget; -import dev.isxander.yacl.gui.YACLScreen; -import dev.isxander.yacl.gui.controllers.ListEntryWidget; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import java.util.function.BiConsumer; -import java.util.function.Function; - -@ApiStatus.Internal -public final class ListOptionEntryImpl<T> implements ListOptionEntry<T> { - private final ListOptionImpl<T> group; - - private T value; - - private final Binding<T> binding; - private final Controller<T> controller; - - ListOptionEntryImpl(ListOptionImpl<T> group, T initialValue, @NotNull Function<ListOptionEntry<T>, Controller<T>> controlGetter) { - this.group = group; - this.value = initialValue; - this.binding = new EntryBinding(); - this.controller = new EntryController<>(controlGetter.apply(this), this); - } - - @Override - public @NotNull Component name() { - return Component.empty(); - } - - @Override - public @NotNull Component tooltip() { - return Component.empty(); - } - - @Override - public @NotNull Controller<T> controller() { - return controller; - } - - @Override - public @NotNull Binding<T> binding() { - return binding; - } - - @Override - public boolean available() { - return parentGroup().available(); - } - - @Override - public void setAvailable(boolean available) { - - } - - @Override - public ListOption<T> parentGroup() { - return group; - } - - @Override - public boolean changed() { - return false; - } - - @Override - public @NotNull T pendingValue() { - return value; - } - - @Override - public void requestSet(T value) { - binding.setValue(value); - } - - @Override - public boolean applyValue() { - return false; - } - - @Override - public void forgetPendingValue() { - - } - - @Override - public void requestSetDefault() { - - } - - @Override - public boolean isPendingValueDefault() { - return false; - } - - @Override - public boolean canResetToDefault() { - return false; - } - - @Override - public void addListener(BiConsumer<Option<T>, T> changedListener) { - - } - - /** - * Open in case mods need to find the real controller type. - */ - @ApiStatus.Internal - public record EntryController<T>(Controller<T> controller, ListOptionEntryImpl<T> entry) implements Controller<T> { - @Override - public Option<T> option() { - return controller.option(); - } - - @Override - public Component formatValue() { - return controller.formatValue(); - } - - @Override - public AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) { - return new ListEntryWidget(screen, entry, controller.provideWidget(screen, widgetDimension)); - } - } - - private class EntryBinding implements Binding<T> { - @Override - public void setValue(T newValue) { - value = newValue; - group.callListeners(); - } - - @Override - public T getValue() { - return value; - } - - @Override - public T defaultValue() { - throw new UnsupportedOperationException(); - } - } -} diff --git a/src/client/java/dev/isxander/yacl/impl/ListOptionImpl.java b/src/client/java/dev/isxander/yacl/impl/ListOptionImpl.java deleted file mode 100644 index 27e90ad..0000000 --- a/src/client/java/dev/isxander/yacl/impl/ListOptionImpl.java +++ /dev/null @@ -1,338 +0,0 @@ -package dev.isxander.yacl.impl; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import dev.isxander.yacl.api.*; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import org.apache.commons.lang3.Validate; -import org.jetbrains.annotations.ApiStatus; -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.Collectors; - -@ApiStatus.Internal -public final class ListOptionImpl<T> implements ListOption<T> { - private final Component name; - private final Component tooltip; - private final Binding<List<T>> binding; - private final T initialValue; - private final List<ListOptionEntry<T>> entries; - private final boolean collapsed; - private boolean available; - private final Class<T> typeClass; - private final ImmutableSet<OptionFlag> flags; - private final EntryFactory entryFactory; - private final List<BiConsumer<Option<List<T>>, List<T>>> listeners; - private final List<Runnable> refreshListeners; - - public ListOptionImpl(@NotNull Component name, @NotNull Component tooltip, @NotNull Binding<List<T>> binding, @NotNull T initialValue, @NotNull Class<T> typeClass, @NotNull Function<ListOptionEntry<T>, Controller<T>> controllerFunction, ImmutableSet<OptionFlag> flags, boolean collapsed, boolean available, Collection<BiConsumer<Option<List<T>>, List<T>>> listeners) { - this.name = name; - this.tooltip = tooltip; - this.binding = binding; - this.initialValue = initialValue; - this.entryFactory = new EntryFactory(controllerFunction); - this.entries = createEntries(binding().getValue()); - this.collapsed = collapsed; - this.typeClass = typeClass; - this.flags = flags; - this.available = available; - this.listeners = new ArrayList<>(); - this.listeners.addAll(listeners); - this.refreshListeners = new ArrayList<>(); - callListeners(); - } - - @Override - public @NotNull Component name() { - return this.name; - } - - @Override - public @NotNull Component tooltip() { - return this.tooltip; - } - - @Override - public @NotNull ImmutableList<ListOptionEntry<T>> options() { - return ImmutableList.copyOf(entries); - } - - @Override - public @NotNull Controller<List<T>> controller() { - throw new UnsupportedOperationException(); - } - - @Override - public @NotNull Binding<List<T>> binding() { - return binding; - } - - @Override - public @NotNull Class<List<T>> typeClass() { - throw new UnsupportedOperationException(); - } - - @Override - public @NotNull Class<T> elementTypeClass() { - return typeClass; - } - - @Override - public boolean collapsed() { - return collapsed; - } - - @Override - public @NotNull ImmutableSet<OptionFlag> flags() { - return flags; - } - - @Override - public @NotNull ImmutableList<T> pendingValue() { - return ImmutableList.copyOf(entries.stream().map(Option::pendingValue).toList()); - } - - @Override - public void insertEntry(int index, ListOptionEntry<?> entry) { - entries.add(index, (ListOptionEntry<T>) entry); - onRefresh(); - } - - @Override - public ListOptionEntry<T> insertNewEntryToTop() { - ListOptionEntry<T> newEntry = entryFactory.create(initialValue); - entries.add(0, newEntry); - onRefresh(); - return newEntry; - } - - @Override - public void removeEntry(ListOptionEntry<?> entry) { - if (entries.remove(entry)) - onRefresh(); - } - - @Override - public int indexOf(ListOptionEntry<?> entry) { - return entries.indexOf(entry); - } - - @Override - public void requestSet(List<T> value) { - entries.clear(); - entries.addAll(createEntries(value)); - onRefresh(); - } - - @Override - public boolean changed() { - return !binding().getValue().equals(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 boolean available() { - return available; - } - - @Override - public void setAvailable(boolean available) { - this.available = available; - } - - @Override - public void addListener(BiConsumer<Option<List<T>>, List<T>> changedListener) { - this.listeners.add(changedListener); - } - - @Override - public void addRefreshListener(Runnable changedListener) { - this.refreshListeners.add(changedListener); - } - - @Override - public boolean isRoot() { - return false; - } - - private List<ListOptionEntry<T>> createEntries(Collection<T> values) { - return values.stream().map(entryFactory::create).collect(Collectors.toList()); - } - - void callListeners() { - List<T> pendingValue = pendingValue(); - this.listeners.forEach(listener -> listener.accept(this, pendingValue)); - } - - private void onRefresh() { - refreshListeners.forEach(Runnable::run); - callListeners(); - } - - private class EntryFactory { - private final Function<ListOptionEntry<T>, Controller<T>> controllerFunction; - - private EntryFactory(Function<ListOptionEntry<T>, Controller<T>> controllerFunction) { - this.controllerFunction = controllerFunction; - } - - public ListOptionEntry<T> create(T initialValue) { - return new ListOptionEntryImpl<>(ListOptionImpl.this, initialValue, controllerFunction); - } - } - - @ApiStatus.Internal - public static final class BuilderImpl<T> implements ListOption.Builder<T> { - private Component name = Component.empty(); - private final List<Component> tooltipLines = new ArrayList<>(); - private Function<ListOptionEntry<T>, Controller<T>> controllerFunction; - private Binding<List<T>> binding = null; - private final Set<OptionFlag> flags = new HashSet<>(); - private T initialValue; - private boolean collapsed = false; - private boolean available = true; - private final List<BiConsumer<Option<List<T>>, List<T>>> listeners = new ArrayList<>(); - private final Class<T> typeClass; - - public BuilderImpl(Class<T> typeClass) { - this.typeClass = typeClass; - } - - @Override - public ListOption.Builder<T> name(@NotNull Component name) { - Validate.notNull(name, "`name` must not be null"); - - this.name = name; - return this; - } - - @Override - public ListOption.Builder<T> tooltip(@NotNull Component... tooltips) { - Validate.notEmpty(tooltips, "`tooltips` cannot be empty"); - - tooltipLines.addAll(List.of(tooltips)); - return this; - } - - @Override - public ListOption.Builder<T> initial(@NotNull T initialValue) { - Validate.notNull(initialValue, "`initialValue` cannot be empty"); - - this.initialValue = initialValue; - return this; - } - - @Override - public ListOption.Builder<T> controller(@NotNull Function<ListOptionEntry<T>, Controller<T>> control) { - Validate.notNull(control, "`control` cannot be null"); - - this.controllerFunction = control; - return this; - } - - @Override - public ListOption.Builder<T> binding(@NotNull Binding<List<T>> binding) { - Validate.notNull(binding, "`binding` cannot be null"); - - this.binding = binding; - return this; - } - - @Override - public ListOption.Builder<T> binding(@NotNull List<T> def, @NotNull Supplier<@NotNull List<T>> getter, @NotNull Consumer<@NotNull List<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; - } - - @Override - public ListOption.Builder<T> available(boolean available) { - this.available = available; - return this; - } - - @Override - public ListOption.Builder<T> flag(@NotNull OptionFlag... flag) { - Validate.notNull(flag, "`flag` must not be null"); - - this.flags.addAll(Arrays.asList(flag)); - return this; - } - - @Override - public ListOption.Builder<T> flags(@NotNull Collection<OptionFlag> flags) { - Validate.notNull(flags, "`flags` must not be null"); - - this.flags.addAll(flags); - return this; - } - - @Override - public ListOption.Builder<T> collapsed(boolean collapsible) { - this.collapsed = collapsible; - return this; - } - - @Override - public ListOption.Builder<T> listener(@NotNull BiConsumer<Option<List<T>>, List<T>> listener) { - this.listeners.add(listener); - return this; - } - - @Override - public ListOption.Builder<T> listeners(@NotNull Collection<BiConsumer<Option<List<T>>, List<T>>> listeners) { - this.listeners.addAll(listeners); - return this; - } - - @Override - public ListOption<T> build() { - Validate.notNull(controllerFunction, "`controller` must not be null"); - Validate.notNull(binding, "`binding` must not be null"); - Validate.notNull(initialValue, "`initialValue` must not be null"); - - MutableComponent concatenatedTooltip = Component.empty(); - boolean first = true; - for (Component line : tooltipLines) { - if (!first) concatenatedTooltip.append("\n"); - first = false; - - concatenatedTooltip.append(line); - } - - return new ListOptionImpl<>(name, concatenatedTooltip, binding, initialValue, typeClass, controllerFunction, ImmutableSet.copyOf(flags), collapsed, available, listeners); - } - } -} diff --git a/src/client/java/dev/isxander/yacl/impl/OptionGroupImpl.java b/src/client/java/dev/isxander/yacl/impl/OptionGroupImpl.java deleted file mode 100644 index 68f53a0..0000000 --- a/src/client/java/dev/isxander/yacl/impl/OptionGroupImpl.java +++ /dev/null @@ -1,129 +0,0 @@ -package dev.isxander.yacl.impl; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.api.ListOption; -import dev.isxander.yacl.api.Option; -import dev.isxander.yacl.api.OptionGroup; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.ComponentContents; -import net.minecraft.network.chat.MutableComponent; -import org.apache.commons.lang3.Validate; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -@ApiStatus.Internal -public final class OptionGroupImpl implements OptionGroup { - private final @NotNull Component name; - private final @NotNull Component tooltip; - private final ImmutableList<? extends Option<?>> options; - private final boolean collapsed; - private final boolean isRoot; - - public OptionGroupImpl(@NotNull Component name, @NotNull Component tooltip, ImmutableList<? extends Option<?>> options, boolean collapsed, boolean isRoot) { - this.name = name; - this.tooltip = tooltip; - this.options = options; - this.collapsed = collapsed; - this.isRoot = isRoot; - } - - @Override - public @NotNull Component name() { - return name; - } - - @Override - public @NotNull Component tooltip() { - return tooltip; - } - - @Override - public @NotNull ImmutableList<? extends Option<?>> options() { - return options; - } - - @Override - public boolean collapsed() { - return collapsed; - } - - @Override - public boolean isRoot() { - return isRoot; - } - - @ApiStatus.Internal - public static final class BuilderImpl implements OptionGroup.Builder { - private Component name = Component.empty(); - private final List<Component> tooltipLines = new ArrayList<>(); - private final List<Option<?>> options = new ArrayList<>(); - private boolean collapsed = false; - - @Override - public Builder name(@NotNull Component name) { - Validate.notNull(name, "`name` must not be null"); - - this.name = name; - return this; - } - - @Override - public Builder tooltip(@NotNull Component... tooltips) { - Validate.notEmpty(tooltips, "`tooltips` cannot be empty"); - - tooltipLines.addAll(List.of(tooltips)); - return this; - } - - @Override - public Builder option(@NotNull Option<?> option) { - Validate.notNull(option, "`option` must not be null"); - - if (option instanceof ListOption<?>) - throw new UnsupportedOperationException("List options must not be added as an option but a group!"); - - this.options.add(option); - return this; - } - - @Override - public Builder options(@NotNull Collection<? extends Option<?>> options) { - Validate.notEmpty(options, "`options` must not be empty"); - - if (options.stream().anyMatch(ListOption.class::isInstance)) - throw new UnsupportedOperationException("List options must not be added as an option but a group!"); - - this.options.addAll(options); - return this; - } - - @Override - public Builder collapsed(boolean collapsible) { - this.collapsed = collapsible; - return this; - } - - @Override - public OptionGroup build() { - Validate.notEmpty(options, "`options` must not be empty to build `OptionGroup`"); - - MutableComponent concatenatedTooltip = Component.empty(); - boolean first = true; - for (Component line : tooltipLines) { - if (line.getContents() == ComponentContents.EMPTY) - continue; - - if (!first) concatenatedTooltip.append("\n"); - first = false; - - concatenatedTooltip.append(line); - } - - return new OptionGroupImpl(name, concatenatedTooltip, ImmutableList.copyOf(options), collapsed, false); - } - } -} diff --git a/src/client/java/dev/isxander/yacl/impl/OptionImpl.java b/src/client/java/dev/isxander/yacl/impl/OptionImpl.java deleted file mode 100644 index 644abc9..0000000 --- a/src/client/java/dev/isxander/yacl/impl/OptionImpl.java +++ /dev/null @@ -1,304 +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.ChatFormatting; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.ComponentContents; -import net.minecraft.network.chat.MutableComponent; -import org.apache.commons.lang3.Validate; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -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; - -@ApiStatus.Internal -public final class OptionImpl<T> implements Option<T> { - private final Component name; - private Component 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 Component name, - @Nullable Function<T, Component> 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 Component name() { - return name; - } - - @Override - public @NotNull Component 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 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); - } - - @ApiStatus.Internal - public static class BuilderImpl<T> implements Option.Builder<T> { - private Component name = Component.literal("Name not specified!").withStyle(ChatFormatting.RED); - - private final List<Function<T, Component>> 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<>(); - - public BuilderImpl(Class<T> typeClass) { - this.typeClass = typeClass; - } - - @Override - public Option.Builder<T> name(@NotNull Component name) { - Validate.notNull(name, "`name` cannot be null"); - - this.name = name; - return this; - } - - @Override - public Builder<T> tooltip(@NotNull Function<T, Component> tooltipGetter) { - Validate.notNull(tooltipGetter, "`tooltipGetter` cannot be null"); - - this.tooltipGetters.add(tooltipGetter); - return this; - } - - @Override - @SafeVarargs - @Deprecated - public final Option.Builder<T> tooltip(@NotNull Function<T, Component>... tooltipGetter) { - Validate.notNull(tooltipGetter, "`tooltipGetter` cannot be null"); - - this.tooltipGetters.addAll(List.of(tooltipGetter)); - return this; - } - - @Override - public Option.Builder<T> tooltip(@NotNull Component... tooltips) { - var tooltipFunctions = Arrays.stream(tooltips) - .map(t -> (Function<T, Component>) opt -> t) - .toList(); - - this.tooltipGetters.addAll(tooltipFunctions); - return this; - } - - @Override - public Option.Builder<T> controller(@NotNull Function<Option<T>, Controller<T>> control) { - Validate.notNull(control, "`control` cannot be null"); - - this.controlGetter = control; - return this; - } - - @Override - public Option.Builder<T> binding(@NotNull Binding<T> binding) { - Validate.notNull(binding, "`binding` cannot be null"); - - this.binding = binding; - return this; - } - - @Override - public Option.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; - } - - @Override - public Option.Builder<T> available(boolean available) { - this.available = available; - return this; - } - - @Override - public Option.Builder<T> flag(@NotNull OptionFlag... flag) { - Validate.notNull(flag, "`flag` must not be null"); - - this.flags.addAll(Arrays.asList(flag)); - return this; - } - - @Override - public Option.Builder<T> flags(@NotNull Collection<OptionFlag> flags) { - Validate.notNull(flags, "`flags` must not be null"); - - this.flags.addAll(flags); - return this; - } - - @Override - public Option.Builder<T> instant(boolean instant) { - this.instant = instant; - return this; - } - - @Override - public Option.Builder<T> listener(@NotNull BiConsumer<Option<T>, T> listener) { - this.listeners.add(listener); - return this; - } - - @Override - public Option.Builder<T> listeners(@NotNull Collection<BiConsumer<Option<T>, T>> listeners) { - this.listeners.addAll(listeners); - return this; - } - - @Override - 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, Component> concatenatedTooltipGetter = value -> { - MutableComponent concatenatedTooltip = Component.empty(); - boolean first = true; - for (Function<T, Component> line : tooltipGetters) { - Component lineComponent = line.apply(value); - - if (lineComponent.getContents() == ComponentContents.EMPTY) - continue; - - if (!first) concatenatedTooltip.append("\n"); - first = false; - - concatenatedTooltip.append(lineComponent); - } - - 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/client/java/dev/isxander/yacl/impl/PlaceholderCategoryImpl.java b/src/client/java/dev/isxander/yacl/impl/PlaceholderCategoryImpl.java deleted file mode 100644 index 0b77466..0000000 --- a/src/client/java/dev/isxander/yacl/impl/PlaceholderCategoryImpl.java +++ /dev/null @@ -1,99 +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.Minecraft; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import org.apache.commons.lang3.Validate; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.BiFunction; - -@ApiStatus.Internal -public final class PlaceholderCategoryImpl implements PlaceholderCategory { - private final Component name; - private final BiFunction<Minecraft, YACLScreen, Screen> screen; - private final Component tooltip; - - public PlaceholderCategoryImpl(Component name, BiFunction<Minecraft, YACLScreen, Screen> screen, Component tooltip) { - this.name = name; - this.screen = screen; - this.tooltip = tooltip; - } - - @Override - public @NotNull ImmutableList<OptionGroup> groups() { - return ImmutableList.of(); - } - - @Override - public @NotNull Component name() { - return name; - } - - @Override - public BiFunction<Minecraft, YACLScreen, Screen> screen() { - return screen; - } - - @Override - public @NotNull Component tooltip() { - return tooltip; - } - - @ApiStatus.Internal - public static final class BuilderImpl implements PlaceholderCategory.Builder { - private Component name; - - private final List<Component> tooltipLines = new ArrayList<>(); - - private BiFunction<Minecraft, YACLScreen, Screen> screenFunction; - - @Override - public Builder name(@NotNull Component name) { - Validate.notNull(name, "`name` cannot be null"); - - this.name = name; - return this; - } - - @Override - public Builder tooltip(@NotNull Component... tooltips) { - Validate.notEmpty(tooltips, "`tooltips` cannot be empty"); - - tooltipLines.addAll(List.of(tooltips)); - return this; - } - - @Override - public Builder screen(@NotNull BiFunction<Minecraft, YACLScreen, Screen> screenFunction) { - Validate.notNull(screenFunction, "`screenFunction` cannot be null"); - - this.screenFunction = screenFunction; - return this; - } - - @Override - public PlaceholderCategory build() { - Validate.notNull(name, "`name` must not be null to build `ConfigCategory`"); - - MutableComponent concatenatedTooltip = Component.empty(); - boolean first = true; - for (Component line : tooltipLines) { - if (!first) concatenatedTooltip.append("\n"); - first = false; - - concatenatedTooltip.append(line); - } - - return new PlaceholderCategoryImpl(name, screenFunction, concatenatedTooltip); - } - } -} diff --git a/src/client/java/dev/isxander/yacl/impl/YetAnotherConfigLibImpl.java b/src/client/java/dev/isxander/yacl/impl/YetAnotherConfigLibImpl.java deleted file mode 100644 index 21c776a..0000000 --- a/src/client/java/dev/isxander/yacl/impl/YetAnotherConfigLibImpl.java +++ /dev/null @@ -1,122 +0,0 @@ -package dev.isxander.yacl.impl; - -import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.api.ConfigCategory; -import dev.isxander.yacl.api.PlaceholderCategory; -import dev.isxander.yacl.api.YetAnotherConfigLib; -import dev.isxander.yacl.gui.YACLScreen; -import dev.isxander.yacl.impl.utils.YACLConstants; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; -import org.apache.commons.lang3.Validate; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.function.Consumer; - -@ApiStatus.Internal -public final class YetAnotherConfigLibImpl implements YetAnotherConfigLib { - private final Component title; - private final ImmutableList<ConfigCategory> categories; - private final Runnable saveFunction; - private final Consumer<YACLScreen> initConsumer; - - private boolean generated = false; - - public YetAnotherConfigLibImpl(Component title, ImmutableList<ConfigCategory> categories, Runnable saveFunction, Consumer<YACLScreen> initConsumer) { - this.title = title; - this.categories = categories; - this.saveFunction = saveFunction; - this.initConsumer = initConsumer; - } - - @Override - public Screen generateScreen(Screen parent) { - if (generated) - throw new UnsupportedOperationException("To prevent memory leaks, you should only generate a Screen once per instance. Please re-build the instance to generate another GUI."); - - YACLConstants.LOGGER.info("Generating YACL screen"); - generated = true; - return new YACLScreen(this, parent); - } - - @Override - public Component title() { - return title; - } - - @Override - public ImmutableList<ConfigCategory> categories() { - return categories; - } - - @Override - public Runnable saveFunction() { - return saveFunction; - } - - @Override - public Consumer<YACLScreen> initConsumer() { - return initConsumer; - } - - @ApiStatus.Internal - public static final class BuilderImpl implements YetAnotherConfigLib.Builder { - private Component title; - private final List<ConfigCategory> categories = new ArrayList<>(); - private Runnable saveFunction = () -> {}; - private Consumer<YACLScreen> initConsumer = screen -> {}; - - @Override - public YetAnotherConfigLib.Builder title(@NotNull Component title) { - Validate.notNull(title, "`title` cannot be null"); - - this.title = title; - return this; - } - - @Override - public YetAnotherConfigLib.Builder category(@NotNull ConfigCategory category) { - Validate.notNull(category, "`category` cannot be null"); - - this.categories.add(category); - return this; - } - - @Override - public YetAnotherConfigLib.Builder categories(@NotNull Collection<? extends ConfigCategory> categories) { - Validate.notNull(categories, "`categories` cannot be null"); - - this.categories.addAll(categories); - return this; - } - - @Override - public YetAnotherConfigLib.Builder save(@NotNull Runnable saveFunction) { - Validate.notNull(saveFunction, "`saveFunction` cannot be null"); - - this.saveFunction = saveFunction; - return this; - } - - @Override - public YetAnotherConfigLib.Builder screenInit(@NotNull Consumer<YACLScreen> initConsumer) { - Validate.notNull(initConsumer, "`initConsumer` cannot be null"); - - this.initConsumer = initConsumer; - return this; - } - - @Override - 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/client/java/dev/isxander/yacl/mixin/client/AbstractSelectionListMixin.java b/src/client/java/dev/isxander/yacl/mixin/client/AbstractSelectionListMixin.java deleted file mode 100644 index 978fd16..0000000 --- a/src/client/java/dev/isxander/yacl/mixin/client/AbstractSelectionListMixin.java +++ /dev/null @@ -1,26 +0,0 @@ -package dev.isxander.yacl.mixin.client; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.AbstractSelectionList; -import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.util.List; - -@Mixin(AbstractSelectionList.class) -public abstract class AbstractSelectionListMixin<E extends AbstractSelectionList.Entry<E>> { - @Shadow public abstract List<E> children(); - - /** - * Mojang use the field access of children to get max index to loop through keyboard navigation to find the next entry. - * YACL modifies these children() method to filter out hidden entries, so we need to redirect the field access to the - * method, so we don't get ArrayIndexOutOfBoundsException. - */ - @Redirect(method = "nextEntry(Lnet/minecraft/client/gui/navigation/ScreenDirection;Ljava/util/function/Predicate;Lnet/minecraft/client/gui/components/AbstractSelectionList$Entry;)Lnet/minecraft/client/gui/components/AbstractSelectionList$Entry;", at = @At(value = "FIELD", target = "Lnet/minecraft/client/gui/components/AbstractSelectionList;children:Ljava/util/List;", opcode = Opcodes.GETFIELD)) - private List<E> modifyChildrenCall(AbstractSelectionList<E> instance) { - return children(); - } -} diff --git a/src/client/java/dev/isxander/yacl/mixin/client/OptionInstanceAccessor.java b/src/client/java/dev/isxander/yacl/mixin/client/OptionInstanceAccessor.java deleted file mode 100644 index b8df39f..0000000 --- a/src/client/java/dev/isxander/yacl/mixin/client/OptionInstanceAccessor.java +++ /dev/null @@ -1,13 +0,0 @@ -package dev.isxander.yacl.mixin.client; - -import net.minecraft.client.OptionInstance; -import org.jetbrains.annotations.ApiStatus; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@ApiStatus.Internal -@Mixin(OptionInstance.class) -public interface OptionInstanceAccessor<T> { - @Accessor - T getInitialValue(); -} diff --git a/src/client/resources/yet-another-config-lib.client.mixins.json b/src/client/resources/yet-another-config-lib.client.mixins.json deleted file mode 100644 index 69c0f25..0000000 --- a/src/client/resources/yet-another-config-lib.client.mixins.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "required": true, - "package": "dev.isxander.yacl.mixin.client", - "compatibilityLevel": "JAVA_17", - "injectors": { - "defaultRequire": 1 - }, - "client": [ - "OptionInstanceAccessor" - ], - "mixins": [ - "AbstractSelectionListMixin" - ] -} 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/config/ConfigEntry.java b/src/main/java/dev/isxander/yacl/config/ConfigEntry.java deleted file mode 100644 index 7f04c33..0000000 --- a/src/main/java/dev/isxander/yacl/config/ConfigEntry.java +++ /dev/null @@ -1,11 +0,0 @@ -package dev.isxander.yacl.config; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface ConfigEntry { -} diff --git a/src/main/java/dev/isxander/yacl/config/ConfigInstance.java b/src/main/java/dev/isxander/yacl/config/ConfigInstance.java deleted file mode 100644 index c207161..0000000 --- a/src/main/java/dev/isxander/yacl/config/ConfigInstance.java +++ /dev/null @@ -1,48 +0,0 @@ -package dev.isxander.yacl.config; - -import java.lang.reflect.InvocationTargetException; - -/** - * Responsible for handing the actual config data type. - * Holds the instance along with a final default instance - * to reference default values for options and should not be changed. - * - * Abstract methods to save and load the class, implementations are responsible for - * how it saves and load. - * - * @param <T> config data type - */ -public abstract class ConfigInstance<T> { - private final Class<T> configClass; - private final T defaultInstance; - private T instance; - - public ConfigInstance(Class<T> configClass) { - this.configClass = configClass; - - try { - this.defaultInstance = this.instance = configClass.getConstructor().newInstance(); - } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { - throw new IllegalStateException(String.format("Could not create default instance of config for %s. Make sure there is a default constructor!", this.configClass.getSimpleName())); - } - } - - public abstract void save(); - public abstract void load(); - - public T getConfig() { - return this.instance; - } - - protected void setConfig(T instance) { - this.instance = instance; - } - - public T getDefaults() { - return this.defaultInstance; - } - - public Class<T> getConfigClass() { - return this.configClass; - } -} diff --git a/src/main/java/dev/isxander/yacl/config/GsonConfigInstance.java b/src/main/java/dev/isxander/yacl/config/GsonConfigInstance.java deleted file mode 100644 index ad7f550..0000000 --- a/src/main/java/dev/isxander/yacl/config/GsonConfigInstance.java +++ /dev/null @@ -1,212 +0,0 @@ -package dev.isxander.yacl.config; - -import com.google.gson.*; -import dev.isxander.yacl.impl.utils.YACLConstants; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.Style; - -import java.awt.*; -import java.io.IOException; -import java.lang.reflect.Type; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.function.UnaryOperator; - -/** - * Uses GSON to serialize and deserialize config data from JSON to a file. - * - * Only fields annotated with {@link ConfigEntry} are included in the JSON. - * {@link Component}, {@link Style} and {@link Color} have default type adapters, so there is no need to provide them in your GSON instance. - * GSON is automatically configured to format fields as {@code lower_camel_case}. - * - * @param <T> config data type - */ -public class GsonConfigInstance<T> extends ConfigInstance<T> { - private final Gson gson; - private final Path path; - - @Deprecated - public GsonConfigInstance(Class<T> configClass, Path path) { - this(configClass, path, new GsonBuilder()); - } - - @Deprecated - public GsonConfigInstance(Class<T> configClass, Path path, Gson gson) { - this(configClass, path, gson.newBuilder()); - } - - @Deprecated - public GsonConfigInstance(Class<T> configClass, Path path, UnaryOperator<GsonBuilder> builder) { - this(configClass, path, builder.apply(new GsonBuilder())); - } - - @Deprecated - public GsonConfigInstance(Class<T> configClass, Path path, GsonBuilder builder) { - super(configClass); - this.path = path; - this.gson = builder - .setExclusionStrategies(new ConfigExclusionStrategy()) - .registerTypeHierarchyAdapter(Component.class, new Component.Serializer()) - .registerTypeHierarchyAdapter(Style.class, new Style.Serializer()) - .registerTypeHierarchyAdapter(Color.class, new ColorTypeAdapter()) - .serializeNulls() - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .create(); - } - - private GsonConfigInstance(Class<T> configClass, Path path, Gson gson, boolean fromBuilder) { - super(configClass); - this.path = path; - this.gson = gson; - } - - @Override - public void save() { - try { - YACLConstants.LOGGER.info("Saving {}...", getConfigClass().getSimpleName()); - Files.writeString(path, gson.toJson(getConfig()), StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public void load() { - try { - if (Files.notExists(path)) { - save(); - return; - } - - YACLConstants.LOGGER.info("Loading {}...", getConfigClass().getSimpleName()); - setConfig(gson.fromJson(Files.readString(path), getConfigClass())); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public Path getPath() { - return this.path; - } - - private static class ConfigExclusionStrategy implements ExclusionStrategy { - @Override - public boolean shouldSkipField(FieldAttributes fieldAttributes) { - return fieldAttributes.getAnnotation(ConfigEntry.class) == null; - } - - @Override - public boolean shouldSkipClass(Class<?> aClass) { - return false; - } - } - - public static class ColorTypeAdapter implements JsonSerializer<Color>, JsonDeserializer<Color> { - @Override - public Color deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { - return new Color(jsonElement.getAsInt(), true); - } - - @Override - public JsonElement serialize(Color color, Type type, JsonSerializationContext jsonSerializationContext) { - return new JsonPrimitive(color.getRGB()); - } - } - - /** - * Creates a builder for a GSON config instance. - * @param configClass the config class - * @return a new builder - * @param <T> the config type - */ - public static <T> Builder<T> createBuilder(Class<T> configClass) { - return new Builder<>(configClass); - } - - public static class Builder<T> { - private final Class<T> configClass; - private Path path; - private UnaryOperator<GsonBuilder> gsonBuilder = builder -> builder - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .serializeNulls() - .registerTypeHierarchyAdapter(Component.class, new Component.Serializer()) - .registerTypeHierarchyAdapter(Style.class, new Style.Serializer()) - .registerTypeHierarchyAdapter(Color.class, new ColorTypeAdapter()); - - private Builder(Class<T> configClass) { - this.configClass = configClass; - } - - /** - * Sets the file path to save and load the config from. - */ - public Builder<T> setPath(Path path) { - this.path = path; - return this; - } - - /** - * Sets the GSON instance to use. Overrides all YACL defaults such as: - * <ul> - * <li>lower_camel_case field naming policy</li> - * <li>null serialization</li> - * <li>{@link Component}, {@link Style} and {@link Color} type adapters</li> - * </ul> - * Still respects the exclusion strategy to only serialize {@link ConfigEntry} - * but these can be added to with setExclusionStrategies. - * - * @param gsonBuilder gson builder to use - */ - public Builder<T> overrideGsonBuilder(GsonBuilder gsonBuilder) { - this.gsonBuilder = builder -> gsonBuilder; - return this; - } - - /** - * Sets the GSON instance to use. Overrides all YACL defaults such as: - * <ul> - * <li>lower_camel_case field naming policy</li> - * <li>null serialization</li> - * <li>{@link Component}, {@link Style} and {@link Color} type adapters</li> - * </ul> - * Still respects the exclusion strategy to only serialize {@link ConfigEntry} - * but these can be added to with setExclusionStrategies. - * - * @param gson gson instance to be converted to a builder - */ - public Builder<T> overrideGsonBuilder(Gson gson) { - return this.overrideGsonBuilder(gson.newBuilder()); - } - - /** - * Appends extra configuration to a GSON builder. - * This is the intended way to add functionality to the GSON instance. - * <p> - * By default, YACL sets the GSON with the following options: - * <ul> - * <li>lower_camel_case field naming policy</li> - * <li>null serialization</li> - * <li>{@link Component}, {@link Style} and {@link Color} type adapters</li> - * </ul> - * - * @param gsonBuilder the function to apply to the builder - */ - public Builder<T> appendGsonBuilder(UnaryOperator<GsonBuilder> gsonBuilder) { - this.gsonBuilder = builder -> gsonBuilder.apply(this.gsonBuilder.apply(builder)); - return this; - } - - /** - * Builds the config instance. - * @return the built config instance - */ - public GsonConfigInstance<T> build() { - UnaryOperator<GsonBuilder> gsonBuilder = builder -> this.gsonBuilder.apply(builder) - .addSerializationExclusionStrategy(new ConfigExclusionStrategy()) - .addDeserializationExclusionStrategy(new ConfigExclusionStrategy()); - - return new GsonConfigInstance<>(configClass, path, gsonBuilder.apply(new GsonBuilder()).create(), true); - } - } -} 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/resources/assets/yet-another-config-lib/lang/el_gr.json b/src/main/resources/assets/yet-another-config-lib/lang/el_gr.json deleted file mode 100644 index b7bc2d2..0000000 --- a/src/main/resources/assets/yet-another-config-lib/lang/el_gr.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "yacl.control.boolean.true": "Ναι", - "yacl.control.boolean.false": "Όχι", - - "yacl.control.action.execute": "ΕΚΤΕΛΕΣΗ", - - "yacl.gui.save": "Αποθήκευση Αλλαγών", - "yacl.gui.save.tooltip": "Μονιμοποιήει τις αλλαγές.", - "yacl.gui.finished.tooltip": "Κλείνει το GUI.", - "yacl.gui.cancel.tooltip": "Ξεχνά τις ενεργές αλλαγές και κλείνει το μενού.", - "yacl.gui.reset.tooltip": "Επαναφέρει όλες τις επιλογές στις προεπιλογές τους. (Μπορεί να ανερεθε)", - "yacl.gui.undo": "Επαναφορά", - "yacl.gui.undo.tooltip": "Επαναφέρει όλες τις ενεργές επιλογές στις προεπιλογές τους.", - "yacl.gui.fail_apply": "Αποτυχία εφαρμογής", - "yacl.gui.fail_apply.tooltip": "Δημιουργήθηκε ένα σφάλμα και οι αλλαγές δεν μπόρεσαν να εφαρμοστούν.", - "yacl.gui.save_before_exit": "Αποθήκευση πριν το κλείσιμο!", - "yacl.gui.save_before_exit.tooltip": "Αποθήκευσε ή ακύρωσε για να βγεις απ' το μενού." - - "yacl.restart.title": "Η ρύθμιση απαιτεί επανεκκήνιση!", - "yacl.restart.message": "Μία ή παραπάνω επιλογές προϋποθέτουν επανεκκήνηση το παιχνιδιού για να εφαρμοστούν.", - "yacl.restart.yes": "Κλείσιμο του Minecraft", - "yacl.restart.no": "Αγνόησε το για τώρα" -} diff --git a/src/main/resources/assets/yet-another-config-lib/lang/en_us.json b/src/main/resources/assets/yet-another-config-lib/lang/en_us.json deleted file mode 100644 index 32621e9..0000000 --- a/src/main/resources/assets/yet-another-config-lib/lang/en_us.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "yacl.control.boolean.true": "True", - "yacl.control.boolean.false": "False", - - "yacl.control.action.execute": "EXECUTE", - - "yacl.gui.save": "Save Changes", - "yacl.gui.save.tooltip": "Makes the changes made permanent.", - "yacl.gui.finished.tooltip": "Closes the GUI.", - "yacl.gui.cancel.tooltip": "Forgets pending changes and closes the GUI.", - "yacl.gui.reset.tooltip": "Resets all options to default. (This is reversible!)", - "yacl.gui.undo": "Undo", - "yacl.gui.undo.tooltip": "Reverts all options back to what they were before editing.", - "yacl.gui.fail_apply": "Failed to apply", - "yacl.gui.fail_apply.tooltip": "There was an error and the changes couldn't be applied.", - "yacl.gui.save_before_exit": "Save before exiting!", - "yacl.gui.save_before_exit.tooltip": "Save or cancel to exit the GUI.", - - "yacl.list.move_up": "Move up", - "yacl.list.move_down": "Move down", - "yacl.list.remove": "Remove", - "yacl.list.add_top": "New entry", - "yacl.list.empty": "List is empty", - - "yacl.restart.title": "Config requires restart!", - "yacl.restart.message": "One or more options needs you to restart the game to apply the changes.", - "yacl.restart.yes": "Close Minecraft", - "yacl.restart.no": "Ignore" -} diff --git a/src/main/resources/assets/yet-another-config-lib/lang/et_ee.json b/src/main/resources/assets/yet-another-config-lib/lang/et_ee.json deleted file mode 100644 index 5f5274a..0000000 --- a/src/main/resources/assets/yet-another-config-lib/lang/et_ee.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "yacl.control.boolean.true": "Tõene", - "yacl.control.boolean.false": "Väär", - - "yacl.control.action.execute": "KÄIVITA", - - "yacl.gui.save": "Salvesta muudatused", - "yacl.gui.save.tooltip": "Teeb tehtud muudatused püsivaks.", - "yacl.gui.finished.tooltip": "Sulgeb liidese.", - "yacl.gui.cancel.tooltip": "Unustab tehtud muudatused ja sulgeb liidese.", - "yacl.gui.reset.tooltip": "Lähtestab kõik valikud vaikeväärtustele. (Seda saab tagasi võtta!)", - "yacl.gui.undo": "Võta tagasi", - "yacl.gui.undo.tooltip": "Lähtestab kõik valikud muutmise-eelsetele väärtustele.", - "yacl.gui.fail_apply": "Rakendamine ebaõnnestus", - "yacl.gui.fail_apply.tooltip": "Esines viga ja muudatusi ei saadud rakendada.", - "yacl.gui.save_before_exit": "Salvesta enne väljumist!", - "yacl.gui.save_before_exit.tooltip": "Liidesest väljumiseks salvesta või loobu." -} diff --git a/src/main/resources/assets/yet-another-config-lib/lang/fr_fr.json b/src/main/resources/assets/yet-another-config-lib/lang/fr_fr.json deleted file mode 100644 index bc069cf..0000000 --- a/src/main/resources/assets/yet-another-config-lib/lang/fr_fr.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "yacl.control.boolean.true": "Vrai", - "yacl.control.boolean.false": "Faux", - - "yacl.control.action.execute": "EXÉCUTION", - - "yacl.gui.save": "Sauvegarder les modifications", - "yacl.gui.save.tooltip": "Rend les changements effectués permanents.", - "yacl.gui.finished.tooltip": "Ferme la superposition.", - "yacl.gui.cancel.tooltip": "Oublie les changements en cours et ferme la superposition.", - "yacl.gui.reset.tooltip": "Réinitialise toutes les options par défaut. (Réversible !)", - "yacl.gui.undo": "Annuler", - "yacl.gui.undo.tooltip": "Rétablit toutes les options telles qu'elles étaient avant l'édition.", - "yacl.gui.fail_apply": "Échec de l'application", - "yacl.gui.fail_apply.tooltip": "Il y a eu une erreur et les changements n'ont pas pu être appliqués.", - "yacl.gui.save_before_exit": "Sauvegardez avant de quitter !", - "yacl.gui.save_before_exit.tooltip": "Sauvegardez ou annulez pour quitter la superposition.", - - "yacl.list.move_up": "Monter en haut", - "yacl.list.move_down": "Monter en bas", - "yacl.list.remove": "Retirer", - "yacl.list.add_top": "Nouvelle entrée", - "yacl.list.empty": "La liste est vide", - - "yacl.restart.title": "La configuration nécessite un redémarrage !", - "yacl.restart.message": "Une ou plusieurs options nécessitent que vous redémarriez le jeu pour appliquer les changements.", - "yacl.restart.yes": "Fermer Minecraft", - "yacl.restart.no": "Ignorer" -} diff --git a/src/main/resources/assets/yet-another-config-lib/lang/pl_pl.json b/src/main/resources/assets/yet-another-config-lib/lang/pl_pl.json deleted file mode 100644 index 49074ea..0000000 --- a/src/main/resources/assets/yet-another-config-lib/lang/pl_pl.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "yacl.control.boolean.true": "Tak", - "yacl.control.boolean.false": "Nie", - - "yacl.control.action.execute": "WYKONAJ", - - "yacl.gui.save": "Zapisz zmiany", - "yacl.gui.save.tooltip": "Sprawia, że wprowadzone zmiany są trwałe.", - "yacl.gui.finished.tooltip": "Zamyka GUI.", - "yacl.gui.cancel.tooltip": "Zapomina oczekujące zmiany i zamyka GUI.", - "yacl.gui.reset.tooltip": "Resetuje wszystkie opcje do wartości domyślnych. (To jest odwracalne!)", - "yacl.gui.undo": "Cofnij", - "yacl.gui.undo.tooltip": "Przywraca wszystkie opcje do stanu sprzed edycji.", - "yacl.gui.fail_apply": "Nie udało się zastosować", - "yacl.gui.fail_apply.tooltip": "Wystąpił błąd i nie udało się zastosować zmian.", - "yacl.gui.save_before_exit": "Zapisz przed wyjściem!", - "yacl.gui.save_before_exit.tooltip": "Zapisz lub anuluj, aby wyjść z GUI.", - - "yacl.restart.title": "Konfiguracja wymaga restartu!", - "yacl.restart.message": "Jedna lub więcej opcji wymaga ponownego uruchomienia gry, aby zastosować zmiany.", - "yacl.restart.yes": "Zamknij Minecrafta", - "yacl.restart.no": "Ignoruj" -} diff --git a/src/main/resources/assets/yet-another-config-lib/lang/pt_br.json b/src/main/resources/assets/yet-another-config-lib/lang/pt_br.json deleted file mode 100644 index 9d4ef8d..0000000 --- a/src/main/resources/assets/yet-another-config-lib/lang/pt_br.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "yacl.control.boolean.true": "Verdadeiro", - "yacl.control.boolean.false": "Falso", - - "yacl.control.action.execute": "EXECUTAR", - - "yacl.gui.save": "Salvar Mudanças", - "yacl.gui.save.tooltip": "Faz as mudanças serem permanentes.", - "yacl.gui.finished.tooltip": "Fecha o GUI.", - "yacl.gui.cancel.tooltip": "Esquece as mudanças pendentes e fecha o GUI.", - "yacl.gui.reset.tooltip": "Reinicia todas as opções para o valor padrão. (Isso é irreversível!)", - "yacl.gui.undo": "Desfazer", - "yacl.gui.undo.tooltip": "Reverte todas as opções como elas estavam antes de serem editadas.", - "yacl.gui.fail_apply": "Falha na aplicação", - "yacl.gui.fail_apply.tooltip": "Houve um erro e as mudanças não puderam ser aplicadas.", - "yacl.gui.save_before_exit": "Salve antes de sair!", - "yacl.gui.save_before_exit.tooltip": "Salve ou calcele para sair do GUI." -} diff --git a/src/main/resources/assets/yet-another-config-lib/lang/ru_ru.json b/src/main/resources/assets/yet-another-config-lib/lang/ru_ru.json deleted file mode 100644 index 5725d34..0000000 --- a/src/main/resources/assets/yet-another-config-lib/lang/ru_ru.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "yacl.control.boolean.true": "§atrue", - "yacl.control.boolean.false": "§cfalse", - - "yacl.control.action.execute": "Выполнить", - - "yacl.gui.save": "Сохранить", - "yacl.gui.save.tooltip": "Сохранить изменения до следующего редактирования.", - "yacl.gui.finished.tooltip": "Закрыть меню.", - "yacl.gui.cancel": "Назад", - "yacl.gui.cancel.tooltip": "Отменить изменения и закрыть настройки.", - "yacl.gui.reset.tooltip": "Сбросить все настройки до значений по умолчанию (их можно восстановить).", - "yacl.gui.undo": "Отменить", - "yacl.gui.undo.tooltip": "Вернуть все настройки к состоянию, в котором они были до изменений.", - "yacl.gui.fail_apply": "Не удалось сохранить", - "yacl.gui.fail_apply.tooltip": "Возникла ошибка; изменения невозможно применить.", - "yacl.gui.save_before_exit": "Сохраните перед закрытием", - "yacl.gui.save_before_exit.tooltip": "Сохраните или отмените изменения, чтобы закрыть настройки.", - - "yacl.restart.title": "Настройки требуют перезагрузки.", - "yacl.restart.message": "Одна или несколько настроек требует перезапуска игры для применения изменений.", - "yacl.restart.yes": "Закрыть Minecraft", - "yacl.restart.no": "Игнорировать" -} diff --git a/src/main/resources/assets/yet-another-config-lib/lang/sl_si.json b/src/main/resources/assets/yet-another-config-lib/lang/sl_si.json deleted file mode 100644 index 743dd4d..0000000 --- a/src/main/resources/assets/yet-another-config-lib/lang/sl_si.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "yacl.control.boolean.true": "Vklopljeno", - "yacl.control.boolean.false": "Izklopljeno", - - "yacl.control.action.execute": "POŽENI", - - "yacl.gui.save": "Shrani spremembe", - "yacl.gui.save.tooltip": "Uvede trajne spremembe.", - "yacl.gui.finished.tooltip": "Zapre meni.", - "yacl.gui.cancel.tooltip": "Zavrže neshranjene spremembe in zapre meni.", - "yacl.gui.reset.tooltip": "Ponastavi vse možnosti na privzete. (To se da razveljaviti!)", - "yacl.gui.undo": "Razveljavi", - "yacl.gui.undo.tooltip": "Ponastavi vse možnosti na take kot pred spreminjanjem.", - "yacl.gui.fail_apply": "Napaka pri uveljavljanju", - "yacl.gui.fail_apply.tooltip": "Prišlo je do napake pri uveljavljanju sprememb.", - "yacl.gui.save_before_exit": "Shrani pred izhodom!", - "yacl.gui.save_before_exit.tooltip": "Shrani ali prekliči za izhod iz menija.", - "yacl.restart.title": "Nastavitve potrebujejo ponovni zagon!", - "yacl.restart.message": "Vsaj ena izmed nastavitev potrebuje ponovni zagon igre za uveljavitev.", - "yacl.restart.yes": "Zapri Minecraft", - "yacl.restart.no": "Prezri" -} diff --git a/src/main/resources/assets/yet-another-config-lib/lang/zh_cn.json b/src/main/resources/assets/yet-another-config-lib/lang/zh_cn.json deleted file mode 100644 index 9307c9b..0000000 --- a/src/main/resources/assets/yet-another-config-lib/lang/zh_cn.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "yacl.control.boolean.true": "是", - "yacl.control.boolean.false": "否", - - "yacl.control.action.execute": "执行", - - "yacl.gui.save": "保存更改", - "yacl.gui.save.tooltip": "永久保存所做更改。", - "yacl.gui.finished.tooltip": "关闭 GUI。", - "yacl.gui.cancel.tooltip": "忽略犹豫不决的更改然后关闭 GUI。", - "yacl.gui.reset.tooltip": "将所有选项重置为默认值。(这是可逆的!)", - "yacl.gui.undo": "撤销", - "yacl.gui.undo.tooltip": "将所有选项恢复到编辑前的状态。", - "yacl.gui.fail_apply": "应用失败", - "yacl.gui.fail_apply.tooltip": "有一个错误以至于更改不能被应用。", - "yacl.gui.save_before_exit": "退出前保存!", - "yacl.gui.save_before_exit.tooltip": "保存或取消以退出 GUI。", - - "yacl.list.move_up": "上移", - "yacl.list.move_down": "下移", - "yacl.list.remove": "移除", - "yacl.list.add_top": "新条目", - "yacl.list.empty": "列表为空", - - "yacl.restart.title": "配置需要重新启动!", - "yacl.restart.message": "一个或多个选项需要你重新启动游戏来应用这些更改。", - "yacl.restart.yes": "关闭 Minecraft", - "yacl.restart.no": "忽略" -} diff --git a/src/main/resources/assets/yet-another-config-lib/lang/zh_tw.json b/src/main/resources/assets/yet-another-config-lib/lang/zh_tw.json deleted file mode 100644 index 67d05a7..0000000 --- a/src/main/resources/assets/yet-another-config-lib/lang/zh_tw.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "yacl.control.boolean.true": "是", - "yacl.control.boolean.false": "否", - - "yacl.control.action.execute": "執行", - - "yacl.gui.save": "儲存變更", - "yacl.gui.save.tooltip": "儲存你的變更。", - "yacl.gui.finished.tooltip": "關閉介面。", - "yacl.gui.cancel.tooltip": "取消變更並關閉介面。", - "yacl.gui.reset.tooltip": "重設所有選項到預設。(這可以復原!)", - "yacl.gui.undo": "復原", - "yacl.gui.undo.tooltip": "將所有選項恢復成編輯前的狀態。", - "yacl.gui.fail_apply": "套用失敗", - "yacl.gui.fail_apply.tooltip": "發生錯誤,無法套用變更。", - "yacl.gui.save_before_exit": "在離開時儲存!", - "yacl.gui.save_before_exit.tooltip": "儲存或是取消並離開介面。", - - "yacl.restart.title": "變更設定需要重開遊戲!", - "yacl.restart.message": "一個或多個選項需要你重開遊戲才能套用變更。", - "yacl.restart.yes": "關閉 Minecraft", - "yacl.restart.no": "忽略" -} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json deleted file mode 100644 index cc2e6b9..0000000 --- a/src/main/resources/fabric.mod.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "schemaVersion": 1, - "id": "${id}", - "version": "${version}", - "name": "${name}", - "description": "${description}", - "authors": [ - "isXander" - ], - "contact": { - "homepage": "https://isxander.dev", - "issues": "https://github.com/${github}/issues", - "sources": "https://github.com/${github}" - }, - "icon": "yacl-128x.png", - "license": "LGPL-3.0-or-later", - "environment": "*", - "entrypoints": { - - }, - "depends": { - "fabricloader": ">=0.14.0", - "minecraft": "~1.19.4", - "java": ">=17", - "fabric-resource-loader-v0": "*" - }, - "mixins": [ - { - "config": "yet-another-config-lib.client.mixins.json", - "environment": "client" - } - ], - "accessWidener": "yacl.accesswidener", - "custom": { - "modmenu": { - "badges": ["library"] - } - } -} diff --git a/src/main/resources/yacl-128x.png b/src/main/resources/yacl-128x.png Binary files differdeleted file mode 100644 index c86981c..0000000 --- a/src/main/resources/yacl-128x.png +++ /dev/null diff --git a/src/main/resources/yacl.accesswidener b/src/main/resources/yacl.accesswidener deleted file mode 100644 index 3a65a38..0000000 --- a/src/main/resources/yacl.accesswidener +++ /dev/null @@ -1,6 +0,0 @@ -accessWidener v1 named - -extendable method net/minecraft/client/gui/components/AbstractSelectionList children ()Ljava/util/List; -extendable method net/minecraft/client/gui/components/AbstractSelectionList getEntryAtPosition (DD)Lnet/minecraft/client/gui/components/AbstractSelectionList$Entry; -accessible class net/minecraft/client/gui/components/AbstractSelectionList$Entry -extendable method net/minecraft/client/gui/components/AbstractButton getTextureY ()I diff --git a/src/testmod/java/dev/isxander/yacl/test/ExampleMod.java b/src/testmod/java/dev/isxander/yacl/test/ExampleMod.java deleted file mode 100644 index 46c5225..0000000 --- a/src/testmod/java/dev/isxander/yacl/test/ExampleMod.java +++ /dev/null @@ -1,11 +0,0 @@ -package dev.isxander.yacl.test; - -import dev.isxander.yacl.test.config.ExampleConfig; -import net.fabricmc.api.ClientModInitializer; - -public class ExampleMod implements ClientModInitializer { - @Override - public void onInitializeClient() { - ExampleConfig.INSTANCE.load(); - } -} diff --git a/src/testmod/java/dev/isxander/yacl/test/config/ExampleConfig.java b/src/testmod/java/dev/isxander/yacl/test/config/ExampleConfig.java deleted file mode 100644 index 717132b..0000000 --- a/src/testmod/java/dev/isxander/yacl/test/config/ExampleConfig.java +++ /dev/null @@ -1,44 +0,0 @@ -package dev.isxander.yacl.test.config; - -import dev.isxander.yacl.config.ConfigEntry; -import dev.isxander.yacl.config.ConfigInstance; -import dev.isxander.yacl.config.GsonConfigInstance; - -import java.awt.*; -import java.util.List; -import java.nio.file.Path; - -public class ExampleConfig { - public static final ConfigInstance<ExampleConfig> INSTANCE = GsonConfigInstance.createBuilder(ExampleConfig.class) - .setPath(Path.of("./config/yacl-test.json")) - .build(); - - @ConfigEntry public boolean booleanToggle = false; - @ConfigEntry public boolean customBooleanToggle = false; - @ConfigEntry public boolean tickbox = false; - @ConfigEntry public int intSlider = 0; - @ConfigEntry public double doubleSlider = 0; - @ConfigEntry public float floatSlider = 0; - @ConfigEntry public long longSlider = 0; - @ConfigEntry public String textField = "Hello"; - @ConfigEntry public Color colorOption = Color.red; - @ConfigEntry public double doubleField = 0.5; - @ConfigEntry public float floatField = 0.5f; - @ConfigEntry public int intField = 5; - @ConfigEntry public long longField = 5; - @ConfigEntry public Alphabet enumOption = Alphabet.A; - - @ConfigEntry public List<String> stringList = List.of("This is quite cool.", "You can add multiple items!", "And it is integrated so well into Option groups!"); - @ConfigEntry public List<Integer> intList = List.of(1, 2, 3); - - @ConfigEntry public boolean groupTestRoot = false; - @ConfigEntry public boolean groupTestFirstGroup = false; - @ConfigEntry public boolean groupTestFirstGroup2 = false; - @ConfigEntry public boolean groupTestSecondGroup = false; - - @ConfigEntry public int scrollingSlider = 0; - - public enum Alphabet { - A, B, C - } -} diff --git a/src/testmod/java/dev/isxander/yacl/test/config/GuiTest.java b/src/testmod/java/dev/isxander/yacl/test/config/GuiTest.java deleted file mode 100644 index 18d2a3c..0000000 --- a/src/testmod/java/dev/isxander/yacl/test/config/GuiTest.java +++ /dev/null @@ -1,449 +0,0 @@ -package dev.isxander.yacl.test.config; - -import dev.isxander.yacl.api.*; -import dev.isxander.yacl.gui.RequireRestartScreen; -import dev.isxander.yacl.gui.controllers.*; -import dev.isxander.yacl.gui.controllers.cycling.EnumController; -import dev.isxander.yacl.gui.controllers.slider.DoubleSliderController; -import dev.isxander.yacl.gui.controllers.slider.FloatSliderController; -import dev.isxander.yacl.gui.controllers.slider.IntegerSliderController; -import dev.isxander.yacl.gui.controllers.slider.LongSliderController; -import dev.isxander.yacl.gui.controllers.string.StringController; -import dev.isxander.yacl.gui.controllers.string.number.DoubleFieldController; -import dev.isxander.yacl.gui.controllers.string.number.FloatFieldController; -import dev.isxander.yacl.gui.controllers.string.number.IntegerFieldController; -import dev.isxander.yacl.gui.controllers.string.number.LongFieldController; -import net.minecraft.client.GraphicsStatus; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.toasts.SystemToast; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.ClickEvent; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.HoverEvent; - -import java.awt.Color; -import java.util.List; - -public class GuiTest { - public static Screen getModConfigScreenFactory(Screen parent) { - return YetAnotherConfigLib.create(ExampleConfig.INSTANCE, (defaults, config, builder) -> builder - .title(Component.literal("Test Suites")) - .category(ConfigCategory.createBuilder() - .name(Component.literal("Suites")) - .option(ButtonOption.createBuilder() - .name(Component.literal("Full Test Suite")) - .controller(ActionController::new) - .action((screen, opt) -> Minecraft.getInstance().setScreen(getFullTestSuite(screen))) - .build()) - .group(OptionGroup.createBuilder() - .name(Component.literal("Wiki")) - .option(ButtonOption.createBuilder() - .name(Component.literal("Get Started")) - .controller(ActionController::new) - .action((screen, opt) -> Minecraft.getInstance().setScreen(getWikiGetStarted(screen))) - .build()) - .build()) - .build()) - ) - .generateScreen(parent); - } - - private static Screen getFullTestSuite(Screen parent) { - return YetAnotherConfigLib.create(ExampleConfig.INSTANCE, (defaults, config, builder) -> builder - .title(Component.literal("Test GUI")) - .category(ConfigCategory.createBuilder() - .name(Component.literal("Control Examples")) - .tooltip(Component.literal("Example Category Description")) - .group(OptionGroup.createBuilder() - .name(Component.literal("Boolean Controllers")) - .tooltip(Component.literal("Test!")) - .option(Option.createBuilder(boolean.class) - .name(Component.literal("Boolean Toggle")) - .tooltip(value -> Component.literal("A simple toggle button that contains the value '" + value + "'")) - .binding( - defaults.booleanToggle, - () -> config.booleanToggle, - (value) -> config.booleanToggle = value - ) - .controller(BooleanController::new) - .flag(OptionFlag.GAME_RESTART) - .build()) - .option(Option.createBuilder(boolean.class) - .name(Component.literal("Custom Boolean Toggle")) - .tooltip(Component.literal("You can customize these controllers like this!")) - .tooltip(Component.empty()) - .tooltip(opt -> Component.empty()) - .binding( - defaults.customBooleanToggle, - () -> config.customBooleanToggle, - (value) -> config.customBooleanToggle = value - ) - .controller(opt -> new BooleanController(opt, state -> state ? Component.literal("Amazing") : Component.literal("Not Amazing"), true)) - .build()) - .option(Option.createBuilder(boolean.class) - .name(Component.literal("Tick Box")) - .tooltip(Component.literal("There are even alternate methods of displaying the same data type!")) - .binding( - defaults.tickbox, - () -> config.tickbox, - (value) -> config.tickbox = value - ) - .controller(TickBoxController::new) - .build()) - .build()) - .group(OptionGroup.createBuilder() - .name(Component.literal("Slider Controllers")) - .option(Option.createBuilder(int.class) - .name(Component.literal("Int Slider")) - .instant(true) - .binding( - defaults.intSlider, - () -> config.intSlider, - value -> config.intSlider = value - - ) - .controller(opt -> new IntegerSliderController(opt, 0, 3, 1)) - .build()) - .option(Option.createBuilder(double.class) - .name(Component.literal("Double Slider")) - .binding( - defaults.doubleSlider, - () -> config.doubleSlider, - (value) -> config.doubleSlider = value - ) - .controller(opt -> new DoubleSliderController(opt, 0, 3, 0.05)) - .build()) - .option(Option.createBuilder(float.class) - .name(Component.literal("Float Slider")) - .binding( - defaults.floatSlider, - () -> config.floatSlider, - (value) -> config.floatSlider = value - ) - .controller(opt -> new FloatSliderController(opt, 0, 3, 0.1f)) - .build()) - .option(Option.createBuilder(long.class) - .name(Component.literal("Long Slider")) - .binding( - defaults.longSlider, - () -> config.longSlider, - (value) -> config.longSlider = value - ) - .controller(opt -> new LongSliderController(opt, 0, 1_000_000, 100)) - .build()) - .build()) - .group(OptionGroup.createBuilder() - .name(Component.literal("Input Field Controllers")) - .option(Option.createBuilder(String.class) - .name(Component.literal("Component Option")) - .binding( - defaults.textField, - () -> config.textField, - value -> config.textField = value - ) - .controller(StringController::new) - .build()) - .option(Option.createBuilder(Color.class) - .name(Component.literal("Color Option")) - .binding( - defaults.colorOption, - () -> config.colorOption, - value -> config.colorOption = value - ) - .controller(ColorController::new) - .build()) - .build()) - .group(OptionGroup.createBuilder() - .name(Component.literal("Number Fields")) - .option(Option.createBuilder(double.class) - .name(Component.literal("Double Field")) - .binding( - defaults.doubleField, - () -> config.doubleField, - value -> config.doubleField = value - ) - .controller(DoubleFieldController::new) - .build()) - .option(Option.createBuilder(float.class) - .name(Component.literal("Float Field")) - .binding( - defaults.floatField, - () -> config.floatField, - value -> config.floatField = value - ) - .controller(FloatFieldController::new) - .build()) - .option(Option.createBuilder(int.class) - .name(Component.literal("Integer Field")) - .binding( - defaults.intField, - () -> config.intField, - value -> config.intField = value - ) - .controller(IntegerFieldController::new) - .build()) - .option(Option.createBuilder(long.class) - .name(Component.literal("Long Field")) - .binding( - defaults.longField, - () -> config.longField, - value -> config.longField = value - ) - .controller(LongFieldController::new) - .build()) - .build()) - .group(OptionGroup.createBuilder() - .name(Component.literal("Enum Controllers")) - .option(Option.createBuilder(ExampleConfig.Alphabet.class) - .name(Component.literal("Enum Cycler")) - .binding( - defaults.enumOption, - () -> config.enumOption, - (value) -> config.enumOption = value - ) - .controller(EnumController::new) - .build()) - .build()) - .group(OptionGroup.createBuilder() - .name(Component.literal("Options that aren't really options")) - .option(ButtonOption.createBuilder() - .name(Component.literal("Button \"Option\"")) - .action((screen, opt) -> SystemToast.add(Minecraft.getInstance().getToasts(), SystemToast.SystemToastIds.TUTORIAL_HINT, Component.literal("Button Pressed"), Component.literal("Button option was invoked!"))) - .controller(ActionController::new) - .build()) - .option(LabelOption.create( - Component.empty() - .append(Component.literal("a").withStyle(style -> style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("a"))))) - .append(Component.literal("b").withStyle(style -> style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("b"))))) - .append(Component.literal("c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c").withStyle(style -> style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("c"))))) - .append(Component.literal("e").withStyle(style -> style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("e"))))) - .withStyle(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://isxander.dev")))) - ) - .build()) - .group(OptionGroup.createBuilder() - .name(Component.literal("Minecraft Bindings")) - .tooltip(Component.literal("YACL can also bind Minecraft options!")) - .option(Option.createBuilder(boolean.class) - .name(Component.literal("Minecraft AutoJump")) - .tooltip(Component.literal("You can even bind minecraft options!")) - .binding(Binding.minecraft(Minecraft.getInstance().options.autoJump())) - .controller(TickBoxController::new) - .build()) - .option(Option.createBuilder(GraphicsStatus.class) - .name(Component.literal("Minecraft Graphics Mode")) - .binding(Binding.minecraft(Minecraft.getInstance().options.graphicsMode())) - .controller(EnumController::new) - .build()) - .build()) - .build()) - .category(ConfigCategory.createBuilder() - .name(Component.literal("List Test")) - .group(ListOption.createBuilder(String.class) - .name(Component.literal("String List")) - .binding( - defaults.stringList, - () -> config.stringList, - val -> config.stringList = val - ) - .controller(StringController::new) - .initial("") - .build()) - .group(ListOption.createBuilder(Integer.class) - .name(Component.literal("Slider List")) - .binding( - defaults.intList, - () -> config.intList, - val -> config.intList = val - ) - .controller(opt -> new IntegerSliderController(opt, 0, 10, 1)) - .initial(0) - .available(false) - .build()) - .group(ListOption.createBuilder(Component.class) - .name(Component.literal("Useless Label List")) - .binding(Binding.immutable(List.of(Component.literal("It's quite impressive that literally every single controller works, without problem.")))) - .controller(LabelController::new) - .initial(Component.literal("Initial label")) - .build()) - .build()) - .category(PlaceholderCategory.createBuilder() - .name(Component.literal("Placeholder Category")) - .screen((client, yaclScreen) -> new RequireRestartScreen(yaclScreen)) - .build()) - .category(ConfigCategory.createBuilder() - .name(Component.literal("Group Test")) - .option(Option.createBuilder(boolean.class) - .name(Component.literal("Root Test")) - .binding( - defaults.groupTestRoot, - () -> config.groupTestRoot, - value -> config.groupTestRoot = value - ) - .controller(TickBoxController::new) - .build()) - .group(OptionGroup.createBuilder() - .name(Component.literal("First Group")) - .option(Option.createBuilder(boolean.class) - .name(Component.literal("First Group Test 1")) - .binding( - defaults.groupTestFirstGroup, - () -> config.groupTestFirstGroup, - value -> config.groupTestFirstGroup = value - ) - .controller(TickBoxController::new) - .build()) - .option(Option.createBuilder(boolean.class) - .name(Component.literal("First Group Test 2")) - .binding( - defaults.groupTestFirstGroup2, - () -> config.groupTestFirstGroup2, - value -> config.groupTestFirstGroup2 = value - ) - .controller(TickBoxController::new) - .build()) - .build()) - .group(OptionGroup.createBuilder() - .name(Component.empty()) - .option(Option.createBuilder(boolean.class) - .name(Component.literal("Second Group Test")) - .binding( - defaults.groupTestSecondGroup, - () -> config.groupTestSecondGroup, - value -> config.groupTestSecondGroup = value - ) - .controller(TickBoxController::new) - .build()) - .build()) - .build()) - .category(ConfigCategory.createBuilder() - .name(Component.literal("Scroll Test")) - .option(Option.createBuilder(int.class) - .name(Component.literal("Int Slider that is cut off because the slider")) - .binding( - defaults.scrollingSlider, - () -> config.scrollingSlider, - (value) -> config.scrollingSlider = value - ) - .controller(opt -> new IntegerSliderController(opt, 0, 10, 1)) - .build()) - .option(ButtonOption.createBuilder() - .name(Component.literal("Option")) - .action((screen, opt) -> {}) - .controller(ActionController::new) - .build()) - .option(ButtonOption.createBuilder() - .name(Component.literal("Option")) - .action((screen, opt) -> {}) - .controller(ActionController::new) - .build()) - .option(ButtonOption.createBuilder() - .name(Component.literal("Option")) - .action((screen, opt) -> {}) - .controller(ActionController::new) - .build()) - .option(ButtonOption.createBuilder() - .name(Component.literal("Option")) - .action((screen, opt) -> {}) - .controller(ActionController::new) - .build()) - .option(ButtonOption.createBuilder() - .name(Component.literal("Option")) - .action((screen, opt) -> {}) - .controller(ActionController::new) - .build()) - .option(ButtonOption.createBuilder() - .name(Component.literal("Option")) - .action((screen, opt) -> {}) - .controller(ActionController::new) - .build()) - .option(ButtonOption.createBuilder() - .name(Component.literal("Option")) - .action((screen, opt) -> {}) - .controller(ActionController::new) - .build()) - .option(ButtonOption.createBuilder() - .name(Component.literal("Option")) - .action((screen, opt) -> {}) - .controller(ActionController::new) - .build()) - .option(ButtonOption.createBuilder() - .name(Component.literal("Option")) - .action((screen, opt) -> {}) - .controller(ActionController::new) - .build()) - .option(ButtonOption.createBuilder() - .name(Component.literal("Option")) - .action((screen, opt) -> {}) - .controller(ActionController::new) - .build()) - .option(ButtonOption.createBuilder() - .name(Component.literal("Option")) - .action((screen, opt) -> {}) - .controller(ActionController::new) - .build()) - .option(ButtonOption.createBuilder() - .name(Component.literal("Option")) - .action((screen, opt) -> {}) - .controller(ActionController::new) - .build()) - .option(ButtonOption.createBuilder() - .name(Component.literal("Option")) - .action((screen, opt) -> {}) - .controller(ActionController::new) - .build()) - .build()) - .category(ConfigCategory.createBuilder() - .name(Component.literal("Category Test")) - .build()) - .category(ConfigCategory.createBuilder() - .name(Component.literal("Category Test")) - .build()) - .category(ConfigCategory.createBuilder() - .name(Component.literal("Category Test")) - .build()) - .category(ConfigCategory.createBuilder() - .name(Component.literal("Category Test")) - .build()) - .category(ConfigCategory.createBuilder() - .name(Component.literal("Category Test")) - .build()) - .category(ConfigCategory.createBuilder() - .name(Component.literal("Category Test")) - .build()) - .category(ConfigCategory.createBuilder() - .name(Component.literal("Category Test")) - .build()) - .category(ConfigCategory.createBuilder() - .name(Component.literal("Category Test")) - .build()) - .save(() -> { - Minecraft.getInstance().options.save(); - ExampleConfig.INSTANCE.save(); - }) - ) - .generateScreen(parent); - } - - private static boolean myBooleanOption = true; - - private static Screen getWikiGetStarted(Screen parent) { - return YetAnotherConfigLib.createBuilder() - .title(Component.literal("Used for narration. Could be used to render a title in the future.")) - .category(ConfigCategory.createBuilder() - .name(Component.literal("Name of the category")) - .tooltip(Component.literal("This Component will appear as a tooltip when you hover or focus the button with Tab. There is no need to add \n to wrap as YACL will do it for you.")) - .group(OptionGroup.createBuilder() - .name(Component.literal("Name of the group")) - .tooltip(Component.literal("This Component will appear when you hover over the name or focus on the collapse button with Tab.")) - .option(Option.createBuilder(boolean.class) - .name(Component.literal("Boolean Option")) - .tooltip(Component.literal("This Component will appear as a tooltip when you hover over the option.")) - .binding(true, () -> myBooleanOption, newVal -> myBooleanOption = newVal) - .controller(TickBoxController::new) - .build()) - .build()) - .build()) - .build() - .generateScreen(parent); - } -} diff --git a/src/testmod/java/dev/isxander/yacl/test/mixins/TitleScreenMixin.java b/src/testmod/java/dev/isxander/yacl/test/mixins/TitleScreenMixin.java deleted file mode 100644 index eac9ff4..0000000 --- a/src/testmod/java/dev/isxander/yacl/test/mixins/TitleScreenMixin.java +++ /dev/null @@ -1,30 +0,0 @@ -package dev.isxander.yacl.test.mixins; - -import dev.isxander.yacl.test.config.GuiTest; -import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.gui.screens.TitleScreen; -import net.minecraft.network.chat.Component; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -/** - * For testing purposes! If you are using this as - * an example, ignore this class! - */ -@Mixin(TitleScreen.class) -public abstract class TitleScreenMixin extends Screen { - protected TitleScreenMixin(Component title) { - super(title); - } - - @Inject(method = "init", at = @At("RETURN")) - private void injectTestButton(CallbackInfo ci) { - addRenderableWidget(Button.builder(Component.literal("YACL"), button -> minecraft.setScreen(GuiTest.getModConfigScreenFactory(minecraft.screen))) - .pos(0, 0) - .width(50) - .build()); - } -} diff --git a/src/testmod/resources/fabric.mod.json b/src/testmod/resources/fabric.mod.json deleted file mode 100644 index d682084..0000000 --- a/src/testmod/resources/fabric.mod.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "schemaVersion": 1, - "id": "test-mod", - "version": "1", - "name": "YACL Test", - "authors": [ - "isXander" - ], - "license": "LGPL-3.0-or-later", - "environment": "client", - "entrypoints": { - "client": [ - "dev.isxander.yacl.test.ExampleMod" - ] - }, - "depends": { - "yet-another-config-lib": "*" - }, - "mixins": [ - "yet-another-config-lib.test.mixins.json" - ] -} diff --git a/src/testmod/resources/yet-another-config-lib.test.mixins.json b/src/testmod/resources/yet-another-config-lib.test.mixins.json deleted file mode 100644 index 9287cdd..0000000 --- a/src/testmod/resources/yet-another-config-lib.test.mixins.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "required": true, - "package": "dev.isxander.yacl.test.mixins", - "compatibilityLevel": "JAVA_17", - "injectors": { - "defaultRequire": 1 - }, - "client": [ - "TitleScreenMixin" - ] -} |