diff options
author | isXander <xandersmith2008@gmail.com> | 2023-05-21 12:41:45 +0100 |
---|---|---|
committer | isXander <xandersmith2008@gmail.com> | 2023-05-21 12:41:45 +0100 |
commit | 21afea0da3956f2d8cca81a54fa9820152e0c077 (patch) | |
tree | e5944f94a5f85d3fcbe048da633e62f5357fe835 /common/src/main/java/dev/isxander/yacl/impl | |
parent | e51af159ba3eba5ebda976bea1c1957cddeee7c6 (diff) | |
download | YetAnotherConfigLib-21afea0da3956f2d8cca81a54fa9820152e0c077.tar.gz YetAnotherConfigLib-21afea0da3956f2d8cca81a54fa9820152e0c077.tar.bz2 YetAnotherConfigLib-21afea0da3956f2d8cca81a54fa9820152e0c077.zip |
Start overhauling UI
Diffstat (limited to 'common/src/main/java/dev/isxander/yacl/impl')
6 files changed, 188 insertions, 23 deletions
diff --git a/common/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java b/common/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java index 11da99e..f0e0bdd 100644 --- a/common/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java +++ b/common/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java @@ -19,7 +19,7 @@ import java.util.function.Function; @ApiStatus.Internal public final class ButtonOptionImpl implements ButtonOption { private final Component name; - private final Component tooltip; + private final OptionDescription description; private final BiConsumer<YACLScreen, ButtonOption> action; private boolean available; private final Controller<BiConsumer<YACLScreen, ButtonOption>> controller; @@ -27,13 +27,13 @@ public final class ButtonOptionImpl implements ButtonOption { public ButtonOptionImpl( @NotNull Component name, - @Nullable Component tooltip, + @Nullable OptionDescription description, @NotNull BiConsumer<YACLScreen, ButtonOption> action, boolean available, @NotNull Function<ButtonOption, Controller<BiConsumer<YACLScreen, ButtonOption>>> controlGetter ) { this.name = name; - this.tooltip = tooltip; + this.description = description; this.action = action; this.available = available; this.controller = controlGetter.apply(this); @@ -46,8 +46,13 @@ public final class ButtonOptionImpl implements ButtonOption { } @Override + public @NotNull OptionDescription description() { + return description; + } + + @Override public @NotNull Component tooltip() { - return tooltip; + return description().description(); } @Override @@ -162,7 +167,7 @@ public final class ButtonOptionImpl implements ButtonOption { public Builder tooltip(@NotNull Component... tooltips) { Validate.notNull(tooltips, "`tooltips` cannot be empty"); - tooltipLines.addAll(List.of(tooltips)); + //tooltipLines.addAll(List.of(tooltips)); return this; } @@ -212,7 +217,7 @@ public final class ButtonOptionImpl implements ButtonOption { concatenatedTooltip.append(line); } - return new ButtonOptionImpl(name, concatenatedTooltip, action, available, controlGetter); + return new ButtonOptionImpl(name, OptionDescription.createBuilder().name(name).description(concatenatedTooltip).build(), action, available, controlGetter); } } } diff --git a/common/src/main/java/dev/isxander/yacl/impl/LabelOptionImpl.java b/common/src/main/java/dev/isxander/yacl/impl/LabelOptionImpl.java index 732a373..2a7759c 100644 --- a/common/src/main/java/dev/isxander/yacl/impl/LabelOptionImpl.java +++ b/common/src/main/java/dev/isxander/yacl/impl/LabelOptionImpl.java @@ -19,6 +19,7 @@ import java.util.function.BiConsumer; 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; @@ -27,6 +28,10 @@ public final class LabelOptionImpl implements LabelOption { this.label = label; this.labelController = new LabelController(this); this.binding = Binding.immutable(label); + this.description = OptionDescription.createBuilder() + .name(this.name) + .description(this.label) + .build(); } @Override @@ -40,6 +45,11 @@ public final class LabelOptionImpl implements LabelOption { } @Override + public @NotNull OptionDescription description() { + return description; + } + + @Override public @NotNull Component tooltip() { return tooltip; } diff --git a/common/src/main/java/dev/isxander/yacl/impl/ListOptionEntryImpl.java b/common/src/main/java/dev/isxander/yacl/impl/ListOptionEntryImpl.java index c15efe6..d02259e 100644 --- a/common/src/main/java/dev/isxander/yacl/impl/ListOptionEntryImpl.java +++ b/common/src/main/java/dev/isxander/yacl/impl/ListOptionEntryImpl.java @@ -34,6 +34,11 @@ public final class ListOptionEntryImpl<T> implements ListOptionEntry<T> { } @Override + public @NotNull OptionDescription description() { + return group.description(); + } + + @Override public @NotNull Component tooltip() { return Component.empty(); } diff --git a/common/src/main/java/dev/isxander/yacl/impl/ListOptionImpl.java b/common/src/main/java/dev/isxander/yacl/impl/ListOptionImpl.java index f47493c..24fe2b1 100644 --- a/common/src/main/java/dev/isxander/yacl/impl/ListOptionImpl.java +++ b/common/src/main/java/dev/isxander/yacl/impl/ListOptionImpl.java @@ -19,7 +19,7 @@ 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 OptionDescription description; private final Binding<List<T>> binding; private final T initialValue; private final List<ListOptionEntry<T>> entries; @@ -31,9 +31,9 @@ public final class ListOptionImpl<T> implements ListOption<T> { 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) { + public ListOptionImpl(@NotNull Component name, @NotNull OptionDescription description, @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.description = description; this.binding = binding; this.initialValue = initialValue; this.entryFactory = new EntryFactory(controllerFunction); @@ -54,8 +54,13 @@ public final class ListOptionImpl<T> implements ListOption<T> { } @Override + public @NotNull OptionDescription description() { + return this.description; + } + + @Override public @NotNull Component tooltip() { - return this.tooltip; + return description().description(); } @Override @@ -332,7 +337,7 @@ public final class ListOptionImpl<T> implements ListOption<T> { concatenatedTooltip.append(line); } - return new ListOptionImpl<>(name, concatenatedTooltip, binding, initialValue, typeClass, controllerFunction, ImmutableSet.copyOf(flags), collapsed, available, listeners); + return new ListOptionImpl<>(name, OptionDescription.createBuilder().name(name).description(concatenatedTooltip).build(), binding, initialValue, typeClass, controllerFunction, ImmutableSet.copyOf(flags), collapsed, available, listeners); } } } diff --git a/common/src/main/java/dev/isxander/yacl/impl/OptionDescriptionImpl.java b/common/src/main/java/dev/isxander/yacl/impl/OptionDescriptionImpl.java new file mode 100644 index 0000000..f57a410 --- /dev/null +++ b/common/src/main/java/dev/isxander/yacl/impl/OptionDescriptionImpl.java @@ -0,0 +1,124 @@ +package dev.isxander.yacl.impl; + +import dev.isxander.yacl.api.OptionDescription; +import dev.isxander.yacl.gui.ImageRenderer; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import org.apache.commons.lang3.Validate; + +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +public record OptionDescriptionImpl(Component descriptiveName, Component description, CompletableFuture<Optional<ImageRenderer>> image) implements OptionDescription { + public static class BuilderImpl implements Builder { + private Component name; + private Component description; + private CompletableFuture<Optional<ImageRenderer>> image = CompletableFuture.completedFuture(Optional.empty()); + private boolean imageUnset = true; + + @Override + public Builder name(Component name) { + this.name = name; + return this; + } + + @Override + public Builder description(Component description) { + this.description = description; + return this; + } + + @Override + public Builder image(ResourceLocation image, int width, int height) { + Validate.isTrue(imageUnset, "Image already set!"); + Validate.isTrue(width > 0, "Width must be greater than 0!"); + Validate.isTrue(height > 0, "Height must be greater than 0!"); + + this.image = CompletableFuture.completedFuture(Optional.of(new ImageRenderer.TextureBacked(image, width, height))); + imageUnset = false; + return this; + } + + @Override + public Builder image(Path path, ResourceLocation uniqueLocation) { + Validate.isTrue(imageUnset, "Image already set!"); + this.image = CompletableFuture.supplyAsync(() -> ImageRenderer.NativeImageBacked.createFromPath(path, uniqueLocation)); + imageUnset = false; + return this; + } + + @Override + public Builder gifImage(ResourceLocation image) { + Validate.isTrue(imageUnset, "Image already set!"); + this.image = CompletableFuture.supplyAsync(() -> { + try { + return Optional.of(ImageRenderer.AnimatedNativeImageBacked.createGIFFromTexture(image)); + } catch (IOException e) { + e.printStackTrace(); + return Optional.empty(); + } + }); + imageUnset = false; + return this; + } + + @Override + public Builder gifImage(Path path, ResourceLocation uniqueLocation) { + Validate.isTrue(imageUnset, "Image already set!"); + this.image = CompletableFuture.supplyAsync(() -> { + try { + return Optional.of(ImageRenderer.AnimatedNativeImageBacked.createGIF(new FileInputStream(path.toFile()), uniqueLocation)); + } catch (IOException e) { + e.printStackTrace(); + return Optional.empty(); + } + }); + imageUnset = false; + return this; + } + + @Override + public Builder webpImage(ResourceLocation image, int frameDelayMS) { + Validate.isTrue(imageUnset, "Image already set!"); + this.image = CompletableFuture.supplyAsync(() -> { + try { + return Optional.of(ImageRenderer.AnimatedNativeImageBacked.createWEBPFromTexture(image, frameDelayMS)); + } catch (IOException e) { + e.printStackTrace(); + return Optional.empty(); + } + }); + imageUnset = false; + return this; + } + + @Override + public Builder webpImage(Path path, ResourceLocation uniqueLocation, int frameDelayMS) { + Validate.isTrue(imageUnset, "Image already set!"); + this.image = CompletableFuture.supplyAsync(() -> { + try { + return Optional.of(ImageRenderer.AnimatedNativeImageBacked.createWEBP(new FileInputStream(path.toFile()), uniqueLocation, frameDelayMS)); + } catch (IOException e) { + e.printStackTrace(); + return Optional.empty(); + } + }); + imageUnset = false; + return this; + } + + @Override + public OptionDescription build() { + Validate.notNull(name, "Name must be set!"); + + if (description == null) + description = Component.empty(); + + return new OptionDescriptionImpl(name.copy().withStyle(ChatFormatting.BOLD), description, image); + } + } +} diff --git a/common/src/main/java/dev/isxander/yacl/impl/OptionImpl.java b/common/src/main/java/dev/isxander/yacl/impl/OptionImpl.java index 4b65d56..ef4d13b 100644 --- a/common/src/main/java/dev/isxander/yacl/impl/OptionImpl.java +++ b/common/src/main/java/dev/isxander/yacl/impl/OptionImpl.java @@ -1,11 +1,9 @@ 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 dev.isxander.yacl.api.*; import net.minecraft.ChatFormatting; +import net.minecraft.Util; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.ComponentContents; import net.minecraft.network.chat.MutableComponent; @@ -23,7 +21,7 @@ import java.util.function.Supplier; @ApiStatus.Internal public final class OptionImpl<T> implements Option<T> { private final Component name; - private Component tooltip; + private OptionDescription description; private final Controller<T> controller; private final Binding<T> binding; private boolean available; @@ -38,7 +36,7 @@ public final class OptionImpl<T> implements Option<T> { public OptionImpl( @NotNull Component name, - @Nullable Function<T, Component> tooltipGetter, + @NotNull Function<T, OptionDescription> descriptionFunction, @NotNull Function<Option<T>, Controller<T>> controlGetter, @NotNull Binding<T> binding, boolean available, @@ -54,7 +52,9 @@ public final class OptionImpl<T> implements Option<T> { this.listeners = new ArrayList<>(listeners); this.controller = controlGetter.apply(this); - addListener((opt, pending) -> tooltip = tooltipGetter.apply(pending)); + var memoizedDescriptionFunction = Util.memoize(descriptionFunction); + addListener((opt, pending) -> description = memoizedDescriptionFunction.apply(pending)); + requestSet(binding().getValue()); } @@ -64,8 +64,13 @@ public final class OptionImpl<T> implements Option<T> { } @Override + public @NotNull OptionDescription description() { + return this.description; + } + + @Override public @NotNull Component tooltip() { - return tooltip; + return description.description(); } @Override @@ -147,6 +152,7 @@ public final class OptionImpl<T> implements Option<T> { public static class BuilderImpl<T> implements Builder<T> { private Component name = Component.literal("Name not specified!").withStyle(ChatFormatting.RED); + private Function<T, OptionDescription> descriptionFunction = null; private final List<Function<T, Component>> tooltipGetters = new ArrayList<>(); private Function<Option<T>, Controller<T>> controlGetter; @@ -176,6 +182,17 @@ public final class OptionImpl<T> implements Option<T> { } @Override + public Builder<T> description(@NotNull OptionDescription description) { + return description(opt -> description); + } + + @Override + public Builder<T> description(@NotNull Function<T, OptionDescription> descriptionFunction) { + this.descriptionFunction = descriptionFunction; + return this; + } + + @Override public Builder<T> tooltip(@NotNull Function<T, Component> tooltipGetter) { Validate.notNull(tooltipGetter, "`tooltipGetter` cannot be null"); @@ -292,12 +309,11 @@ public final class OptionImpl<T> implements Option<T> { return concatenatedTooltip; }; - - if (instant) { - listeners.add((opt, pendingValue) -> opt.applyValue()); + if (descriptionFunction == null) { + descriptionFunction = opt -> OptionDescription.createBuilder().name(name).description(concatenatedTooltipGetter.apply(opt)).build(); } - return new OptionImpl<>(name, concatenatedTooltipGetter, controlGetter, binding, available, ImmutableSet.copyOf(flags), typeClass, listeners); + return new OptionImpl<>(name, descriptionFunction, controlGetter, binding, available, ImmutableSet.copyOf(flags), typeClass, listeners); } } } |