diff options
author | isXander <xandersmith2008@gmail.com> | 2023-05-22 19:33:00 +0100 |
---|---|---|
committer | isXander <xandersmith2008@gmail.com> | 2023-05-22 19:33:00 +0100 |
commit | ead0b794ac57e9ab2558338f7f3da7545d2e12ff (patch) | |
tree | d1c92f8d3283a8989923e038a377af4a00c24124 /common | |
parent | 590e69f4bf445a39737b0b1552cf116ff780d75e (diff) | |
download | YetAnotherConfigLib-ead0b794ac57e9ab2558338f7f3da7545d2e12ff.tar.gz YetAnotherConfigLib-ead0b794ac57e9ab2558338f7f3da7545d2e12ff.tar.bz2 YetAnotherConfigLib-ead0b794ac57e9ab2558338f7f3da7545d2e12ff.zip |
scrollable navbar, group descriptions, auto-scroll descriptions
Diffstat (limited to 'common')
11 files changed, 254 insertions, 60 deletions
diff --git a/common/src/main/java/dev/isxander/yacl/api/OptionDescription.java b/common/src/main/java/dev/isxander/yacl/api/OptionDescription.java index 22eebc9..e5ed0b6 100644 --- a/common/src/main/java/dev/isxander/yacl/api/OptionDescription.java +++ b/common/src/main/java/dev/isxander/yacl/api/OptionDescription.java @@ -6,6 +6,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import java.nio.file.Path; +import java.util.Collection; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -23,7 +24,8 @@ public interface OptionDescription { interface Builder { Builder name(Component name); - Builder description(Component description); + Builder description(Component... description); + Builder description(Collection<? extends Component> lines); Builder image(ResourceLocation image, int width, int height); Builder image(Path path, ResourceLocation uniqueLocation); diff --git a/common/src/main/java/dev/isxander/yacl/api/OptionGroup.java b/common/src/main/java/dev/isxander/yacl/api/OptionGroup.java index 4fe43c7..f1b2b5a 100644 --- a/common/src/main/java/dev/isxander/yacl/api/OptionGroup.java +++ b/common/src/main/java/dev/isxander/yacl/api/OptionGroup.java @@ -19,9 +19,12 @@ public interface OptionGroup { */ Component name(); + OptionDescription description(); + /** * Tooltip displayed on hover. */ + @Deprecated Component tooltip(); /** @@ -55,6 +58,8 @@ public interface OptionGroup { */ Builder name(@NotNull Component name); + Builder description(@NotNull OptionDescription description); + /** * Sets the tooltip to be used by the option group. * Can be invoked twice to append more lines. @@ -62,6 +67,7 @@ public interface OptionGroup { * * @param tooltips Component lines - merged with a new-line on {@link Builder#build()}. */ + @Deprecated Builder tooltip(@NotNull Component... tooltips); /** diff --git a/common/src/main/java/dev/isxander/yacl/gui/OptionDescriptionWidget.java b/common/src/main/java/dev/isxander/yacl/gui/OptionDescriptionWidget.java index 882d75b..5c346d0 100644 --- a/common/src/main/java/dev/isxander/yacl/gui/OptionDescriptionWidget.java +++ b/common/src/main/java/dev/isxander/yacl/gui/OptionDescriptionWidget.java @@ -1,5 +1,7 @@ package dev.isxander.yacl.gui; +import com.mojang.blaze3d.Blaze3D; +import com.mojang.blaze3d.platform.InputConstants; import dev.isxander.yacl.api.OptionDescription; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; @@ -17,6 +19,9 @@ import java.util.List; import java.util.function.Supplier; public class OptionDescriptionWidget extends AbstractWidget { + private static final int AUTO_SCROLL_TIMER = 3000; + private static final float AUTO_SCROLL_SPEED = 1; + private @Nullable OptionDescription description; private List<FormattedCharSequence> wrappedText; @@ -25,10 +30,13 @@ public class OptionDescriptionWidget extends AbstractWidget { private Supplier<ScreenRectangle> dimensions; - private int scrollAmount; + private float targetScrollAmount, currentScrollAmount; private int maxScrollAmount; private int descriptionY; + private int lastInteractionTime; + private boolean scrollingBackward; + public OptionDescriptionWidget(Supplier<ScreenRectangle> dimensions, @Nullable OptionDescription description) { super(0, 0, 0, 0, description == null ? Component.empty() : description.descriptiveName()); this.dimensions = dimensions; @@ -39,6 +47,8 @@ public class OptionDescriptionWidget extends AbstractWidget { public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float delta) { if (description == null) return; + currentScrollAmount = Mth.lerp(delta * 0.5f, currentScrollAmount, targetScrollAmount); + ScreenRectangle dimensions = this.dimensions.get(); this.setX(dimensions.left()); this.setY(dimensions.top()); @@ -58,7 +68,7 @@ public class OptionDescriptionWidget extends AbstractWidget { graphics.enableScissor(getX(), y, getX() + getWidth(), getY() + getHeight()); - y -= scrollAmount; + y -= (int)currentScrollAmount; if (description.image().isDone()) { var image = description.image().join(); @@ -79,12 +89,19 @@ public class OptionDescriptionWidget extends AbstractWidget { graphics.disableScissor(); - maxScrollAmount = Math.max(0, y + scrollAmount - getY() - getHeight()); + maxScrollAmount = Math.max(0, y + (int)currentScrollAmount - getY() - getHeight()); + if (isHoveredOrFocused()) { + lastInteractionTime = currentTimeMS(); + } Style hoveredStyle = getDescStyle(mouseX, mouseY); if (hoveredStyle != null && hoveredStyle.getHoverEvent() != null) { graphics.renderComponentHoverEffect(font, hoveredStyle, mouseX, mouseY); } + + if (isFocused()) { + graphics.renderOutline(getX(), getY(), getWidth(), getHeight(), -1); + } } @Override @@ -104,12 +121,50 @@ public class OptionDescriptionWidget extends AbstractWidget { @Override public boolean mouseScrolled(double mouseX, double mouseY, double amount) { if (isMouseOver(mouseX, mouseY)) { - scrollAmount = Mth.clamp(scrollAmount - (int) amount * 10, 0, maxScrollAmount); + targetScrollAmount = Mth.clamp(targetScrollAmount - (int) amount * 10, 0, maxScrollAmount); + lastInteractionTime = currentTimeMS(); + return true; + } + return false; + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (isFocused()) { + switch (keyCode) { + case InputConstants.KEY_UP -> + targetScrollAmount = Mth.clamp(targetScrollAmount - 10, 0, maxScrollAmount); + case InputConstants.KEY_DOWN -> + targetScrollAmount = Mth.clamp(targetScrollAmount + 10, 0, maxScrollAmount); + default -> { + return false; + } + } return true; } return false; } + public void tick() { + float pxPerTick = AUTO_SCROLL_SPEED / 20f * font.lineHeight; + if (maxScrollAmount > 0 && currentTimeMS() - lastInteractionTime > AUTO_SCROLL_TIMER) { + if (scrollingBackward) { + pxPerTick *= -1; + if (targetScrollAmount + pxPerTick < 0) { + scrollingBackward = false; + lastInteractionTime = currentTimeMS(); + } + } else { + if (targetScrollAmount + pxPerTick > maxScrollAmount) { + scrollingBackward = true; + lastInteractionTime = currentTimeMS(); + } + } + + targetScrollAmount = Mth.clamp(targetScrollAmount + pxPerTick, 0, maxScrollAmount); + } + } + private Style getDescStyle(int mouseX, int mouseY) { if (!clicked(mouseX, mouseY)) return null; @@ -135,5 +190,12 @@ public class OptionDescriptionWidget extends AbstractWidget { public void setOptionDescription(OptionDescription description) { this.description = description; this.wrappedText = null; + this.targetScrollAmount = 0; + this.currentScrollAmount = 0; + this.lastInteractionTime = currentTimeMS(); + } + + private int currentTimeMS() { + return (int)(Blaze3D.getTime() * 1000); } } diff --git a/common/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java b/common/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java index 390e6c0..98272d1 100644 --- a/common/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java +++ b/common/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java @@ -27,10 +27,10 @@ public class OptionListWidget extends ElementListWidgetExt<OptionListWidget.Entr private final ConfigCategory category; private ImmutableList<Entry> viewableChildren; private String searchQuery = ""; - private final Consumer<Option<?>> hoverEvent; - private Option<?> lastHoveredOption; + private final Consumer<OptionDescription> hoverEvent; + private OptionDescription lastHoveredOption; - public OptionListWidget(YACLScreen screen, ConfigCategory category, Minecraft client, int x, int y, int width, int height, Consumer<Option<?>> hoverEvent) { + public OptionListWidget(YACLScreen screen, ConfigCategory category, Minecraft client, int x, int y, int width, int height, Consumer<OptionDescription> hoverEvent) { super(client, x, y, width, height, true); this.yaclScreen = screen; this.category = category; @@ -237,6 +237,13 @@ public class OptionListWidget extends ElementListWidgetExt<OptionListWidget.Entr return ret; } + private void setHoverDescription(OptionDescription description) { + if (description != lastHoveredOption) { + lastHoveredOption = description; + hoverEvent.accept(description); + } + } + public abstract class Entry extends ElementListWidgetExt.Entry<Entry> { public boolean isViewable() { return true; @@ -292,11 +299,8 @@ public class OptionListWidget extends ElementListWidgetExt<OptionListWidget.Entr resetButton.render(graphics, mouseX, mouseY, tickDelta); } - if (isHovered()) { - if (lastHoveredOption != option) { - lastHoveredOption = option; - hoverEvent.accept(option); - } + if (isHovered() || isFocused()) { + setHoverDescription(option.description()); } } @@ -392,12 +396,9 @@ public class OptionListWidget extends ElementListWidgetExt<OptionListWidget.Entr expandMinimizeButton.render(graphics, mouseX, mouseY, tickDelta); wrappedName.renderCentered(graphics, x + entryWidth / 2, y + getYPadding()); - } - @Override - public void postRender(GuiGraphics graphics, int mouseX, int mouseY, float delta) { - if ((isHovered() && !expandMinimizeButton.isMouseOver(mouseX, mouseY)) || expandMinimizeButton.isFocused()) { - YACLScreen.renderMultilineTooltip(graphics, font, wrappedTooltip, getRowLeft() + getRowWidth() / 2, y - 3, y + getItemHeight() + 3, screen.width, screen.height); + if (isHovered() || isFocused()) { + setHoverDescription(group.description()); } } diff --git a/common/src/main/java/dev/isxander/yacl/gui/ScrollableNavigationBar.java b/common/src/main/java/dev/isxander/yacl/gui/ScrollableNavigationBar.java new file mode 100644 index 0000000..e2d9ab8 --- /dev/null +++ b/common/src/main/java/dev/isxander/yacl/gui/ScrollableNavigationBar.java @@ -0,0 +1,79 @@ +package dev.isxander.yacl.gui; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.TabButton; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.components.tabs.Tab; +import net.minecraft.client.gui.components.tabs.TabManager; +import net.minecraft.client.gui.components.tabs.TabNavigationBar; +import net.minecraft.util.Mth; +import org.jetbrains.annotations.Nullable; + +public class ScrollableNavigationBar extends TabNavigationBar { + private static final int NAVBAR_MARGIN = 28; + + private static final Font font = Minecraft.getInstance().font; + + private int scrollOffset; + private int maxScrollOffset; + + public ScrollableNavigationBar(int i, TabManager tabManager, Iterable<Tab> iterable) { + super(i, tabManager, iterable); + } + + @Override + public void arrangeElements() { + int noScrollWidth = this.width - NAVBAR_MARGIN*2; + int minimumSize = tabButtons.stream() + .map(AbstractWidget::getMessage) + .mapToInt(label -> font.width(label) + 3) + .min().orElse(0); + int singleTabWidth = Math.max(noScrollWidth / Math.min(this.tabButtons.size(), 3), minimumSize); + for (TabButton tabButton : this.tabButtons) { + tabButton.setWidth(singleTabWidth); + } + + this.layout.arrangeElements(); + this.layout.setY(0); + this.scrollOffset = 0; + + int allTabsWidth = singleTabWidth * this.tabButtons.size(); + this.layout.setX(Math.max((this.width - allTabsWidth) / 2, NAVBAR_MARGIN)); + this.maxScrollOffset = Math.max(0, allTabsWidth - noScrollWidth); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + this.setScrollOffset(this.scrollOffset - (int)(amount*10)); + return true; + } + + @Override + public boolean isMouseOver(double mouseX, double mouseY) { + return mouseY <= 24; + } + + public void setScrollOffset(int scrollOffset) { + layout.setX(layout.getX() + this.scrollOffset); + this.scrollOffset = Mth.clamp(scrollOffset, 0, maxScrollOffset); + layout.setX(layout.getX() - this.scrollOffset); + } + + @Override + public void setFocused(@Nullable GuiEventListener child) { + super.setFocused(child); + if (child instanceof TabButton tabButton) { + this.ensureVisible(tabButton); + } + } + + protected void ensureVisible(TabButton tabButton) { + if (tabButton.getX() < NAVBAR_MARGIN) { + this.setScrollOffset(this.scrollOffset - (NAVBAR_MARGIN - tabButton.getX())); + } else if (tabButton.getX() + tabButton.getWidth() > this.width - NAVBAR_MARGIN) { + this.setScrollOffset(this.scrollOffset + (tabButton.getX() + tabButton.getWidth() - (this.width - NAVBAR_MARGIN))); + } + } +} diff --git a/common/src/main/java/dev/isxander/yacl/gui/TabListWidget.java b/common/src/main/java/dev/isxander/yacl/gui/TabListWidget.java index b9e756c..041c06a 100644 --- a/common/src/main/java/dev/isxander/yacl/gui/TabListWidget.java +++ b/common/src/main/java/dev/isxander/yacl/gui/TabListWidget.java @@ -1,11 +1,13 @@ package dev.isxander.yacl.gui; import com.google.common.collect.ImmutableList; +import net.minecraft.client.gui.ComponentPath; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractWidget; 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.client.gui.navigation.FocusNavigationEvent; import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.network.chat.CommonComponents; import org.jetbrains.annotations.Nullable; @@ -102,4 +104,16 @@ public class TabListWidget<T extends ElementListWidgetExt<?>> extends AbstractWi public void setFocused(@Nullable GuiEventListener listener) { this.list.setFocused(listener); } + + @Nullable + @Override + public ComponentPath nextFocusPath(FocusNavigationEvent event) { + return this.list.nextFocusPath(event); + } + + @Nullable + @Override + public ComponentPath getCurrentFocusPath() { + return this.list.getCurrentFocusPath(); + } } diff --git a/common/src/main/java/dev/isxander/yacl/gui/YACLScreen.java b/common/src/main/java/dev/isxander/yacl/gui/YACLScreen.java index 0ce98ba..a72640e 100644 --- a/common/src/main/java/dev/isxander/yacl/gui/YACLScreen.java +++ b/common/src/main/java/dev/isxander/yacl/gui/YACLScreen.java @@ -56,17 +56,13 @@ public class YACLScreen extends Screen { @Override protected void init() { - tabNavigationBar = TabNavigationBar.builder(tabManager, this.width) - .addTabs(tabs = config.categories() - .stream() - .map(category -> { - if (category instanceof PlaceholderCategory placeholder) - return new PlaceholderTab(placeholder); - return new CategoryTab(category); - }) - .toArray(Tab[]::new) - ) - .build(); + tabNavigationBar = new ScrollableNavigationBar(this.width, tabManager, config.categories() + .stream() + .map(category -> { + if (category instanceof PlaceholderCategory placeholder) + return new PlaceholderTab(placeholder); + return new CategoryTab(category); + }).toList()); tabNavigationBar.selectTab(0, false); tabNavigationBar.arrangeElements(); ScreenRectangle navBarArea = tabNavigationBar.getRectangle(); @@ -239,8 +235,8 @@ public class YACLScreen extends Screen { this.optionList = new TabListWidget<>( () -> new ScreenRectangle(tabArea.position(), tabArea.width() / 3 * 2 + 1, tabArea.height()), - new OptionListWidget(YACLScreen.this, category, minecraft, 0, 0, width / 3 * 2 + 1, height, hoveredOption -> { - descriptionWidget.setOptionDescription(hoveredOption.description()); + new OptionListWidget(YACLScreen.this, category, minecraft, 0, 0, width / 3 * 2 + 1, height, desc -> { + descriptionWidget.setOptionDescription(desc); }) ); @@ -316,6 +312,7 @@ public class YACLScreen extends Screen { public void tick() { updateButtons(); searchField.tick(); + descriptionWidget.tick(); } private void updateButtons() { diff --git a/common/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java b/common/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java index 2d39eb9..ed73174 100644 --- a/common/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java +++ b/common/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java @@ -1,10 +1,7 @@ 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.api.*; import dev.isxander.yacl.impl.utils.YACLConstants; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.ComponentContents; @@ -114,7 +111,7 @@ public final class ConfigCategoryImpl implements ConfigCategory { 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.add(new OptionGroupImpl(Component.empty(), OptionDescription.createBuilder().name(Component.literal("Root")).build(), ImmutableList.copyOf(rootOptions), false, true)); combinedGroups.addAll(groups); Validate.notEmpty(combinedGroups, "at least one option must be added to build `ConfigCategory`"); diff --git a/common/src/main/java/dev/isxander/yacl/impl/OptionDescriptionImpl.java b/common/src/main/java/dev/isxander/yacl/impl/OptionDescriptionImpl.java index c866b43..5d09828 100644 --- a/common/src/main/java/dev/isxander/yacl/impl/OptionDescriptionImpl.java +++ b/common/src/main/java/dev/isxander/yacl/impl/OptionDescriptionImpl.java @@ -4,19 +4,20 @@ 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.network.chat.MutableComponent; 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.*; 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 final List<Component> descriptionLines = new ArrayList<>(); private CompletableFuture<Optional<ImageRenderer>> image = CompletableFuture.completedFuture(Optional.empty()); private boolean imageUnset = true; @@ -27,8 +28,14 @@ public record OptionDescriptionImpl(Component descriptiveName, Component descrip } @Override - public Builder description(Component description) { - this.description = description; + public Builder description(Component... description) { + this.descriptionLines.addAll(Arrays.asList(description)); + return this; + } + + @Override + public Builder description(Collection<? extends Component> lines) { + this.descriptionLines.addAll(lines); return this; } @@ -115,10 +122,14 @@ public record OptionDescriptionImpl(Component descriptiveName, Component descrip public OptionDescription build() { Validate.notNull(name, "Name must be set!"); - if (description == null) - description = Component.empty(); + MutableComponent concatenatedDescription = Component.empty(); + Iterator<Component> iter = descriptionLines.iterator(); + while (iter.hasNext()) { + concatenatedDescription.append(iter.next()); + if (iter.hasNext()) concatenatedDescription.append("\n"); + } - return new OptionDescriptionImpl(name.copy().withStyle(ChatFormatting.BOLD), description, image); + return new OptionDescriptionImpl(name.copy().withStyle(ChatFormatting.BOLD), concatenatedDescription, image); } } } diff --git a/common/src/main/java/dev/isxander/yacl/impl/OptionGroupImpl.java b/common/src/main/java/dev/isxander/yacl/impl/OptionGroupImpl.java index 113aefc..a72aa71 100644 --- a/common/src/main/java/dev/isxander/yacl/impl/OptionGroupImpl.java +++ b/common/src/main/java/dev/isxander/yacl/impl/OptionGroupImpl.java @@ -3,6 +3,7 @@ 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.OptionDescription; import dev.isxander.yacl.api.OptionGroup; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.ComponentContents; @@ -10,6 +11,7 @@ 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.Collection; @@ -18,14 +20,14 @@ import java.util.List; @ApiStatus.Internal public final class OptionGroupImpl implements OptionGroup { private final @NotNull Component name; - private final @NotNull Component tooltip; + private final @NotNull OptionDescription description; 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) { + public OptionGroupImpl(@NotNull Component name, @NotNull OptionDescription description, ImmutableList<? extends Option<?>> options, boolean collapsed, boolean isRoot) { this.name = name; - this.tooltip = tooltip; + this.description = description; this.options = options; this.collapsed = collapsed; this.isRoot = isRoot; @@ -37,8 +39,13 @@ public final class OptionGroupImpl implements OptionGroup { } @Override + public OptionDescription description() { + return description; + } + + @Override public @NotNull Component tooltip() { - return tooltip; + return description.description(); } @Override @@ -59,7 +66,8 @@ public final class OptionGroupImpl implements OptionGroup { @ApiStatus.Internal public static final class BuilderImpl implements Builder { private Component name = Component.empty(); - private final List<Component> tooltipLines = new ArrayList<>(); + private OptionDescription description = null; + private OptionDescription.Builder legacyBuilder = null; private final List<Option<?>> options = new ArrayList<>(); private boolean collapsed = false; @@ -72,10 +80,22 @@ public final class OptionGroupImpl implements OptionGroup { } @Override + public Builder description(@NotNull OptionDescription description) { + Validate.isTrue(legacyBuilder == null, "Cannot set description when deprecated `tooltip` method is used"); + Validate.notNull(description, "`description` must not be null"); + + this.description = description; + return this; + } + + @Override public Builder tooltip(@NotNull Component... tooltips) { + Validate.isTrue(description == null, "Cannot use deprecated `tooltip` method when `description` in use."); Validate.notEmpty(tooltips, "`tooltips` cannot be empty"); - tooltipLines.addAll(List.of(tooltips)); + ensureLegacyDescriptionBuilder(); + + legacyBuilder.description(tooltips); return this; } @@ -111,19 +131,18 @@ public final class OptionGroupImpl implements OptionGroup { 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 (description == null) { + ensureLegacyDescriptionBuilder(); + description = legacyBuilder.name(name).build(); + } - if (!first) concatenatedTooltip.append("\n"); - first = false; + return new OptionGroupImpl(name, description, ImmutableList.copyOf(options), collapsed, false); + } - concatenatedTooltip.append(line); + private void ensureLegacyDescriptionBuilder() { + if (legacyBuilder == null) { + legacyBuilder = OptionDescription.createBuilder(); } - - return new OptionGroupImpl(name, concatenatedTooltip, ImmutableList.copyOf(options), collapsed, false); } } } diff --git a/common/src/main/resources/yacl.accesswidener b/common/src/main/resources/yacl.accesswidener index 2188ea5..303b57a 100644 --- a/common/src/main/resources/yacl.accesswidener +++ b/common/src/main/resources/yacl.accesswidener @@ -3,4 +3,10 @@ accessWidener v2 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
\ No newline at end of file +extendable method net/minecraft/client/gui/components/AbstractButton getTextureY ()I +accessible method net/minecraft/client/gui/components/tabs/TabNavigationBar <init> (ILnet/minecraft/client/gui/components/tabs/TabManager;Ljava/lang/Iterable;)V +accessible field net/minecraft/client/gui/components/tabs/TabNavigationBar layout Lnet/minecraft/client/gui/layouts/GridLayout; +accessible field net/minecraft/client/gui/components/tabs/TabNavigationBar width I +accessible field net/minecraft/client/gui/components/tabs/TabNavigationBar tabManager Lnet/minecraft/client/gui/components/tabs/TabManager; +accessible field net/minecraft/client/gui/components/tabs/TabNavigationBar tabs Lcom/google/common/collect/ImmutableList; +accessible field net/minecraft/client/gui/components/tabs/TabNavigationBar tabButtons Lcom/google/common/collect/ImmutableList; |