aboutsummaryrefslogtreecommitdiff
path: root/common/src/main/java/dev/isxander/yacl3/impl
diff options
context:
space:
mode:
authorisXander <xandersmith2008@gmail.com>2023-06-03 23:10:03 +0100
committerisXander <xandersmith2008@gmail.com>2023-06-04 16:25:09 +0100
commit3e36feeef60e56ef8cb7f737ac8eeab9fbcd6abb (patch)
treef9c3395b4da2235681b87a35ac5056a0724a181b /common/src/main/java/dev/isxander/yacl3/impl
parentd00a486d3bdf6105f8ca8af1034c384058b8c832 (diff)
downloadYetAnotherConfigLib-3e36feeef60e56ef8cb7f737ac8eeab9fbcd6abb.tar.gz
YetAnotherConfigLib-3e36feeef60e56ef8cb7f737ac8eeab9fbcd6abb.tar.bz2
YetAnotherConfigLib-3e36feeef60e56ef8cb7f737ac8eeab9fbcd6abb.zip
Change package and modid to yacl3 and yet_another_config_lib_3 respectively
Diffstat (limited to 'common/src/main/java/dev/isxander/yacl3/impl')
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/ButtonOptionImpl.java195
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/ConfigCategoryImpl.java135
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/GenericBindingImpl.java35
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/LabelOptionImpl.java158
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/ListOptionEntryImpl.java154
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/ListOptionImpl.java325
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/OptionDescriptionImpl.java146
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/OptionGroupImpl.java121
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/OptionImpl.java257
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/PlaceholderCategoryImpl.java99
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/YetAnotherConfigLibImpl.java122
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/AbstractControllerBuilderImpl.java12
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/BooleanControllerBuilderImpl.java56
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/ColorControllerBuilderImpl.java27
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/CyclingListControllerBuilderImpl.java43
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/DoubleFieldControllerBuilderImpl.java50
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/DoubleSliderControllerBuilderImpl.java43
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/EnumControllerBuilderImpl.java35
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/FloatFieldControllerBuilderImpl.java50
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/FloatSliderControllerBuilderImpl.java43
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/IntegerFieldControllerBuilderImpl.java50
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/IntegerSliderControllerBuilderImpl.java43
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/LongFieldControllerBuilderImpl.java50
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/LongSliderControllerBuilderImpl.java43
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/StringControllerBuilderImpl.java17
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/controller/TickBoxControllerBuilderImpl.java17
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/utils/DimensionIntegerImpl.java115
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/utils/YACLConstants.java13
28 files changed, 2454 insertions, 0 deletions
diff --git a/common/src/main/java/dev/isxander/yacl3/impl/ButtonOptionImpl.java b/common/src/main/java/dev/isxander/yacl3/impl/ButtonOptionImpl.java
new file mode 100644
index 0000000..99a6e83
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/impl/ButtonOptionImpl.java
@@ -0,0 +1,195 @@
+package dev.isxander.yacl3.impl;
+
+import com.google.common.collect.ImmutableSet;
+import dev.isxander.yacl3.api.*;
+import dev.isxander.yacl3.gui.YACLScreen;
+import dev.isxander.yacl3.gui.controllers.ActionController;
+import net.minecraft.network.chat.Component;
+import org.apache.commons.lang3.Validate;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+@ApiStatus.Internal
+public final class ButtonOptionImpl implements ButtonOption {
+ private final Component name;
+ private final OptionDescription description;
+ 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 OptionDescription description,
+ @NotNull BiConsumer<YACLScreen, ButtonOption> action,
+ boolean available
+ ) {
+ this.name = name;
+ this.description = description;
+ this.action = action;
+ this.available = available;
+ this.controller = new ActionController(this);
+ this.binding = new EmptyBinderImpl();
+ }
+
+ @Override
+ public @NotNull Component name() {
+ return name;
+ }
+
+ @Override
+ public @NotNull OptionDescription description() {
+ return description;
+ }
+
+ @Override
+ public @NotNull Component tooltip() {
+ return description().text();
+ }
+
+ @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 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 Builder {
+ private Component name;
+ private OptionDescription description = OptionDescription.EMPTY;
+ private boolean available = true;
+ private BiConsumer<YACLScreen, ButtonOption> action;
+
+ @Override
+ public Builder name(@NotNull Component name) {
+ Validate.notNull(name, "`name` cannot be null");
+
+ this.name = name;
+ return this;
+ }
+
+ @Override
+ public Builder description(@NotNull OptionDescription description) {
+ Validate.notNull(description, "`description` cannot be null");
+
+ this.description = description;
+ return this;
+ }
+
+ @Override
+ public Builder action(@NotNull BiConsumer<YACLScreen, ButtonOption> action) {
+ Validate.notNull(action, "`action` cannot be null");
+
+ this.action = action;
+ return this;
+ }
+
+ @Override
+ @Deprecated
+ public Builder action(@NotNull Consumer<YACLScreen> action) {
+ Validate.notNull(action, "`action` cannot be null");
+
+ this.action = (screen, button) -> action.accept(screen);
+ return this;
+ }
+
+ @Override
+ public Builder available(boolean available) {
+ this.available = available;
+ return this;
+ }
+
+ @Override
+ public ButtonOption build() {
+ Validate.notNull(name, "`name` must not be null when building `ButtonOption`");
+ Validate.notNull(action, "`action` must not be null when building `ButtonOption`");
+
+ return new ButtonOptionImpl(name, description, action, available);
+ }
+ }
+}
diff --git a/common/src/main/java/dev/isxander/yacl3/impl/ConfigCategoryImpl.java b/common/src/main/java/dev/isxander/yacl3/impl/ConfigCategoryImpl.java
new file mode 100644
index 0000000..195f6d7
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/impl/ConfigCategoryImpl.java
@@ -0,0 +1,135 @@
+package dev.isxander.yacl3.impl;
+
+import com.google.common.collect.ImmutableList;
+import dev.isxander.yacl3.api.*;
+import dev.isxander.yacl3.impl.utils.YACLConstants;
+import net.minecraft.network.chat.CommonComponents;
+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(CommonComponents.EMPTY, OptionDescription.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/common/src/main/java/dev/isxander/yacl3/impl/GenericBindingImpl.java b/common/src/main/java/dev/isxander/yacl3/impl/GenericBindingImpl.java
new file mode 100644
index 0000000..972c891
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/impl/GenericBindingImpl.java
@@ -0,0 +1,35 @@
+package dev.isxander.yacl3.impl;
+
+import dev.isxander.yacl3.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/common/src/main/java/dev/isxander/yacl3/impl/LabelOptionImpl.java b/common/src/main/java/dev/isxander/yacl3/impl/LabelOptionImpl.java
new file mode 100644
index 0000000..c8287bd
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/impl/LabelOptionImpl.java
@@ -0,0 +1,158 @@
+package dev.isxander.yacl3.impl;
+
+import com.google.common.collect.ImmutableSet;
+import dev.isxander.yacl3.api.*;
+import dev.isxander.yacl3.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 OptionDescription description;
+ 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);
+ this.description = OptionDescription.createBuilder()
+ .text(this.label)
+ .build();
+ }
+
+ @Override
+ public @NotNull Component label() {
+ return label;
+ }
+
+ @Override
+ public @NotNull Component name() {
+ return name;
+ }
+
+ @Override
+ public @NotNull OptionDescription description() {
+ return description;
+ }
+
+ @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 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 Builder {
+ private final List<Component> lines = new ArrayList<>();
+
+ @Override
+ public Builder line(@NotNull Component line) {
+ Validate.notNull(line, "`line` must not be null");
+
+ this.lines.add(line);
+ return this;
+ }
+
+ @Override
+ public 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/common/src/main/java/dev/isxander/yacl3/impl/ListOptionEntryImpl.java b/common/src/main/java/dev/isxander/yacl3/impl/ListOptionEntryImpl.java
new file mode 100644
index 0000000..0c74976
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/impl/ListOptionEntryImpl.java
@@ -0,0 +1,154 @@
+package dev.isxander.yacl3.impl;
+
+import dev.isxander.yacl3.api.*;
+import dev.isxander.yacl3.api.utils.Dimension;
+import dev.isxander.yacl3.gui.AbstractWidget;
+import dev.isxander.yacl3.gui.YACLScreen;
+import dev.isxander.yacl3.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 OptionDescription description() {
+ return group.description();
+ }
+
+ @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/common/src/main/java/dev/isxander/yacl3/impl/ListOptionImpl.java b/common/src/main/java/dev/isxander/yacl3/impl/ListOptionImpl.java
new file mode 100644
index 0000000..82f5576
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/impl/ListOptionImpl.java
@@ -0,0 +1,325 @@
+package dev.isxander.yacl3.impl;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import dev.isxander.yacl3.api.*;
+import dev.isxander.yacl3.api.controller.ControllerBuilder;
+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.*;
+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 OptionDescription description;
+ 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 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 OptionDescription description, @NotNull Binding<List<T>> binding, @NotNull T initialValue, @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.description = description;
+ this.binding = binding;
+ this.initialValue = initialValue;
+ this.entryFactory = new EntryFactory(controllerFunction);
+ this.entries = createEntries(binding().getValue());
+ this.collapsed = collapsed;
+ 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 OptionDescription description() {
+ return this.description;
+ }
+
+ @Override
+ public @NotNull Component tooltip() {
+ return description().text();
+ }
+
+ @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 boolean collapsed() {
+ return collapsed;
+ }
+
+ @Override