diff options
Diffstat (limited to 'src/client/java/dev/isxander/yacl/impl')
6 files changed, 397 insertions, 12 deletions
diff --git a/src/client/java/dev/isxander/yacl/impl/ButtonOptionImpl.java b/src/client/java/dev/isxander/yacl/impl/ButtonOptionImpl.java index dcb9c7a..f526d42 100644 --- a/src/client/java/dev/isxander/yacl/impl/ButtonOptionImpl.java +++ b/src/client/java/dev/isxander/yacl/impl/ButtonOptionImpl.java @@ -79,11 +79,6 @@ public class ButtonOptionImpl implements ButtonOption { } @Override - public boolean requiresRestart() { - return false; - } - - @Override public boolean changed() { return false; } diff --git a/src/client/java/dev/isxander/yacl/impl/ListOptionEntryImpl.java b/src/client/java/dev/isxander/yacl/impl/ListOptionEntryImpl.java new file mode 100644 index 0000000..dc7aa88 --- /dev/null +++ b/src/client/java/dev/isxander/yacl/impl/ListOptionEntryImpl.java @@ -0,0 +1,122 @@ +package dev.isxander.yacl.impl; + +import dev.isxander.yacl.api.*; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +public class ListOptionEntryImpl<T> implements ListOptionEntry<T> { + private final ListOptionImpl<T> group; + + private T value; + + private final Binding<T> binding; + private final Controller<T> controller; + + public 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 = controlGetter.apply(this); + } + + @Override + public @NotNull Text name() { + return Text.empty(); + } + + @Override + public @NotNull Text tooltip() { + return Text.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) { + + } + + 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 new file mode 100644 index 0000000..128d3e7 --- /dev/null +++ b/src/client/java/dev/isxander/yacl/impl/ListOptionImpl.java @@ -0,0 +1,208 @@ +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.text.Text; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class ListOptionImpl<T> implements ListOption<T> { + private final Text name; + private final Text 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 Text name, @NotNull Text 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) { + 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.refreshListeners = new ArrayList<>(); + callListeners(); + } + + @Override + public @NotNull Text name() { + return this.name; + } + + @Override + public @NotNull Text 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 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) { + 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(); + listeners.forEach(listener -> listener.accept(this, value)); + } + + @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); + } + } +} diff --git a/src/client/java/dev/isxander/yacl/impl/OptionGroupImpl.java b/src/client/java/dev/isxander/yacl/impl/OptionGroupImpl.java index 58bc96b..02ef04c 100644 --- a/src/client/java/dev/isxander/yacl/impl/OptionGroupImpl.java +++ b/src/client/java/dev/isxander/yacl/impl/OptionGroupImpl.java @@ -6,5 +6,5 @@ import dev.isxander.yacl.api.OptionGroup; import net.minecraft.text.Text; import org.jetbrains.annotations.NotNull; -public record OptionGroupImpl(@NotNull Text name, @NotNull Text tooltip, ImmutableList<Option<?>> options, boolean collapsed, boolean isRoot) implements OptionGroup { +public record OptionGroupImpl(@NotNull Text name, @NotNull Text tooltip, ImmutableList<? extends Option<?>> options, boolean collapsed, boolean isRoot) implements OptionGroup { } diff --git a/src/client/java/dev/isxander/yacl/impl/OptionImpl.java b/src/client/java/dev/isxander/yacl/impl/OptionImpl.java index 90158c7..0cc156f 100644 --- a/src/client/java/dev/isxander/yacl/impl/OptionImpl.java +++ b/src/client/java/dev/isxander/yacl/impl/OptionImpl.java @@ -93,11 +93,6 @@ public class OptionImpl<T> implements Option<T> { } @Override - public boolean requiresRestart() { - return flags.contains(OptionFlag.GAME_RESTART); - } - - @Override public boolean changed() { return !binding().getValue().equals(pendingValue); } diff --git a/src/client/java/dev/isxander/yacl/impl/YetAnotherConfigLibImpl.java b/src/client/java/dev/isxander/yacl/impl/YetAnotherConfigLibImpl.java index eb23eac..380929c 100644 --- a/src/client/java/dev/isxander/yacl/impl/YetAnotherConfigLibImpl.java +++ b/src/client/java/dev/isxander/yacl/impl/YetAnotherConfigLibImpl.java @@ -8,12 +8,77 @@ import dev.isxander.yacl.impl.utils.YACLConstants; import net.minecraft.client.gui.screen.Screen; import net.minecraft.text.Text; +import java.util.Objects; import java.util.function.Consumer; -public record YetAnotherConfigLibImpl(Text title, ImmutableList<ConfigCategory> categories, Runnable saveFunction, Consumer<YACLScreen> initConsumer) implements YetAnotherConfigLib { +public final class YetAnotherConfigLibImpl implements YetAnotherConfigLib { + private final Text title; + private final ImmutableList<ConfigCategory> categories; + private final Runnable saveFunction; + private final Consumer<YACLScreen> initConsumer; + + private boolean generated = false; + + public YetAnotherConfigLibImpl(Text 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 Text title() { + return title; + } + + @Override + public ImmutableList<ConfigCategory> categories() { + return categories; + } + + @Override + public Runnable saveFunction() { + return saveFunction; + } + + @Override + public Consumer<YACLScreen> initConsumer() { + return initConsumer; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (YetAnotherConfigLibImpl) obj; + return Objects.equals(this.title, that.title) && + Objects.equals(this.categories, that.categories) && + Objects.equals(this.saveFunction, that.saveFunction) && + Objects.equals(this.initConsumer, that.initConsumer); + } + + @Override + public int hashCode() { + return Objects.hash(title, categories, saveFunction, initConsumer); + } + + @Override + public String toString() { + return "YetAnotherConfigLibImpl[" + + "title=" + title + ", " + + "categories=" + categories + ", " + + "saveFunction=" + saveFunction + ", " + + "initConsumer=" + initConsumer + ']'; + } + } |