Compare commits

..
1 Commits
Author SHA1 Message Date
selimaj-devandclaude a7e3e537b1 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]>
2026-09-28 18:59:47 +02:00
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.provider.Providers;
import org.saturnclient.common.ref.asset.IdentifierRef; import org.saturnclient.common.ref.asset.IdentifierRef;
import org.saturnclient.config.property.BoolProperty; import org.saturnclient.config.property.BoolProperty;
import org.saturnclient.config.property.FloatProperty;
import org.saturnclient.config.property.IntProperty; import org.saturnclient.config.property.IntProperty;
import org.saturnclient.config.property.KeybindingProperty; import org.saturnclient.config.property.KeybindingProperty;
import org.saturnclient.config.property.Property; import org.saturnclient.config.property.Property;
@@ -19,8 +20,16 @@ public class Config {
public static BoolProperty cloakPhysics = Property.bool(true); public static BoolProperty cloakPhysics = Property.bool(true);
public static BoolProperty stagger = Property.bool(true); public static BoolProperty stagger = Property.bool(true);
public static IntProperty backgroundBlur = Property.integer(5).range(0, 10); 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); 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() { public static IdentifierRef getLogo() {
return realisticLogo.value ? Textures.REALISTIC_LOGO : Textures.LOGO; 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("Cloak Physics", cloakPhysics, "Let cloaks swing as you move");
config.property("Stagger Animations", stagger, "Animate list items one after another"); 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("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 // Initialize a sub namespace for theme
Theme.init(config); Theme.init(config);
@@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.saturnclient.config.Config; import org.saturnclient.config.Config;
import org.saturnclient.config.property.FloatProperty;
public abstract class SaturnScreen { public abstract class SaturnScreen {
/** How long the background blur takes to fade in, in ms */ /** How long the background blur takes to fade in, in ms */
@@ -14,8 +15,10 @@ public abstract class SaturnScreen {
public static interface ScreenProvider { public static interface ScreenProvider {
public void close(); public void close();
/** The screen's width in GUI pixels */
public int getWidth(); public int getWidth();
/** The screen's height in GUI pixels */
public int getHeight(); public int getHeight();
} }
@@ -23,6 +26,10 @@ public abstract class SaturnScreen {
public int width; public int width;
public int height; public int height;
public String title; 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 // Saturn Screen
public List<Element> elements = new ArrayList<>(); 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)); 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() { public void init() {
elements.clear(); elements.clear();
width = provider.getWidth(); scale = getScale();
height = provider.getHeight(); width = (int) (provider.getWidth() / scale);
height = (int) (provider.getHeight() / scale);
Popup.reset(width, height); Popup.reset(width, height);
ui(); // abstraction to render the saturn ui and also render extra stuff here 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) { public void render(RenderScope renderScope, int mouseX, int mouseY, float delta, long elapsed) {
renderScope.getMatrixStack().push(); renderScope.getMatrixStack().push();
renderScope.getMatrixStack().scale(0.5f, 0.5f); renderScope.getMatrixStack().scale(scale, scale);
ElementRenderer.render(new ArrayList<>(elements), elapsed, renderScope, mouseX, mouseY); ElementRenderer.render(new ArrayList<>(elements), elapsed, renderScope, mouseX, mouseY);
Popup.render(renderScope, elapsed, 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) { public boolean mouseClicked(double mouseX, double mouseY, int button) {
mouseX *= 2; mouseDown = true;
mouseY *= 2; mouseX /= scale;
mouseY /= scale;
if (!Popup.mouseClicked(mouseX, mouseY, button)) { if (!Popup.mouseClicked(mouseX, mouseY, button)) {
ElementRenderer.mouseClicked(elements, 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) { public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
mouseX *= 2; mouseX /= scale;
mouseY *= 2; mouseY /= scale;
if (!Popup.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) { if (!Popup.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) {
ElementRenderer.mouseDragged(elements, 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) { public boolean mouseReleased(double mouseX, double mouseY, int button) {
mouseX *= 2; mouseDown = false;
mouseY *= 2; mouseX /= scale;
mouseY /= scale;
// Everything hears the release, so no element is left thinking it's being dragged. // Everything hears the release, so no element is left thinking it's being dragged.
Popup.mouseReleased(mouseX, mouseY, button); Popup.mouseReleased(mouseX, mouseY, button);
@@ -122,8 +160,8 @@ public abstract class SaturnScreen {
double mouseY, double mouseY,
double horizontalAmount, double horizontalAmount,
double verticalAmount) { double verticalAmount) {
mouseX *= 2; mouseX /= scale;
mouseY *= 2; mouseY /= scale;
if (!Popup.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)) { if (!Popup.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)) {
ElementRenderer.mouseScrolled(elements, 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.common.ref.asset.IdentifierRef;
import org.saturnclient.config.AnimationConfig; import org.saturnclient.config.AnimationConfig;
import org.saturnclient.config.Config; import org.saturnclient.config.Config;
import org.saturnclient.config.property.FloatProperty;
import org.saturnclient.config.Theme; import org.saturnclient.config.Theme;
import org.saturnclient.cosmetics.Emotes; import org.saturnclient.cosmetics.Emotes;
import org.saturnclient.ui.Element; import org.saturnclient.ui.Element;
@@ -43,6 +44,11 @@ public class EmoteWheel extends SaturnScreen {
super("Emote Wheel"); super("Emote Wheel");
} }
@Override
protected FloatProperty getScaleSetting() {
return Config.hudMenuScale;
}
@Override @Override
public void ui() { public void ui() {
List<String> emotes = Emotes.availableEmotes; 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 * 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. * to move it, or drag its corner handle to resize it.
* *
* Unlike other Saturn screens this works in GUI pixels, like the HUD itself: * Unlike other Saturn screens this works in GUI pixels, like the HUD itself,
* it draws without the half scale and takes the mouse unscaled. * whatever Saturn's GUI scale.
*/ */
public class HudEditor extends SaturnScreen { public class HudEditor extends SaturnScreen {
private static final String HINT = "Drag to move · Drag the corner to resize · Esc when done"; 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 @Override
public void ui() { public void ui() {
// Placing HUDs needs a clear view of the game. // Placing HUDs needs a clear view of the game.
@@ -102,10 +107,7 @@ public class HudEditor extends SaturnScreen {
@Override @Override
public void render(RenderScope renderScope, int mouseX, int mouseY, float delta, long elapsed) { 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. HudMod hovered = draggingMod != null ? draggingMod : getModAt(mouseX, mouseY);
int guiMouseX = mouseX / 2;
int guiMouseY = mouseY / 2;
HudMod hovered = draggingMod != null ? draggingMod : getModAt(guiMouseX, guiMouseY);
for (HudMod mod : hudMods) { for (HudMod mod : hudMods) {
ModLayout dim = mod.getDimensions(); ModLayout dim = mod.getDimensions();
@@ -149,12 +151,11 @@ public class HudEditor extends SaturnScreen {
} }
private void drawHint(RenderScope renderScope) { private void drawHint(RenderScope renderScope) {
int guiWidth = width / 2;
int textWidth = (int) (Fonts.getWidth(HINT, Theme.getBodyFont()) * HINT_SCALE); int textWidth = (int) (Fonts.getWidth(HINT, Theme.getBodyFont()) * HINT_SCALE);
int textHeight = (int) (Fonts.getHeight() * HINT_SCALE); int textHeight = (int) (Fonts.getHeight() * HINT_SCALE);
int pillWidth = textWidth + 20; int pillWidth = textWidth + 20;
int pillHeight = textHeight + 10; int pillHeight = textHeight + 10;
int x = (guiWidth - pillWidth) / 2; int x = (width - pillWidth) / 2;
int y = 8; int y = 8;
renderScope.drawRoundedRectangle(x, y, pillWidth, pillHeight, pillHeight / 2, 1, Theme.getPanelBg(), 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) { private void keepOnScreen(ModLayout dim) {
int guiWidth = width / 2;
int guiHeight = height / 2;
int w = right(dim) - dim.x.value; int w = right(dim) - dim.x.value;
int h = bottom(dim) - dim.y.value; int h = bottom(dim) - dim.y.value;
dim.x.value = Math.max(0, Math.min(dim.x.value, guiWidth - w)); dim.x.value = Math.max(0, Math.min(dim.x.value, width - w));
dim.y.value = Math.max(0, Math.min(dim.y.value, guiHeight - h)); dim.y.value = Math.max(0, Math.min(dim.y.value, height - h));
} }
private static int right(ModLayout dim) { private static int right(ModLayout dim) {
@@ -3,6 +3,7 @@ package org.saturnclient.ui.screens;
import org.saturnclient.common.provider.Providers; import org.saturnclient.common.provider.Providers;
import org.saturnclient.config.AnimationConfig; import org.saturnclient.config.AnimationConfig;
import org.saturnclient.config.Config; import org.saturnclient.config.Config;
import org.saturnclient.config.property.FloatProperty;
import org.saturnclient.ui.SaturnScreen; import org.saturnclient.ui.SaturnScreen;
import org.saturnclient.ui.anim.Fade; import org.saturnclient.ui.anim.Fade;
import org.saturnclient.ui.anim.SlideY; import org.saturnclient.ui.anim.SlideY;
@@ -24,6 +25,11 @@ public class ShiftMenu extends SaturnScreen {
super("Shift Menu"); super("Shift Menu");
} }
@Override
protected FloatProperty getScaleSetting() {
return Config.hudMenuScale;
}
@Override @Override
public void ui() { public void ui() {
draw(new ImageTexture(Textures.LOGO_TEXT) 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.common.ref.game.MinecraftClientRef.MinecraftScreen;
import org.saturnclient.config.AnimationConfig; import org.saturnclient.config.AnimationConfig;
import org.saturnclient.config.Config; import org.saturnclient.config.Config;
import org.saturnclient.config.property.FloatProperty;
import org.saturnclient.config.Theme; import org.saturnclient.config.Theme;
import org.saturnclient.ui.Element; import org.saturnclient.ui.Element;
import org.saturnclient.ui.SaturnScreen; import org.saturnclient.ui.SaturnScreen;
@@ -39,6 +40,11 @@ public class TitleMenu extends SaturnScreen {
super("Title Menu"); super("Title Menu");
} }
@Override
protected FloatProperty getScaleSetting() {
return Config.titleScale;
}
@Override @Override
public void ui() { public void ui() {
blurBackground = false; blurBackground = false;