From 13c7ba45ff201423eb8dba8a40cfb66ebb531439 Mon Sep 17 00:00:00 2001 From: Xander Date: Tue, 25 Apr 2023 16:28:41 +0100 Subject: Architectury! (#61) --- .../java/dev/isxander/yacl/gui/AbstractWidget.java | 107 ---- .../dev/isxander/yacl/gui/CategoryListWidget.java | 99 ---- .../java/dev/isxander/yacl/gui/CategoryWidget.java | 38 -- .../isxander/yacl/gui/ElementListWidgetExt.java | 179 ------- .../isxander/yacl/gui/LowProfileButtonWidget.java | 29 -- .../dev/isxander/yacl/gui/OptionListWidget.java | 568 --------------------- .../isxander/yacl/gui/RequireRestartScreen.java | 21 - .../dev/isxander/yacl/gui/SearchFieldWidget.java | 66 --- .../isxander/yacl/gui/TextScaledButtonWidget.java | 34 -- .../dev/isxander/yacl/gui/TooltipButtonWidget.java | 34 -- .../java/dev/isxander/yacl/gui/YACLScreen.java | 316 ------------ .../yacl/gui/controllers/ActionController.java | 120 ----- .../yacl/gui/controllers/BooleanController.java | 157 ------ .../yacl/gui/controllers/ColorController.java | 221 -------- .../yacl/gui/controllers/ControllerWidget.java | 170 ------ .../yacl/gui/controllers/LabelController.java | 193 ------- .../yacl/gui/controllers/ListEntryWidget.java | 133 ----- .../yacl/gui/controllers/TickBoxController.java | 120 ----- .../cycling/CyclingControllerElement.java | 60 --- .../controllers/cycling/CyclingListController.java | 79 --- .../gui/controllers/cycling/EnumController.java | 60 --- .../controllers/cycling/ICyclingController.java | 38 -- .../yacl/gui/controllers/package-info.java | 12 - .../controllers/slider/DoubleSliderController.java | 114 ----- .../controllers/slider/FloatSliderController.java | 114 ----- .../gui/controllers/slider/ISliderController.java | 54 -- .../slider/IntegerSliderController.java | 111 ---- .../controllers/slider/LongSliderController.java | 111 ---- .../slider/SliderControllerElement.java | 164 ------ .../yacl/gui/controllers/slider/package-info.java | 10 - .../gui/controllers/string/IStringController.java | 44 -- .../gui/controllers/string/StringController.java | 40 -- .../string/StringControllerElement.java | 408 --------------- .../string/number/DoubleFieldController.java | 104 ---- .../string/number/FloatFieldController.java | 104 ---- .../string/number/IntegerFieldController.java | 109 ---- .../string/number/LongFieldController.java | 109 ---- .../string/number/NumberFieldController.java | 69 --- .../controllers/string/number/package-info.java | 10 - .../java/dev/isxander/yacl/gui/utils/GuiUtils.java | 41 -- 40 files changed, 4570 deletions(-) delete mode 100644 src/client/java/dev/isxander/yacl/gui/AbstractWidget.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/CategoryListWidget.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/CategoryWidget.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/ElementListWidgetExt.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/LowProfileButtonWidget.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/OptionListWidget.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/RequireRestartScreen.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/SearchFieldWidget.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/TextScaledButtonWidget.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/TooltipButtonWidget.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/YACLScreen.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/ActionController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/BooleanController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/ColorController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/LabelController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/ListEntryWidget.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/TickBoxController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/cycling/CyclingListController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/cycling/EnumController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/cycling/ICyclingController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/package-info.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/slider/DoubleSliderController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/slider/FloatSliderController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/slider/ISliderController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/slider/IntegerSliderController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/slider/LongSliderController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/slider/package-info.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/string/IStringController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/string/StringController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/string/number/DoubleFieldController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/string/number/FloatFieldController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/string/number/IntegerFieldController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/string/number/LongFieldController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/string/number/NumberFieldController.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/controllers/string/number/package-info.java delete mode 100644 src/client/java/dev/isxander/yacl/gui/utils/GuiUtils.java (limited to 'src/client/java/dev/isxander/yacl/gui') diff --git a/src/client/java/dev/isxander/yacl/gui/AbstractWidget.java b/src/client/java/dev/isxander/yacl/gui/AbstractWidget.java deleted file mode 100644 index c6d2b09..0000000 --- a/src/client/java/dev/isxander/yacl/gui/AbstractWidget.java +++ /dev/null @@ -1,107 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import dev.isxander.yacl.api.utils.Dimension; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.GuiComponent; -import net.minecraft.client.gui.components.Renderable; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.narration.NarratableEntry; -import net.minecraft.client.gui.narration.NarrationElementOutput; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.resources.sounds.SimpleSoundInstance; -import net.minecraft.sounds.SoundEvents; - -import java.awt.Color; - -public abstract class AbstractWidget implements GuiEventListener, Renderable, NarratableEntry { - protected final Minecraft client = Minecraft.getInstance(); - protected final Font textRenderer = client.font; - protected final int inactiveColor = 0xFFA0A0A0; - - private Dimension dim; - - public AbstractWidget(Dimension dim) { - this.dim = dim; - } - - public void postRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - - } - - public boolean canReset() { - return false; - } - - @Override - public boolean isMouseOver(double mouseX, double mouseY) { - if (dim == null) return false; - return this.dim.isPointInside((int) mouseX, (int) mouseY); - } - - public void setDimension(Dimension dim) { - this.dim = dim; - } - - public Dimension getDimension() { - return dim; - } - - @Override - public NarrationPriority narrationPriority() { - return NarrationPriority.NONE; - } - - public void unfocus() { - - } - - public boolean matchesSearch(String query) { - return true; - } - - @Override - public void updateNarration(NarrationElementOutput builder) { - - } - - protected void drawButtonRect(PoseStack matrices, int x1, int y1, int x2, int y2, boolean hovered, boolean enabled) { - if (x1 > x2) { - int xx1 = x1; - x1 = x2; - x2 = xx1; - } - if (y1 > y2) { - int yy1 = y1; - y1 = y2; - y2 = yy1; - } - int width = x2 - x1; - int height = y2 - y1; - - RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderTexture(0, net.minecraft.client.gui.components.AbstractWidget.WIDGETS_LOCATION); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - int i = !enabled ? 0 : hovered ? 2 : 1; - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.enableDepthTest(); - GuiComponent.blit(matrices, x1, y1, 0, 0, 46 + i * 20, width / 2, height, 256, 256); - GuiComponent.blit(matrices, x1 + width / 2, y1, 0, 200 - width / 2f, 46 + i * 20, width / 2, height, 256, 256); - } - - protected int multiplyColor(int hex, float amount) { - Color color = new Color(hex, true); - - return new Color(Math.max((int)(color.getRed() * amount), 0), - Math.max((int)(color.getGreen() * amount), 0), - Math.max((int)(color.getBlue() * amount), 0), - color.getAlpha()).getRGB(); - } - - public void playDownSound() { - Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/CategoryListWidget.java b/src/client/java/dev/isxander/yacl/gui/CategoryListWidget.java deleted file mode 100644 index 41286ff..0000000 --- a/src/client/java/dev/isxander/yacl/gui/CategoryListWidget.java +++ /dev/null @@ -1,99 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import dev.isxander.yacl.api.ConfigCategory; -import dev.isxander.yacl.gui.utils.GuiUtils; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.narration.NarratableEntry; - -import java.util.List; - -public class CategoryListWidget extends ElementListWidgetExt { - private final YACLScreen yaclScreen; - - public CategoryListWidget(Minecraft client, YACLScreen yaclScreen, int screenWidth, int screenHeight) { - super(client, 0, 0, screenWidth / 3, yaclScreen.searchFieldWidget.getY() - 5, true); - this.yaclScreen = yaclScreen; - setRenderBackground(false); - setRenderTopAndBottom(false); - - for (ConfigCategory category : yaclScreen.config.categories()) { - addEntry(new CategoryEntry(category)); - } - } - - @Override - public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - GuiUtils.enableScissor(0, 0, width, height); - super.render(matrices, mouseX, mouseY, delta); - RenderSystem.disableScissor(); - } - - @Override - public int getRowWidth() { - return Math.min(width - width / 10, 396); - } - - @Override - public int getRowLeft() { - return super.getRowLeft() - 2; - } - - @Override - protected int getScrollbarPosition() { - return width - 2; - } - - @Override - protected void renderBackground(PoseStack matrices) { - - } - - public class CategoryEntry extends Entry { - private final CategoryWidget categoryButton; - public final int categoryIndex; - - public CategoryEntry(ConfigCategory category) { - this.categoryIndex = yaclScreen.config.categories().indexOf(category); - categoryButton = new CategoryWidget( - yaclScreen, - category, - categoryIndex, - getRowLeft(), 0, - getRowWidth(), 20 - ); - } - - @Override - public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - if (mouseY > y1) { - mouseY = -20; - } - - categoryButton.setY(y); - categoryButton.render(matrices, mouseX, mouseY, tickDelta); - } - - public void postRender(PoseStack matrices, int mouseX, int mouseY, float tickDelta) { - categoryButton.renderHoveredTooltip(matrices); - } - - @Override - public int getItemHeight() { - return 21; - } - - @Override - public List children() { - return ImmutableList.of(categoryButton); - } - - @Override - public List narratables() { - return ImmutableList.of(categoryButton); - } - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/CategoryWidget.java b/src/client/java/dev/isxander/yacl/gui/CategoryWidget.java deleted file mode 100644 index 60817a2..0000000 --- a/src/client/java/dev/isxander/yacl/gui/CategoryWidget.java +++ /dev/null @@ -1,38 +0,0 @@ -package dev.isxander.yacl.gui; - -import dev.isxander.yacl.api.ConfigCategory; -import net.minecraft.client.sounds.SoundManager; - -public class CategoryWidget extends TooltipButtonWidget { - private final int categoryIndex; - - public CategoryWidget(YACLScreen screen, ConfigCategory category, int categoryIndex, int x, int y, int width, int height) { - super(screen, x, y, width, height, category.name(), category.tooltip(), btn -> { - screen.searchFieldWidget.setValue(""); - screen.changeCategory(categoryIndex); - }); - this.categoryIndex = categoryIndex; - } - - private boolean isCurrentCategory() { - return ((YACLScreen) screen).getCurrentCategoryIdx() == categoryIndex; - } - - @Override - protected int getTextureY() { - int i = 1; - if (!this.active) { - i = 0; - } else if (this.isHoveredOrFocused() || isCurrentCategory()) { - i = 2; - } - - return 46 + i * 20; - } - - @Override - public void playDownSound(SoundManager soundManager) { - if (!isCurrentCategory()) - super.playDownSound(soundManager); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/ElementListWidgetExt.java b/src/client/java/dev/isxander/yacl/gui/ElementListWidgetExt.java deleted file mode 100644 index 46503a6..0000000 --- a/src/client/java/dev/isxander/yacl/gui/ElementListWidgetExt.java +++ /dev/null @@ -1,179 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.platform.InputConstants; -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.ContainerObjectSelectionList; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.util.Mth; -import org.jetbrains.annotations.Nullable; - -import java.util.Iterator; - -public class ElementListWidgetExt> extends ContainerObjectSelectionList { - protected final int x, y; - - private double smoothScrollAmount = getScrollAmount(); - private boolean returnSmoothAmount = false; - private final boolean doSmoothScrolling; - - public ElementListWidgetExt(Minecraft client, int x, int y, int width, int height, boolean smoothScrolling) { - super(client, width, height, y, y + height, 22); - this.x = this.x0 = x; - this.y = y; - this.x1 = this.x0 + 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(PoseStack matrices) { - // render transparent background if in-game. - setRenderBackground(minecraft.level == null); - if (minecraft.level != null) - fill(matrices, x0, y0, x1, y1, 0x6B000000); - } - - @Override - protected int getScrollbarPosition() { - // default implementation does not respect left/right - return this.x1 - 2; - } - - @Override - public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - smoothScrollAmount = Mth.lerp(Minecraft.getInstance().getDeltaFrameTime() * 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(PoseStack matrices, int mouseX, int mouseY, float delta) { - for (E entry : children()) { - entry.postRender(matrices, mouseX, mouseY, delta); - } - } - - @Nullable - @Override - protected E getEntryAtPosition(double x, double y) { - y += getScrollAmount(); - - if (x < this.x0 || x > this.x1) - return null; - - int currentY = this.y0 - headerHeight + 4; - for (E entry : children()) { - if (y >= currentY && y <= currentY + entry.getItemHeight()) { - return entry; - } - - currentY += entry.getItemHeight(); - } - - return null; - } - - /* - 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 - */ - - @Override - protected int getMaxPosition() { - return children().stream().map(E::getItemHeight).reduce(0, Integer::sum) + headerHeight; - } - - @Override - protected void centerScrollOn(E entry) { - double d = (this.height) / -2d; - for (int i = 0; i < this.children().indexOf(entry) && i < this.getItemCount(); i++) - d += children().get(i).getItemHeight(); - this.setScrollAmount(d); - } - - @Override - protected int getRowTop(int index) { - int integer = y0 + 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(PoseStack matrices, int mouseX, int mouseY, float delta) { - int left = this.getRowLeft(); - int right = this.getRowWidth(); - int count = this.getItemCount(); - - 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.y0 && top <= this.y1) { - this.renderItem(matrices, mouseX, mouseY, delta, i, left, top, right, entryHeight); - } - } - } - - /* END cloth config code */ - - public abstract static class Entry> extends ContainerObjectSelectionList.Entry { - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - for (GuiEventListener child : this.children()) { - if (child.mouseClicked(mouseX, mouseY, button)) { - if (button == InputConstants.MOUSE_BUTTON_LEFT) - this.setDragging(true); - return true; - } - } - - return false; - } - - @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - if (isDragging() && button == InputConstants.MOUSE_BUTTON_LEFT) { - for (GuiEventListener child : this.children()) { - if (child.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) - return true; - } - } - return false; - } - - public void postRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - - } - - public int getItemHeight() { - return 22; - } - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/LowProfileButtonWidget.java b/src/client/java/dev/isxander/yacl/gui/LowProfileButtonWidget.java deleted file mode 100644 index 7e17aac..0000000 --- a/src/client/java/dev/isxander/yacl/gui/LowProfileButtonWidget.java +++ /dev/null @@ -1,29 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.Tooltip; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; - -public class LowProfileButtonWidget extends Button { - public LowProfileButtonWidget(int x, int y, int width, int height, Component message, OnPress onPress) { - super(x, y, width, height, message, onPress, DEFAULT_NARRATION); - } - - public LowProfileButtonWidget(int x, int y, int width, int height, Component message, OnPress onPress, Tooltip tooltip) { - this(x, y, width, height, message, onPress); - setTooltip(tooltip); - } - - @Override - public void renderWidget(PoseStack matrices, int mouseX, int mouseY, float deltaTicks) { - if (!isHoveredOrFocused() || !active) { - int j = this.active ? 0xFFFFFF : 0xA0A0A0; - this.renderString(matrices, Minecraft.getInstance().font, j); - } else { - super.renderWidget(matrices, mouseX, mouseY, deltaTicks); - } - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/OptionListWidget.java b/src/client/java/dev/isxander/yacl/gui/OptionListWidget.java deleted file mode 100644 index 8f96ddf..0000000 --- a/src/client/java/dev/isxander/yacl/gui/OptionListWidget.java +++ /dev/null @@ -1,568 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.vertex.PoseStack; -import dev.isxander.yacl.api.*; -import dev.isxander.yacl.api.utils.Dimension; -import dev.isxander.yacl.impl.utils.YACLConstants; -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.components.MultiLineLabel; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.narration.NarratableEntry; -import net.minecraft.client.gui.narration.NarratedElementType; -import net.minecraft.client.gui.narration.NarrationElementOutput; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -public class OptionListWidget extends ElementListWidgetExt { - private final YACLScreen yaclScreen; - private boolean singleCategory = false; - - private ImmutableList viewableChildren; - - public OptionListWidget(YACLScreen screen, Minecraft client, int width, int height) { - super(client, width / 3, 0, width / 3 * 2 + 1, height, true); - this.yaclScreen = screen; - - refreshOptions(); - - for (ConfigCategory category : screen.config.categories()) { - for (OptionGroup group : category.groups()) { - if (group instanceof ListOption listOption) { - listOption.addRefreshListener(() -> refreshListEntries(listOption, category)); - } - } - } - } - - public void refreshOptions() { - clearEntries(); - - List categories = new ArrayList<>(); - if (yaclScreen.getCurrentCategoryIdx() == -1) { - // -1 = no category, search in progress, so use all categories for search - categories.addAll(yaclScreen.config.categories()); - } else { - categories.add(yaclScreen.config.categories().get(yaclScreen.getCurrentCategoryIdx())); - } - singleCategory = categories.size() == 1; - - for (ConfigCategory category : categories) { - for (OptionGroup group : category.groups()) { - GroupSeparatorEntry groupSeparatorEntry; - if (!group.isRoot()) { - groupSeparatorEntry = group instanceof ListOption listOption - ? new ListGroupSeparatorEntry(listOption, yaclScreen) - : new GroupSeparatorEntry(group, yaclScreen); - addEntry(groupSeparatorEntry); - } else { - groupSeparatorEntry = null; - } - - List optionEntries = new ArrayList<>(); - - // add empty entry to make sure users know it's empty not just bugging out - if (groupSeparatorEntry instanceof ListGroupSeparatorEntry listGroupSeparatorEntry) { - if (listGroupSeparatorEntry.listOption.options().isEmpty()) { - EmptyListLabel emptyListLabel = new EmptyListLabel(listGroupSeparatorEntry, category); - addEntry(emptyListLabel); - optionEntries.add(emptyListLabel); - } - } - - for (Option option : group.options()) { - OptionEntry entry = new OptionEntry(option, category, group, groupSeparatorEntry, option.controller().provideWidget(yaclScreen, getDefaultEntryDimension())); - addEntry(entry); - optionEntries.add(entry); - } - - if (groupSeparatorEntry != null) { - groupSeparatorEntry.setChildEntries(optionEntries); - } - } - } - - recacheViewableChildren(); - setScrollAmount(0); - resetSmoothScrolling(); - } - - private void refreshListEntries(ListOption listOption, ConfigCategory category) { - // find group separator for group - ListGroupSeparatorEntry groupSeparator = super.children().stream().filter(e -> e instanceof ListGroupSeparatorEntry gs && gs.group == listOption).map(ListGroupSeparatorEntry.class::cast).findAny().orElse(null); - - if (groupSeparator == null) { - YACLConstants.LOGGER.warn("Can't find group seperator to refresh list option entries for list option " + listOption.name()); - return; - } - - for (dev.isxander.yacl.gui.OptionListWidget.Entry entry : groupSeparator.childEntries) - super.removeEntry(entry); - groupSeparator.childEntries.clear(); - - // if no entries, below loop won't run where addEntryBelow() recaches viewable children - if (listOption.options().isEmpty()) { - EmptyListLabel emptyListLabel; - addEntryBelow(groupSeparator, emptyListLabel = new EmptyListLabel(groupSeparator, category)); - groupSeparator.childEntries.add(emptyListLabel); - return; - } - - dev.isxander.yacl.gui.OptionListWidget.Entry lastEntry = groupSeparator; - for (ListOptionEntry listOptionEntry : listOption.options()) { - OptionEntry optionEntry = new OptionEntry(listOptionEntry, category, listOption, groupSeparator, listOptionEntry.controller().provideWidget(yaclScreen, getDefaultEntryDimension())); - addEntryBelow(lastEntry, optionEntry); - groupSeparator.childEntries.add(optionEntry); - lastEntry = optionEntry; - } - } - - public Dimension getDefaultEntryDimension() { - return Dimension.ofInt(getRowLeft(), 0, getRowWidth(), 20); - } - - public void expandAllGroups() { - for (dev.isxander.yacl.gui.OptionListWidget.Entry entry : super.children()) { - if (entry instanceof GroupSeparatorEntry groupSeparatorEntry) { - groupSeparatorEntry.setExpanded(true); - } - } - } - - @Override - public int getRowWidth() { - return Math.min(396, (int)(width / 1.3f)); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - for (dev.isxander.yacl.gui.OptionListWidget.Entry child : children()) { - if (child != getEntryAtPosition(mouseX, mouseY) && child instanceof OptionEntry optionEntry) - optionEntry.widget.unfocus(); - } - - return super.mouseClicked(mouseX, mouseY, button); - } - - @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - super.mouseScrolled(mouseX, mouseY, amount); - - for (dev.isxander.yacl.gui.OptionListWidget.Entry child : children()) { - if (child.mouseScrolled(mouseX, mouseY, amount)) - break; - } - - return true; - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - for (dev.isxander.yacl.gui.OptionListWidget.Entry child : children()) { - if (child.keyPressed(keyCode, scanCode, modifiers)) - return true; - } - - return super.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - public boolean charTyped(char chr, int modifiers) { - for (dev.isxander.yacl.gui.OptionListWidget.Entry child : children()) { - if (child.charTyped(chr, modifiers)) - return true; - } - - return super.charTyped(chr, modifiers); - } - - @Override - protected int getScrollbarPosition() { - return x1 - (int)(width * 0.05f); - } - - public void recacheViewableChildren() { - this.viewableChildren = ImmutableList.copyOf(super.children().stream().filter(dev.isxander.yacl.gui.OptionListWidget.Entry::isViewable).toList()); - - // update y positions before they need to be rendered are rendered - int i = 0; - for (dev.isxander.yacl.gui.OptionListWidget.Entry entry : viewableChildren) { - if (entry instanceof OptionEntry optionEntry) - optionEntry.widget.setDimension(optionEntry.widget.getDimension().withY(getRowTop(i))); - i++; - } - } - - @Override - public List children() { - return viewableChildren; - } - - public void addEntry(int index, Entry entry) { - super.children().add(index, entry); - recacheViewableChildren(); - } - - public void addEntryBelow(Entry below, Entry entry) { - int idx = super.children().indexOf(below) + 1; - - if (idx == 0) - throw new IllegalStateException("The entry to insert below does not exist!"); - - addEntry(idx, entry); - } - - public void addEntryBelowWithoutScroll(Entry below, Entry entry) { - double d = (double)this.getMaxScroll() - this.getScrollAmount(); - addEntryBelow(below, entry); - setScrollAmount(getMaxScroll() - d); - } - - @Override - public boolean removeEntryFromTop(Entry entry) { - boolean ret = super.removeEntryFromTop(entry); - recacheViewableChildren(); - return ret; - } - - @Override - public boolean removeEntry(Entry entry) { - boolean ret = super.removeEntry(entry); - recacheViewableChildren(); - return ret; - } - - public abstract class Entry extends ElementListWidgetExt.Entry { - public boolean isViewable() { - return true; - } - - protected boolean isHovered() { - return Objects.equals(getHovered(), this); - } - } - - public class OptionEntry extends Entry { - public final Option option; - public final ConfigCategory category; - public final OptionGroup group; - - public final @Nullable GroupSeparatorEntry groupSeparatorEntry; - - public final AbstractWidget widget; - - private final TextScaledButtonWidget resetButton; - - private final String categoryName; - private final String groupName; - - public OptionEntry(Option option, ConfigCategory category, OptionGroup group, @Nullable GroupSeparatorEntry groupSeparatorEntry, AbstractWidget widget) { - this.option = option; - this.category = category; - this.group = group; - this.groupSeparatorEntry = groupSeparatorEntry; - this.widget = widget; - this.categoryName = category.name().getString().toLowerCase(); - this.groupName = group.name().getString().toLowerCase(); - if (option.canResetToDefault() && this.widget.canReset()) { - this.widget.setDimension(this.widget.getDimension().expanded(-20, 0)); - this.resetButton = new TextScaledButtonWidget(widget.getDimension().xLimit(), -50, 20, 20, 2f, Component.literal("\u21BB"), button -> { - option.requestSetDefault(); - }); - option.addListener((opt, val) -> this.resetButton.active = !opt.isPendingValueDefault() && opt.available()); - this.resetButton.active = !option.isPendingValueDefault() && option.available(); - } else { - this.resetButton = null; - } - } - - @Override - public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - widget.setDimension(widget.getDimension().withY(y)); - - widget.render(matrices, mouseX, mouseY, tickDelta); - - if (resetButton != null) { - resetButton.setY(y); - resetButton.render(matrices, mouseX, mouseY, tickDelta); - } - } - - @Override - public void postRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - widget.postRender(matrices, mouseX, mouseY, delta); - } - - @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - return widget.mouseScrolled(mouseX, mouseY, amount); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - return widget.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - public boolean charTyped(char chr, int modifiers) { - return widget.charTyped(chr, modifiers); - } - - @Override - public boolean isViewable() { - String query = yaclScreen.searchFieldWidget.getQuery(); - return (groupSeparatorEntry == null || groupSeparatorEntry.isExpanded()) - && (yaclScreen.searchFieldWidget.isEmpty() - || (!singleCategory && categoryName.contains(query)) - || groupName.contains(query) - || widget.matchesSearch(query)); - } - - @Override - public int getItemHeight() { - return Math.max(widget.getDimension().height(), resetButton != null ? resetButton.getHeight() : 0) + 2; - } - - @Override - public void setFocused(boolean focused) { - super.setFocused(focused); - } - - @Override - public List narratables() { - if (resetButton == null) - return ImmutableList.of(widget); - - return ImmutableList.of(widget, resetButton); - } - - @Override - public List children() { - if (resetButton == null) - return ImmutableList.of(widget); - - return ImmutableList.of(widget, resetButton); - } - } - - public class GroupSeparatorEntry extends Entry { - protected final OptionGroup group; - protected final MultiLineLabel wrappedName; - protected final MultiLineLabel wrappedTooltip; - - protected final LowProfileButtonWidget expandMinimizeButton; - - protected final Screen screen; - protected final Font font = Minecraft.getInstance().font; - - protected boolean groupExpanded; - - protected List childEntries = new ArrayList<>(); - - private int y; - - private GroupSeparatorEntry(OptionGroup group, Screen screen) { - this.group = group; - this.screen = screen; - this.wrappedName = MultiLineLabel.create(font, group.name(), getRowWidth() - 45); - this.wrappedTooltip = MultiLineLabel.create(font, group.tooltip(), screen.width / 3 * 2 - 10); - this.groupExpanded = !group.collapsed(); - this.expandMinimizeButton = new LowProfileButtonWidget(0, 0, 20, 20, Component.empty(), btn -> onExpandButtonPress()); - updateExpandMinimizeText(); - } - - @Override - public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - this.y = y; - - int buttonY = y + entryHeight / 2 - expandMinimizeButton.getHeight() / 2 + 1; - - expandMinimizeButton.setY(buttonY); - expandMinimizeButton.setX(x); - expandMinimizeButton.render(matrices, mouseX, mouseY, tickDelta); - - wrappedName.renderCentered(matrices, x + entryWidth / 2, y + getYPadding()); - } - - @Override - public void postRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - if ((isHovered() && !expandMinimizeButton.isMouseOver(mouseX, mouseY)) || expandMinimizeButton.isFocused()) { - YACLScreen.renderMultilineTooltip(matrices, font, wrappedTooltip, getRowLeft() + getRowWidth() / 2, y - 3, y + getItemHeight() + 3, screen.width, screen.height); - } - } - - public boolean isExpanded() { - return groupExpanded; - } - - public void setExpanded(boolean expanded) { - if (this.groupExpanded == expanded) - return; - - this.groupExpanded = expanded; - updateExpandMinimizeText(); - recacheViewableChildren(); - } - - protected void onExpandButtonPress() { - setExpanded(!isExpanded()); - } - - protected void updateExpandMinimizeText() { - expandMinimizeButton.setMessage(Component.literal(isExpanded() ? "▼" : "▶")); - } - - public void setChildEntries(List childEntries) { - this.childEntries.clear(); - this.childEntries.addAll(childEntries); - } - - @Override - public boolean isViewable() { - return yaclScreen.searchFieldWidget.isEmpty() || childEntries.stream().anyMatch(Entry::isViewable); - } - - @Override - public int getItemHeight() { - return Math.max(wrappedName.getLineCount(), 1) * font.lineHeight + getYPadding() * 2; - } - - private int getYPadding() { - return 6; - } - - @Override - public List narratables() { - return ImmutableList.of(new NarratableEntry() { - @Override - public NarratableEntry.NarrationPriority narrationPriority() { - return NarrationPriority.HOVERED; - } - - @Override - public void updateNarration(NarrationElementOutput builder) { - builder.add(NarratedElementType.TITLE, group.name()); - builder.add(NarratedElementType.HINT, group.tooltip()); - } - }); - } - - @Override - public List children() { - return ImmutableList.of(expandMinimizeButton); - } - } - - public class ListGroupSeparatorEntry extends GroupSeparatorEntry { - private final ListOption listOption; - private final TextScaledButtonWidget resetListButton; - private final TooltipButtonWidget addListButton; - - private ListGroupSeparatorEntry(ListOption group, Screen screen) { - super(group, screen); - this.listOption = group; - - this.resetListButton = new TextScaledButtonWidget(getRowRight() - 20, -50, 20, 20, 2f, Component.literal("\u21BB"), button -> { - group.requestSetDefault(); - }); - group.addListener((opt, val) -> this.resetListButton.active = !opt.isPendingValueDefault() && opt.available()); - this.resetListButton.active = !group.isPendingValueDefault() && group.available(); - - this.addListButton = new TooltipButtonWidget(yaclScreen, resetListButton.getX() - 20, -50, 20, 20, Component.literal("+"), Component.translatable("yacl.list.add_top"), btn -> { - group.insertNewEntryToTop(); - setExpanded(true); - }); - - updateExpandMinimizeText(); - minimizeIfUnavailable(); - } - - @Override - public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - updateExpandMinimizeText(); // update every render because option could become available/unavailable at any time - - super.render(matrices, index, y, x, entryWidth, entryHeight, mouseX, mouseY, hovered, tickDelta); - - int buttonY = expandMinimizeButton.getY(); - - resetListButton.setY(buttonY); - addListButton.setY(buttonY); - - resetListButton.render(matrices, mouseX, mouseY, tickDelta); - addListButton.render(matrices, mouseX, mouseY, tickDelta); - } - - @Override - public void postRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - minimizeIfUnavailable(); // cannot run in render because it *should* cause a ConcurrentModificationException (but doesn't) - - super.postRender(matrices, mouseX, mouseY, delta); - - addListButton.renderHoveredTooltip(matrices); - } - - private void minimizeIfUnavailable() { - if (!listOption.available() && isExpanded()) { - setExpanded(false); - } - } - - @Override - protected void updateExpandMinimizeText() { - super.updateExpandMinimizeText(); - expandMinimizeButton.active = listOption == null || listOption.available(); - if (addListButton != null) - addListButton.active = expandMinimizeButton.active; - } - - @Override - public List children() { - return ImmutableList.of(expandMinimizeButton, addListButton, resetListButton); - } - } - - public class EmptyListLabel extends Entry { - private final ListGroupSeparatorEntry parent; - private final String groupName; - private final String categoryName; - - public EmptyListLabel(ListGroupSeparatorEntry parent, ConfigCategory category) { - this.parent = parent; - this.groupName = parent.group.name().getString().toLowerCase(); - this.categoryName = category.name().getString().toLowerCase(); - } - - @Override - public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - drawCenteredString(matrices, Minecraft.getInstance().font, Component.translatable("yacl.list.empty").withStyle(ChatFormatting.DARK_GRAY, ChatFormatting.ITALIC), x + entryWidth / 2, y, -1); - } - - @Override - public boolean isViewable() { - String query = yaclScreen.searchFieldWidget.getQuery(); - return parent.isExpanded() && (yaclScreen.searchFieldWidget.isEmpty() - || (!singleCategory && categoryName.contains(query)) - || groupName.contains(query)); - } - - @Override - public int getItemHeight() { - return 11; - } - - @Override - public List children() { - return ImmutableList.of(); - } - - @Override - public List narratables() { - return ImmutableList.of(); - } - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/RequireRestartScreen.java b/src/client/java/dev/isxander/yacl/gui/RequireRestartScreen.java deleted file mode 100644 index 18b6033..0000000 --- a/src/client/java/dev/isxander/yacl/gui/RequireRestartScreen.java +++ /dev/null @@ -1,21 +0,0 @@ -package dev.isxander.yacl.gui; - -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.ConfirmScreen; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; - -public class RequireRestartScreen extends ConfirmScreen { - public RequireRestartScreen(Screen parent) { - super(option -> { - if (option) Minecraft.getInstance().stop(); - else Minecraft.getInstance().setScreen(parent); - }, - Component.translatable("yacl.restart.title").withStyle(ChatFormatting.RED, ChatFormatting.BOLD), - Component.translatable("yacl.restart.message"), - Component.translatable("yacl.restart.yes"), - Component.translatable("yacl.restart.no") - ); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/SearchFieldWidget.java b/src/client/java/dev/isxander/yacl/gui/SearchFieldWidget.java deleted file mode 100644 index 5cf38e0..0000000 --- a/src/client/java/dev/isxander/yacl/gui/SearchFieldWidget.java +++ /dev/null @@ -1,66 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.components.EditBox; -import net.minecraft.network.chat.Component; - -public class SearchFieldWidget extends EditBox { - private Component emptyText; - private final YACLScreen yaclScreen; - private final Font font; - - private boolean isEmpty = true; - - public SearchFieldWidget(YACLScreen yaclScreen, Font font, int x, int y, int width, int height, Component text, Component emptyText) { - super(font, x, y, width, height, text); - setResponder(string -> update()); - setFilter(string -> !string.endsWith(" ") && !string.startsWith(" ")); - this.yaclScreen = yaclScreen; - this.font = font; - this.emptyText = emptyText; - } - - @Override - public void renderWidget(PoseStack matrices, int mouseX, int mouseY, float delta) { - super.renderWidget(matrices, mouseX, mouseY, delta); - if (isVisible() && isEmpty()) { - font.drawShadow(matrices, emptyText, getX() + 4, this.getY() + (this.height - 8) / 2f, 0x707070); - } - } - - private void update() { - boolean wasEmpty = isEmpty; - isEmpty = getValue().isEmpty(); - - if (isEmpty && wasEmpty) - return; - - if (!isEmpty && yaclScreen.getCurrentCategoryIdx() != -1) - yaclScreen.changeCategory(-1); - if (isEmpty && yaclScreen.getCurrentCategoryIdx() == -1) - yaclScreen.changeCategory(0); - - yaclScreen.optionList.expandAllGroups(); - yaclScreen.optionList.recacheViewableChildren(); - - yaclScreen.optionList.setScrollAmount(0); - yaclScreen.categoryList.setScrollAmount(0); - } - - public String getQuery() { - return getValue().toLowerCase(); - } - - public boolean isEmpty() { - return isEmpty; - } - - public Component getEmptyText() { - return emptyText; - } - - public void setEmptyText(Component emptyText) { - this.emptyText = emptyText; - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/TextScaledButtonWidget.java b/src/client/java/dev/isxander/yacl/gui/TextScaledButtonWidget.java deleted file mode 100644 index b955912..0000000 --- a/src/client/java/dev/isxander/yacl/gui/TextScaledButtonWidget.java +++ /dev/null @@ -1,34 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.Tooltip; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; - -public class TextScaledButtonWidget extends Button { - public float textScale; - - public TextScaledButtonWidget(int x, int y, int width, int height, float textScale, Component message, OnPress onPress) { - super(x, y, width, height, message, onPress, DEFAULT_NARRATION); - this.textScale = textScale; - } - - public TextScaledButtonWidget(int x, int y, int width, int height, float textScale, Component message, OnPress onPress, Tooltip tooltip) { - this(x, y, width, height, textScale, message, onPress); - setTooltip(tooltip); - } - - @Override - public void renderString(PoseStack matrices, Font textRenderer, int color) { - Font font = Minecraft.getInstance().font; - - matrices.pushPose(); - matrices.translate(((this.getX() + this.width / 2f) - font.width(getMessage()) * textScale / 2), (float)this.getY() + (this.height - 8 * textScale) / 2f / textScale, 0); - matrices.scale(textScale, textScale, 1); - font.drawShadow(matrices, getMessage(), 0, 0, color | Mth.ceil(this.alpha * 255.0F) << 24); - matrices.popPose(); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/TooltipButtonWidget.java b/src/client/java/dev/isxander/yacl/gui/TooltipButtonWidget.java deleted file mode 100644 index 1395a3f..0000000 --- a/src/client/java/dev/isxander/yacl/gui/TooltipButtonWidget.java +++ /dev/null @@ -1,34 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.MultiLineLabel; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; - -public class TooltipButtonWidget extends TextScaledButtonWidget { - - protected final Screen screen; - protected MultiLineLabel wrappedDescription; - - public TooltipButtonWidget(Screen screen, int x, int y, int width, int height, Component message, float textScale, Component tooltip, Button.OnPress onPress) { - super(x, y, width, height, textScale, message, onPress); - this.screen = screen; - setTooltip(tooltip); - } - - public TooltipButtonWidget(Screen screen, int x, int y, int width, int height, Component message, Component tooltip, Button.OnPress onPress) { - this(screen, x, y, width, height, message, 1, tooltip, onPress); - } - - public void renderHoveredTooltip(PoseStack matrices) { - if (isHoveredOrFocused()) { - YACLScreen.renderMultilineTooltip(matrices, Minecraft.getInstance().font, wrappedDescription, getX() + width / 2, getY() - 4, getY() + height + 4, screen.width, screen.height); - } - } - - public void setTooltip(Component tooltip) { - wrappedDescription = MultiLineLabel.create(Minecraft.getInstance().font, tooltip, screen.width / 3 - 5); - } -} diff --git a/src/client/java/dev/isxander/yacl/gui/YACLScreen.java b/src/client/java/dev/isxander/yacl/gui/YACLScreen.java deleted file mode 100644 index d653d8c..0000000 --- a/src/client/java/dev/isxander/yacl/gui/YACLScreen.java +++ /dev/null @@ -1,316 +0,0 @@ -package dev.isxander.yacl.gui; - -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.*; -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.utils.GuiUtils; -import dev.isxander.yacl.impl.utils.YACLConstants; -import net.minecraft.ChatFormatting; -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.GuiComponent; -import net.minecraft.client.gui.components.MultiLineLabel; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.screens.Screen; -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 org.joml.Matrix4f; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; - -public class YACLScreen extends Screen { - public final YetAnotherConfigLib config; - private int currentCategoryIdx; - - private final Screen parent; - - public OptionListWidget optionList; - public CategoryListWidget categoryList; - public TooltipButtonWidget finishedSaveButton, cancelResetButton, undoButton; - public SearchFieldWidget searchFieldWidget; - - public Component saveButtonMessage, saveButtonTooltipMessage; - private int saveButtonMessageTime; - - - public YACLScreen(YetAnotherConfigLib config, Screen parent) { - super(config.title()); - this.config = config; - this.parent = parent; - this.currentCategoryIdx = 0; - } - - @Override - protected void init() { - int columnWidth = width / 3; - int padding = columnWidth / 20; - columnWidth = Math.min(columnWidth, 400); - int paddedWidth = columnWidth - padding * 2; - - MutableDimension actionDim = Dimension.ofInt(width / 3 / 2, height - padding - 20, paddedWidth, 20); - finishedSaveButton = new TooltipButtonWidget( - this, - actionDim.x() - actionDim.width() / 2, - actionDim.y(), - actionDim.width(), - actionDim.height(), - Component.empty(), - Component.empty(), - btn -> finishOrSave() - ); - actionDim.expand(-actionDim.width() / 2 - 2, 0).move(-actionDim.width() / 2 - 2, -22); - cancelResetButton = new TooltipButtonWidget( - this, - actionDim.x() - actionDim.width() / 2, - actionDim.y(), - actionDim.width(), - actionDim.height(), - Component.empty(), - Component.empty(), - btn -> cancelOrReset() - ); - actionDim.move(actionDim.width() + 4, 0); - undoButton = new TooltipButtonWidget( - this, - actionDim.x() - actionDim.width() / 2, - actionDim.y(), - actionDim.width(), - actionDim.height(), - Component.translatable("yacl.gui.undo"), - Component.translatable("yacl.gui.undo.tooltip"), - btn -> undo() - ); - - searchFieldWidget = new SearchFieldWidget( - this, - font, - width / 3 / 2 - paddedWidth / 2 + 1, - undoButton.getY() - 22, - paddedWidth - 2, 18, - Component.translatable("gui.recipebook.search_hint"), - Component.translatable("gui.recipebook.search_hint") - ); - - categoryList = new CategoryListWidget(minecraft, this, width, height); - addWidget(categoryList); - - updateActionAvailability(); - addRenderableWidget(searchFieldWidget); - addRenderableWidget(cancelResetButton); - addRenderableWidget(undoButton); - addRenderableWidget(finishedSaveButton); - - optionList = new OptionListWidget(this, minecraft, width, height); - addWidget(optionList); - - config.initConsumer().accept(this); - } - - @Override - public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - renderBackground(matrices); - - super.render(matrices, mouseX, mouseY, delta); - categoryList.render(matrices, mouseX, mouseY, delta); - searchFieldWidget.render(matrices, mouseX, mouseY, delta); - optionList.render(matrices, mouseX, mouseY, delta); - - categoryList.postRender(matrices, mouseX, mouseY, delta); - optionList.postRender(matrices, mouseX, mouseY, delta); - - for (GuiEventListener child : children()) { - if (child instanceof TooltipButtonWidget tooltipButtonWidget) { - tooltipButtonWidget.renderHoveredTooltip(matrices); - } - } - } - - protected void finishOrSave() { - saveButtonMessage = null; - - if (pendingChanges()) { - Set flags = new HashSet<>(); - OptionUtils.forEachOptions(config, option -> { - if (option.applyValue()) { - flags.addAll(option.flags()); - } - }); - OptionUtils.forEachOptions(config, option -> { - if (option.changed()) { - // if still changed after applying, reset to the current value from binding - // as something has gone wrong. - option.forgetPendingValue(); - YACLConstants.LOGGER.error("Option '{}' value mismatch after applying! Reset to binding's getter.", option.name().getString()); - } - }); - config.saveFunction().run(); - - flags.forEach(flag -> flag.accept(minecraft)); - } else onClose(); - } - - protected void cancelOrReset() { - if (pendingChanges()) { // if pending changes, button acts as a cancel button - OptionUtils.forEachOptions(config, Option::forgetPendingValue); - onClose(); - } else { // if not, button acts as a reset button - OptionUtils.forEachOptions(config, Option::requestSetDefault); - } - } - - protected void undo() { - OptionUtils.forEachOptions(config, Option::forgetPendingValue); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (optionList.keyPressed(keyCode, scanCode, modifiers)) { - return true; - } - - return super.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - public boolean charTyped(char chr, int modifiers) { - if (optionList.charTyped(chr, modifiers)) { - return true; - } - - return super.charTyped(chr, modifiers); - } - - public void changeCategory(int idx) { - if (idx == currentCategoryIdx) - return; - - if (idx != -1 && config.categories().get(idx) instanceof PlaceholderCategory placeholderCategory) { - minecraft.setScreen(placeholderCategory.screen().apply(minecraft, this)); - } else { - currentCategoryIdx = idx; - optionList.refreshOptions(); - } - } - - public int getCurrentCategoryIdx() { - return currentCategoryIdx; - } - - private void updateActionAvailability() { - boolean pendingChanges = pendingChanges(); - - undoButton.active = pendingChanges; - finishedSaveButton.setMessage(pendingChanges ? Component.translatable("yacl.gui.save") : GuiUtils.translatableFallback("yacl.gui.done", CommonComponents.GUI_DONE)); - finishedSaveButton.setTooltip(pendingChanges ? Component.translatable("yacl.gui.save.tooltip") : Component.translatable("yacl.gui.finished.tooltip")); - cancelResetButton.setMessage(pendingChanges ? GuiUtils.translatableFallback("yacl.gui.cancel", CommonComponents.GUI_CANCEL) : Component.translatable("controls.reset")); - cancelResetButton.setTooltip(pendingChanges ? Component.translatable("yacl.gui.cancel.tooltip") : Component.translatable("yacl.gui.reset.tooltip")); - } - - @Override - public void tick() { - searchFieldWidget.tick(); - - updateActionAvailability(); - - if (saveButtonMessage != null) { - if (saveButtonMessageTime > 140) { - saveButtonMessage = null; - saveButtonTooltipMessage = null; - saveButtonMessageTime = 0; - } else { - saveButtonMessageTime++; - finishedSaveButton.setMessage(saveButtonMessage); - if (saveButtonTooltipMessage != null) { - finishedSaveButton.setTooltip(saveButtonTooltipMessage); - } - } - } - } - - private void setSaveButtonMessage(Component message, Component tooltip) { - saveButtonMessage = message; - saveButtonTooltipMessage = tooltip; - saveButtonMessageTime = 0; - } - - private boolean pendingChanges() { - AtomicBoolean pendingChanges = new AtomicBoolean(false); - OptionUtils.consumeOptions(config, (option) -> { - if (option.changed()) { - pendingChanges.set(true); - return true; - } - return false; - }); - - return pendingChanges.get(); - } - - @Override - public boolean shouldCloseOnEsc() { - if (pendingChanges()) { - setSaveButtonMessage(Component.translatable("yacl.gui.save_before_exit").withStyle(ChatFormatting.RED), Component.translatable("yacl.gui.save_before_exit.tooltip")); - return false; - } - return true; - } - - @Override - public void onClose() { - minecraft.setScreen(parent); - } - - public static void renderMultilineTooltip(PoseStack matrices, Font font, MultiLineLabel text, int centerX, int yAbove, int yBelow, int screenWidth, int screenHeight) { - if (text.getLineCount() > 0) { - int maxWidth = text.getWidth(); - int lineHeight = font.lineHeight + 1; - int height = text.getLineCount() * lineHeight - 1; - - int belowY = yBelow + 12; - int aboveY = yAbove - height + 12; - int maxBelow = screenHeight - (belowY + height); - int minAbove = aboveY - height; - int y = aboveY; - if (minAbove < 8) - y = maxBelow > minAbove ? belowY : aboveY; - - int x = Math.max(centerX - text.getWidth() / 2 - 12, -6); - - int drawX = x + 12; - int drawY = y - 12; - - matrices.pushPose(); - Tesselator tesselator = Tesselator.getInstance(); - BufferBuilder bufferBuilder = tesselator.getBuilder(); - RenderSystem.setShader(GameRenderer::getPositionColorShader); - bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); - Matrix4f matrix4f = matrices.last().pose(); - TooltipRenderUtil.renderTooltipBackground( - GuiComponent::fillGradient, - matrix4f, - bufferBuilder, -