aboutsummaryrefslogtreecommitdiff
path: root/runtime-frontend/overlay/src/main/java
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2022-08-28 18:50:24 +0900
committershedaniel <daniel@shedaniel.me>2022-08-28 18:50:24 +0900
commit94e323f75c17e297c33fba1d3afb5c47ae66a8ad (patch)
tree3c6cb6c1721fbda792050b96707fad50d1db64e9 /runtime-frontend/overlay/src/main/java
parentf5061d043cac7f0217bbe9d4c041b77f9ef911a1 (diff)
downloadRoughlyEnoughItems-94e323f75c17e297c33fba1d3afb5c47ae66a8ad.tar.gz
RoughlyEnoughItems-94e323f75c17e297c33fba1d3afb5c47ae66a8ad.tar.bz2
RoughlyEnoughItems-94e323f75c17e297c33fba1d3afb5c47ae66a8ad.zip
Separate EntryListWidget and FavoritesListWidget more
Diffstat (limited to 'runtime-frontend/overlay/src/main/java')
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/DraggingContextImpl.java311
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/AbstractMenuEntry.java77
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/Menu.java209
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/MenuAccess.java64
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/MenuAccessImpl.java134
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/MenuEntry.java44
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/entries/EmptyMenuEntry.java58
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/entries/SeparatorMenuEntry.java53
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/entries/SubMenuEntry.java153
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/entries/TextMenuEntry.java70
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/entries/ToggleMenuEntry.java143
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/AbstractScreenOverlay.java330
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/EntryListProvider.java9
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/FavoritesListProvider.java11
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/InternalOverlayBounds.java56
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/LateRenderable.java30
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/ScreenOverlayImpl.java231
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListProvider.java33
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListWidget.java44
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListProvider.java34
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListWidget.java36
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/DisplayTooltipComponent.java82
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/DisplayedEntryWidget.java236
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/OverlayWidgetProvider.java37
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/RegionRenderingDebugger.java80
-rw-r--r--runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/ScaleIndicatorWidget.java72
26 files changed, 2617 insertions, 20 deletions
diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/DraggingContextImpl.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/DraggingContextImpl.java
new file mode 100644
index 000000000..ea78fa47a
--- /dev/null
+++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/DraggingContextImpl.java
@@ -0,0 +1,311 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.client.gui.dragging;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+import me.shedaniel.clothconfig2.api.animator.NumberAnimator;
+import me.shedaniel.clothconfig2.api.animator.ValueAnimator;
+import me.shedaniel.math.FloatingRectangle;
+import me.shedaniel.math.Point;
+import me.shedaniel.math.Rectangle;
+import me.shedaniel.rei.api.client.gui.drag.DraggableBoundsProvider;
+import me.shedaniel.rei.api.client.gui.drag.DraggableStack;
+import me.shedaniel.rei.api.client.gui.drag.DraggedAcceptorResult;
+import me.shedaniel.rei.api.client.gui.drag.DraggingContext;
+import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponent;
+import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentProvider;
+import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentVisitor;
+import me.shedaniel.rei.api.client.gui.widgets.Widget;
+import me.shedaniel.rei.impl.client.gui.InternalCursorState;
+import net.minecraft.Util;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.components.events.GuiEventListener;
+import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.world.phys.Vec2;
+import net.minecraft.world.phys.shapes.VoxelShape;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+import java.util.function.Supplier;
+
+@SuppressWarnings("UnstableApiUsage")
+public class DraggingContextImpl extends Widget implements DraggingContext<Screen> {
+ private DraggableComponentProvider<Screen, ?> provider;
+ private DraggableComponentVisitor<Screen> visitor;
+ @Nullable
+ private DraggableEntry entry;
+ private final List<RenderBackEntry> backToOriginals = new ArrayList<>();
+ private final Set<ShapeBounds> bounds = new HashSet<>();
+
+ public void set(DraggableComponentProvider<Screen, ?> provider, DraggableComponentVisitor<Screen> visitor) {
+ this.provider = provider;
+ this.visitor = visitor;
+ }
+
+ @Override
+ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
+ Integer hash = null;
+
+ if (entry != null) {
+ if (!entry.dragging) {
+ Point startPoint = entry.start;
+ double xDistance = Math.abs(startPoint.x - mouseX);
+ double yDistance = Math.abs(startPoint.y - mouseY);
+ double requiredDistance = 8;
+
+ if (xDistance * xDistance + yDistance * yDistance > requiredDistance * requiredDistance) {
+ entry.dragging = true;
+ entry.startDragging = Util.getMillis();
+ entry.component.drag();
+ }
+ }
+
+ if (entry.dragging) {
+ matrices.pushPose();
+ matrices.translate(0, 0, 600);
+ entry.bounds.update(delta);
+ int width = entry.component.getWidth();
+ int height = entry.component.getHeight();
+ Vec2 mouseStartOffset = entry.mouseStartOffset;
+ entry.bounds.setTo(new FloatingRectangle(mouseX - width / 2 - mouseStartOffset.x, mouseY - height / 2 - mouseStartOffset.y, width, height),
+ 30);
+ entry.component.render(matrices, entry.bounds.value().getBounds(), mouseX, mouseY, delta);
+ matrices.popPose();
+
+ VoxelShape shape = entry.getBoundsProvider().bounds();
+ ShapeBounds shapeBounds = new ShapeBounds(shape);
+ shapeBounds.alpha.setTo(60, 300);
+ bounds.add(shapeBounds);
+ hash = shapeBounds.hash;
+ }
+
+ if (!InternalCursorState.isLeftMousePressed) {
+ drop();
+ }
+ }
+
+ for (ShapeBounds bound : bounds) {
+ if ((hash == null || hash != bound.hash) && bound.alpha.target() != 0) {
+ bound.alpha.setTo(0, 300);
+ }
+ }
+
+ {
+ Iterator<ShapeBounds> iterator = bounds.iterator();
+ while (iterator.hasNext()) {
+ ShapeBounds bounds = iterator.next();
+ bounds.update(delta);
+ if (bounds.alpha.target() == 0 && bounds.alpha.value() <= 2) {
+ iterator.remove();
+ } else {
+ bounds.shape.forAllBoxes((x1, y1, z1, x2, y2, z2) -> {
+ matrices.pushPose();
+ matrices.translate(0, 0, 500);
+ fillGradient(matrices, (int) x1, (int) y1, (int) x2, (int) y2, 0xfdff6b | (bounds.alpha.intValue() << 24), 0xfdff6b | (bounds.alpha.intValue() << 24));
+ matrices.popPose();
+ });
+ }
+ }
+ }
+
+ Iterator<RenderBackEntry> iterator = backToOriginals.iterator();
+ while (iterator.hasNext()) {
+ RenderBackEntry renderBackEntry = iterator.next();
+ renderBackEntry.update(delta);
+ FloatingRectangle value = renderBackEntry.bounds.value();
+ FloatingRectangle target = renderBackEntry.bounds.target();
+ if (value.width < 2 || value.height < 2 || (Math.abs(value.x - target.x) <= 1.3 && Math.abs(value.y - target.y) <= 1.3 && Math.abs(value.width - target.width) <= 1 && Math.abs(value.height - target.height) <= 1)) {
+ iterator.remove();
+ } else {
+ matrices.pushPose();
+ matrices.translate(0, 0, 600);
+ renderBackEntry.component.render(matrices, value.getBounds(), mouseX, mouseY, delta);
+ matrices.popPose();
+ }
+ }
+ }
+
+ @Override
+ public List<? extends GuiEventListener> children() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public boolean mouseClicked(double mouseX, double mouseY, int button) {
+ drop();
+ DraggableComponent<?> hoveredStack = provider.getHovered(this, mouseX, mouseY);
+ if (hoveredStack != null) {
+ entry = new DraggableEntry(hoveredStack, new Point(mouseX, mouseY));
+ }
+ return false;
+ }
+
+ @Override
+ public boolean mouseReleased(double d, double e, int i) {
+ return false;
+ }
+
+ @Override
+ public boolean mouseDragged(double mouseX1, double mouseY1, int button, double mouseX2, double mouseY2) {
+ return entry != null && entry.dragging;
+ }
+
+ private boolean drop() {
+ if (entry != null && entry.dragging) {
+ DraggedAcceptorResult result = visitor.acceptDragged(this, entry.component);
+ entry.component.release(result);
+ entry = null;
+ return true;
+ }
+
+ entry = null;
+ return false;
+ }
+
+ @Override
+ public Screen getScreen() {
+ return Minecraft.getInstance().screen;
+ }
+
+ @Override
+ @Nullable
+ public DraggableStack getCurrentStack() {
+ DraggableComponent<?> dragged = getDragged();
+ return dragged instanceof DraggableStack ? (DraggableStack) dragged : null;
+ }
+
+ @Override
+ @Nullable
+ public DraggableComponent<?> getDragged() {
+ return entry != null && entry.dragging ? entry.component : null;
+ }
+
+ @Override
+ @Nullable
+ public Point getCurrentPosition() {
+ if (!isDraggingComponent()) return null;
+ Vec2 mouseStartOffset = entry.mouseStartOffset;
+ FloatingRectangle rectangle = entry.bounds.value();
+ return new Point(rectangle.getCenterX() + mouseStartOffset.x, rectangle.getCenterY() + mouseStartOffset.y);
+ }
+
+ @Override
+ @Nullable
+ public Rectangle getCurrentBounds() {
+ if (!isDraggingComponent()) return null;
+ FloatingRectangle rectangle = entry.bounds.value();
+ return rectangle.getBounds();
+ }
+
+ @Override
+ public void renderBack(DraggableComponent<?> component, Point initialPosition, Supplier<Point> position) {
+ int width = component.getWidth();
+ int height = component.getHeight();
+ backToOriginals.add(new RenderBackEntry(component, new Rectangle(initialPosition.x - width / 2, initialPosition.y - height / 2, width, height), () -> {
+ Point point = position.get();
+ return new Rectangle(point.x, point.y, width, height);
+ }));
+ }
+
+ @Override
+ public void renderBack(DraggableComponent<?> component, Rectangle initialPosition, Supplier<Rectangle> bounds) {
+ backToOriginals.add(new RenderBackEntry(component, initialPosition, bounds));
+ }
+
+ private class DraggableEntry {
+ private final DraggableComponent<?> component;
+ private final Point start;
+ private long startDragging = -1;
+ private final ValueAnimator<FloatingRectangle> bounds;
+ private final Vec2 mouseStartOffset;
+ private boolean dragging = false;
+ private DraggableBoundsProvider boundsProvider;
+
+ private DraggableEntry(DraggableComponent<?> component, Point start) {
+ this.component = component;
+ this.start = start;
+ this.bounds = ValueAnimator.ofFloatingRectangle()
+ .setAs(component.getOriginBounds(start).getFloatingBounds());
+ this.mouseStartOffset = new Vec2((float) (start.x - bounds.value().getCenterX()), (float) (start.y - bounds.value().getCenterY()));
+ }
+
+ public DraggableBoundsProvider getBoundsProvider() {
+ if (boundsProvider == null) {
+ boundsProvider = DraggableBoundsProvider.concat(visitor.getDraggableAcceptingBounds(DraggingContextImpl.this, component).toList());
+ }
+
+ return boundsProvider;
+ }
+ }
+
+ private static class ShapeBounds {
+ private final VoxelShape shape;
+ private final NumberAnimator<Double> alpha;
+ private final int hash;
+
+ public ShapeBounds(VoxelShape shape) {
+ this.shape = shape;
+ this.alpha = ValueAnimator.ofDouble(0);
+ this.hash = shape.toAabbs().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ShapeBounds shapeBounds)) return false;
+ return hash == shapeBounds.hash;
+ }
+
+ @Override
+ public int hashCode() {
+ return hash;
+ }
+
+ public void update(double delta) {
+ this.alpha.update(delta);
+ }
+ }
+
+ private static class RenderBackEntry {
+ private final DraggableComponent<?> component;
+ private final Supplier<Rectangle> position;
+ private final ValueAnimator<FloatingRectangle> bounds = ValueAnimator.ofFloatingRectangle();
+ private final int lastDestination = -1;
+
+ public RenderBackEntry(DraggableComponent<?> component, Rectangle initialPosition, Supplier<Rectangle> position) {
+ this.component = component;
+ this.bounds.setAs(new FloatingRectangle(initialPosition));
+ this.position = position;
+ }
+
+ public Rectangle getPosition() {
+ return position.get();
+ }
+
+ public void update(double delta) {
+ this.bounds.update(delta);
+ this.bounds.setTo(new FloatingRectangle(getPosition()), 200);
+ }
+ }
+}
diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/AbstractMenuEntry.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/AbstractMenuEntry.java
new file mode 100644
index 000000000..0debff33b
--- /dev/null
+++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/AbstractMenuEntry.java
@@ -0,0 +1,77 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.client.gui.menu;
+
+public abstract class AbstractMenuEntry extends MenuEntry {
+ private int x, y, width;
+ private boolean selected, containsMouse, rendering;
+
+ @Override
+ public void updateInformation(int xPos, int yPos, boolean selected, boolean containsMouse, boolean rendering, int width) {
+ this.x = xPos;
+ this.y = yPos;
+ this.selected = selected;
+ this.containsMouse = containsMouse;
+ this.rendering = rendering;
+ this.width = width;
+ }
+
+ @Override
+ public boolean mouseClicked(double mouseX, double mouseY, int button) {
+ if (isRendering() && mouseX >= getX() && mouseX <= getX() + getWidth() && mouseY >= getY() && mouseY < getY() + getEntryHeight()) {
+ if (onClick(mouseX, mouseY, button)) {
+ return true;
+ }
+ }
+ return super.mouseClicked(mouseX, mouseY, button);
+ }
+
+ protected boolean onClick(double mouseX, double mouseY, int button) {
+ return false;
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public boolean isSelected() {
+ return selected;
+ }
+
+ public boolean containsMouse() {
+ return containsMouse;
+ }
+
+ public boolean isRendering() {
+ return rendering;
+ }
+}
diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/Menu.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/Menu.java
new file mode 100644
index 000000000..4bbb47671
--- /dev/null
+++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/menu/Menu.java
@@ -0,0 +1,209 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.client.gui.menu;
+
+import com.google.common.collect.Lists;
+import com.mojang.blaze3d.vertex.PoseStack;
+import me.shedaniel.clothconfig2.ClothConfigInitializer;
+import me.shedaniel.clothconfig2.api.ScissorsHandler;
+import me.shedaniel.clothconfig2.api.scroll.ScrollingContainer;
+import me.shedaniel.math.Point;
+import me.shedaniel.math.Rectangle;
+import me.shedaniel.rei.api.client.config.ConfigObject;
+import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds;
+import me.shedaniel.rei.impl.client.gui.menu.entries.SubMenuEntry;
+import net.minecraft.client.Minecraft;
+import org.jetbrains.annotations.ApiStatus;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.UUID;
+
+@ApiStatus.Internal
+public class Menu extends WidgetWithBounds {
+ public static final UUID WEATHER = UUID.randomUUID();
+ public static final UUID GAME_TYPE = UUID.randomUUID();
+
+ public final Point menuStartPoint;
+ public final boolean facingRight;
+ public final boolean facingDownwards;
+ private final List<MenuEntry> entries = Lists.newArrayList();
+ public final ScrollingContainer scrolling = new ScrollingContainer() {
+ @Override
+ public int getMaxScrollHeight() {
+ int i = 0;
+ for (MenuEntry entry : children()) {
+ i += entry.getEntryHeight();
+ }
+ return i;
+ }
+
+ @Override
+ public Rectangle getBounds() {
+ return Menu.this.getInnerBounds();
+ }
+
+ @Override
+ public boolean hasScrollBar() {
+ return Menu.this.hasScrollBar();
+ }
+ };
+
+ public Menu(Rectangle menuStart, Collection<MenuEntry> entries, boolean sort) {
+ buildEntries(entries, sort);
+ int fullWidth = Minecraft.getInstance().screen.width;
+ int fullHeight = Minecraft.getInstance().screen.height;
+ boolean facingRight = true;
+ this.facingDownwards = fullHeight - menuStart.getMaxY() > menuStart.y;
+ int y = facingDownwards ? menuStart.getMaxY() : menuStart.y - (scrolling.getMaxScrollHeight() + 2);
+ boolean hasScrollBar = scrolling.getMaxScrollHeight() > getInnerHeight(y);
+ int menuWidth = getMaxEntryWidth() + 2 + (hasScrollBar ? 6 : 0);
+ if (facingRight && fullWidth - menuStart.getMaxX() < menuWidth + 10) {
+ facingRight = false;
+ } else if (!facingRight && menuStart.x < menuWidth + 10) {
+ facingRight = true;
+ }
+ this.facingRight = facingRight;
+ int x = facingRight ? menuStart.x : menuStart.getMaxX() - (getMaxEntryWidth() + 2 + (hasScrollBar ? 6 : 0));
+ this.menuStartPoint = new Point(x, y);
+ }
+
+ @SuppressWarnings("deprecation")
+ private void buildEntries(Collection<MenuEntry> entries, boolean sort) {
+ this.entries.clear();
+ this.entries.addAll(entries);
+ if (sort) {
+ this.entries.sort(Comparator.comparing(entry -> entry instanceof SubMenuEntry ? 0 : 1)
+ .thenComparing(entry -> entry instanceof SubMenuEntry menuEntry ? menuEntry.text.getString() : ""));
+ }
+ for (MenuEntry entry : this.entries) {
+ entry.parent = this;
+ }
+ }
+
+ @Override
+ public Rectangle getBounds() {
+ return new Rectangle(menuStartPoint.x, menuStartPoint.y, getMaxEntryWidth() + 2 + (hasScrollBar() ? 6 : 0), getInnerHeight(menuStartPoint.y) + 2);
+ }
+
+ public Rectangle getInnerBounds() {
+ return new Rectangle(menuStartPoint.x + 1, menuStartPoint.y + 1, getMaxEntryWidth() + (hasScrollBar() ? 6 : 0), getInnerHeight(menuStartPoint.y));
+ }
+
+ public boolean hasScrollBar() {
+ return scrolling.getMaxScrollHeight() > getInnerHeight(menuStartPoint.y);
+ }
+
+ public int getInnerHeight(int y) {
+ return Math.min(scrolling.getMaxScrollHeight(), minecraft.screen.height - 20 - y);
+ }
+
+ public int getMaxEntryWidth() {
+ int i = 0;
+ for (MenuEntry entry : children()) {
+ if (entry.getEntryWidth() > i)
+ i = entry.getEntryWidth();
+ }
+ return Math.max(10, i);
+ }
+
+ @Override
+ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
+ Rectangle bounds = getBounds();
+ Rectangle innerBounds = getInnerBounds();
+ fill(matrices, bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), containsMouse(mouseX, mouseY) ? (ConfigObject.getInstance().isUsingDarkTheme() ? -17587 : -1) : -6250336);
+ fill(matrices, innerBounds.x, innerBounds.y, innerBounds.getMaxX(), innerBounds.getMaxY(), -16777216);
+ boolean contains = innerBounds.contains(mouseX, mouseY);
+ MenuEntry focused = getFocused() instanceof MenuEntry menuEntry ? menuEntry : null;
+ int currentY = innerBounds.y - scrolling.scrollAmountInt();
+ for (MenuEntry child : children()) {
+ boolean containsMouse = contains && mouseY >= currentY && mouseY < currentY + child.getEntryHeight();
+ if (containsMouse) {
+ focused = child;
+ }
+ currentY += child.getEntryHeight();
+ }
+ currentY = innerBounds.y - scrolling.scrollAmountInt();
+ ScissorsHandler.INSTANCE.scissor(scrolling.getScissorBounds());
+ for (MenuEntry child : children()) {
+ boolean rendering = currentY + child.getEntryHeight() >= innerBounds.y && currentY <= innerBounds.getMaxY();
+ boolean containsMouse = contains && mouseY >= currentY && mouseY < currentY + child.getEntryHeight();
+ child.updateInformation(innerBounds.x, currentY, focused == child || containsMouse, containsMouse, rendering, getMaxEntryWidth());
+ if (rendering) {
+ child.render(matrices, mouseX, mouseY, delta);
+ }
+ currentY += child.getEntryHeight();
+ }
+ ScissorsHandler.INSTANCE.removeLastScissor();
+ setFocused(focused);
+ scrolling.renderScrollBar(0, 1, ConfigObject.getInstance().isUsingDarkTheme() ? 0.8f : 1f);
+ scrolling.updatePosition(delta);
+ }
+
+ @Override
+ public boolean mouseClicked(double mouseX, double mouseY, int button) {
+ if (scrolling.updateDraggingState(mouseX, mouseY, button))
+ return true;
+ return super.mouseClicked(mouseX, mouseY, button) || getInnerBounds().contains(mouseX, mouseY);
+ }
+
+ @Override
+ public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
+ if (scrolling.mouseDragged(mouseX, mouseY, button, deltaX, deltaY))
+ return true;
+ return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
+ }
+
+ @Override
+ public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
+ if (getInnerBounds().contains(mouseX, mouseY)) {
+ scrolling.offset(ClothConfigInitializer.getScrollStep() * -amount, true);
+ return true;
+ }
+ for (MenuEntry child : children()) {
+ if (child instanceof SubMenuEntry) {
+ if (child.mouseScrolled(mouseX, mouseY, amount))
+ return true;
+ }
+ }
+ return super.mouseScrolled(mouseX, mouseY, amount);
+ }
+
+ @Override
+ public boolean containsMouse(double mouseX, double mouseY) {
+ if (super.containsMouse(mouseX, mouseY)) return true;
+ for (M