diff --git a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/Gui.java b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/Gui.java index 91a69d00a..dc37fd791 100644 --- a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/Gui.java +++ b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/Gui.java @@ -43,6 +43,7 @@ import org.quiltmc.enigma.gui.util.ScaleUtil; import org.quiltmc.enigma.network.ServerMessage; import org.quiltmc.enigma.util.I18n; +import org.quiltmc.enigma.util.Utils; import org.quiltmc.enigma.util.validation.Message; import org.quiltmc.enigma.util.validation.ParameterizedMessage; import org.quiltmc.enigma.util.validation.ValidationContext; @@ -63,6 +64,7 @@ import java.awt.Container; import java.awt.Dimension; import java.awt.Point; +import java.awt.Toolkit; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; @@ -77,6 +79,8 @@ import java.util.stream.Stream; public class Gui { + private static final int DEFAULT_MIN_TOP_ON_SCREEN = 200; + private final MainWindow mainWindow; private final GuiController controller; @@ -230,7 +234,21 @@ private void setupUi() { frame.setMinimumSize(ScaleUtil.getDimension(640, 480)); frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - Point windowPos = Config.main().windowPos.value().toPoint(); + final Point windowPos = Config.main().windowPos.value().toPoint(); + final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + + // keep the whole width (or as much as will fit) on-screen so window controls in the title bar are accessible + final int clampedX = Utils.clamp(windowPos.x, 0, Math.max(0, screenSize.width - frame.getWidth())); + // allow some of the bottom to be off-screen, but not the top, because of the title bar + final int clampedY = Utils.clamp(windowPos.y, 0, screenSize.height - ScaleUtil.scale(DEFAULT_MIN_TOP_ON_SCREEN)); + + if (windowPos.x != clampedX || windowPos.y != clampedY) { + windowPos.x = clampedX; + windowPos.y = clampedY; + + Config.main().windowPos.setValue(Config.Vec2i.fromPoint(windowPos)); + } + frame.setLocation(windowPos); this.retranslateUi(); diff --git a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/config/Config.java b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/config/Config.java index dbb64fbc3..97c43f8d2 100644 --- a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/config/Config.java +++ b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/config/Config.java @@ -32,6 +32,7 @@ import java.awt.Point; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Objects; /** * Enigma config is separated into several {@value #FORMAT} files with names matching the methods used to access them: @@ -237,7 +238,11 @@ public static Vec2i fromPoint(Point point) { @Override public Vec2i convertFrom(ValueMap representation) { - return new Vec2i(representation.get("x"), representation.get("y")); + final int defaultValue = Objects.requireNonNullElse(representation.getDefaultValue(), 0); + return new Vec2i( + representation.getOrDefault("x", defaultValue), + representation.getOrDefault("y", defaultValue) + ); } @Override