package de.shiewk.widgets.client.screen; import de.shiewk.widgets.Dimensionable; 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.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.text.Text; import net.minecraft.util.Util; import org.jetbrains.annotations.Nullable; import java.awt.*; import java.util.function.Consumer; import static de.shiewk.widgets.WidgetUtils.translateToScreen; import static de.shiewk.widgets.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; } } 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; this.onEdit = onEdit; } @Override public void close() { assert client != null; client.setScreen(parent); } 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 double nwx = rect.getX(this.width); final double nww = rect.width(); 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(this.width / 2 - rel.width() / 2, this.height / 2 - rel.height() / 2, rel.width(), rel.height())); 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 double nwy = rect.getY(this.height); final double nwh = rect.height(); 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; @Override public void renderScreenContents(DrawContext context, int mouseX, int mouseY, float delta) { assert client != null; for (ModWidget widget : WidgetManager.getEnabledWidgets()) { final WidgetSettings settings = widget.getSettings(); final int ww = widget.width(); double wx = Math.min(translateToScreen(settings.posX, this.width), this.width - ww); final int wh = widget.height(); double wy = Math.min(translateToScreen(settings.posY, this.height), this.height - wh); if (selectedWidget == widget){ final AlignResult alignedX = alignX(wx, ww, 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(); } final AlignResult alignedY = alignY(wy, wh, 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(); } } if (hoveredWidget == null || hoveredWidget == widget){ if (mouseX <= wx + ww && mouseX >= wx && mouseY <= wy + wh && mouseY >= wy){ if (hoveredWidget == null){ hoveredWidget = widget; } } else { hoveredWidget = null; } } if (selectedWidget == null ? hoveredWidget == widget : selectedWidget == widget){ context.drawBorder((int) Math.round(wx-1), (int) Math.round(wy-1), ww+2, wh+2, SELECT_COLOR); context.drawBorder((int) Math.round(wx), (int) Math.round(wy), ww, wh, SELECT_COLOR); } widget.render(context, Util.getMeasuringTimeNano(), textRenderer, (int) Math.round(wx), (int) Math.round(wy)); } } @Override public boolean mouseReleased(double mouseX, double mouseY, int button) { if (button == 0 && selectedWidget != null){ final AlignResult alignedX = alignX(translateToScreen(selectedWidget.getSettings().posX, this.width), selectedWidget.width(), selectedWidget); if (alignedX != null){ selectedWidget.getSettings().setPosX(translateToWidgetSettingsValue(alignedX.result(), this.width), selectedWidget.width(), this.width); } final AlignResult alignedY = alignY(translateToScreen(selectedWidget.getSettings().posY, this.height), selectedWidget.height(), selectedWidget); if (alignedY != null){ selectedWidget.getSettings().setPosY(translateToWidgetSettingsValue(alignedY.result(), this.height), selectedWidget.height(), this.height); } onEdit.accept(selectedWidget); selectedWidget = null; } return super.mouseReleased(mouseX, mouseY, button); } @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { if (button == 0 && hoveredWidget != null){ selectedWidget = hoveredWidget; } return super.mouseClicked(mouseX, mouseY, button); } @Override public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { if (button == 0){ assert client != null; final ModWidget widget = selectedWidget; if (widget != null){ final WidgetSettings settings = widget.getSettings(); final int ww = widget.width(); final int wx = (int) Math.min(translateToScreen(settings.posX, this.width), this.width - ww); final int wh = widget.height(); final int wy = (int) Math.min(translateToScreen(settings.posY, this.height), this.height - wh); if (mouseX <= wx + ww + deltaX && mouseX >= wx + deltaX){ if (mouseY <= wy + wh + deltaY && mouseY >= 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); return true; } } } } return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); } }