From aba4bcb529e7613de181ea7410fc3d371c9b3d07 Mon Sep 17 00:00:00 2001 From: isXander Date: Thu, 1 Dec 2022 18:17:59 +0000 Subject: generify element list widgets and prevent wrapping soft-lock --- .../dev/isxander/yacl/gui/CategoryListWidget.java | 20 ++- .../isxander/yacl/gui/ElementListWidgetExt.java | 152 +++++++++++++++++++++ .../dev/isxander/yacl/gui/OptionListWidget.java | 125 ++--------------- .../java/dev/isxander/yacl/gui/YACLScreen.java | 5 +- .../yacl/gui/controllers/BooleanController.java | 9 +- .../yacl/gui/controllers/ControllerWidget.java | 4 + 6 files changed, 187 insertions(+), 128 deletions(-) create mode 100644 src/client/java/dev/isxander/yacl/gui/ElementListWidgetExt.java diff --git a/src/client/java/dev/isxander/yacl/gui/CategoryListWidget.java b/src/client/java/dev/isxander/yacl/gui/CategoryListWidget.java index 46a9fdf..4dbcb11 100644 --- a/src/client/java/dev/isxander/yacl/gui/CategoryListWidget.java +++ b/src/client/java/dev/isxander/yacl/gui/CategoryListWidget.java @@ -11,11 +11,11 @@ import net.minecraft.client.util.math.MatrixStack; import java.util.List; -public class CategoryListWidget extends ElementListWidget { +public class CategoryListWidget extends ElementListWidgetExt { private final YACLScreen yaclScreen; public CategoryListWidget(MinecraftClient client, YACLScreen yaclScreen, int screenWidth, int screenHeight) { - super(client, screenWidth / 3, yaclScreen.searchFieldWidget.getY() - 5, 0, yaclScreen.searchFieldWidget.getY() - 5, 21); + super(client, 0, 0, screenWidth / 3, yaclScreen.searchFieldWidget.getY() - 5, true); this.yaclScreen = yaclScreen; setRenderBackground(false); setRenderHorizontalShadows(false); @@ -26,10 +26,10 @@ public class CategoryListWidget extends ElementListWidget { private final CategoryWidget categoryButton; public final int categoryIndex; @@ -79,10 +84,15 @@ public class CategoryListWidget extends ElementListWidget children() { return ImmutableList.of(categoryButton); diff --git a/src/client/java/dev/isxander/yacl/gui/ElementListWidgetExt.java b/src/client/java/dev/isxander/yacl/gui/ElementListWidgetExt.java new file mode 100644 index 0000000..f2a19f2 --- /dev/null +++ b/src/client/java/dev/isxander/yacl/gui/ElementListWidgetExt.java @@ -0,0 +1,152 @@ +package dev.isxander.yacl.gui; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.widget.ElementListWidget; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.MathHelper; +import org.jetbrains.annotations.Nullable; + +public class ElementListWidgetExt> extends ElementListWidget { + protected final int x, y; + + private double smoothScrollAmount = getScrollAmount(); + private boolean returnSmoothAmount = false; + private final boolean doSmoothScrolling; + + public ElementListWidgetExt(MinecraftClient client, int x, int y, int width, int height, boolean smoothScrolling) { + super(client, width, height, y, y + height, 22); + this.x = x; + this.y = y; + this.left = x; + this.right = this.left + width; + this.doSmoothScrolling = smoothScrolling; + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + // default implementation bases scroll step from total height of entries, this is constant + this.setScrollAmount(this.getScrollAmount() - amount * 20); + return true; + } + + @Override + protected void renderBackground(MatrixStack matrices) { + // render transparent background if in-game. + setRenderBackground(client.world == null); + if (client.world != null) + fill(matrices, left, top, right, bottom, 0x6B000000); + } + + @Override + protected int getScrollbarPositionX() { + // default implementation does not respect left/right + return this.right - 2; + } + + @Override + public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { + smoothScrollAmount = MathHelper.lerp(MinecraftClient.getInstance().getLastFrameDuration() * 0.5, smoothScrollAmount, getScrollAmount()); + returnSmoothAmount = true; + super.render(matrices, mouseX, mouseY, delta); + returnSmoothAmount = false; + } + + /** + * awful code to only use smooth scroll state when rendering, + * not other code that needs target scroll amount + */ + @Override + public double getScrollAmount() { + if (returnSmoothAmount && doSmoothScrolling) + return smoothScrollAmount; + + return super.getScrollAmount(); + } + + protected void resetSmoothScrolling() { + this.smoothScrollAmount = getScrollAmount(); + } + + public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) { + for (E entry : children()) { + entry.postRender(matrices, mouseX, mouseY, delta); + } + } + + /* + below code is licensed from cloth-config under LGPL3 + modified to inherit vanilla's EntryListWidget and use yarn mappings + + code is responsible for having dynamic item heights + */ + + @Nullable + @Override + protected E getEntryAtPosition(double x, double y) { + int listMiddleX = this.left + this.width / 2; + int minX = listMiddleX - this.getRowWidth() / 2; + int maxX = listMiddleX + this.getRowWidth() / 2; + int currentY = MathHelper.floor(y - (double) this.top) - this.headerHeight + (int) this.getScrollAmount() - 4; + int itemY = 0; + int itemIndex = -1; + for (int i = 0; i < children().size(); i++) { + E item = children().get(i); + itemY += item.getItemHeight(); + if (itemY > currentY) { + itemIndex = i; + break; + } + } + return x < (double) this.getScrollbarPositionX() && x >= minX && y <= maxX && itemIndex >= 0 && currentY >= 0 && itemIndex < this.getEntryCount() ? this.children().get(itemIndex) : null; + } + + @Override + protected int getMaxPosition() { + return children().stream().map(E::getItemHeight).reduce(0, Integer::sum) + headerHeight; + } + + @Override + protected void centerScrollOn(E entry) { + double d = (this.bottom - this.top) / -2d; + for (int i = 0; i < this.children().indexOf(entry) && i < this.getEntryCount(); i++) + d += children().get(i).getItemHeight(); + this.setScrollAmount(d); + } + + @Override + protected int getRowTop(int index) { + int integer = top + 4 - (int) this.getScrollAmount() + headerHeight; + for (int i = 0; i < children().size() && i < index; i++) + integer += children().get(i).getItemHeight(); + return integer; + } + + @Override + protected void renderList(MatrixStack matrices, int mouseX, int mouseY, float delta) { + int left = this.getRowLeft(); + int right = this.getRowWidth(); + int count = this.getEntryCount(); + + for(int i = 0; i < count; ++i) { + E entry = children().get(i); + int top = this.getRowTop(i); + int bottom = top + entry.getItemHeight(); + int entryHeight = entry.getItemHeight() - 4; + if (bottom >= this.top && top <= this.bottom) { + this.renderEntry(matrices, mouseX, mouseY, delta, i, left, top, right, entryHeight); + } + } + } + + /* END cloth config code */ + + public abstract static class Entry> extends ElementListWidget.Entry { + public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) { + + } + + public int getItemHeight() { + return 22; + } + } +} diff --git a/src/client/java/dev/isxander/yacl/gui/OptionListWidget.java b/src/client/java/dev/isxander/yacl/gui/OptionListWidget.java index eed3aff..785f4e2 100644 --- a/src/client/java/dev/isxander/yacl/gui/OptionListWidget.java +++ b/src/client/java/dev/isxander/yacl/gui/OptionListWidget.java @@ -22,20 +22,15 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.function.Supplier; -public class OptionListWidget extends ElementListWidget { +public class OptionListWidget extends ElementListWidgetExt { private final YACLScreen yaclScreen; private boolean singleCategory = false; private ImmutableList viewableChildren; - private double smoothScrollAmount = getScrollAmount(); - private boolean returnSmoothAmount = false; - public OptionListWidget(YACLScreen screen, MinecraftClient client, int width, int height) { - super(client, width / 3 * 2, height, 0, height, 22); + super(client, width / 3, 0, width / 3 * 2, height, true); this.yaclScreen = screen; - left = width - this.width; - right = width; refreshOptions(); } @@ -78,6 +73,7 @@ public class OptionListWidget extends ElementListWidget recacheViewableChildren(); setScrollAmount(0); + resetSmoothScrolling(); } public void expandAllGroups() { @@ -88,97 +84,6 @@ public class OptionListWidget extends ElementListWidget } } - /* - below code is licensed from cloth-config under LGPL3 - modified to inherit vanilla's EntryListWidget and use yarn mappings - */ - - @Nullable - @Override - protected Entry getEntryAtPosition(double x, double y) { - int listMiddleX = this.left + this.width / 2; - int minX = listMiddleX - this.getRowWidth() / 2; - int maxX = listMiddleX + this.getRowWidth() / 2; - int currentY = MathHelper.floor(y - (double) this.top) - this.headerHeight + (int) this.getScrollAmount() - 4; - int itemY = 0; - int itemIndex = -1; - for (int i = 0; i < children().size(); i++) { - Entry item = children().get(i); - itemY += item.getItemHeight(); - if (itemY > currentY) { - itemIndex = i; - break; - } - } - return x < (double) this.getScrollbarPositionX() && x >= minX && y <= maxX && itemIndex >= 0 && currentY >= 0 && itemIndex < this.getEntryCount() ? this.children().get(itemIndex) : null; - } - - @Override - protected int getMaxPosition() { - return children().stream().map(Entry::getItemHeight).reduce(0, Integer::sum) + headerHeight; - } - - @Override - protected void centerScrollOn(Entry entry) { - double d = (this.bottom - this.top) / -2d; - for (int i = 0; i < this.children().indexOf(entry) && i < this.getEntryCount(); i++) - d += children().get(i).getItemHeight(); - this.setScrollAmount(d); - } - - @Override - protected int getRowTop(int index) { - int integer = top + 4 - (int) this.getScrollAmount() + headerHeight; - for (int i = 0; i < children().size() && i < index; i++) - integer += children().get(i).getItemHeight(); - return integer; - } - - @Override - protected void renderList(MatrixStack matrices, int mouseX, int mouseY, float delta) { - int left = this.getRowLeft(); - int right = this.getRowWidth(); - int count = this.getEntryCount(); - - for(int i = 0; i < count; ++i) { - Entry entry = children().get(i); - int top = this.getRowTop(i); - int bottom = top + entry.getItemHeight(); - int entryHeight = entry.getItemHeight() - 4; - if (bottom >= this.top && top <= this.bottom) { - this.renderEntry(matrices, mouseX, mouseY, delta, i, left, top, right, entryHeight); - } - } - } - - /* END cloth config code */ - - @Override - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - smoothScrollAmount = MathHelper.lerp(MinecraftClient.getInstance().getLastFrameDuration() * 0.5, smoothScrollAmount, getScrollAmount()); - returnSmoothAmount = true; - super.render(matrices, mouseX, mouseY, delta); - returnSmoothAmount = false; - } - - /** - * awful code to only use smooth scroll state when rendering, - * not other code that needs target scroll amount - */ - @Override - public double getScrollAmount() { - if (returnSmoothAmount) - return smoothScrollAmount; - - return super.getScrollAmount(); - } - - public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) { - for (Entry entry : children()) { - entry.postRender(matrices, mouseX, mouseY, delta); - } - } - @Override public int getRowWidth() { return Math.min(396, (int)(width / 1.3f)); @@ -196,12 +101,13 @@ public class OptionListWidget extends ElementListWidget @Override public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + super.mouseScrolled(mouseX, mouseY, amount); + for (Entry child : children()) { if (child.mouseScrolled(mouseX, mouseY, amount)) - return true; + break; } - this.setScrollAmount(this.getScrollAmount() - amount * 20 /* * (double) (getMaxScroll() / getEntryCount()) / 2.0D */); return true; } @@ -227,14 +133,7 @@ public class OptionListWidget extends ElementListWidget @Override protected int getScrollbarPositionX() { - return left + width - (int)(width * 0.05f); - } - - @Override - protected void renderBackground(MatrixStack matrices) { - setRenderBackground(client.world == null); - if (client.world != null) - fill(matrices, left, top, right, bottom, 0x6B000000); + return right - (int)(width * 0.05f); } public void recacheViewableChildren() { @@ -254,19 +153,11 @@ public class OptionListWidget extends ElementListWidget return viewableChildren; } - public abstract class Entry extends ElementListWidget.Entry { - public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) { - - } - + public abstract class Entry extends ElementListWidgetExt.Entry { public boolean isViewable() { return true; } - public int getItemHeight() { - return 22; - } - protected boolean isHovered() { return Objects.equals(getHoveredEntry(), this); } diff --git a/src/client/java/dev/isxander/yacl/gui/YACLScreen.java b/src/client/java/dev/isxander/yacl/gui/YACLScreen.java index e700009..1fbc769 100644 --- a/src/client/java/dev/isxander/yacl/gui/YACLScreen.java +++ b/src/client/java/dev/isxander/yacl/gui/YACLScreen.java @@ -13,6 +13,7 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.tooltip.TooltipBackgroundRenderer; import net.minecraft.client.render.*; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.screen.ScreenTexts; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import org.joml.Matrix4f; @@ -160,9 +161,9 @@ public class YACLScreen extends Screen { boolean pendingChanges = pendingChanges(); undoButton.active = pendingChanges; - finishedSaveButton.setMessage(pendingChanges ? Text.translatable("yacl.gui.save") : Text.translatable("gui.done")); + finishedSaveButton.setMessage(pendingChanges ? Text.translatable("yacl.gui.save") : ScreenTexts.DONE); finishedSaveButton.setTooltip(pendingChanges ? Text.translatable("yacl.gui.save.tooltip") : Text.translatable("yacl.gui.finished.tooltip")); - cancelResetButton.setMessage(pendingChanges ? Text.translatable("gui.cancel") : Text.translatable("controls.reset")); + cancelResetButton.setMessage(pendingChanges ? ScreenTexts.CANCEL : Text.translatable("controls.reset")); cancelResetButton.setTooltip(pendingChanges ? Text.translatable("yacl.gui.cancel.tooltip") : Text.translatable("yacl.gui.reset.tooltip")); } diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/BooleanController.java b/src/client/java/dev/isxander/yacl/gui/controllers/BooleanController.java index 7037ff5..b696831 100644 --- a/src/client/java/dev/isxander/yacl/gui/controllers/BooleanController.java +++ b/src/client/java/dev/isxander/yacl/gui/controllers/BooleanController.java @@ -6,6 +6,7 @@ import dev.isxander.yacl.api.utils.Dimension; import dev.isxander.yacl.gui.AbstractWidget; import dev.isxander.yacl.gui.YACLScreen; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.screen.ScreenTexts; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import org.lwjgl.glfw.GLFW; @@ -19,8 +20,8 @@ public class BooleanController implements Controller { public static final Function ON_OFF_FORMATTER = (state) -> state - ? Text.translatable("options.on") - : Text.translatable("options.off"); + ? ScreenTexts.ON + : ScreenTexts.OFF; public static final Function TRUE_FALSE_FORMATTER = (state) -> state @@ -29,8 +30,8 @@ public class BooleanController implements Controller { public static final Function YES_NO_FORMATTER = (state) -> state - ? Text.translatable("gui.yes") - : Text.translatable("gui.no"); + ? ScreenTexts.YES + : ScreenTexts.NO; private final Option option; private final Function valueFormatter; diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java b/src/client/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java index c7f9e97..cebaba7 100644 --- a/src/client/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java +++ b/src/client/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java @@ -4,6 +4,7 @@ import dev.isxander.yacl.api.Controller; import dev.isxander.yacl.api.utils.Dimension; import dev.isxander.yacl.gui.AbstractWidget; import dev.isxander.yacl.gui.YACLScreen; +import dev.isxander.yacl.impl.utils.YACLConstants; import net.minecraft.client.font.MultilineText; import net.minecraft.client.gui.DrawableHelper; import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; @@ -44,6 +45,9 @@ public abstract class ControllerWidget> extends Abstract nameString = nameString.substring(0, Math.max(nameString.length() - (firstIter ? 2 : 5), 0)).trim(); nameString += "..."; + if (nameString.equals("...")) + break; + firstIter = false; } -- cgit