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;
|
package de.shiewk.widgets;
|
||||||
|
|
||||||
import de.shiewk.widgets.utils.WidgetUtils;
|
|
||||||
import net.minecraft.client.font.TextRenderer;
|
import net.minecraft.client.font.TextRenderer;
|
||||||
import net.minecraft.client.gui.DrawContext;
|
import net.minecraft.client.gui.DrawContext;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
@@ -9,7 +8,7 @@ import net.minecraft.util.Identifier;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public abstract class ModWidget implements Dimensionable {
|
public abstract class ModWidget {
|
||||||
|
|
||||||
private final Identifier id;
|
private final Identifier id;
|
||||||
private final WidgetSettings settings;
|
private final WidgetSettings settings;
|
||||||
@@ -37,14 +36,27 @@ public abstract class ModWidget implements Dimensionable {
|
|||||||
public abstract Text getDescription();
|
public abstract Text getDescription();
|
||||||
public abstract void onSettingsChanged(WidgetSettings settings);
|
public abstract void onSettingsChanged(WidgetSettings settings);
|
||||||
|
|
||||||
@Override
|
public int getX(int scaledScreenWidth){
|
||||||
public double getX(int mx) {
|
return settings.anchor.getAlignStartPosX(scaledScreenWidth) + settings.offsetX;
|
||||||
return (int) WidgetUtils.translateToScreen(settings.posX, mx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public int getY(int scaledScreenHeight){
|
||||||
public double getY(int my) {
|
return settings.anchor.getAlignStartPosY(scaledScreenHeight) + settings.offsetY;
|
||||||
return (int) WidgetUtils.translateToScreen(settings.posY, my);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
import de.shiewk.widgets.client.WidgetManager;
|
import de.shiewk.widgets.client.WidgetManager;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.math.MathHelper;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static de.shiewk.widgets.WidgetsMod.LOGGER;
|
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 class WidgetSettings {
|
||||||
public double posX = 0; // posx * 100 = screen width
|
public Anchor anchor = Anchor.TOP_LEFT;
|
||||||
public double posY = 0; // posy * 100 = screen height
|
public int offsetX = 0;
|
||||||
|
public int offsetY = 0;
|
||||||
private boolean enabled = false;
|
private boolean enabled = false;
|
||||||
private final ObjectArrayList<WidgetSettingOption> customSettings;
|
private final ObjectArrayList<WidgetSettingOption> customSettings;
|
||||||
|
|
||||||
private WidgetSettings(JsonObject data, List<WidgetSettingOption> settings){
|
private WidgetSettings(JsonObject data, List<WidgetSettingOption> settings){
|
||||||
customSettings = new ObjectArrayList<>(settings);
|
customSettings = new ObjectArrayList<>(settings);
|
||||||
if (data != null){
|
if (data != null){
|
||||||
final JsonElement enabled = data.get("enabled");
|
try {
|
||||||
this.enabled = enabled.isJsonPrimitive() && enabled.getAsJsonPrimitive().isBoolean() && enabled.getAsBoolean();
|
this.enabled = Objects.requireNonNullElse(gson.fromJson(data.get("enabled"), Boolean.class), false);
|
||||||
final JsonElement x = data.get("x");
|
this.anchor = gson.fromJson(data.get("anchor"), Anchor.class);
|
||||||
this.posX = x.isJsonPrimitive() ? x.getAsJsonPrimitive().isNumber() ? x.getAsDouble() : 0 : 0;
|
this.offsetX = Objects.requireNonNullElse(gson.fromJson(data.get("ox"), Integer.class), 0);
|
||||||
final JsonElement y = data.get("y");
|
this.offsetY = Objects.requireNonNullElse(gson.fromJson(data.get("oy"), Integer.class), 0);
|
||||||
this.posY = y.isJsonPrimitive() ? y.getAsJsonPrimitive().isNumber() ? y.getAsDouble() : 0 : 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");
|
final JsonElement s = data.get("settings");
|
||||||
if (s != null && s.isJsonObject()){
|
if (s != null && s.isJsonObject()){
|
||||||
final JsonObject savedSettings = s.getAsJsonObject();
|
final JsonObject savedSettings = s.getAsJsonObject();
|
||||||
@@ -52,11 +61,10 @@ public class WidgetSettings {
|
|||||||
return new WidgetSettings(data, customSettings);
|
return new WidgetSettings(data, customSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPosX(double v, int widgetWidth, int maxWidth) {
|
public void setPos(Anchor anchor, int offsetX, int offsetY){
|
||||||
posX = MathHelper.clamp(v, 0, 100 - translateToWidgetSettingsValue(widgetWidth, maxWidth));
|
this.anchor = anchor;
|
||||||
}
|
this.offsetX = offsetX;
|
||||||
public void setPosY(double v, int widgetHeight, int maxHeight) {
|
this.offsetY = offsetY;
|
||||||
posY = MathHelper.clamp(v, 0, 100 - translateToWidgetSettingsValue(widgetHeight, maxHeight));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnabled(){
|
public boolean isEnabled(){
|
||||||
@@ -78,14 +86,17 @@ public class WidgetSettings {
|
|||||||
|
|
||||||
public final JsonObject saveState(){
|
public final JsonObject saveState(){
|
||||||
JsonObject object = new JsonObject();
|
JsonObject object = new JsonObject();
|
||||||
object.addProperty("x", posX);
|
object.add("anchor", gson.toJsonTree(this.anchor));
|
||||||
object.addProperty("y", posY);
|
object.add("enabled", gson.toJsonTree(this.enabled));
|
||||||
object.addProperty("enabled", enabled);
|
object.add("ox", gson.toJsonTree(this.offsetX));
|
||||||
|
object.add("oy", gson.toJsonTree(this.offsetY));
|
||||||
|
|
||||||
JsonObject customSettings = new JsonObject();
|
JsonObject customSettings = new JsonObject();
|
||||||
for (WidgetSettingOption customSetting : this.customSettings) {
|
for (WidgetSettingOption customSetting : this.customSettings) {
|
||||||
customSettings.add(customSetting.getId(), customSetting.saveState());
|
customSettings.add(customSetting.getId(), customSetting.saveState());
|
||||||
}
|
}
|
||||||
object.add("settings", customSettings);
|
object.add("settings", customSettings);
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ public class WidgetManager {
|
|||||||
enabled.remove(widget);
|
enabled.remove(widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Function<Identifier, File> saveFileFactory = id -> new File(MinecraftClient.getInstance().runDirectory.getPath() + "/config/widgets/" + id.getNamespace() + "/" + id.getPath() + ".json");;
|
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();
|
public static final Gson gson = new Gson();
|
||||||
|
|
||||||
public static void saveWidgets(List<ModWidget> widgets) {
|
public static void saveWidgets(List<ModWidget> widgets) {
|
||||||
for (ModWidget widget : widgets) {
|
for (ModWidget widget : widgets) {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package de.shiewk.widgets.client;
|
package de.shiewk.widgets.client;
|
||||||
|
|
||||||
import de.shiewk.widgets.ModWidget;
|
import de.shiewk.widgets.ModWidget;
|
||||||
import de.shiewk.widgets.WidgetSettings;
|
|
||||||
import de.shiewk.widgets.WidgetsMod;
|
import de.shiewk.widgets.WidgetsMod;
|
||||||
import de.shiewk.widgets.client.screen.EditWidgetPositionsScreen;
|
import de.shiewk.widgets.client.screen.EditWidgetPositionsScreen;
|
||||||
import de.shiewk.widgets.client.screen.WidgetConfigScreen;
|
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.Profiler;
|
||||||
import net.minecraft.util.profiler.Profilers;
|
import net.minecraft.util.profiler.Profilers;
|
||||||
|
|
||||||
import static de.shiewk.widgets.utils.WidgetUtils.translateToScreen;
|
|
||||||
|
|
||||||
public class WidgetRenderer implements ClientTickEvents.StartTick, ClientLifecycleEvents.ClientStarted {
|
public class WidgetRenderer implements ClientTickEvents.StartTick, ClientLifecycleEvents.ClientStarted {
|
||||||
|
|
||||||
public static final Identifier LAYER_ID = Identifier.of(WidgetsMod.MOD_ID, "widgets-hud-layer");
|
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++) {
|
for (int i = 0, enabledSize = enabled.size(); i < enabledSize; i++) {
|
||||||
final ModWidget widget = enabled.get(i);
|
final ModWidget widget = enabled.get(i);
|
||||||
profiler.push(widget.getId().toString());
|
profiler.push(widget.getId().toString());
|
||||||
final WidgetSettings settings = widget.getSettings();
|
|
||||||
widget.render(
|
widget.render(
|
||||||
drawContext,
|
drawContext,
|
||||||
timeNano,
|
timeNano,
|
||||||
textRenderer,
|
textRenderer,
|
||||||
(int) Math.round(Math.min(translateToScreen(settings.posX, windowWidth), windowWidth - (widget.width() * widget.getScaleFactor()))),
|
widget.getX(windowWidth),
|
||||||
(int) Math.round(Math.min(translateToScreen(settings.posY, windowHeight), windowHeight - (widget.height() * widget.getScaleFactor())))
|
widget.getY(windowHeight)
|
||||||
);
|
);
|
||||||
profiler.pop();
|
profiler.pop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
package de.shiewk.widgets.client.screen;
|
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.ModWidget;
|
||||||
import de.shiewk.widgets.WidgetSettings;
|
import de.shiewk.widgets.WidgetSettings;
|
||||||
import de.shiewk.widgets.client.WidgetManager;
|
import de.shiewk.widgets.client.WidgetManager;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
|
||||||
import net.minecraft.client.gui.Click;
|
import net.minecraft.client.gui.Click;
|
||||||
import net.minecraft.client.gui.DrawContext;
|
import net.minecraft.client.gui.DrawContext;
|
||||||
import net.minecraft.client.gui.screen.Screen;
|
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.client.gui.widget.ButtonWidget;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
import net.minecraft.util.Util;
|
import net.minecraft.util.Util;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.joml.Vector2i;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.function.Consumer;
|
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 {
|
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 Screen parent;
|
||||||
private final Consumer<ModWidget> onEdit;
|
private final Consumer<ModWidget> onEdit;
|
||||||
private boolean alignX = true;
|
|
||||||
private boolean alignY = true;
|
|
||||||
public EditWidgetPositionsScreen(Screen parent, Consumer<ModWidget> onEdit) {
|
public EditWidgetPositionsScreen(Screen parent, Consumer<ModWidget> onEdit) {
|
||||||
super(Text.translatable("widgets.ui.editPositions"), parent, 500);
|
super(Text.translatable("widgets.ui.editPositions"), parent, 500);
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
@@ -58,85 +35,46 @@ public class EditWidgetPositionsScreen extends AnimatedScreen {
|
|||||||
|
|
||||||
private record AlignResult(double result, boolean isEnd){}
|
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 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 selectedWidget = null;
|
||||||
private ModWidget hoveredWidget = 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
|
@Override
|
||||||
public void renderScreenContents(DrawContext context, int mouseX, int mouseY, float delta) {
|
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()) {
|
for (ModWidget widget : WidgetManager.getEnabledWidgets()) {
|
||||||
final WidgetSettings settings = widget.getSettings();
|
|
||||||
final int ww = (int) (widget.width() * widget.getScaleFactor());
|
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());
|
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){
|
if (selectedWidget == widget){
|
||||||
final AlignResult alignedX = alignX(wx, ww, widget);
|
AlignResult alignedX = alignX(widget);
|
||||||
if (alignedX != null){
|
if (alignedX != null){
|
||||||
context.drawVerticalLine((int) (!alignedX.isEnd() ? alignedX.result() : alignedX.result() + ww), 0, this.height, alignX ? ALIGN_COLOR : ALIGN_DISABLED_COLOR);
|
context.drawVerticalLine(
|
||||||
wx = alignedX.result();
|
(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){
|
if (alignedY != null){
|
||||||
context.drawHorizontalLine(0, this.width, (int) (!alignedY.isEnd() ? alignedY.result() : alignedY.result() + wh), alignY ? ALIGN_COLOR : ALIGN_DISABLED_COLOR);
|
context.drawHorizontalLine(
|
||||||
wy = alignedY.result();
|
0,
|
||||||
|
scaledWindowWidth,
|
||||||
|
(int) Math.round(alignedY.result),
|
||||||
|
align ? ALIGN_COLOR : ALIGN_DISABLED_COLOR
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hoveredWidget == null || hoveredWidget == widget){
|
if (hoveredWidget == null || hoveredWidget == widget){
|
||||||
@@ -149,23 +87,96 @@ public class EditWidgetPositionsScreen extends AnimatedScreen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (selectedWidget == null ? hoveredWidget == widget : selectedWidget == widget){
|
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(wx-1,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, 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
|
@Override
|
||||||
public boolean mouseReleased(Click click) {
|
public boolean mouseReleased(Click click) {
|
||||||
if (click.button() == 0 && selectedWidget != null){
|
if (click.button() == 0 && selectedWidget != null){
|
||||||
final AlignResult alignedX = alignX(translateToScreen(selectedWidget.getSettings().posX, this.width), (int) (selectedWidget.width() * selectedWidget.getScaleFactor()), selectedWidget);
|
if (align){
|
||||||
if (alignedX != null){
|
AlignResult alignedX = alignX(selectedWidget);
|
||||||
selectedWidget.getSettings().setPosX(translateToWidgetSettingsValue(alignedX.result(), this.width), (int) (selectedWidget.width() * selectedWidget.getScaleFactor()), this.width);
|
if (alignedX != null){
|
||||||
}
|
double diff = Math.round(alignedX.result - selectedWidget.getX(scaledWindowWidth));
|
||||||
final AlignResult alignedY = alignY(translateToScreen(selectedWidget.getSettings().posY, this.height), (int) (selectedWidget.height() * selectedWidget.getScaleFactor()), selectedWidget);
|
if (alignedX.isEnd){
|
||||||
if (alignedY != null){
|
diff -= selectedWidget.scaledWidth();
|
||||||
selectedWidget.getSettings().setPosY(translateToWidgetSettingsValue(alignedY.result(), this.height), (int) (selectedWidget.height() * selectedWidget.getScaleFactor()), this.height);
|
}
|
||||||
|
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);
|
onEdit.accept(selectedWidget);
|
||||||
selectedWidget = null;
|
selectedWidget = null;
|
||||||
@@ -177,6 +188,8 @@ public class EditWidgetPositionsScreen extends AnimatedScreen {
|
|||||||
public boolean mouseClicked(Click click, boolean doubled) {
|
public boolean mouseClicked(Click click, boolean doubled) {
|
||||||
if (click.button() == 0 && hoveredWidget != null){
|
if (click.button() == 0 && hoveredWidget != null){
|
||||||
selectedWidget = hoveredWidget;
|
selectedWidget = hoveredWidget;
|
||||||
|
focusedExtraX = (int) (click.x() - hoveredWidget.getX(scaledWindowWidth));
|
||||||
|
focusedExtraY = (int) (click.y() - hoveredWidget.getY(scaledWindowHeight));
|
||||||
}
|
}
|
||||||
return super.mouseClicked(click, doubled);
|
return super.mouseClicked(click, doubled);
|
||||||
}
|
}
|
||||||
@@ -189,15 +202,35 @@ public class EditWidgetPositionsScreen extends AnimatedScreen {
|
|||||||
if (widget != null){
|
if (widget != null){
|
||||||
final WidgetSettings settings = widget.getSettings();
|
final WidgetSettings settings = widget.getSettings();
|
||||||
final int ww = (int) (widget.width() * widget.getScaleFactor());
|
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 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.x() <= wx + ww + deltaX && click.x() >= wx + deltaX){
|
||||||
if (click.y() <= wy + wh + deltaY && click.y() >= wy + deltaY){
|
if (click.y() <= wy + wh + deltaY && click.y() >= wy + deltaY){
|
||||||
double newPosX = settings.posX + translateToWidgetSettingsValue(deltaX, this.width);
|
Anchor anchor = Anchor.getAnchor(scaledWindowWidth, scaledWindowHeight, (int) click.x(), (int) click.y());
|
||||||
double newPosY = settings.posY + translateToWidgetSettingsValue(deltaY, this.height);
|
int newOffX = (int) (click.x() - anchor.getAlignStartPosX(scaledWindowWidth)) - focusedExtraX;
|
||||||
settings.setPosX(newPosX, ww, this.width);
|
int newOffY = (int) (click.y() - anchor.getAlignStartPosY(scaledWindowHeight)) - focusedExtraY;
|
||||||
settings.setPosY(newPosY, wh, this.height);
|
|
||||||
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,10 +242,29 @@ public class EditWidgetPositionsScreen extends AnimatedScreen {
|
|||||||
@Override
|
@Override
|
||||||
protected void init() {
|
protected void init() {
|
||||||
super.init();
|
super.init();
|
||||||
this.addDrawableChild(new ButtonWidget.Builder(Text.translatable("widgets.ui.editPositions.snap", alignX ? Text.translatable("gui.yes") : Text.translatable("gui.no")), button -> {
|
this.addDrawableChild(
|
||||||
alignX = !alignX;
|
new ButtonWidget.Builder(
|
||||||
alignY = !alignY;
|
Text.translatable(
|
||||||
button.setMessage(Text.translatable("widgets.ui.editPositions.snap", alignX ? Text.translatable("gui.yes") : Text.translatable("gui.no")));
|
"widgets.ui.editPositions.snap",
|
||||||
}).position(this.width / 2 - 75, this.height / 2 - 10).tooltip(Tooltip.of(Text.translatable("widgets.ui.editPositions.snap.help"))).build());
|
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 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) {
|
public static double computeEasing(double x) {
|
||||||
return 1d - Math.pow(1d - x, 3.5d);
|
return 1d - Math.pow(1d - x, 3.5d);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user