From a7e3e537b180638beadc0adcdc642935311e99ee Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Mon, 28 Sep 2026 18:59:47 +0200 Subject: [PATCH] Add GUI scale sliders for Saturn's screens The title screen, the menus and the HUD menus (emote wheel, shift menu) each get a scale slider, relative to Minecraft's GUI scale. The HUD editor stays in GUI pixels. Co-Authored-By: Claude Opus 5.5 --- .../java/org/saturnclient/config/Config.java | 12 ++++ .../org/saturnclient/ui/SaturnScreen.java | 60 +++++++++++++++---- .../saturnclient/ui/screens/EmoteWheel.java | 6 ++ .../saturnclient/ui/screens/HudEditor.java | 23 ++++--- .../saturnclient/ui/screens/ShiftMenu.java | 6 ++ .../saturnclient/ui/screens/TitleMenu.java | 6 ++ 6 files changed, 90 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/saturnclient/config/Config.java b/src/main/java/org/saturnclient/config/Config.java index 01a0ed2..4012c9e 100644 --- a/src/main/java/org/saturnclient/config/Config.java +++ b/src/main/java/org/saturnclient/config/Config.java @@ -6,6 +6,7 @@ import org.saturnclient.common.provider.GLFWProvider; import org.saturnclient.common.provider.Providers; import org.saturnclient.common.ref.asset.IdentifierRef; import org.saturnclient.config.property.BoolProperty; +import org.saturnclient.config.property.FloatProperty; import org.saturnclient.config.property.IntProperty; import org.saturnclient.config.property.KeybindingProperty; import org.saturnclient.config.property.Property; @@ -19,8 +20,16 @@ public class Config { public static BoolProperty cloakPhysics = Property.bool(true); public static BoolProperty stagger = Property.bool(true); public static IntProperty backgroundBlur = Property.integer(5).range(0, 10); + // How big Saturn's screens are, relative to Minecraft's GUI scale + public static FloatProperty titleScale = guiScale(); + public static FloatProperty menuScale = guiScale(); + public static FloatProperty hudMenuScale = guiScale(); public static KeybindingProperty openEmoteWheel = Property.keybinding(GLFWProvider.GLFW_KEY_B); + private static FloatProperty guiScale() { + return Property.floatProp(1f).range(0.5f, 2f, 0.05f).unit("×"); + } + public static IdentifierRef getLogo() { return realisticLogo.value ? Textures.REALISTIC_LOGO : Textures.LOGO; } @@ -35,6 +44,9 @@ public class Config { config.property("Cloak Physics", cloakPhysics, "Let cloaks swing as you move"); config.property("Stagger Animations", stagger, "Animate list items one after another"); config.property("Background blur", backgroundBlur, "How much the game behind Saturn's screens is blurred"); + config.property("Title screen scale", titleScale, "How big the title screen is, relative to Minecraft's GUI scale"); + config.property("Menu scale", menuScale, "How big the mods, settings and cosmetics menus are, relative to Minecraft's GUI scale"); + config.property("HUD menu scale", hudMenuScale, "How big the emote wheel and shift menu are, relative to Minecraft's GUI scale"); // Initialize a sub namespace for theme Theme.init(config); diff --git a/src/main/java/org/saturnclient/ui/SaturnScreen.java b/src/main/java/org/saturnclient/ui/SaturnScreen.java index aea1cfe..14e6b46 100644 --- a/src/main/java/org/saturnclient/ui/SaturnScreen.java +++ b/src/main/java/org/saturnclient/ui/SaturnScreen.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; import org.saturnclient.config.Config; +import org.saturnclient.config.property.FloatProperty; public abstract class SaturnScreen { /** How long the background blur takes to fade in, in ms */ @@ -14,8 +15,10 @@ public abstract class SaturnScreen { public static interface ScreenProvider { public void close(); + /** The screen's width in GUI pixels */ public int getWidth(); + /** The screen's height in GUI pixels */ public int getHeight(); } @@ -23,6 +26,10 @@ public abstract class SaturnScreen { public int width; public int height; public String title; + /** GUI pixels per Saturn unit, from {@link #getScale()} when the screen was built */ + public float scale = 0.5f; + /** Whether a mouse button is held, so the screen isn't rebuilt under a drag */ + private boolean mouseDown = false; // Saturn Screen public List elements = new ArrayList<>(); @@ -51,10 +58,39 @@ public abstract class SaturnScreen { return Math.round(Config.backgroundBlur.value * Math.min(elapsed / (float) BLUR_FADE_IN, 1f)); } + /** + * The GUI scale setting this screen follows; the menu scale unless the + * screen is another kind. + */ + protected FloatProperty getScaleSetting() { + return Config.menuScale; + } + + /** + * GUI pixels per Saturn unit. At 1× a Saturn unit is half a GUI pixel. + * Enlarging stops where the screen would be smaller than 320x240 GUI + * pixels, the least Minecraft's own GUI scale leaves. + */ + public float getScale() { + float fit = Math.min(provider.getWidth() / 320f, provider.getHeight() / 240f); + return 0.5f * Math.min(getScaleSetting().value, Math.max(1f, fit)); + } + + /** + * Rebuilds the screen if its scale setting changed, once no drag is going + * on (the slider being dragged would be replaced). + */ + public void updateScale() { + if (!mouseDown && getScale() != scale) { + init(); + } + } + public void init() { elements.clear(); - width = provider.getWidth(); - height = provider.getHeight(); + scale = getScale(); + width = (int) (provider.getWidth() / scale); + height = (int) (provider.getHeight() / scale); Popup.reset(width, height); ui(); // abstraction to render the saturn ui and also render extra stuff here } @@ -72,7 +108,7 @@ public abstract class SaturnScreen { public void render(RenderScope renderScope, int mouseX, int mouseY, float delta, long elapsed) { renderScope.getMatrixStack().push(); - renderScope.getMatrixStack().scale(0.5f, 0.5f); + renderScope.getMatrixStack().scale(scale, scale); ElementRenderer.render(new ArrayList<>(elements), elapsed, renderScope, mouseX, mouseY); Popup.render(renderScope, elapsed, mouseX, mouseY); @@ -85,8 +121,9 @@ public abstract class SaturnScreen { // -------------- public boolean mouseClicked(double mouseX, double mouseY, int button) { - mouseX *= 2; - mouseY *= 2; + mouseDown = true; + mouseX /= scale; + mouseY /= scale; if (!Popup.mouseClicked(mouseX, mouseY, button)) { ElementRenderer.mouseClicked(elements, mouseX, mouseY, button); @@ -96,8 +133,8 @@ public abstract class SaturnScreen { } public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - mouseX *= 2; - mouseY *= 2; + mouseX /= scale; + mouseY /= scale; if (!Popup.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) { ElementRenderer.mouseDragged(elements, mouseX, mouseY, button, deltaX, deltaY); @@ -107,8 +144,9 @@ public abstract class SaturnScreen { } public boolean mouseReleased(double mouseX, double mouseY, int button) { - mouseX *= 2; - mouseY *= 2; + mouseDown = false; + mouseX /= scale; + mouseY /= scale; // Everything hears the release, so no element is left thinking it's being dragged. Popup.mouseReleased(mouseX, mouseY, button); @@ -122,8 +160,8 @@ public abstract class SaturnScreen { double mouseY, double horizontalAmount, double verticalAmount) { - mouseX *= 2; - mouseY *= 2; + mouseX /= scale; + mouseY /= scale; if (!Popup.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)) { ElementRenderer.mouseScrolled(elements, mouseX, mouseY, horizontalAmount, verticalAmount); diff --git a/src/main/java/org/saturnclient/ui/screens/EmoteWheel.java b/src/main/java/org/saturnclient/ui/screens/EmoteWheel.java index 771fd40..3f6b9c3 100644 --- a/src/main/java/org/saturnclient/ui/screens/EmoteWheel.java +++ b/src/main/java/org/saturnclient/ui/screens/EmoteWheel.java @@ -7,6 +7,7 @@ import org.saturnclient.common.provider.Providers; import org.saturnclient.common.ref.asset.IdentifierRef; import org.saturnclient.config.AnimationConfig; import org.saturnclient.config.Config; +import org.saturnclient.config.property.FloatProperty; import org.saturnclient.config.Theme; import org.saturnclient.cosmetics.Emotes; import org.saturnclient.ui.Element; @@ -43,6 +44,11 @@ public class EmoteWheel extends SaturnScreen { super("Emote Wheel"); } + @Override + protected FloatProperty getScaleSetting() { + return Config.hudMenuScale; + } + @Override public void ui() { List emotes = Emotes.availableEmotes; diff --git a/src/main/java/org/saturnclient/ui/screens/HudEditor.java b/src/main/java/org/saturnclient/ui/screens/HudEditor.java index 8f10f80..363cec8 100644 --- a/src/main/java/org/saturnclient/ui/screens/HudEditor.java +++ b/src/main/java/org/saturnclient/ui/screens/HudEditor.java @@ -18,8 +18,8 @@ import org.saturnclient.ui.resources.Fonts; * Moves and resizes the enabled HUD mods, drawn as they are in game. Drag one * to move it, or drag its corner handle to resize it. * - * Unlike other Saturn screens this works in GUI pixels, like the HUD itself: - * it draws without the half scale and takes the mouse unscaled. + * Unlike other Saturn screens this works in GUI pixels, like the HUD itself, + * whatever Saturn's GUI scale. */ public class HudEditor extends SaturnScreen { private static final String HINT = "Drag to move · Drag the corner to resize · Esc when done"; @@ -45,6 +45,11 @@ public class HudEditor extends SaturnScreen { } } + @Override + public float getScale() { + return 1f; + } + @Override public void ui() { // Placing HUDs needs a clear view of the game. @@ -102,10 +107,7 @@ public class HudEditor extends SaturnScreen { @Override public void render(RenderScope renderScope, int mouseX, int mouseY, float delta, long elapsed) { - // The screen hands over the mouse in Saturn units, twice GUI pixels. - int guiMouseX = mouseX / 2; - int guiMouseY = mouseY / 2; - HudMod hovered = draggingMod != null ? draggingMod : getModAt(guiMouseX, guiMouseY); + HudMod hovered = draggingMod != null ? draggingMod : getModAt(mouseX, mouseY); for (HudMod mod : hudMods) { ModLayout dim = mod.getDimensions(); @@ -149,12 +151,11 @@ public class HudEditor extends SaturnScreen { } private void drawHint(RenderScope renderScope) { - int guiWidth = width / 2; int textWidth = (int) (Fonts.getWidth(HINT, Theme.getBodyFont()) * HINT_SCALE); int textHeight = (int) (Fonts.getHeight() * HINT_SCALE); int pillWidth = textWidth + 20; int pillHeight = textHeight + 10; - int x = (guiWidth - pillWidth) / 2; + int x = (width - pillWidth) / 2; int y = 8; renderScope.drawRoundedRectangle(x, y, pillWidth, pillHeight, pillHeight / 2, 1, Theme.getPanelBg(), @@ -176,13 +177,11 @@ public class HudEditor extends SaturnScreen { } private void keepOnScreen(ModLayout dim) { - int guiWidth = width / 2; - int guiHeight = height / 2; int w = right(dim) - dim.x.value; int h = bottom(dim) - dim.y.value; - dim.x.value = Math.max(0, Math.min(dim.x.value, guiWidth - w)); - dim.y.value = Math.max(0, Math.min(dim.y.value, guiHeight - h)); + dim.x.value = Math.max(0, Math.min(dim.x.value, width - w)); + dim.y.value = Math.max(0, Math.min(dim.y.value, height - h)); } private static int right(ModLayout dim) { diff --git a/src/main/java/org/saturnclient/ui/screens/ShiftMenu.java b/src/main/java/org/saturnclient/ui/screens/ShiftMenu.java index 3f2d512..58b932f 100644 --- a/src/main/java/org/saturnclient/ui/screens/ShiftMenu.java +++ b/src/main/java/org/saturnclient/ui/screens/ShiftMenu.java @@ -3,6 +3,7 @@ package org.saturnclient.ui.screens; import org.saturnclient.common.provider.Providers; import org.saturnclient.config.AnimationConfig; import org.saturnclient.config.Config; +import org.saturnclient.config.property.FloatProperty; import org.saturnclient.ui.SaturnScreen; import org.saturnclient.ui.anim.Fade; import org.saturnclient.ui.anim.SlideY; @@ -24,6 +25,11 @@ public class ShiftMenu extends SaturnScreen { super("Shift Menu"); } + @Override + protected FloatProperty getScaleSetting() { + return Config.hudMenuScale; + } + @Override public void ui() { draw(new ImageTexture(Textures.LOGO_TEXT) diff --git a/src/main/java/org/saturnclient/ui/screens/TitleMenu.java b/src/main/java/org/saturnclient/ui/screens/TitleMenu.java index 3821d69..cc1b450 100644 --- a/src/main/java/org/saturnclient/ui/screens/TitleMenu.java +++ b/src/main/java/org/saturnclient/ui/screens/TitleMenu.java @@ -6,6 +6,7 @@ import org.saturnclient.common.provider.Providers; import org.saturnclient.common.ref.game.MinecraftClientRef.MinecraftScreen; import org.saturnclient.config.AnimationConfig; import org.saturnclient.config.Config; +import org.saturnclient.config.property.FloatProperty; import org.saturnclient.config.Theme; import org.saturnclient.ui.Element; import org.saturnclient.ui.SaturnScreen; @@ -39,6 +40,11 @@ public class TitleMenu extends SaturnScreen { super("Title Menu"); } + @Override + protected FloatProperty getScaleSetting() { + return Config.titleScale; + } + @Override public void ui() { blurBackground = false;