diff options
20 files changed, 72 insertions, 71 deletions
diff --git a/changelogs/1.4.2.md b/changelogs/1.4.2.md index c87d133..691610b 100644 --- a/changelogs/1.4.2.md +++ b/changelogs/1.4.2.md @@ -1 +1,3 @@ +- Improve search performance (even when empty) by a LOT +- API to add listeners before building - Fix cancel/reset button tooltip going off-screen diff --git a/src/main/java/dev/isxander/yacl/api/Controller.java b/src/main/java/dev/isxander/yacl/api/Controller.java index 1a00920..7fbc466 100644 --- a/src/main/java/dev/isxander/yacl/api/Controller.java +++ b/src/main/java/dev/isxander/yacl/api/Controller.java @@ -25,6 +25,5 @@ public interface Controller<T> { * * @param screen parent screen */ - @ApiStatus.Internal AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension); } diff --git a/src/main/java/dev/isxander/yacl/api/Option.java b/src/main/java/dev/isxander/yacl/api/Option.java index fe11778..8ec7338 100644 --- a/src/main/java/dev/isxander/yacl/api/Option.java +++ b/src/main/java/dev/isxander/yacl/api/Option.java @@ -136,6 +136,8 @@ public interface Option<T> { private final Class<T> typeClass; + private final List<BiConsumer<Option<T>, T>> listeners = new ArrayList<>(); + private Builder(Class<T> typeClass) { this.typeClass = typeClass; } @@ -270,6 +272,26 @@ public interface Option<T> { } /** + * Adds a listener to the option. Invoked upon changing the pending value. + * + * @see Option#addListener(BiConsumer) + */ + public Builder<T> listener(@NotNull BiConsumer<Option<T>, T> listener) { + this.listeners.add(listener); + return this; + } + + /** + * Adds multiple listeners to the option. Invoked upon changing the pending value. + * + * @see Option#addListener(BiConsumer) + */ + public Builder<T> listeners(@NotNull Collection<BiConsumer<Option<T>, T>> listeners) { + this.listeners.addAll(listeners); + return this; + } + + /** * Dictates whether the option should require a restart. * {@link Option#requiresRestart()} */ @@ -299,11 +321,11 @@ public interface Option<T> { return concatenatedTooltip; }; - OptionImpl<T> option = new OptionImpl<>(name, concatenatedTooltipGetter, controlGetter, binding, available, ImmutableSet.copyOf(flags), typeClass); if (instant) { - option.addListener((opt, pendingValue) -> opt.applyValue()); + listeners.add((opt, pendingValue) -> opt.applyValue()); } - return option; + + return new OptionImpl<>(name, concatenatedTooltipGetter, controlGetter, binding, available, ImmutableSet.copyOf(flags), typeClass, listeners); } } } diff --git a/src/main/java/dev/isxander/yacl/api/OptionGroup.java b/src/main/java/dev/isxander/yacl/api/OptionGroup.java index f8c346b..3364bdf 100644 --- a/src/main/java/dev/isxander/yacl/api/OptionGroup.java +++ b/src/main/java/dev/isxander/yacl/api/OptionGroup.java @@ -106,7 +106,7 @@ public interface OptionGroup { * * @see OptionGroup#options() */ - public Builder options(@NotNull Collection<Option<?>> options) { + public Builder options(@NotNull Collection<? extends Option<?>> options) { Validate.notEmpty(options, "`options` must not be empty"); this.options.addAll(options); diff --git a/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java b/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java index 729e063..7789520 100644 --- a/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java +++ b/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java @@ -233,11 +233,16 @@ public class OptionListWidget extends ElementListWidget<OptionListWidget.Entry> public final AbstractWidget widget; private final Supplier<Boolean> viewableSupplier; + private final String categoryName; + private final String groupName; + private OptionEntry(ConfigCategory category, OptionGroup group, AbstractWidget widget, Supplier<Boolean> viewableSupplier) { this.category = category; this.group = group; this.widget = widget; this.viewableSupplier = viewableSupplier; + this.categoryName = category.name().getString().toLowerCase(); + this.groupName = group.name().getString().toLowerCase(); } @Override @@ -269,7 +274,12 @@ public class OptionListWidget extends ElementListWidget<OptionListWidget.Entry> @Override public boolean isViewable() { - return viewableSupplier.get() && yaclScreen.searchFieldWidget.matches(this, singleCategory); + String query = yaclScreen.searchFieldWidget.getText(); + return viewableSupplier.get() + && (yaclScreen.searchFieldWidget.isEmpty() + || (!singleCategory && categoryName.contains(query)) + || groupName.contains(query) + || widget.matchesSearch(query)); } @Override @@ -353,7 +363,7 @@ public class OptionListWidget extends ElementListWidget<OptionListWidget.Entry> @Override public boolean isViewable() { - return yaclScreen.searchFieldWidget.getText().isEmpty() || optionEntries.stream().anyMatch(OptionEntry::isViewable); + return yaclScreen.searchFieldWidget.isEmpty() || optionEntries.stream().anyMatch(OptionEntry::isViewable); } @Override diff --git a/src/main/java/dev/isxander/yacl/gui/SearchFieldWidget.java b/src/main/java/dev/isxander/yacl/gui/SearchFieldWidget.java index 2405dbd..1f0f49b 100644 --- a/src/main/java/dev/isxander/yacl/gui/SearchFieldWidget.java +++ b/src/main/java/dev/isxander/yacl/gui/SearchFieldWidget.java @@ -1,7 +1,5 @@ package dev.isxander.yacl.gui; -import dev.isxander.yacl.api.ConfigCategory; -import dev.isxander.yacl.api.OptionGroup; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.client.util.math.MatrixStack; @@ -12,8 +10,11 @@ public class SearchFieldWidget extends TextFieldWidget { private final YACLScreen yaclScreen; private final TextRenderer textRenderer; + private boolean isEmpty = true; + public SearchFieldWidget(YACLScreen yaclScreen, TextRenderer textRenderer, int x, int y, int width, int height, Text text, Text emptyText) { super(textRenderer, x, y, width, height, text); + setTextPredicate(string -> !string.endsWith(" ") && !string.startsWith(" ")); this.yaclScreen = yaclScreen; this.textRenderer = textRenderer; this.emptyText = emptyText; @@ -22,48 +23,41 @@ public class SearchFieldWidget extends TextFieldWidget { @Override public void renderButton(MatrixStack matrices, int mouseX, int mouseY, float delta) { super.renderButton(matrices, mouseX, mouseY, delta); - if (isVisible() && getText().isEmpty()) { + if (isVisible() && isEmpty()) { textRenderer.drawWithShadow(matrices, emptyText, x + 4, this.y + (this.height - 8) / 2f, 0x707070); } } @Override public void write(String text) { - yaclScreen.optionList.setScrollAmount(0); - yaclScreen.categoryList.setScrollAmount(0); - for (OptionListWidget.Entry entry : yaclScreen.optionList.children()) { - if (entry instanceof OptionListWidget.GroupSeparatorEntry groupSeparatorEntry) { - groupSeparatorEntry.setExpanded(true); - } - } + update(); super.write(text); + + isEmpty = getText().isEmpty(); } @Override public void eraseCharacters(int characterOffset) { - yaclScreen.optionList.setScrollAmount(0); + update(); super.eraseCharacters(characterOffset); - } - public boolean matches(OptionListWidget.OptionEntry optionEntry, boolean ignoreCategory) { - return (matchesCategory(optionEntry.category) && !ignoreCategory) || matchesGroup(optionEntry.group) || matchesWidget(optionEntry.widget); + isEmpty = getText().isEmpty(); } - public boolean matchesCategory(ConfigCategory category) { - return category.name().getString().toLowerCase().contains(getText().trim()); - } - - public boolean matchesGroup(OptionGroup group) { - if (group.isRoot()) - return false; - - return group.name().getString().toLowerCase().contains(getText().trim()); + private void update() { + yaclScreen.optionList.setScrollAmount(0); + yaclScreen.categoryList.setScrollAmount(0); + for (OptionListWidget.Entry entry : yaclScreen.optionList.children()) { + if (entry instanceof OptionListWidget.GroupSeparatorEntry groupSeparatorEntry) { + groupSeparatorEntry.setExpanded(true); + } + } } - public boolean matchesWidget(AbstractWidget widget) { - return widget.matchesSearch(getText().trim()); + public boolean isEmpty() { + return isEmpty; } public Text getEmptyText() { diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/ActionController.java b/src/main/java/dev/isxander/yacl/gui/controllers/ActionController.java index ee3f988..6207f03 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/ActionController.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/ActionController.java @@ -6,7 +6,6 @@ import dev.isxander.yacl.api.utils.Dimension; import dev.isxander.yacl.gui.AbstractWidget; import dev.isxander.yacl.gui.YACLScreen; import net.minecraft.text.Text; -import org.jetbrains.annotations.ApiStatus; import org.lwjgl.glfw.GLFW; import java.util.function.BiConsumer; @@ -67,10 +66,12 @@ public class ActionController implements Controller<BiConsumer<YACLScreen, Butto return new ActionControllerElement(this, screen, widgetDimension); } - @ApiStatus.Internal 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() { @@ -108,7 +109,7 @@ public class ActionController implements Controller<BiConsumer<YACLScreen, Butto @Override public boolean matchesSearch(String query) { - return super.matchesSearch(query) || getValueText().getString().toLowerCase().contains(query); + return super.matchesSearch(query) || buttonString.contains(query); } } } diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/BooleanController.java b/src/main/java/dev/isxander/yacl/gui/controllers/BooleanController.java index bb5304b..cea6028 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/BooleanController.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/BooleanController.java @@ -102,7 +102,6 @@ public class BooleanController implements Controller<Boolean> { return new BooleanControllerElement(this, screen, widgetDimension); } - @ApiStatus.Internal public static class BooleanControllerElement extends ControllerWidget<BooleanController> { private BooleanControllerElement(BooleanController control, YACLScreen screen, Dimension<Integer> dim) { super(control, screen, dim); diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java b/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java index 8385dfb..6ef7e56 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java @@ -18,12 +18,15 @@ public abstract class ControllerWidget<T extends Controller<?>> extends Abstract protected boolean focused = false; protected boolean hovered = false; + protected final String optionName; + 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.optionName = control.option().name().getString().toLowerCase(); } @Override @@ -145,7 +148,7 @@ public abstract class ControllerWidget<T extends Controller<?>> extends Abstract @Override public boolean matchesSearch(String query) { - return control.option().name().getString().toLowerCase().contains(query.toLowerCase()); + return optionName.contains(query.toLowerCase()); } @Override diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java b/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java index 261c067..5cf680d 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java @@ -77,7 +77,6 @@ public class EnumController<T extends Enum<T>> implements Controller<T> { return new EnumControllerElement<>(this, screen, widgetDimension, option().typeClass().getEnumConstants()); } - @ApiStatus.Internal public static class EnumControllerElement<T extends Enum<T>> extends ControllerWidget<EnumController<T>> { private final T[] values; diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/LabelController.java b/src/main/java/dev/isxander/yacl/gui/controllers/LabelController.java index 57927f5..4e72d97 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/LabelController.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/LabelController.java @@ -44,7 +44,6 @@ public class LabelController implements Controller<Text> { return new LabelControllerElement(widgetDimension); } - @ApiStatus.Internal public class LabelControllerElement extends AbstractWidget { private MultilineText wrappedText; diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/TickBoxController.java b/src/main/java/dev/isxander/yacl/gui/controllers/TickBoxController.java index d7864e0..ece6bce 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/TickBoxController.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/TickBoxController.java @@ -50,7 +50,6 @@ public class TickBoxController implements Controller<Boolean> { return new TickBoxControllerElement(this, screen, widgetDimension); } - @ApiStatus.Internal public static class TickBoxControllerElement extends ControllerWidget<TickBoxController> { private TickBoxControllerElement(TickBoxController control, YACLScreen screen, Dimension<Integer> dim) { super(control, screen, dim); diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java b/src/main/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java index 01ac336..dd977f7 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java @@ -7,10 +7,8 @@ import net.minecraft.client.gui.DrawableHelper; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.math.MathHelper; -import org.jetbrains.annotations.ApiStatus; import org.lwjgl.glfw.GLFW; -@ApiStatus.Internal public class SliderControllerElement extends ControllerWidget<ISliderController<?>> { private final double min, max, interval; diff --git a/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java b/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java index f6c8b6d..7d856b0 100644 --- a/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java +++ b/src/main/java/dev/isxander/yacl/impl/ButtonOptionImpl.java @@ -4,15 +4,12 @@ import com.google.common.collect.ImmutableSet; import dev.isxander.yacl.api.*; import dev.isxander.yacl.gui.YACLScreen; import net.minecraft.text.Text; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.function.BiConsumer; -import java.util.function.Consumer; import java.util.function.Function; -@ApiStatus.Internal public class ButtonOptionImpl implements ButtonOption { private final Text name; private final Text tooltip; diff --git a/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java b/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java index 5a7c9b0..971fecf 100644 --- a/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java +++ b/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java @@ -4,9 +4,7 @@ import com.google.common.collect.ImmutableList; import dev.isxander.yacl.api.ConfigCategory; import dev.isxander.yacl.api.OptionGroup; import net.minecraft.text.Text; -import org.jetbrains.annotations.ApiStatus; -@ApiStatus.Internal public record ConfigCategoryImpl(Text name, ImmutableList<OptionGroup> groups, Text tooltip) implements ConfigCategory { } diff --git a/src/main/java/dev/isxander/yacl/impl/GenericBindingImpl.java b/src/main/java/dev/isxander/yacl/impl/GenericBindingImpl.java index 9dfe2b0..1867bb6 100644 --- a/src/main/java/dev/isxander/yacl/impl/GenericBindingImpl.java +++ b/src/main/java/dev/isxander/yacl/impl/GenericBindingImpl.java @@ -1,12 +1,10 @@ package dev.isxander.yacl.impl; import dev.isxander.yacl.api.Binding; -import org.jetbrains.annotations.ApiStatus; import java.util.function.Consumer; import java.util.function.Supplier; -@ApiStatus.Internal public class GenericBindingImpl<T> implements Binding<T> { private final T def; private final Supplier<T> getter; diff --git a/src/main/java/dev/isxander/yacl/impl/OptionImpl.java b/src/main/java/dev/isxander/yacl/impl/OptionImpl.java index 36cb217..14cf6a8 100644 --- a/src/main/java/dev/isxander/yacl/impl/OptionImpl.java +++ b/src/main/java/dev/isxander/yacl/impl/OptionImpl.java @@ -11,15 +11,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.function.BiConsumer; import java.util.function.Function; -@ApiStatus.Internal public class OptionImpl<T> implements Option<T> { private final Text name; private Text tooltip; - private final Function<T, Text> tooltipGetter; private final Controller<T> controller; private final Binding<T> binding; private boolean available; @@ -39,16 +38,16 @@ public class OptionImpl<T> implements Option<T> { @NotNull Binding<T> binding, boolean available, ImmutableSet<OptionFlag> flags, - @NotNull Class<T> typeClass + @NotNull Class<T> typeClass, + @NotNull Collection<BiConsumer<Option<T>, T>> listeners ) { this.name = name; - this.tooltipGetter = tooltipGetter; this.controller = controlGetter.apply(this); this.binding = binding; this.available = available; this.flags = flags; this.typeClass = typeClass; - this.listeners = new ArrayList<>(); + this.listeners = new ArrayList<>(listeners); addListener((opt, pending) -> tooltip = tooltipGetter.apply(pending)); requestSet(binding().getValue()); diff --git a/src/main/java/dev/isxander/yacl/impl/YetAnotherConfigLibImpl.java b/src/main/java/dev/isxander/yacl/impl/YetAnotherConfigLibImpl.java index 5938bad..7e2afdb 100644 --- a/src/main/java/dev/isxander/yacl/impl/YetAnotherConfigLibImpl.java +++ b/src/main/java/dev/isxander/yacl/impl/YetAnotherConfigLibImpl.java @@ -6,11 +6,9 @@ import dev.isxander.yacl.api.YetAnotherConfigLib; import dev.isxander.yacl.gui.YACLScreen; import net.minecraft.client.gui.screen.Screen; import net.minecraft.text.Text; -import org.jetbrains.annotations.ApiStatus; import java.util.function.Consumer; -@ApiStatus.Internal public record YetAnotherConfigLibImpl(Text title, ImmutableList<ConfigCategory> categories, Runnable saveFunction, Consumer<YACLScreen> initConsumer) implements YetAnotherConfigLib { @Override public Screen generateScreen(Screen parent) { diff --git a/src/main/java/dev/isxander/yacl/impl/utils/DimensionIntegerImpl.java b/src/main/java/dev/isxander/yacl/impl/utils/DimensionIntegerImpl.java index 4cb1c0e..76a5868 100644 --- a/src/main/java/dev/isxander/yacl/impl/utils/DimensionIntegerImpl.java +++ b/src/main/java/dev/isxander/yacl/impl/utils/DimensionIntegerImpl.java @@ -1,9 +1,7 @@ package dev.isxander.yacl.impl.utils; import dev.isxander.yacl.api.utils.Dimension; -import org.jetbrains.annotations.ApiStatus; -@ApiStatus.Internal public class DimensionIntegerImpl implements Dimension<Integer> { private int x, y; private int width, height; 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 index 63bf7e6..17972a1 100644 --- 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 @@ -19,17 +19,5 @@ "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", - - "yacl.config.category.tooltips": "Tooltips", - "yacl.config.category.tooltips.description": "Modify how YACL's tooltips behave.", - "yacl.config.tooltip.group.option": "Options", - "yacl.config.tooltip.group.group": "Groups", - "yacl.config.tooltip.group.category": "Categories", - "yacl.config.opt.hover_ticks": "Hover Time", - "yacl.config.opt.hover_ticks.tooltip": "How long to hover before the tooltip appears.", - "yacl.config.opt.tooltip_location": "Tooltip Location", - "yacl.config.opt.tooltip_location.tooltip": "Where the tooltip should appear on the screen.", - "yacl.config.tooltip_location.adjacent": "Adjacent", - "yacl.config.tooltip_location.mouse": "Mouse" + "yacl.restart.no": "Ignore" } |