From 42cce53d6b5eccd1218c0fe0ea576417cb5e0119 Mon Sep 17 00:00:00 2001 From: isXander Date: Sat, 27 May 2023 21:32:41 +0100 Subject: reimplement category tooltips --- .../java/dev/isxander/yacl/gui/ImageRenderer.java | 2 +- .../isxander/yacl/gui/ScrollableNavigationBar.java | 83 -------------- .../java/dev/isxander/yacl/gui/TabListWidget.java | 119 --------------------- .../java/dev/isxander/yacl/gui/YACLScreen.java | 32 ++++-- .../isxander/yacl/gui/tab/ListHolderWidget.java | 116 ++++++++++++++++++++ .../yacl/gui/tab/ScrollableNavigationBar.java | 91 ++++++++++++++++ .../java/dev/isxander/yacl/gui/tab/TabExt.java | 9 ++ 7 files changed, 240 insertions(+), 212 deletions(-) delete mode 100644 common/src/main/java/dev/isxander/yacl/gui/ScrollableNavigationBar.java delete mode 100644 common/src/main/java/dev/isxander/yacl/gui/TabListWidget.java create mode 100644 common/src/main/java/dev/isxander/yacl/gui/tab/ListHolderWidget.java create mode 100644 common/src/main/java/dev/isxander/yacl/gui/tab/ScrollableNavigationBar.java create mode 100644 common/src/main/java/dev/isxander/yacl/gui/tab/TabExt.java (limited to 'common/src') diff --git a/common/src/main/java/dev/isxander/yacl/gui/ImageRenderer.java b/common/src/main/java/dev/isxander/yacl/gui/ImageRenderer.java index 25be791..5a48f5f 100644 --- a/common/src/main/java/dev/isxander/yacl/gui/ImageRenderer.java +++ b/common/src/main/java/dev/isxander/yacl/gui/ImageRenderer.java @@ -32,7 +32,7 @@ import java.util.function.Supplier; import java.util.stream.IntStream; public interface ImageRenderer { - int render(GuiGraphics graphics, int x, int y, int width); + int render(GuiGraphics graphics, int x, int y, int renderWidth); void close(); diff --git a/common/src/main/java/dev/isxander/yacl/gui/ScrollableNavigationBar.java b/common/src/main/java/dev/isxander/yacl/gui/ScrollableNavigationBar.java deleted file mode 100644 index 62c63db..0000000 --- a/common/src/main/java/dev/isxander/yacl/gui/ScrollableNavigationBar.java +++ /dev/null @@ -1,83 +0,0 @@ -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 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); - } - - public int getScrollOffset() { - return 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 deleted file mode 100644 index 041c06a..0000000 --- a/common/src/main/java/dev/isxander/yacl/gui/TabListWidget.java +++ /dev/null @@ -1,119 +0,0 @@ -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; - -import java.util.List; -import java.util.function.Supplier; - -/** - * Author: MrCrayfish - */ -public class TabListWidget> extends AbstractWidget implements ContainerEventHandler -{ - private final Supplier dimensions; - private final T list; - - public TabListWidget(Supplier dimensions, T list) { - super(0, 0, 100, 0, CommonComponents.EMPTY); - this.dimensions = dimensions; - this.list = list; - } - - @Override - public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float deltaTick) { - ScreenRectangle dimensions = this.dimensions.get(); - this.setX(dimensions.left()); - this.setY(dimensions.top()); - this.width = dimensions.width(); - this.height = dimensions.height(); - this.list.updateDimensions(dimensions); - this.list.render(guiGraphics, mouseX, mouseY, deltaTick); - } - - @Override - protected void updateWidgetNarration(NarrationElementOutput output) { - this.list.updateNarration(output); - } - - @Override - public List children() { - return ImmutableList.of(this.list); - } - - public T getList() { - return list; - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - return this.list.mouseClicked(mouseX, mouseY, button); - } - - @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - return this.list.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); - } - - @Override - public boolean mouseReleased(double mouseX, double mouseY, int button) { - return this.list.mouseReleased(mouseX, mouseY, button); - } - - @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - return this.list.mouseScrolled(mouseX, mouseY, amount); - } - - @Override - public boolean keyPressed(int i, int j, int k) { - return this.list.keyPressed(i, j, k); - } - - @Override - public boolean charTyped(char c, int i) { - return this.list.charTyped(c, i); - } - - @Override - public boolean isDragging() { - return this.list.isDragging(); - } - - @Override - public void setDragging(boolean dragging) { - this.list.setDragging(dragging); - } - - @Nullable - @Override - public GuiEventListener getFocused() { - return this.list.getFocused(); - } - - @Override - 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 d225d7e..1e52cde 100644 --- a/common/src/main/java/dev/isxander/yacl/gui/YACLScreen.java +++ b/common/src/main/java/dev/isxander/yacl/gui/YACLScreen.java @@ -6,6 +6,9 @@ import dev.isxander.yacl.api.*; import dev.isxander.yacl.api.utils.Dimension; import dev.isxander.yacl.api.utils.MutableDimension; import dev.isxander.yacl.api.utils.OptionUtils; +import dev.isxander.yacl.gui.tab.ScrollableNavigationBar; +import dev.isxander.yacl.gui.tab.ListHolderWidget; +import dev.isxander.yacl.gui.tab.TabExt; import dev.isxander.yacl.gui.utils.GuiUtils; import dev.isxander.yacl.impl.utils.YACLConstants; import net.minecraft.ChatFormatting; @@ -15,7 +18,6 @@ import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.MultiLineLabel; import net.minecraft.client.gui.components.Tooltip; -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; @@ -25,13 +27,10 @@ import net.minecraft.client.gui.screens.inventory.tooltip.TooltipRenderUtil; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; -import java.io.*; import java.util.HashSet; -import java.util.Optional; import java.util.Set; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; @@ -213,10 +212,11 @@ public class YACLScreen extends Screen { } } - private class CategoryTab implements Tab { + private class CategoryTab implements TabExt { private final ConfigCategory category; + private final Tooltip tooltip; - private TabListWidget optionList; + private ListHolderWidget optionList; private final Button saveFinishedButton; private final Button cancelResetButton; private final Button undoButton; @@ -225,6 +225,7 @@ public class YACLScreen extends Screen { public CategoryTab(ConfigCategory category) { this.category = category; + this.tooltip = Tooltip.create(category.tooltip()); int columnWidth = width / 3; int padding = columnWidth / 20; @@ -261,7 +262,7 @@ public class YACLScreen extends Screen { searchQuery -> optionList.getList().updateSearchQuery(searchQuery) ); - this.optionList = new TabListWidget<>( + this.optionList = new ListHolderWidget<>( () -> new ScreenRectangle(tabArea.position(), tabArea.width() / 3 * 2 + 1, tabArea.height()), new OptionListWidget(YACLScreen.this, category, minecraft, 0, 0, width / 3 * 2 + 1, height, desc -> { descriptionWidget.setOptionDescription(desc); @@ -308,6 +309,12 @@ public class YACLScreen extends Screen { descriptionWidget.tick(); } + @Nullable + @Override + public Tooltip getTooltip() { + return tooltip; + } + private void updateButtons() { boolean pendingChanges = pendingChanges(); @@ -319,11 +326,13 @@ public class YACLScreen extends Screen { } } - private class PlaceholderTab implements Tab { + private class PlaceholderTab implements TabExt { private final PlaceholderCategory category; + private final Tooltip tooltip; public PlaceholderTab(PlaceholderCategory category) { this.category = category; + this.tooltip = Tooltip.create(category.tooltip()); } @Override @@ -340,5 +349,10 @@ public class YACLScreen extends Screen { public void doLayout(ScreenRectangle screenRectangle) { minecraft.setScreen(category.screen().apply(minecraft, YACLScreen.this)); } + + @Override + public @Nullable Tooltip getTooltip() { + return this.tooltip; + } } } diff --git a/common/src/main/java/dev/isxander/yacl/gui/tab/ListHolderWidget.java b/common/src/main/java/dev/isxander/yacl/gui/tab/ListHolderWidget.java new file mode 100644 index 0000000..84aba61 --- /dev/null +++ b/common/src/main/java/dev/isxander/yacl/gui/tab/ListHolderWidget.java @@ -0,0 +1,116 @@ +package dev.isxander.yacl.gui.tab; + +import com.google.common.collect.ImmutableList; +import dev.isxander.yacl.gui.ElementListWidgetExt; +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; + +import java.util.List; +import java.util.function.Supplier; + +public class ListHolderWidget> extends AbstractWidget implements ContainerEventHandler { + private final Supplier dimensions; + private final T list; + + public ListHolderWidget(Supplier dimensions, T list) { + super(0, 0, 100, 0, CommonComponents.EMPTY); + this.dimensions = dimensions; + this.list = list; + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float deltaTick) { + ScreenRectangle dimensions = this.dimensions.get(); + this.setX(dimensions.left()); + this.setY(dimensions.top()); + this.width = dimensions.width(); + this.height = dimensions.height(); + this.list.updateDimensions(dimensions); + this.list.render(guiGraphics, mouseX, mouseY, deltaTick); + } + + @Override + protected void updateWidgetNarration(NarrationElementOutput output) { + this.list.updateNarration(output); + } + + @Override + public List children() { + return ImmutableList.of(this.list); + } + + public T getList() { + return list; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + return this.list.mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + return this.list.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + return this.list.mouseReleased(mouseX, mouseY, button); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + return this.list.mouseScrolled(mouseX, mouseY, amount); + } + + @Override + public boolean keyPressed(int i, int j, int k) { + return this.list.keyPressed(i, j, k); + } + + @Override + public boolean charTyped(char c, int i) { + return this.list.charTyped(c, i); + } + + @Override + public boolean isDragging() { + return this.list.isDragging(); + } + + @Override + public void setDragging(boolean dragging) { + this.list.setDragging(dragging); + } + + @Nullable + @Override + public GuiEventListener getFocused() { + return this.list.getFocused(); + } + + @Override + 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/tab/ScrollableNavigationBar.java b/common/src/main/java/dev/isxander/yacl/gui/tab/ScrollableNavigationBar.java new file mode 100644 index 0000000..17d53b8 --- /dev/null +++ b/common/src/main/java/dev/isxander/yacl/gui/tab/ScrollableNavigationBar.java @@ -0,0 +1,91 @@ +package dev.isxander.yacl.gui.tab; + +import com.google.common.collect.ImmutableList; +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 width, TabManager tabManager, Iterable tabs) { + super(width, tabManager, ImmutableList.copyOf(tabs)); + + // add tab tooltips to the tab buttons + for (TabButton tabButton : this.tabButtons) { + if (tabButton.tab() instanceof TabExt tab) { + tabButton.setTooltip(tab.getTooltip()); + } + } + } + + @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); + } + + public int getScrollOffset() { + return 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/tab/TabExt.java b/common/src/main/java/dev/isxander/yacl/gui/tab/TabExt.java new file mode 100644 index 0000000..7462a2c --- /dev/null +++ b/common/src/main/java/dev/isxander/yacl/gui/tab/TabExt.java @@ -0,0 +1,9 @@ +package dev.isxander.yacl.gui.tab; + +import net.minecraft.client.gui.components.Tooltip; +import net.minecraft.client.gui.components.tabs.Tab; +import org.jetbrains.annotations.Nullable; + +public interface TabExt extends Tab { + @Nullable Tooltip getTooltip(); +} -- cgit