From ceb507078cf480bfd5fbb58166f54027c323f58f Mon Sep 17 00:00:00 2001 From: Shiewk Date: Thu, 20 Nov 2025 19:33:12 +0100 Subject: [PATCH] Rework widget positioning --- src/main/java/de/shiewk/widgets/Anchor.java | 61 ++++ .../java/de/shiewk/widgets/Dimensionable.java | 9 - .../java/de/shiewk/widgets/ModWidget.java | 28 +- .../de/shiewk/widgets/WidgetSettings.java | 47 +-- .../shiewk/widgets/client/WidgetManager.java | 4 +- .../shiewk/widgets/client/WidgetRenderer.java | 8 +- .../screen/EditWidgetPositionsScreen.java | 278 +++++++++++------- .../de/shiewk/widgets/utils/WidgetUtils.java | 8 - 8 files changed, 279 insertions(+), 164 deletions(-) create mode 100644 src/main/java/de/shiewk/widgets/Anchor.java delete mode 100644 src/main/java/de/shiewk/widgets/Dimensionable.java diff --git a/src/main/java/de/shiewk/widgets/Anchor.java b/src/main/java/de/shiewk/widgets/Anchor.java new file mode 100644 index 0000000..2e27e9a --- /dev/null +++ b/src/main/java/de/shiewk/widgets/Anchor.java @@ -0,0 +1,61 @@ +package de.shiewk.widgets; + +import org.joml.Vector2i; + +public enum Anchor { + TOP_LEFT, + TOP_CENTER, + TOP_RIGHT, + CENTER_LEFT, + CENTER, + CENTER_RIGHT, + BOTTOM_LEFT, + BOTTOM_CENTER, + BOTTOM_RIGHT; + + public int getAlignStartPosX(int scaledScreenWidth){ + return switch (this){ + case TOP_LEFT, CENTER_LEFT, BOTTOM_LEFT -> 0; + case TOP_CENTER, CENTER, BOTTOM_CENTER -> scaledScreenWidth / 2; + case TOP_RIGHT, CENTER_RIGHT, BOTTOM_RIGHT -> scaledScreenWidth; + }; + } + + public int getAlignStartPosY(int scaledScreenHeight){ + return switch (this){ + case TOP_LEFT, TOP_CENTER, TOP_RIGHT -> 0; + case CENTER_LEFT, CENTER, CENTER_RIGHT -> scaledScreenHeight / 2; + case BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT -> scaledScreenHeight; + }; + } + + public Vector2i getTopLeft(int scaledScreenWidth, int scaledScreenHeight){ + return new Vector2i( + // X component + switch (this){ + case TOP_LEFT, CENTER_LEFT, BOTTOM_LEFT -> 0; + case TOP_CENTER, CENTER, BOTTOM_CENTER -> scaledScreenWidth / 3; + case TOP_RIGHT, CENTER_RIGHT, BOTTOM_RIGHT -> (int) (scaledScreenWidth / 3d * 2d); + }, + // Y component + switch (this){ + case TOP_LEFT, TOP_CENTER, TOP_RIGHT -> 0; + case CENTER_LEFT, CENTER, CENTER_RIGHT -> scaledScreenHeight / 3; + case BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT -> (int) (scaledScreenHeight / 3d * 2d); + } + ); + } + + public static Anchor getAnchor(int scaledScreenWidth, int scaledScreenHeight, int posX, int posY){ + for (Anchor anchor : values()) { + Vector2i topLeft = anchor.getTopLeft(scaledScreenWidth, scaledScreenHeight); + if ( + topLeft.x <= posX && topLeft.x + scaledScreenWidth / 3 >= posX && + topLeft.y <= posY && topLeft.y + scaledScreenHeight / 3 >= posY + ){ + return anchor; + } + } + return Anchor.TOP_LEFT; + } +} diff --git a/src/main/java/de/shiewk/widgets/Dimensionable.java b/src/main/java/de/shiewk/widgets/Dimensionable.java deleted file mode 100644 index 4ebb3c3..0000000 --- a/src/main/java/de/shiewk/widgets/Dimensionable.java +++ /dev/null @@ -1,9 +0,0 @@ -package de.shiewk.widgets; - -public interface Dimensionable { - int width(); - int height(); - double getX(int mx); - double getY(int my); - float getScaleFactor(); -} diff --git a/src/main/java/de/shiewk/widgets/ModWidget.java b/src/main/java/de/shiewk/widgets/ModWidget.java index 8831829..41f0d82 100644 --- a/src/main/java/de/shiewk/widgets/ModWidget.java +++ b/src/main/java/de/shiewk/widgets/ModWidget.java @@ -1,6 +1,5 @@ package de.shiewk.widgets; -import de.shiewk.widgets.utils.WidgetUtils; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; import net.minecraft.text.Text; @@ -9,7 +8,7 @@ import net.minecraft.util.Identifier; import java.util.List; import java.util.Objects; -public abstract class ModWidget implements Dimensionable { +public abstract class ModWidget { private final Identifier id; private final WidgetSettings settings; @@ -37,14 +36,27 @@ public abstract class ModWidget implements Dimensionable { public abstract Text getDescription(); public abstract void onSettingsChanged(WidgetSettings settings); - @Override - public double getX(int mx) { - return (int) WidgetUtils.translateToScreen(settings.posX, mx); + public int getX(int scaledScreenWidth){ + return settings.anchor.getAlignStartPosX(scaledScreenWidth) + settings.offsetX; } - @Override - public double getY(int my) { - return (int) WidgetUtils.translateToScreen(settings.posY, my); + public int getY(int scaledScreenHeight){ + return settings.anchor.getAlignStartPosY(scaledScreenHeight) + settings.offsetY; } + public abstract int width(); + public abstract int height(); + + public float scaledWidth() { + return width() * getScaleFactor(); + } + + public float scaledHeight() { + return height() * getScaleFactor(); + } + + public void move(int dx, int dy) { + settings.offsetX += dx; + settings.offsetY += dy; + } } diff --git a/src/main/java/de/shiewk/widgets/WidgetSettings.java b/src/main/java/de/shiewk/widgets/WidgetSettings.java index 221c2bd..de99835 100644 --- a/src/main/java/de/shiewk/widgets/WidgetSettings.java +++ b/src/main/java/de/shiewk/widgets/WidgetSettings.java @@ -2,31 +2,40 @@ package de.shiewk.widgets; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; import de.shiewk.widgets.client.WidgetManager; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.util.Identifier; -import net.minecraft.util.math.MathHelper; import java.util.List; +import java.util.Objects; import static de.shiewk.widgets.WidgetsMod.LOGGER; -import static de.shiewk.widgets.utils.WidgetUtils.translateToWidgetSettingsValue; +import static de.shiewk.widgets.client.WidgetManager.gson; public class WidgetSettings { - public double posX = 0; // posx * 100 = screen width - public double posY = 0; // posy * 100 = screen height + public Anchor anchor = Anchor.TOP_LEFT; + public int offsetX = 0; + public int offsetY = 0; private boolean enabled = false; private final ObjectArrayList customSettings; private WidgetSettings(JsonObject data, List settings){ customSettings = new ObjectArrayList<>(settings); if (data != null){ - final JsonElement enabled = data.get("enabled"); - this.enabled = enabled.isJsonPrimitive() && enabled.getAsJsonPrimitive().isBoolean() && enabled.getAsBoolean(); - final JsonElement x = data.get("x"); - this.posX = x.isJsonPrimitive() ? x.getAsJsonPrimitive().isNumber() ? x.getAsDouble() : 0 : 0; - final JsonElement y = data.get("y"); - this.posY = y.isJsonPrimitive() ? y.getAsJsonPrimitive().isNumber() ? y.getAsDouble() : 0 : 0; + try { + this.enabled = Objects.requireNonNullElse(gson.fromJson(data.get("enabled"), Boolean.class), false); + this.anchor = gson.fromJson(data.get("anchor"), Anchor.class); + this.offsetX = Objects.requireNonNullElse(gson.fromJson(data.get("ox"), Integer.class), 0); + this.offsetY = Objects.requireNonNullElse(gson.fromJson(data.get("oy"), Integer.class), 0); + } catch (JsonSyntaxException | NullPointerException e) { + LOGGER.info("Failed to load widget positioning:", e); + } finally { + if (anchor == null){ + anchor = Anchor.TOP_LEFT; + } + } + final JsonElement s = data.get("settings"); if (s != null && s.isJsonObject()){ final JsonObject savedSettings = s.getAsJsonObject(); @@ -52,11 +61,10 @@ public class WidgetSettings { return new WidgetSettings(data, customSettings); } - public void setPosX(double v, int widgetWidth, int maxWidth) { - posX = MathHelper.clamp(v, 0, 100 - translateToWidgetSettingsValue(widgetWidth, maxWidth)); - } - public void setPosY(double v, int widgetHeight, int maxHeight) { - posY = MathHelper.clamp(v, 0, 100 - translateToWidgetSettingsValue(widgetHeight, maxHeight)); + public void setPos(Anchor anchor, int offsetX, int offsetY){ + this.anchor = anchor; + this.offsetX = offsetX; + this.offsetY = offsetY; } public boolean isEnabled(){ @@ -78,14 +86,17 @@ public class WidgetSettings { public final JsonObject saveState(){ JsonObject object = new JsonObject(); - object.addProperty("x", posX); - object.addProperty("y", posY); - object.addProperty("enabled", enabled); + object.add("anchor", gson.toJsonTree(this.anchor)); + object.add("enabled", gson.toJsonTree(this.enabled)); + object.add("ox", gson.toJsonTree(this.offsetX)); + object.add("oy", gson.toJsonTree(this.offsetY)); + JsonObject customSettings = new JsonObject(); for (WidgetSettingOption customSetting : this.customSettings) { customSettings.add(customSetting.getId(), customSetting.saveState()); } object.add("settings", customSettings); + return object; } diff --git a/src/main/java/de/shiewk/widgets/client/WidgetManager.java b/src/main/java/de/shiewk/widgets/client/WidgetManager.java index 40c4f90..55e6d06 100644 --- a/src/main/java/de/shiewk/widgets/client/WidgetManager.java +++ b/src/main/java/de/shiewk/widgets/client/WidgetManager.java @@ -46,8 +46,8 @@ public class WidgetManager { enabled.remove(widget); } - static Function saveFileFactory = id -> new File(MinecraftClient.getInstance().runDirectory.getPath() + "/config/widgets/" + id.getNamespace() + "/" + id.getPath() + ".json");; - private static final Gson gson = new Gson(); + static Function saveFileFactory = id -> new File(MinecraftClient.getInstance().runDirectory.getPath() + "/config/widgets/" + id.getNamespace() + "/" + id.getPath() + ".json"); + public static final Gson gson = new Gson(); public static void saveWidgets(List widgets) { for (ModWidget widget : widgets) { diff --git a/src/main/java/de/shiewk/widgets/client/WidgetRenderer.java b/src/main/java/de/shiewk/widgets/client/WidgetRenderer.java index d19543d..9fb5cb3 100644 --- a/src/main/java/de/shiewk/widgets/client/WidgetRenderer.java +++ b/src/main/java/de/shiewk/widgets/client/WidgetRenderer.java @@ -1,7 +1,6 @@ package de.shiewk.widgets.client; import de.shiewk.widgets.ModWidget; -import de.shiewk.widgets.WidgetSettings; import de.shiewk.widgets.WidgetsMod; import de.shiewk.widgets.client.screen.EditWidgetPositionsScreen; import de.shiewk.widgets.client.screen.WidgetConfigScreen; @@ -18,8 +17,6 @@ import net.minecraft.util.Util; import net.minecraft.util.profiler.Profiler; import net.minecraft.util.profiler.Profilers; -import static de.shiewk.widgets.utils.WidgetUtils.translateToScreen; - public class WidgetRenderer implements ClientTickEvents.StartTick, ClientLifecycleEvents.ClientStarted { public static final Identifier LAYER_ID = Identifier.of(WidgetsMod.MOD_ID, "widgets-hud-layer"); @@ -46,13 +43,12 @@ public class WidgetRenderer implements ClientTickEvents.StartTick, ClientLifecyc for (int i = 0, enabledSize = enabled.size(); i < enabledSize; i++) { final ModWidget widget = enabled.get(i); profiler.push(widget.getId().toString()); - final WidgetSettings settings = widget.getSettings(); widget.render( drawContext, timeNano, textRenderer, - (int) Math.round(Math.min(translateToScreen(settings.posX, windowWidth), windowWidth - (widget.width() * widget.getScaleFactor()))), - (int) Math.round(Math.min(translateToScreen(settings.posY, windowHeight), windowHeight - (widget.height() * widget.getScaleFactor()))) + widget.getX(windowWidth), + widget.getY(windowHeight) ); profiler.pop(); } diff --git a/src/main/java/de/shiewk/widgets/client/screen/EditWidgetPositionsScreen.java b/src/main/java/de/shiewk/widgets/client/screen/EditWidgetPositionsScreen.java index 3f64add..c5b45b9 100644 --- a/src/main/java/de/shiewk/widgets/client/screen/EditWidgetPositionsScreen.java +++ b/src/main/java/de/shiewk/widgets/client/screen/EditWidgetPositionsScreen.java @@ -1,10 +1,9 @@ package de.shiewk.widgets.client.screen; -import de.shiewk.widgets.Dimensionable; +import de.shiewk.widgets.Anchor; import de.shiewk.widgets.ModWidget; import de.shiewk.widgets.WidgetSettings; import de.shiewk.widgets.client.WidgetManager; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.client.gui.Click; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; @@ -12,38 +11,16 @@ import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.text.Text; import net.minecraft.util.Util; -import org.jetbrains.annotations.Nullable; +import org.joml.Vector2i; import java.awt.*; import java.util.function.Consumer; -import static de.shiewk.widgets.utils.WidgetUtils.translateToScreen; -import static de.shiewk.widgets.utils.WidgetUtils.translateToWidgetSettingsValue; - public class EditWidgetPositionsScreen extends AnimatedScreen { - private record Alignment(int x, int y, int width, int height) implements Dimensionable { - - @Override - public double getX(int mx) { - return x; - } - - @Override - public double getY(int my) { - return y; - } - - @Override - public float getScaleFactor() { - return 1f; - } - } - private final Screen parent; private final Consumer onEdit; - private boolean alignX = true; - private boolean alignY = true; + public EditWidgetPositionsScreen(Screen parent, Consumer onEdit) { super(Text.translatable("widgets.ui.editPositions"), parent, 500); this.parent = parent; @@ -58,85 +35,46 @@ public class EditWidgetPositionsScreen extends AnimatedScreen { private record AlignResult(double result, boolean isEnd){} - private @Nullable AlignResult alignX(double x, int width, ModWidget widget){ - double endX = x + width; - int factor = alignX ? 2 : 0; - for (Dimensionable rect : this.getAlignments(widget)) { - if (rect == widget) continue; - final int rectWidth = rect.width(); - final double nwx = Math.min(rect.getX(this.width), this.width - rectWidth); - final double nww = rectWidth * rect.getScaleFactor(); - if (endX < nwx + factor && endX > nwx - factor){ - return new AlignResult(nwx - width, true); - } else if (x < nwx + factor && x > nwx - factor){ - return new AlignResult(nwx, false); - } else if (endX < nwx+nww + factor && endX > nwx + nww - factor){ - return new AlignResult(nwx + nww - width, true); - } else if (x < nwx+nww + factor && x > nwx + nww - factor){ - return new AlignResult(nwx + nww, false); - } - } - return null; - } - - private Iterable getAlignments(Dimensionable rel) { - ObjectArrayList alignments = new ObjectArrayList<>(); - for (ModWidget widget : WidgetManager.getEnabledWidgets()) { - alignments.add(widget); - } - alignments.add(new Alignment(2, 2, this.width / 2 - 2, this.height / 2 - 2)); - alignments.add(new Alignment(this.width / 2, this.height / 2, this.width / 2 - 2, this.height / 2 - 2)); - alignments.add(new Alignment(2, this.height / 2, this.width / 2 - 2, this.height / 2 - 2)); - alignments.add(new Alignment(this.width / 2, 2, this.width / 2 - 2, this.height / 2 - 2)); - alignments.add(new Alignment((int) ((float) this.width / 2 - (rel.width() * rel.getScaleFactor()) / 2), (int) ((float) this.height / 2 - (rel.height() * rel.getScaleFactor()) / 2), (int) (rel.width() * rel.getScaleFactor()), (int) (rel.height() * rel.getScaleFactor()))); - return alignments; - } - - - private @Nullable AlignResult alignY(double y, int height, ModWidget widget){ - double endY = y + height; - int factor = alignY ? 2 : 0; - for (Dimensionable rect : this.getAlignments(widget)) { - if (rect == widget) continue; - final int rectHeight = rect.height(); - final double nwy = Math.min(rect.getY(this.height), this.height - rectHeight); - final double nwh = rectHeight * rect.getScaleFactor(); - if (endY < nwy + factor && endY > nwy - factor){ - return new AlignResult(nwy - height, true); - } else if (y < nwy + factor && y > nwy - factor){ - return new AlignResult(nwy, false); - } else if (endY < nwy+nwh + factor && endY > nwy + nwh - factor){ - return new AlignResult(nwy + nwh - height, true); - } else if (y < nwy+nwh + factor && y > nwy + nwh - factor){ - return new AlignResult(nwy + nwh, false); - } - } - return null; - } - private static final int SELECT_COLOR = Color.GREEN.getRGB(), ALIGN_COLOR = Color.ORANGE.getRGB(), ALIGN_DISABLED_COLOR = Color.GRAY.getRGB(); private ModWidget selectedWidget = null; private ModWidget hoveredWidget = null; + private int focusedExtraX = 0; + private int focusedExtraY = 0; + private boolean align = true; + + private int scaledWindowWidth = 1920; + private int scaledWindowHeight = 1080; @Override public void renderScreenContents(DrawContext context, int mouseX, int mouseY, float delta) { - assert client != null; + this.scaledWindowWidth = context.getScaledWindowWidth(); + this.scaledWindowHeight = context.getScaledWindowHeight(); + long mt = Util.getMeasuringTimeNano(); + renderAnchorArea(context, mouseX, mouseY); + for (ModWidget widget : WidgetManager.getEnabledWidgets()) { - final WidgetSettings settings = widget.getSettings(); final int ww = (int) (widget.width() * widget.getScaleFactor()); - double wx = Math.min(translateToScreen(settings.posX, this.width), this.width - ww); + int wx = Math.min(widget.getX(scaledWindowWidth), this.width - ww); final int wh = (int) (widget.height() * widget.getScaleFactor()); - double wy = Math.min(translateToScreen(settings.posY, this.height), this.height - wh); + int wy = Math.min(widget.getY(scaledWindowHeight), this.height - wh); if (selectedWidget == widget){ - final AlignResult alignedX = alignX(wx, ww, widget); + AlignResult alignedX = alignX(widget); if (alignedX != null){ - context.drawVerticalLine((int) (!alignedX.isEnd() ? alignedX.result() : alignedX.result() + ww), 0, this.height, alignX ? ALIGN_COLOR : ALIGN_DISABLED_COLOR); - wx = alignedX.result(); + context.drawVerticalLine( + (int) Math.round(alignedX.result), + 0, + scaledWindowHeight, + align ? ALIGN_COLOR : ALIGN_DISABLED_COLOR + ); } - final AlignResult alignedY = alignY(wy, wh, widget); + AlignResult alignedY = alignY(widget); if (alignedY != null){ - context.drawHorizontalLine(0, this.width, (int) (!alignedY.isEnd() ? alignedY.result() : alignedY.result() + wh), alignY ? ALIGN_COLOR : ALIGN_DISABLED_COLOR); - wy = alignedY.result(); + context.drawHorizontalLine( + 0, + scaledWindowWidth, + (int) Math.round(alignedY.result), + align ? ALIGN_COLOR : ALIGN_DISABLED_COLOR + ); } } if (hoveredWidget == null || hoveredWidget == widget){ @@ -149,23 +87,96 @@ public class EditWidgetPositionsScreen extends AnimatedScreen { } } if (selectedWidget == null ? hoveredWidget == widget : selectedWidget == widget){ - context.drawStrokedRectangle((int) Math.round(wx-1), (int) Math.round(wy-1), ww+2, wh+2, SELECT_COLOR); - context.drawStrokedRectangle((int) Math.round(wx), (int) Math.round(wy), ww, wh, SELECT_COLOR); + context.drawStrokedRectangle(wx-1,wy-1, ww+2, wh+2, SELECT_COLOR); + context.drawStrokedRectangle(wx, wy, ww, wh, SELECT_COLOR); } - widget.render(context, Util.getMeasuringTimeNano(), textRenderer, (int) Math.round(wx), (int) Math.round(wy)); + widget.render(context, mt, textRenderer, wx, wy); } } + private boolean canAlign(int val1, int val2){ + return ((val2 - val1) * (val2 - val1)) < 9; + } + + private AlignResult alignX(ModWidget widget) { + // Align with other widgets + for (ModWidget other : WidgetManager.getEnabledWidgets()) { + if (other == widget) continue; + if (canAlign(widget.getX(scaledWindowWidth), other.getX(scaledWindowWidth))){ + return new AlignResult(other.getX(scaledWindowWidth), false); + + } else if (canAlign(widget.getX(scaledWindowWidth) + (int) widget.scaledWidth(), other.getX(scaledWindowWidth) + (int) other.scaledWidth())) { + return new AlignResult(other.getX(scaledWindowWidth) + other.scaledWidth(), true); + + } else if (canAlign(widget.getX(scaledWindowWidth), other.getX(scaledWindowWidth) + (int) other.scaledWidth())){ + return new AlignResult(other.getX(scaledWindowWidth) + other.scaledWidth(), false); + + } else if (canAlign(widget.getX(scaledWindowWidth) + (int) widget.scaledWidth(), other.getX(scaledWindowWidth))){ + return new AlignResult(other.getX(scaledWindowWidth), true); + + } + } + return null; + } + + private AlignResult alignY(ModWidget widget) { + // Align with other widgets + for (ModWidget other : WidgetManager.getEnabledWidgets()) { + if (other == widget) continue; + if (canAlign(widget.getY(scaledWindowHeight), other.getY(scaledWindowHeight))){ + return new AlignResult(other.getY(scaledWindowHeight), false); + + } else if (canAlign(widget.getY(scaledWindowHeight) + (int) widget.scaledHeight(), other.getY(scaledWindowHeight) + (int) other.scaledHeight())) { + return new AlignResult(other.getY(scaledWindowHeight) + other.scaledHeight(), true); + + } else if (canAlign(widget.getY(scaledWindowHeight), other.getY(scaledWindowHeight) + (int) other.scaledHeight())){ + return new AlignResult(other.getY(scaledWindowHeight) + other.scaledHeight(), false); + + } else if (canAlign(widget.getY(scaledWindowHeight) + (int) widget.scaledHeight(), other.getY(scaledWindowHeight))){ + return new AlignResult(other.getY(scaledWindowHeight), true); + + } + } + return null; + } + + private void renderAnchorArea(DrawContext context, int mouseX, int mouseY) { + Anchor anchor = Anchor.getAnchor( + scaledWindowWidth, + scaledWindowHeight, + mouseX, + mouseY + ); + Vector2i topLeft = anchor.getTopLeft(scaledWindowWidth, scaledWindowHeight); + context.fill( + topLeft.x, + topLeft.y, + topLeft.x + scaledWindowWidth / 3, + topLeft.y + scaledWindowHeight / 3, + 0x08ffffff + ); + } + @Override public boolean mouseReleased(Click click) { if (click.button() == 0 && selectedWidget != null){ - final AlignResult alignedX = alignX(translateToScreen(selectedWidget.getSettings().posX, this.width), (int) (selectedWidget.width() * selectedWidget.getScaleFactor()), selectedWidget); - if (alignedX != null){ - selectedWidget.getSettings().setPosX(translateToWidgetSettingsValue(alignedX.result(), this.width), (int) (selectedWidget.width() * selectedWidget.getScaleFactor()), this.width); - } - final AlignResult alignedY = alignY(translateToScreen(selectedWidget.getSettings().posY, this.height), (int) (selectedWidget.height() * selectedWidget.getScaleFactor()), selectedWidget); - if (alignedY != null){ - selectedWidget.getSettings().setPosY(translateToWidgetSettingsValue(alignedY.result(), this.height), (int) (selectedWidget.height() * selectedWidget.getScaleFactor()), this.height); + if (align){ + AlignResult alignedX = alignX(selectedWidget); + if (alignedX != null){ + double diff = Math.round(alignedX.result - selectedWidget.getX(scaledWindowWidth)); + if (alignedX.isEnd){ + diff -= selectedWidget.scaledWidth(); + } + selectedWidget.move((int) diff, 0); + } + AlignResult alignedY = alignY(selectedWidget); + if (alignedY != null){ + double diff = Math.round(alignedY.result - selectedWidget.getY(scaledWindowHeight)); + if (alignedY.isEnd){ + diff -= selectedWidget.scaledHeight(); + } + selectedWidget.move(0, (int) diff); + } } onEdit.accept(selectedWidget); selectedWidget = null; @@ -177,6 +188,8 @@ public class EditWidgetPositionsScreen extends AnimatedScreen { public boolean mouseClicked(Click click, boolean doubled) { if (click.button() == 0 && hoveredWidget != null){ selectedWidget = hoveredWidget; + focusedExtraX = (int) (click.x() - hoveredWidget.getX(scaledWindowWidth)); + focusedExtraY = (int) (click.y() - hoveredWidget.getY(scaledWindowHeight)); } return super.mouseClicked(click, doubled); } @@ -189,15 +202,35 @@ public class EditWidgetPositionsScreen extends AnimatedScreen { if (widget != null){ final WidgetSettings settings = widget.getSettings(); final int ww = (int) (widget.width() * widget.getScaleFactor()); - final int wx = (int) Math.min(translateToScreen(settings.posX, this.width), this.width - ww); + int wx = Math.min(widget.getX(scaledWindowWidth), this.width - ww); final int wh = (int) (widget.height() * widget.getScaleFactor()); - final int wy = (int) Math.min(translateToScreen(settings.posY, this.height), this.height - wh); + int wy = Math.min(widget.getY(scaledWindowHeight), this.height - wh); if (click.x() <= wx + ww + deltaX && click.x() >= wx + deltaX){ if (click.y() <= wy + wh + deltaY && click.y() >= wy + deltaY){ - double newPosX = settings.posX + translateToWidgetSettingsValue(deltaX, this.width); - double newPosY = settings.posY + translateToWidgetSettingsValue(deltaY, this.height); - settings.setPosX(newPosX, ww, this.width); - settings.setPosY(newPosY, wh, this.height); + Anchor anchor = Anchor.getAnchor(scaledWindowWidth, scaledWindowHeight, (int) click.x(), (int) click.y()); + int newOffX = (int) (click.x() - anchor.getAlignStartPosX(scaledWindowWidth)) - focusedExtraX; + int newOffY = (int) (click.y() - anchor.getAlignStartPosY(scaledWindowHeight)) - focusedExtraY; + + // Ensure the thing does not go out of bounds + settings.setPos(anchor, newOffX, newOffY); + + if (widget.getX(scaledWindowWidth) + ww > scaledWindowWidth){ + newOffX -= widget.getX(scaledWindowWidth) - scaledWindowWidth + ww; + settings.setPos(anchor, newOffX, newOffY); + } + if (widget.getX(scaledWindowWidth) < 0){ + newOffX -= widget.getX(scaledWindowWidth); + settings.setPos(anchor, newOffX, newOffY); + } + if (widget.getY(scaledWindowHeight) + wh > scaledWindowHeight){ + newOffY -= widget.getY(scaledWindowHeight) - scaledWindowHeight + wh; + settings.setPos(anchor, newOffX, newOffY); + } + if (widget.getY(scaledWindowHeight) < 0){ + newOffY -= widget.getY(scaledWindowHeight); + settings.setPos(anchor, newOffX, newOffY); + } + return true; } } @@ -209,10 +242,29 @@ public class EditWidgetPositionsScreen extends AnimatedScreen { @Override protected void init() { super.init(); - this.addDrawableChild(new ButtonWidget.Builder(Text.translatable("widgets.ui.editPositions.snap", alignX ? Text.translatable("gui.yes") : Text.translatable("gui.no")), button -> { - alignX = !alignX; - alignY = !alignY; - button.setMessage(Text.translatable("widgets.ui.editPositions.snap", alignX ? Text.translatable("gui.yes") : Text.translatable("gui.no"))); - }).position(this.width / 2 - 75, this.height / 2 - 10).tooltip(Tooltip.of(Text.translatable("widgets.ui.editPositions.snap.help"))).build()); + this.addDrawableChild( + new ButtonWidget.Builder( + Text.translatable( + "widgets.ui.editPositions.snap", + align ? + Text.translatable("gui.yes") : + Text.translatable("gui.no") + ), button -> { + align = !align; + button.setMessage( + Text.translatable( + "widgets.ui.editPositions.snap", + align ? + Text.translatable("gui.yes") + : Text.translatable("gui.no") + ) + ); + }).position( + this.width / 2 - 75, + this.height / 2 - 10 + ).tooltip( + Tooltip.of(Text.translatable("widgets.ui.editPositions.snap.help")) + ).build() + ); } } diff --git a/src/main/java/de/shiewk/widgets/utils/WidgetUtils.java b/src/main/java/de/shiewk/widgets/utils/WidgetUtils.java index 53de0d5..17b99fe 100644 --- a/src/main/java/de/shiewk/widgets/utils/WidgetUtils.java +++ b/src/main/java/de/shiewk/widgets/utils/WidgetUtils.java @@ -9,14 +9,6 @@ public class WidgetUtils { public static final BooleanSupplier TRUE_SUPPLIER = () -> true; - public static double translateToWidgetSettingsValue(double value, int max){ - return (value / max) * 100; - } - - public static double translateToScreen(double value, int max){ - return value / 100d * max; - } - public static double computeEasing(double x) { return 1d - Math.pow(1d - x, 3.5d); }