mirror of
https://github.com/Shiewk/Widgets.git
synced 2026-04-28 11:34:17 +02:00
Rework widget positioning
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<WidgetSettingOption> customSettings;
|
||||
|
||||
private WidgetSettings(JsonObject data, List<WidgetSettingOption> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ public class WidgetManager {
|
||||
enabled.remove(widget);
|
||||
}
|
||||
|
||||
static Function<Identifier, File> saveFileFactory = id -> new File(MinecraftClient.getInstance().runDirectory.getPath() + "/config/widgets/" + id.getNamespace() + "/" + id.getPath() + ".json");;
|
||||
private static final Gson gson = new Gson();
|
||||
static Function<Identifier, File> 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<ModWidget> widgets) {
|
||||
for (ModWidget widget : widgets) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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<ModWidget> onEdit;
|
||||
private boolean alignX = true;
|
||||
private boolean alignY = true;
|
||||
|
||||
public EditWidgetPositionsScreen(Screen parent, Consumer<ModWidget> 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<? extends Dimensionable> getAlignments(Dimensionable rel) {
|
||||
ObjectArrayList<Dimensionable> 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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user