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 <[email protected]>
This commit is contained in:
2026-09-28 18:59:47 +02:00
co-authored by claude
parent ef0ead6bf8
commit a7e3e537b1
6 changed files with 90 additions and 23 deletions
@@ -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);
@@ -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<Element> 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);
@@ -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<String> emotes = Emotes.availableEmotes;
@@ -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) {
@@ -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)
@@ -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;