diff options
author | vicisacat <victor.branchu@gmail.com> | 2024-04-17 23:07:49 +0200 |
---|---|---|
committer | vicisacat <victor.branchu@gmail.com> | 2024-04-20 16:09:49 +0200 |
commit | f0ff0b555621f2d7f240bc72ccc1c7667badab6f (patch) | |
tree | 76feeb4c44483a364cce571eecc4809022c13411 /src/main/java/de/hysky/skyblocker/skyblock/fancybars | |
parent | b791e38cbd36360935164e337fa992bf514cbb36 (diff) | |
download | Skyblocker-f0ff0b555621f2d7f240bc72ccc1c7667badab6f.tar.gz Skyblocker-f0ff0b555621f2d7f240bc72ccc1c7667badab6f.tar.bz2 Skyblocker-f0ff0b555621f2d7f240bc72ccc1c7667badab6f.zip |
things happened yea
rewrote the entire thing to use semi data-driven BarAnchors
help button in the config screen
Diffstat (limited to 'src/main/java/de/hysky/skyblocker/skyblock/fancybars')
3 files changed, 494 insertions, 151 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/fancybars/BarPositioner.java b/src/main/java/de/hysky/skyblocker/skyblock/fancybars/BarPositioner.java new file mode 100644 index 00000000..7fde9117 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/fancybars/BarPositioner.java @@ -0,0 +1,319 @@ +package de.hysky.skyblocker.skyblock.fancybars; + +import net.minecraft.client.gui.ScreenPos; +import net.minecraft.client.gui.ScreenRect; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class BarPositioner { + + private final Map<BarAnchor, LinkedList<LinkedList<StatusBar>>> map = new HashMap<>(BarAnchor.values().length); + + public BarPositioner() { + for (BarAnchor value : BarAnchor.values()) { + map.put(value, new LinkedList<>()); + } + } + + + public int getRowCount(@NotNull BarAnchor barAnchor) { + return map.get(barAnchor).size(); + } + + /** + * Adds a row to the end of an anchor + * + * @param barAnchor the anchor + */ + public void addRow(@NotNull BarAnchor barAnchor) { + map.get(barAnchor).add(new LinkedList<>()); + } + + /** + * Adds a row at the specified index + * + * @param barAnchor the anchor + * @param row row index + */ + public void addRow(@NotNull BarAnchor barAnchor, int row) { + map.get(barAnchor).add(row, new LinkedList<>()); + } + + /** + * adds a bar to the end of a row + * + * @param barAnchor the anchor + * @param row the row + * @param bar the bar to add + */ + public void addBar(@NotNull BarAnchor barAnchor, int row, StatusBar bar) { + LinkedList<StatusBar> statusBars = map.get(barAnchor).get(row); + statusBars.add(bar); + bar.gridY = row; + bar.gridX = statusBars.lastIndexOf(bar); // optimization baby, start with the end! + bar.anchor = barAnchor; + } + + /** + * adds a bar to the specified x in a row + * + * @param barAnchor the anchor + * @param row the row + * @param x the index in the row + * @param bar the bar to add + */ + public void addBar(@NotNull BarAnchor barAnchor, int row, int x, StatusBar bar) { + LinkedList<StatusBar> statusBars = map.get(barAnchor).get(row); + statusBars.add(x, bar); + bar.gridY = row; + bar.gridX = statusBars.indexOf(bar); + bar.anchor = barAnchor; + } + + /** + * removes the specified bar at x on the row. If it's row is empty after being removed, the row will be auto removed + * + * @param barAnchor the anchor + * @param row dah row + * @param x dah x + */ + public void removeBar(@NotNull BarAnchor barAnchor, int row, int x) { + LinkedList<StatusBar> statusBars = map.get(barAnchor).get(row); + StatusBar remove = statusBars.remove(x); + remove.anchor = null; + for (int i = x; i < statusBars.size(); i++) { + statusBars.get(i).gridX--; + } + if (statusBars.isEmpty()) removeRow(barAnchor, row); + } + + /** + * removes the specified bar on the row. If it's row is empty after being removed, the row will be auto removed + * + * @param barAnchor the anchor + * @param row dah row + * @param bar dah bar + */ + public void removeBar(@NotNull BarAnchor barAnchor, int row, StatusBar bar) { + LinkedList<StatusBar> barRow = map.get(barAnchor).get(row); + int x = barRow.indexOf(bar); + if (x < 0) return; // probably a bad idea + + barRow.remove(bar); + bar.anchor = null; + for (int i = x; i < barRow.size(); i++) { + barRow.get(i).gridX--; + } + if (barRow.isEmpty()) removeRow(barAnchor, row); + } + + /** + * row must be empty + * + * @param barAnchor the anchor + * @param row the row to remove + */ + public void removeRow(@NotNull BarAnchor barAnchor, int row) { + LinkedList<StatusBar> barRow = map.get(barAnchor).get(row); + if (!barRow.isEmpty()) + throw new IllegalStateException("Can't remove a non-empty row (" + barAnchor + "," + row + ")"); + map.get(barAnchor).remove(row); + for (int i = row; i < map.get(barAnchor).size(); i++) { + for (StatusBar statusBar : map.get(barAnchor).get(i)) { + statusBar.gridY--; + } + } + } + + + public LinkedList<StatusBar> getRow(@NotNull BarAnchor barAnchor, int row) { + return map.get(barAnchor).get(row); + } + + public StatusBar getBar(@NotNull BarAnchor barAnchor, int row, int x) { + return map.get(barAnchor).get(row).get(x); + } + + public boolean hasNeighbor(@NotNull BarAnchor barAnchor, int row, int x, boolean right) { + LinkedList<StatusBar> statusBars = map.get(barAnchor).get(row); + if (barAnchor.isRight()) { + return (right && x < statusBars.size() - 1) || (!right && x > 0); + } else { + return (right && x > 0) || (!right && x < statusBars.size() - 1); + } + } + + + public enum BarAnchor { + HOTBAR_LEFT(true, false, + (scaledWidth, scaledHeight) -> new ScreenPos(scaledWidth / 2 - 91 - 2, scaledHeight - 5), + SizeRule.freeSize(25, 2, 6)), + + HOTBAR_RIGHT(true, true, + (scaledWidth, scaledHeight) -> new ScreenPos(scaledWidth / 2 + 91 + 2, scaledHeight - 5), + SizeRule.freeSize(25, 2, 6)), + + HOTBAR_TOP(true, true, + (scaledWidth, scaledHeight) -> new ScreenPos(scaledWidth / 2 - 91, scaledHeight - 23), + SizeRule.targetSize(12, 182, 2), + anchorPosition -> new ScreenRect(anchorPosition.x(), anchorPosition.y() - 20, 182, 20)), + + SCREEN_TOP_LEFT(false, true, + ((scaledWidth, scaledHeight) -> new ScreenPos(5, 5)), + SizeRule.freeSize(25, 2, 6) + ), + SCREEN_TOP_RIGHT(false, false, + ((scaledWidth, scaledHeight) -> new ScreenPos(scaledWidth - 5, 5)), + SizeRule.freeSize(25, 2, 6) + ), + SCREEN_BOTTOM_LEFT(true, true, + ((scaledWidth, scaledHeight) -> new ScreenPos(5, scaledHeight - 5)), + SizeRule.freeSize(25, 2, 6) + ), + SCREEN_BOTTOM_RIGHT(true, false, + ((scaledWidth, scaledHeight) -> new ScreenPos(scaledWidth - 5, scaledHeight - 5)), + SizeRule.freeSize(25, 2, 6) + ), + ; + + private final AnchorPositionProvider positionProvider; + private final AnchorHitboxProvider hitboxProvider; + private final boolean up; + private final boolean right; + private final SizeRule sizeRule; + + /** + * @param up whether the rows stack towards the top of the screen from the anchor (false is bottom) + * @param right whether the bars are line up towards the right of the screen from the anchor (false is left) + * @param positionProvider provides the position of the anchor for a give screen size + * @param sizeRule the rule the bars should follow. See {@link SizeRule} + * @param hitboxProvider provides the hitbox for when the anchor has no bars for the config screen + */ + BarAnchor(boolean up, boolean right, AnchorPositionProvider positionProvider, SizeRule sizeRule, AnchorHitboxProvider hitboxProvider) { + this.positionProvider = positionProvider; + this.up = up; + this.right = right; + this.hitboxProvider = hitboxProvider; + this.sizeRule = sizeRule; + } + + BarAnchor(boolean up, boolean right, AnchorPositionProvider positionProvider, SizeRule sizeRule) { + this(up, right, positionProvider, sizeRule, + anchorPosition -> new ScreenRect(anchorPosition.x() - (right ? 0 : 20), anchorPosition.y() - (up ? 20 : 0), 20, 20)); + } + + public ScreenPos getAnchorPosition(int scaledWidth, int scaledHeight) { + return positionProvider.getPosition(scaledWidth, scaledHeight); + } + + public ScreenRect getAnchorHitbox(ScreenPos anchorPosition) { + return hitboxProvider.getHitbox(anchorPosition); + } + + /** + * whether the rows stack towards the top of the screen from the anchor (false is bottom) + * + * @return true if towards the top, false otherwise + */ + public boolean isUp() { + return up; + } + + /** + * whether the bars are line up towards the right of the screen from the anchor (false is left) + * + * @return true if towards the right, false otherwise + */ + public boolean isRight() { + return right; + } + + public SizeRule getSizeRule() { + return sizeRule; + } + + private static final List<BarAnchor> cached = List.of(values()); + + /** + * cached version of {@link BarAnchor#values()} + * + * @return the list of anchors + */ + public static List<BarAnchor> allAnchors() { + return cached; + } + } + + /** + * The rules the bars on an anchor should follow + * + * @param isTargetSize whether the bars went to fit to a target width + * @param targetSize the size of all the bars on a row should add up to this (target size) + * @param totalWidth the total width taken by all the bars on the row (target size) + * @param widthPerSize the width of each size "unit" (free size) + * @param minSize the minimum (free and target size) + * @param maxSize the maximum (free and target size, THIS SHOULD BE THE SAME AS {@code targetSize} FOR {@code isTargetSize = true}) + */ + public record SizeRule(boolean isTargetSize, int targetSize, int totalWidth, int widthPerSize, int minSize, + int maxSize) { + public static SizeRule freeSize(int widthPerSize, int minSize, int maxSize) { + return new SizeRule(false, -1, -1, widthPerSize, minSize, maxSize); + } + + public static SizeRule targetSize(int targetSize, int totalWidth, int minSize) { + return new SizeRule(true, targetSize, totalWidth, -1, minSize, targetSize); + } + } + + /** + * A record representing a snapshot of a bar's position + * + * @param barAnchor + * @param x + * @param y the row + */ + public record BarLocation(@Nullable BarAnchor barAnchor, int x, int y) { + + public static final BarLocation NULL = new BarLocation(null, -1, -1); + + public static BarLocation of(StatusBar bar) { + return new BarLocation(bar.anchor, bar.gridX, bar.gridY); + } + + @Override + public boolean equals(Object object) { + if (this == object) return true; + if (object == null || getClass() != object.getClass()) return false; + + BarLocation that = (BarLocation) object; + return x == that.x && y == that.y && barAnchor == that.barAnchor; + } + + public boolean equals(BarAnchor barAnchor, int x, int y) { + return x == this.x && y == this.y && barAnchor == this.barAnchor; + } + } + + /** + * provides the position of the anchor for a give screen size + */ + @FunctionalInterface + interface AnchorPositionProvider { + + ScreenPos getPosition(int scaledWidth, int scaledHeight); + } + + @FunctionalInterface + interface AnchorHitboxProvider { + + /** + * The hitbox, as in how large the area of "snapping" is if there are no bars on this anchor + * + * @param anchorPosition the position of the anchor + * @return the rectangle that represents the hitbox + */ + ScreenRect getHitbox(ScreenPos anchorPosition); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBar.java b/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBar.java index ea4a0388..5ece1934 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBar.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBar.java @@ -86,12 +86,14 @@ public class StatusBar implements Widget, Drawable, Element, Selectable { private @Nullable OnClick onClick = null; public int gridX = 0; public int gridY = 0; + public @Nullable BarPositioner.BarAnchor anchor = null; public int size = 1; private int width = 0; public float fill = 0; public float overflowFill = 0; + public boolean ghost = false; private Object value = ""; @@ -116,6 +118,8 @@ public class StatusBar implements Widget, Drawable, Element, Selectable { @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { if (width <= 0) return; + // half works lol. only puts transparency on the filler of the bar + if (ghost) context.setShaderColor(1f,1f,1f,0.25f); switch (iconPosition) { case LEFT -> context.drawGuiTexture(icon, x, y, 9, 9); case RIGHT -> context.drawGuiTexture(icon, x + width - 9, y, 9, 9); @@ -130,6 +134,7 @@ public class StatusBar implements Widget, Drawable, Element, Selectable { if (hasOverflow && overflowFill > 0) { RenderHelper.renderNineSliceColored(context, BAR_FILL, barX + 1, y + 2, (int) ((barWith - 2) * overflowFill), 5, colors[1]); } + if (ghost) context.setShaderColor(1f,1f,1f,1f); //context.drawText(MinecraftClient.getInstance().textRenderer, gridX + " " + gridY + " s:" + size , x, y-9, Colors.WHITE, true); } @@ -159,13 +164,19 @@ public class StatusBar implements Widget, Drawable, Element, Selectable { int temp_x = x; int temp_y = y; int temp_width = width; + boolean temp_ghost = ghost; + x = mouseX; y = mouseY; width = 100; + ghost = false; + render(context, mouseX, mouseY, delta); + x = temp_x; y = temp_y; width = temp_width; + ghost = temp_ghost; } // GUI shenanigans @@ -204,14 +215,6 @@ public class StatusBar implements Widget, Drawable, Element, Selectable { return 9; } - public int getMinimumSize() { - return 2; - } - - public int getMaximumSize() { - return gridY < 0 ? 6 : 12; - } - @Override public ScreenRect getNavigationFocus() { return Widget.super.getNavigationFocus(); @@ -267,6 +270,7 @@ public class StatusBar implements Widget, Drawable, Element, Selectable { .append("x", x) .append("y", y) .append("width", width) + .append("anchor", anchor) .toString(); } @@ -315,11 +319,13 @@ public class StatusBar implements Widget, Drawable, Element, Selectable { if (object.has("text_color")) this.textColor = new Color(Integer.parseInt(object.get("text_color").getAsString(), 16)); + String maybeAnchor = object.get("anchor").getAsString().trim(); + this.anchor = maybeAnchor.equals("null") ? null : BarPositioner.BarAnchor.valueOf(maybeAnchor); this.size = object.get("size").getAsInt(); this.gridX = object.get("x").getAsInt(); this.gridY = object.get("y").getAsInt(); // these are optional too, why not - if (object.has("icon_position")) this.iconPosition = IconPosition.valueOf(object.get("icon_position").getAsString()); + if (object.has("icon_position")) this.iconPosition = IconPosition.valueOf(object.get("icon_position").getAsString().trim()); if (object.has("show_text")) this.showText = object.get("show_text").getAsBoolean(); } @@ -335,6 +341,9 @@ public class StatusBar implements Widget, Drawable, Element, Selectable { object.addProperty("text_color", Integer.toHexString(textColor.getRGB()).substring(2)); } object.addProperty("size", size); + if (anchor != null) { + object.addProperty("anchor", anchor.toString()); + } else object.addProperty("anchor", "null"); object.addProperty("x", gridX); object.addProperty("y", gridY); object.addProperty("icon_position", iconPosition.toString()); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBarsConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBarsConfigScreen.java index 3bcc2011..7c1aa71b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBarsConfigScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBarsConfigScreen.java @@ -10,12 +10,14 @@ import net.minecraft.client.gui.ScreenPos; import net.minecraft.client.gui.ScreenRect; import net.minecraft.client.gui.navigation.NavigationAxis; import net.minecraft.client.gui.navigation.NavigationDirection; +import net.minecraft.client.gui.screen.PopupScreen; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.text.Text; -import net.minecraft.util.Colors; import net.minecraft.util.Identifier; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; +import de.hysky.skyblocker.skyblock.fancybars.BarPositioner.BarLocation; import java.util.Collection; import java.util.HashMap; @@ -27,7 +29,7 @@ public class StatusBarsConfigScreen extends Screen { public static final long RESIZE_CURSOR = GLFW.glfwCreateStandardCursor(GLFW.GLFW_HRESIZE_CURSOR); - private final Map<ScreenRect, int[]> meaningFullName = new HashMap<>(); + private final Map<ScreenRect, BarLocation> meaningFullName = new HashMap<>(); private static final int HOTBAR_WIDTH = 182; private @Nullable StatusBar cursorBar = null; @@ -37,21 +39,24 @@ public class StatusBarsConfigScreen extends Screen { FancyStatusBars.updatePositions(); } - private final int[] currentCursorCoords = new int[]{0, 0}; + private BarLocation currentInsertLocation = new BarLocation(null, 0, 0); - private final Pair<int[], Boolean> resizeHover = new ObjectBooleanMutablePair<>(new int[]{0, 0}, false); + private final Pair<BarLocation, Boolean> resizeHover = new ObjectBooleanMutablePair<>(BarLocation.NULL, false); - private final Pair<int[], int[]> resizedBars = ObjectObjectMutablePair.of(new int[]{0, 0}, new int[]{0, 0}); + private final Pair<BarLocation, BarLocation> resizedBars = ObjectObjectMutablePair.of(BarLocation.NULL, BarLocation.NULL); private boolean resizing = false; private EditBarWidget editBarWidget; + // prioritize left and right cuz they are much smaller space than up and down + private static final NavigationDirection[] DIRECTION_CHECK_ORDER = new NavigationDirection[]{NavigationDirection.LEFT, NavigationDirection.RIGHT, NavigationDirection.UP, NavigationDirection.DOWN}; + @SuppressWarnings("UnreachableCode") // IntelliJ big stupid @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { - for (ScreenRect screenRect : meaningFullName.keySet()) { + /*for (ScreenRect screenRect : meaningFullName.keySet()) { context.fillGradient(screenRect.position().x(), screenRect.position().y(), screenRect.position().x() + screenRect.width(), screenRect.position().y() + screenRect.height(), 0xFFFF0000, 0xFF0000FF); - } + }*/ super.render(context, mouseX, mouseY, delta); context.drawGuiTexture(HOTBAR_TEXTURE, width / 2 - HOTBAR_WIDTH / 2, height - 22, HOTBAR_WIDTH, 22); editBarWidget.render(context, mouseX, mouseY, delta); @@ -60,109 +65,99 @@ public class StatusBarsConfigScreen extends Screen { assert client != null; WindowAccessor window = (WindowAccessor) (Object) client.getWindow(); assert window != null; + if (cursorBar != null) { cursorBar.renderCursor(context, mouseX, mouseY, delta); - context.drawText(textRenderer, currentCursorCoords[0] + " " + currentCursorCoords[1], 100, 5, Colors.WHITE, true); - - - if (FancyStatusBars.barGrid.getTopSize() == 0 && topBarZone.overlaps(mouseRect) && currentCursorCoords[1] != 1) { - FancyStatusBars.barGrid.remove(cursorBar.gridX, cursorBar.gridY); - FancyStatusBars.barGrid.addRow(1, true); - FancyStatusBars.barGrid.add(1, 1, cursorBar); - currentCursorCoords[1] = 1; - FancyStatusBars.updatePositions(); - } else if (FancyStatusBars.barGrid.getBottomLeftSize() == 0 && bottomLeftBarZone.overlaps(mouseRect) && (currentCursorCoords[0] != -1 || currentCursorCoords[1] != -1)) { - FancyStatusBars.barGrid.remove(cursorBar.gridX, cursorBar.gridY); - FancyStatusBars.barGrid.addRow(-1, false); - FancyStatusBars.barGrid.add(-1, -1, cursorBar); - currentCursorCoords[0] = -1; - currentCursorCoords[1] = -1; - FancyStatusBars.updatePositions(); - } else if (FancyStatusBars.barGrid.getBottomRightSize() == 0 && bottomRightBarZone.overlaps(mouseRect) && (currentCursorCoords[0] != 1 || currentCursorCoords[1] != -1)) { - FancyStatusBars.barGrid.remove(cursorBar.gridX, cursorBar.gridY); - FancyStatusBars.barGrid.addRow(-1, true); - FancyStatusBars.barGrid.add(1, -1, cursorBar); - currentCursorCoords[0] = 1; - currentCursorCoords[1] = -1; - FancyStatusBars.updatePositions(); - } else rectLoop:for (ScreenRect screenRect : meaningFullName.keySet()) { - for (NavigationDirection direction : NavigationDirection.values()) { + boolean inserted = false; + rectLoop: + for (ScreenRect screenRect : meaningFullName.keySet()) { + for (NavigationDirection direction : DIRECTION_CHECK_ORDER) { boolean overlaps = screenRect.getBorder(direction).add(direction).overlaps(mouseRect); if (overlaps) { - int[] ints = meaningFullName.get(screenRect); - final boolean vertical = direction.getAxis().equals(NavigationAxis.VERTICAL); - int offsetX = 0; - int offsetY = 0; - if (vertical) { - if (!direction.isPositive()) { - offsetY = ints[1] > 0 ? 1 : 0; - } else { - offsetY = ints[1] > 0 ? 0 : -1; + BarLocation barSnap = meaningFullName.get(screenRect); + if (direction.getAxis().equals(NavigationAxis.VERTICAL)) { + int neighborInsertY = getNeighborInsertY(barSnap, !direction.isPositive()); + if (!currentInsertLocation.equals(barSnap.barAnchor(), barSnap.x(), neighborInsertY)) { + if (cursorBar.anchor != null) + FancyStatusBars.barPositioner.removeBar(cursorBar.anchor, cursorBar.gridY, cursorBar); + FancyStatusBars.barPositioner.addRow(barSnap.barAnchor(), neighborInsertY); + FancyStatusBars.barPositioner.addBar(barSnap.barAnchor(), neighborInsertY, cursorBar); + currentInsertLocation = BarLocation.of(cursorBar); + inserted = true; } } else { - if (direction.isPositive()) { - offsetX = ints[0] > 0 ? 1 : 0; - } else { - offsetX = ints[0] > 0 ? 0 : -1; - } - } - context.drawText(textRenderer, ints[0] + offsetX + " " + ints[1] + offsetY, 100, 15, Colors.WHITE, true); - if (ints[0] + offsetX != currentCursorCoords[0] || ints[1] + offsetY != currentCursorCoords[1]) { - currentCursorCoords[0] = ints[0] + offsetX; - currentCursorCoords[1] = ints[1] + offsetY; - FancyStatusBars.barGrid.remove(cursorBar.gridX, cursorBar.gridY); - - - if (vertical) { - - FancyStatusBars.barGrid.addRow(ints[1] + offsetY, ints[0] > 0); - FancyStatusBars.barGrid.add(ints[0] < 0 ? -1 : 1, ints[1] + offsetY, cursorBar); - } else { - - FancyStatusBars.barGrid.add(ints[0] + offsetX, ints[1], cursorBar); + int neighborInsertX = getNeighborInsertX(barSnap, direction.isPositive()); + if (!currentInsertLocation.equals(barSnap.barAnchor(), neighborInsertX, barSnap.y())) { + if (cursorBar.anchor != null) + FancyStatusBars.barPositioner.removeBar(cursorBar.anchor, cursorBar.gridY, cursorBar); + FancyStatusBars.barPositioner.addBar(barSnap.barAnchor(), barSnap.y(), neighborInsertX, cursorBar); + currentInsertLocation = BarLocation.of(cursorBar); + inserted = true; } - FancyStatusBars.updatePositions(); } break rectLoop; } } } + if (inserted) { + FancyStatusBars.updatePositions(); + return; + } + // check for hovering empty anchors + for (BarPositioner.BarAnchor barAnchor : BarPositioner.BarAnchor.allAnchors()) { + if (FancyStatusBars.barPositioner.getRowCount(barAnchor) != 0) continue; + ScreenRect anchorHitbox = barAnchor.getAnchorHitbox(barAnchor.getAnchorPosition(width, height)); + context.fill(anchorHitbox.getLeft(), anchorHitbox.getTop(), anchorHitbox.getRight(), anchorHitbox.getBottom(), 0x99FFFFFF); + if (anchorHitbox.overlaps(mouseRect) && currentInsertLocation.barAnchor() != barAnchor) { + if (cursorBar.anchor != null) + FancyStatusBars.barPositioner.removeBar(cursorBar.anchor, cursorBar.gridY, cursorBar); + FancyStatusBars.barPositioner.addRow(barAnchor); + FancyStatusBars.barPositioner.addBar(barAnchor, 0, cursorBar); + currentInsertLocation = BarLocation.of(cursorBar); + FancyStatusBars.updatePositions(); + } + } } else { - // RESIZING STATE - if (resizing) { + if (resizing) { // actively resizing one or 2 bars int middleX; - boolean bottom; - int[] left = resizedBars.left(); - int[] right = resizedBars.right(); - boolean hasRight = right[0] != 0; - boolean hasLeft = left[0] != 0; + BarLocation left = resizedBars.left(); + BarLocation right = resizedBars.right(); + boolean hasRight = !right.equals(BarLocation.NULL); + boolean hasLeft = !left.equals(BarLocation.NULL); + BarPositioner.BarAnchor barAnchor; if (!hasRight) { - StatusBar bar = FancyStatusBars.barGrid.getBar(left[0], left[1]); + barAnchor = left.barAnchor(); + StatusBar bar = FancyStatusBars.barPositioner.getBar(barAnchor, left.y(), left.x()); middleX = bar.getX() + bar.getWidth(); - bottom = bar.gridY < 0; } else { - middleX = FancyStatusBars.barGrid.getBar(right[0], right[1]).getX(); - bottom = right[1] < 0; + barAnchor = right.barAnchor(); + middleX = FancyStatusBars.barPositioner.getBar(barAnchor, right.y(), right.x()).getX(); } - int i = bottom ? 20 : 10; + boolean doResize = true; StatusBar rightBar = null; StatusBar leftBar = null; - context.drawText(textRenderer, Integer.toString(mouseX - middleX), 100, 25, -1, true); + BarPositioner.SizeRule sizeRule = barAnchor.getSizeRule(); - if (mouseX < middleX) { - if (middleX - mouseX > i) { + float widthPerSize; + if (sizeRule.isTargetSize()) + widthPerSize = (float) sizeRule.totalWidth() / sizeRule.targetSize(); + else + widthPerSize = sizeRule.widthPerSize(); + // resize towards the left + if (mouseX < middleX) { + if (middleX - mouseX > widthPerSize / .75f) { if (hasRight) { - rightBar = FancyStatusBars.barGrid.getBar(right[0], right[1]); - if (rightBar.size + 1 > rightBar.getMaximumSize()) doResize = false; + rightBar = FancyStatusBars.barPositioner.getBar(barAnchor, right.y(), right.x()); + if (rightBar.size + 1 > sizeRule.maxSize()) doResize = false; } if (hasLeft) { - leftBar = FancyStatusBars.barGrid.getBar(left[0], left[1]); - if (leftBar.size - 1 < leftBar.getMinimumSize()) doResize = false; + leftBar = FancyStatusBars.barPositioner.getBar(barAnchor, left.y(), left.x()); + if (leftBar.size - 1 < sizeRule.minSize()) doResize = false; } if (doResize) { @@ -171,18 +166,16 @@ public class StatusBarsConfigScreen extends Screen { FancyStatusBars.updatePositions(); } } - } else { - if (mouseX - middleX > i) { - + } else { // towards the right + if (mouseX - middleX > widthPerSize / .75f) { if (hasRight) { - rightBar = FancyStatusBars.barGrid.getBar(right[0], right[1]); - if (rightBar.size - 1 < rightBar.getMinimumSize()) doResize = false; + rightBar = FancyStatusBars.barPositioner.getBar(barAnchor, right.y(), right.x()); + if (rightBar.size - 1 < sizeRule.minSize()) doResize = false; } if (hasLeft) { - leftBar = FancyStatusBars.barGrid.getBar(left[0], left[1]); - if (leftBar.size + 1 > leftBar.getMaximumSize()) doResize = false; + leftBar = FancyStatusBars.barPositioner.getBar(barAnchor, left.y(), left.x()); + if (leftBar.size + 1 > sizeRule.maxSize()) doResize = false; } - context.drawText(textRenderer, leftBar.size + " " + leftBar.getMaximumSize(), 100, 35, -1, true); if (doResize) { if (hasRight) rightBar.size--; @@ -191,29 +184,26 @@ public class StatusBarsConfigScreen extends Screen { } } } - GLFW.glfwSetCursor(window.getHandle(), RESIZE_CURSOR); - } - // NOT RESIZING STATE - else { + + } else { // hovering bars rectLoop: for (ScreenRect screenRect : meaningFullName.keySet()) { for (NavigationDirection direction : new NavigationDirection[]{NavigationDirection.LEFT, NavigationDirection.RIGHT}) { boolean overlaps = screenRect.getBorder(direction).add(direction).overlaps(mouseRect); if (overlaps && !editBarWidget.isMouseOver(mouseX, mouseY)) { - int[] ints = meaningFullName.get(screenRect); - boolean left = direction.equals(NavigationDirection.LEFT); - if ((ints[0] == 1 && left) || (ints[0] == -1 && !left) || (!left && ints[1] > 0 && ints[0] == FancyStatusBars.barGrid.getRow(ints[1], true).size())) { + BarLocation barLocation = meaningFullName.get(screenRect); + boolean right = direction.equals(NavigationDirection.RIGHT); + // can't resize on the edge of a target size row! + if (barLocation.barAnchor().getSizeRule().isTargetSize() && !FancyStatusBars.barPositioner.hasNeighbor(barLocation.barAnchor(), barLocation.y(), barLocation.x(), right)) { break; } - resizeHover.first()[0] = ints[0]; - resizeHover.first()[1] = ints[1]; - resizeHover.right(!left); + resizeHover.first(barLocation); + resizeHover.right(right); GLFW.glfwSetCursor(window.getHandle(), RESIZE_CURSOR); break rectLoop; } else { - resizeHover.first()[0] = 0; - resizeHover.first()[1] = 0; + resizeHover.first(BarLocation.NULL); GLFW.glfwSetCursor(window.getHandle(), 0); } } @@ -222,9 +212,27 @@ public class StatusBarsConfigScreen extends Screen { } } - private ScreenRect topBarZone = new ScreenRect(0, 0, 0, 0); - private ScreenRect bottomLeftBarZone = new ScreenRect(0, 0, 0, 0); - private ScreenRect bottomRightBarZone = new ScreenRect(0, 0, 0, 0); + private static int getNeighborInsertX(BarLocation barLocation, boolean right) { + BarPositioner.BarAnchor barAnchor = barLocation.barAnchor(); + int gridX = barLocation.x(); + if (barAnchor == null) return 0; + if (right) { + return barAnchor.isRight() ? gridX + 1 : gridX; + } else { + return barAnchor.isRight() ? gridX : gridX + 1; + } + } + + private static int getNeighborInsertY(BarLocation barLocation, boolean up) { + BarPositioner.BarAnchor barAnchor = barLocation.barAnchor(); + int gridY = barLocation.y(); + if (barAnchor == null) return 0; + if (up) { + return barAnchor.isUp() ? gridY + 1 : gridY; + } else { + return barAnchor.isUp() ? gridY : gridY + 1; + } + } @Override protected void init() { @@ -234,24 +242,31 @@ public class StatusBarsConfigScreen extends Screen { addSelectableChild(editBarWidget); // rendering separately to have it above hotbar Collection<StatusBar> values = FancyStatusBars.statusBars.values(); values.forEach(this::setup); - checkZeroCoordinates(values); + checkNullAnchor(values); updateScreenRects(); - topBarZone = new ScreenRect(width / 2 - HOTBAR_WIDTH / 2, height - 22 - 15, HOTBAR_WIDTH, 15); - bottomLeftBarZone = new ScreenRect(width / 2 - HOTBAR_WIDTH / 2 - 20, height - 22, 20, 22); - bottomRightBarZone = new ScreenRect(width / 2 + HOTBAR_WIDTH / 2, height - 22, 20, 22); + this.addDrawableChild(ButtonWidget.builder(Text.literal("?"), + button -> { + assert client != null; + client.setScreen(new PopupScreen.Builder(this, Text.translatable("skyblocker.bars.config.explanationTitle")) + .button(Text.translatable("gui.ok"), PopupScreen::close) + .message(Text.translatable("skyblocker.bars.config.explanation")) + .build()); + }) + .dimensions(width - 20, (height - 15) / 2, 15, 15) + .build()); } private void setup(StatusBar statusBar) { this.addDrawableChild(statusBar); - statusBar.setOnClick(this::onClick); + statusBar.setOnClick(this::onBarClick); } - private static void checkZeroCoordinates(Iterable<StatusBar> bars) { + private static void checkNullAnchor(Iterable<StatusBar> bars) { int offset = 0; for (StatusBar statusBar : bars) { - if (statusBar.gridX == 0 || statusBar.gridY == 0) { + if (statusBar.anchor == null) { statusBar.setX(5); - statusBar.setY(5 + offset); + statusBar.setY(50 + offset); statusBar.setWidth(30); offset += statusBar.getHeight(); } @@ -263,6 +278,7 @@ public class StatusBarsConfigScreen extends Screen { public void removed() { super.removed(); FancyStatusBars.statusBars.values().forEach(statusBar -> statusBar.setOnClick(null)); + if (cursorBar != null) cursorBar.ghost = false; FancyStatusBars.updatePositions(); assert client != null; GLFW.glfwSetCursor(((WindowAccessor) (Object) client.getWindow()).getHandle(), 0); @@ -274,11 +290,14 @@ public class StatusBarsConfigScreen extends Screen { return false; } - private void onClick(StatusBar statusBar, int button, int mouseX, int mouseY) { + private void onBarClick(StatusBar statusBar, int button, int mouseX, int mouseY) { if (button == 0) { cursorBar = statusBar; - FancyStatusBars.barGrid.remove(statusBar.gridX, statusBar.gridY); + cursorBar.ghost = true; + if (statusBar.anchor != null) + FancyStatusBars.barPositioner.removeBar(statusBar.anchor, statusBar.gridY, statusBar); FancyStatusBars.updatePositions(); + cursorBar.setX(width + 5); // send it to limbo lol updateScreenRects(); } else if (button == 1) { int x = Math.min(mouseX - 1, width - editBarWidget.getWidth()); @@ -292,25 +311,27 @@ public class StatusBarsConfigScreen extends Screen { private void updateScreenRects() { meaningFullName.clear(); - FancyStatusBars.statusBars.values().forEach(statusBar1 -> meaningFullName.put( - new ScreenRect(new ScreenPos(statusBar1.getX(), statusBar1.getY()), statusBar1.getWidth(), statusBar1.getHeight()), - new int[]{statusBar1.gridX, statusBar1.gridY})); + FancyStatusBars.statusBars.values().forEach(statusBar1 -> { + if (statusBar1.anchor == null) return; + meaningFullName.put( + new ScreenRect(new ScreenPos(statusBar1.getX(), statusBar1.getY()), statusBar1.getWidth(), statusBar1.getHeight()), + BarLocation.of(statusBar1)); + }); } @Override public boolean mouseReleased(double mouseX, double mouseY, int button) { if (cursorBar != null) { + cursorBar.ghost = false; cursorBar = null; FancyStatusBars.updatePositions(); - checkZeroCoordinates(FancyStatusBars.statusBars.values()); + checkNullAnchor(FancyStatusBars.statusBars.values()); updateScreenRects(); return true; } else if (resizing) { resizing = false; - resizedBars.left()[0] = 0; - resizedBars.left()[1] = 0; - resizedBars.right()[0] = 0; - resizedBars.right()[1] = 0; + resizedBars.left(BarLocation.NULL); + resizedBars.right(BarLocation.NULL); updateScreenRects(); return true; } @@ -319,29 +340,23 @@ public class StatusBarsConfigScreen extends Screen { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - int[] first = resizeHover.first(); + BarLocation first = resizeHover.first(); // want the right click thing to have priority - if (!editBarWidget.isMouseOver(mouseX, mouseY) && button == 0 && first[0] != 0 && first[1] != 0) { + if (!editBarWidget.isMouseOver(mouseX, mouseY) && button == 0 && !first.equals(BarLocation.NULL)) { + BarPositioner.BarAnchor barAnchor = first.barAnchor(); + assert barAnchor != null; if (resizeHover.right()) { - resizedBars.left()[0] = first[0]; - resizedBars.left()[1] = first[1]; - if (FancyStatusBars.barGrid.coordinatesExist(first[0] + 1, first[1])) { - resizedBars.right()[0] = first[0] + 1; - resizedBars.right()[1] = first[1]; - } else { - resizedBars.right()[0] = 0; - resizedBars.right()[1] = 0; - } + resizedBars.left(first); + + if (FancyStatusBars.barPositioner.hasNeighbor(barAnchor, first.y(), first.x(), true)) { + resizedBars.right(new BarLocation(barAnchor, first.x() + (barAnchor.isRight() ? 1 : -1), first.y())); + } else resizedBars.right(BarLocation.NULL); } else { - resizedBars.right()[0] = first[0]; - resizedBars.right()[1] = first[1]; - if (FancyStatusBars.barGrid.coordinatesExist(first[0] - 1, first[1])) { - resizedBars.left()[0] = first[0] - 1; - resizedBars.left()[1] = first[1]; - } else { - resizedBars.left()[0] = 0; - resizedBars.left()[1] = 0; - } + resizedBars.right(first); + + if (FancyStatusBars.barPositioner.hasNeighbor(barAnchor, first.y(), first.x(), false)) { + resizedBars.left(new BarLocation(barAnchor, first.x() + (barAnchor.isRight() ? -1 : 1), first.y())); + } else resizedBars.left(BarLocation.NULL); } resizing = true; return true; |