From 8baf28fcfe93ba9366d98caadda405d88a8403a6 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 18:05:26 +0100 Subject: [PATCH 01/42] Implemented theme --- .../saturnclient/SaturnClient.java | 1 + .../{ => config}/SaturnClientConfig.java | 8 +- .../saturnclient/config/Theme.java | 20 ++++ .../saturnclient/config/ThemeManager.java | 93 ------------------- .../cosmetics/CloakFeatureRenderer.java | 2 +- .../saturnclient/event/KeyInputHandler.java | 2 +- .../saturnclient/mixin/NameTagMixin.java | 2 +- .../saturnclient/mixin/SetScreenMixin.java | 2 +- .../saturnclient/mixin/TabListMixin.java | 2 +- .../saturnclient/ui2/components/Sidebar.java | 2 +- .../saturnclient/ui2/screens/EmoteWheel.java | 2 +- .../saturnclient/ui2/screens/ShiftMenu.java | 2 +- .../saturnclient/ui2/screens/TitleMenu.java | 2 +- 13 files changed, 34 insertions(+), 106 deletions(-) rename src/main/java/org/saturnclient/saturnclient/{ => config}/SaturnClientConfig.java (93%) create mode 100644 src/main/java/org/saturnclient/saturnclient/config/Theme.java delete mode 100644 src/main/java/org/saturnclient/saturnclient/config/ThemeManager.java diff --git a/src/main/java/org/saturnclient/saturnclient/SaturnClient.java b/src/main/java/org/saturnclient/saturnclient/SaturnClient.java index e922ee9..7a6c803 100644 --- a/src/main/java/org/saturnclient/saturnclient/SaturnClient.java +++ b/src/main/java/org/saturnclient/saturnclient/SaturnClient.java @@ -9,6 +9,7 @@ import net.minecraft.client.util.math.MatrixStack; import org.saturnclient.modules.ModManager; import org.saturnclient.saturnclient.client.ServiceClient; import org.saturnclient.saturnclient.config.ConfigManager; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.saturnclient.cosmetics.Emotes; import org.saturnclient.saturnclient.cosmetics.Hats; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; diff --git a/src/main/java/org/saturnclient/saturnclient/SaturnClientConfig.java b/src/main/java/org/saturnclient/saturnclient/config/SaturnClientConfig.java similarity index 93% rename from src/main/java/org/saturnclient/saturnclient/SaturnClientConfig.java rename to src/main/java/org/saturnclient/saturnclient/config/SaturnClientConfig.java index 4f603b9..cd09f65 100644 --- a/src/main/java/org/saturnclient/saturnclient/SaturnClientConfig.java +++ b/src/main/java/org/saturnclient/saturnclient/config/SaturnClientConfig.java @@ -1,12 +1,9 @@ -package org.saturnclient.saturnclient; - -import org.saturnclient.saturnclient.config.Property; +package org.saturnclient.saturnclient.config; import java.util.Map; import java.util.UUID; import org.lwjgl.glfw.GLFW; -import org.saturnclient.saturnclient.config.ConfigManager; import org.saturnclient.ui2.resources.Textures; import net.minecraft.util.Formatting; @@ -79,5 +76,8 @@ public class SaturnClientConfig { config.property("Saturn client title screen", saturnTitleScreen); config.property("Open Emote Wheel", openEmoteWheel); config.property("Bendy Cloaks", bendyCloaks); + + // Initialize a sub namespace for theme + Theme.init(config); } } diff --git a/src/main/java/org/saturnclient/saturnclient/config/Theme.java b/src/main/java/org/saturnclient/saturnclient/config/Theme.java new file mode 100644 index 0000000..6eb9241 --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/config/Theme.java @@ -0,0 +1,20 @@ +package org.saturnclient.saturnclient.config; + +public class Theme { + public static Property BACKGROUND = Property.color(0x00000000); + public static Property FOREGROUND = Property.color(0x00000000); + public static Property PRIMARY = Property.color(0x00000000); + public static Property PRIMARY_FG = Property.color(0x00000000); + public static Property ACCENT = Property.color(0x00000000); + public static Property ACCENT_FG = Property.color(0x00000000); + + public static void init(ConfigManager parent) { + ConfigManager config = new ConfigManager(parent, "UI Style"); + config.property("Background", BACKGROUND); + config.property("Foreground", FOREGROUND); + config.property("Primary", PRIMARY); + config.property("Primary Foreground", PRIMARY_FG); + config.property("Accent", ACCENT); + config.property("Accent Foreground", ACCENT_FG); + } +} diff --git a/src/main/java/org/saturnclient/saturnclient/config/ThemeManager.java b/src/main/java/org/saturnclient/saturnclient/config/ThemeManager.java deleted file mode 100644 index 0bcc14b..0000000 --- a/src/main/java/org/saturnclient/saturnclient/config/ThemeManager.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.saturnclient.saturnclient.config; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.saturnclient.saturnclient.SaturnClient; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -public class ThemeManager { - private static File themeFile = new File( - SaturnClient.client.runDirectory, - "saturn.theme.json"); - private static List theme = new ArrayList<>(); - private static JsonObject cachedThemeJson = null; - - private Map> states; - private Map> currentStyling; - private String namespace; - - public ThemeManager(String namespace, String... states) { - this.namespace = namespace; - this.states = new LinkedHashMap<>(); - this.currentStyling = new LinkedHashMap<>(); - this.states.put(null, new LinkedHashMap<>()); - for (String s : states) { - this.states.put(s, new LinkedHashMap<>()); - } - theme.add(this); - } - - public void setState(String state) { - for (Map.Entry tProp : states.get(state).entrySet()) { - currentStyling.get(tProp.getKey()).setValue(tProp.getValue()); - } - } - - public void applyState(String state) { - for (Map.Entry tProp : states.get(state).entrySet()) { - if (!states.get(null).get(tProp.getKey()).equals(tProp.getValue())) - currentStyling.get(tProp.getKey()).setValue(tProp.getValue()); - } - } - - public Property property(String name, Property prop) { - for (Map.Entry> state : this.states.entrySet()) { - Property property = prop.copy(); - if (cachedThemeJson == null) { - load(); - } - String stateName = state.getKey(); - property.load(name, cachedThemeJson.get(stateName != null ? namespace + "@" + stateName : namespace)); - state.getValue().put(name, property.value); - } - - currentStyling.put(name, prop); - - return prop; - } - - public void propertyStateDefault(String state, String name, T value) { - Property prop = currentStyling.get(name).copy(); - prop.setValue(value, value); - if (cachedThemeJson == null) { - load(); - } - prop.load(name, cachedThemeJson.get(state != null ? namespace + "@" + state : namespace)); - states.get(state).put(name, prop.value); - } - - public static void load() { - try { - SaturnClient.LOGGER.info("Starting to load theme..."); - if (!themeFile.exists()) { - themeFile.createNewFile(); - Files.write(themeFile.toPath(), "{}".getBytes()); - } - - cachedThemeJson = JsonParser.parseString( - new String(Files.readAllBytes(themeFile.toPath()))).getAsJsonObject(); - - SaturnClient.LOGGER.info("Theme loaded"); - } catch (IOException e) { - SaturnClient.LOGGER.error("Error reading the theme file", e); - } - } -} diff --git a/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java b/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java index 7f869a3..9f4344f 100644 --- a/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java +++ b/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java @@ -1,7 +1,7 @@ package org.saturnclient.saturnclient.cosmetics; -import org.saturnclient.saturnclient.SaturnClientConfig; import org.saturnclient.saturnclient.client.player.SaturnPlayer; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; import net.minecraft.client.render.OverlayTexture; diff --git a/src/main/java/org/saturnclient/saturnclient/event/KeyInputHandler.java b/src/main/java/org/saturnclient/saturnclient/event/KeyInputHandler.java index 1504913..dae59f3 100644 --- a/src/main/java/org/saturnclient/saturnclient/event/KeyInputHandler.java +++ b/src/main/java/org/saturnclient/saturnclient/event/KeyInputHandler.java @@ -6,8 +6,8 @@ import net.minecraft.client.option.KeyBinding; import net.minecraft.client.util.InputUtil; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.SaturnClientConfig; import org.saturnclient.saturnclient.client.ServiceClient; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.ui2.screens.EmoteWheel; import org.saturnclient.ui2.screens.ShiftMenu; diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java index b0e9d34..112295a 100644 --- a/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java +++ b/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java @@ -14,8 +14,8 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.math.Vec3d; -import org.saturnclient.saturnclient.SaturnClientConfig; import org.saturnclient.saturnclient.client.player.SaturnPlayer; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import java.util.UUID; diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/SetScreenMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/SetScreenMixin.java index 7e4e0af..4a398a5 100644 --- a/src/main/java/org/saturnclient/saturnclient/mixin/SetScreenMixin.java +++ b/src/main/java/org/saturnclient/saturnclient/mixin/SetScreenMixin.java @@ -1,6 +1,6 @@ package org.saturnclient.saturnclient.mixin; -import org.saturnclient.saturnclient.SaturnClientConfig; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.ui2.screens.TitleMenu; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java index a1f4f37..93513cc 100644 --- a/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java +++ b/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java @@ -7,8 +7,8 @@ import net.minecraft.util.Formatting; import java.util.UUID; import org.jetbrains.annotations.Nullable; -import org.saturnclient.saturnclient.SaturnClientConfig; import org.saturnclient.saturnclient.client.player.SaturnPlayer; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; diff --git a/src/main/java/org/saturnclient/ui2/components/Sidebar.java b/src/main/java/org/saturnclient/ui2/components/Sidebar.java index 0a93dff..36b9492 100644 --- a/src/main/java/org/saturnclient/ui2/components/Sidebar.java +++ b/src/main/java/org/saturnclient/ui2/components/Sidebar.java @@ -1,8 +1,8 @@ package org.saturnclient.ui2.components; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.SaturnClientConfig; import org.saturnclient.saturnclient.config.Property; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.saturnclient.config.ThemeManager; import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.Element; diff --git a/src/main/java/org/saturnclient/ui2/screens/EmoteWheel.java b/src/main/java/org/saturnclient/ui2/screens/EmoteWheel.java index 6e4ad52..55d6fe1 100644 --- a/src/main/java/org/saturnclient/ui2/screens/EmoteWheel.java +++ b/src/main/java/org/saturnclient/ui2/screens/EmoteWheel.java @@ -1,8 +1,8 @@ package org.saturnclient.ui2.screens; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.SaturnClientConfig; import org.saturnclient.saturnclient.client.ServiceClient; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.saturnclient.cosmetics.Emotes; import org.saturnclient.ui2.SaturnScreen; import org.saturnclient.ui2.Utils; diff --git a/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java b/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java index 004308e..92866ef 100644 --- a/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java +++ b/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java @@ -1,7 +1,7 @@ package org.saturnclient.ui2.screens; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.SaturnClientConfig; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.saturnclient.menus.HudEditor; import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.screens.cosmetics.CloakMenu; diff --git a/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java b/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java index a97a6c4..7f0636a 100644 --- a/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java +++ b/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java @@ -1,7 +1,7 @@ package org.saturnclient.ui2.screens; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.SaturnClientConfig; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.saturnclient.menus.HudEditor; import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.screens.cosmetics.CloakMenu; From 39cea1418348b349a1d11db8f935a14038ffb055 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 18:10:57 +0100 Subject: [PATCH 02/42] Theme padding and radius --- .../java/org/saturnclient/saturnclient/config/Theme.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/org/saturnclient/saturnclient/config/Theme.java b/src/main/java/org/saturnclient/saturnclient/config/Theme.java index 6eb9241..33dd5d6 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/Theme.java +++ b/src/main/java/org/saturnclient/saturnclient/config/Theme.java @@ -7,6 +7,9 @@ public class Theme { public static Property PRIMARY_FG = Property.color(0x00000000); public static Property ACCENT = Property.color(0x00000000); public static Property ACCENT_FG = Property.color(0x00000000); + public static Property BG_RADIUS = Property.integer(10); + public static Property WIDGET_RADIUS = Property.integer(10); + public static Property PADDING = Property.integer(15); public static void init(ConfigManager parent) { ConfigManager config = new ConfigManager(parent, "UI Style"); @@ -16,5 +19,7 @@ public class Theme { config.property("Primary Foreground", PRIMARY_FG); config.property("Accent", ACCENT); config.property("Accent Foreground", ACCENT_FG); + config.property("Background Radius", BG_RADIUS); + config.property("Widget Radius", WIDGET_RADIUS); } } From 953182e56a41a1a1916d90241245aac616a86edd Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 18:13:36 +0100 Subject: [PATCH 03/42] Theme font, and implemented input --- .../saturnclient/config/Theme.java | 2 ++ .../ui2/components/inputs/Input.java | 18 +++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/saturnclient/saturnclient/config/Theme.java b/src/main/java/org/saturnclient/saturnclient/config/Theme.java index 33dd5d6..5e3ffb0 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/Theme.java +++ b/src/main/java/org/saturnclient/saturnclient/config/Theme.java @@ -10,6 +10,7 @@ public class Theme { public static Property BG_RADIUS = Property.integer(10); public static Property WIDGET_RADIUS = Property.integer(10); public static Property PADDING = Property.integer(15); + public static Property FONT = Property.font(1); public static void init(ConfigManager parent) { ConfigManager config = new ConfigManager(parent, "UI Style"); @@ -21,5 +22,6 @@ public class Theme { config.property("Accent Foreground", ACCENT_FG); config.property("Background Radius", BG_RADIUS); config.property("Widget Radius", WIDGET_RADIUS); + config.property("Font", WIDGET_RADIUS); } } diff --git a/src/main/java/org/saturnclient/ui2/components/inputs/Input.java b/src/main/java/org/saturnclient/ui2/components/inputs/Input.java index 99997e4..fbd48d9 100644 --- a/src/main/java/org/saturnclient/ui2/components/inputs/Input.java +++ b/src/main/java/org/saturnclient/ui2/components/inputs/Input.java @@ -2,21 +2,20 @@ package org.saturnclient.ui2.components.inputs; import org.lwjgl.glfw.GLFW; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; import org.saturnclient.ui2.resources.Fonts; public abstract class Input extends Element { - private static ThemeManager theme = new ThemeManager("Input"); - private static Property font = theme.property("font", Property.font(1)); - String text = ""; public int cursorPosition = 0; + public abstract void checkReset(); + public abstract void backspace(); + public boolean validateBackspace() { return true; } @@ -71,11 +70,12 @@ public abstract class Input extends Element { int scrollOffset = getScrollOffset(); String visibleText = getVisibleText(scrollOffset); int textColor = focused ? 0xFFFFFF : 0xAAAAAA; - renderScope.drawText(0.6f, visibleText, 4, 4, font.value, textColor); + renderScope.drawText(0.6f, visibleText, 4, 4, Theme.FONT.value, textColor); if (focused) { int cursorX = 4 + - (int) (Fonts.getWidth(visibleText.substring(0, cursorPosition - scrollOffset), font.value) * 0.6f); + (int) (Fonts.getWidth(visibleText.substring(0, cursorPosition - scrollOffset), Theme.FONT.value) + * 0.6f); renderScope.drawRect(cursorX, 2, 1, height - 4, 0xFFFFFFFF); } @@ -90,7 +90,7 @@ public abstract class Input extends Element { int maxWidth = width - 4; // Available width for text while (offset < cursorPosition) { // Ensure cursor remains visible String visibleText = text.substring(offset, cursorPosition); - if (Fonts.getWidth(visibleText, font.value) > maxWidth) { + if (Fonts.getWidth(visibleText, Theme.FONT.value) > maxWidth) { offset++; } else { break; @@ -104,7 +104,7 @@ public abstract class Input extends Element { // Ensure text does not overflow past the available width for (int i = 1; i <= visibleText.length(); i++) { - if (Fonts.getWidth(visibleText.substring(0, i), font.value) > width - 4) { + if (Fonts.getWidth(visibleText.substring(0, i), Theme.FONT.value) > width - 4) { return visibleText.substring(0, i - 1); // Trim overflow } } From 3bc21a5b30f08ff6818fda8c1b497be9ab6078b1 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 18:19:44 +0100 Subject: [PATCH 04/42] Keybinding selector and select --- .../components/inputs/KeybindingSelector.java | 6 ++---- .../ui2/components/inputs/Select.java | 16 +++++----------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/components/inputs/KeybindingSelector.java b/src/main/java/org/saturnclient/ui2/components/inputs/KeybindingSelector.java index c4f07ad..d65ebfd 100644 --- a/src/main/java/org/saturnclient/ui2/components/inputs/KeybindingSelector.java +++ b/src/main/java/org/saturnclient/ui2/components/inputs/KeybindingSelector.java @@ -2,15 +2,13 @@ package org.saturnclient.ui2.components.inputs; import org.lwjgl.glfw.GLFW; import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; import org.saturnclient.ui2.resources.Fonts; public class KeybindingSelector extends Element { - private static ThemeManager theme = new ThemeManager("Input"); - private static Property font = theme.property("font", Property.font(1)); Property prop; public KeybindingSelector(Property prop) { @@ -25,7 +23,7 @@ public class KeybindingSelector extends Element { renderScope.drawRoundedRectangle(0, 0, width, height, 10, 0xFF000000); renderScope.drawText(0.6f, prop.value == -1 ? "" : GLFW.glfwGetKeyName(prop.value, GLFW.glfwGetKeyScancode(prop.value)).toUpperCase(), - 4, 4, font.value, textColor); + 4, 4, Theme.FONT.value, textColor); } @Override diff --git a/src/main/java/org/saturnclient/ui2/components/inputs/Select.java b/src/main/java/org/saturnclient/ui2/components/inputs/Select.java index c4d207c..31aeedf 100644 --- a/src/main/java/org/saturnclient/ui2/components/inputs/Select.java +++ b/src/main/java/org/saturnclient/ui2/components/inputs/Select.java @@ -1,7 +1,7 @@ package org.saturnclient.ui2.components.inputs; import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; @@ -10,11 +10,6 @@ import org.saturnclient.ui2.resources.Fonts; import net.minecraft.client.render.RenderLayer; public class Select extends Element { - private static ThemeManager theme = new ThemeManager("Toggle"); - private static Property fgColor = theme.property("fg-color", Property.color(0xAAAAAA)); - private static Property arrowColor = theme.property("arrow-color", Property.color(0xff8B5CF6)); - private static Property font = theme.property("font", Property.font(1)); - private Property prop; public Select(Property prop) { @@ -27,15 +22,14 @@ public class Select extends Element { public void render(RenderScope renderScope, ElementContext ctx) { renderScope.setRenderLayer(RenderLayer::getGuiTextured); - renderScope.drawText(0.8f, "<", 0, 0, font.value, arrowColor.value); + renderScope.drawText(0.8f, "<", 0, 0, Theme.FONT.value, Theme.FOREGROUND.value); String text = prop.getSelection(); - renderScope.drawText(0.6f, text, (int) (width - ((float) Fonts.getWidth(text, font.value) * 0.6f)) / 2, 1, font.value, fgColor.value); + renderScope.drawText(0.6f, text, (int) (width - ((float) Fonts.getWidth(text, Theme.FONT.value) * 0.6f)) / 2, 1, + Theme.FONT.value, Theme.FOREGROUND.value); - renderScope.drawText(0.8f, ">", width - 10, 0, font.value, arrowColor.value); - - theme.setState(null); + renderScope.drawText(0.8f, ">", width - 10, 0, Theme.FONT.value, Theme.FOREGROUND.value); } @Override From b0dbdeafa3e63e6815f99c7354cbdbfab3c8f76c Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 18:25:17 +0100 Subject: [PATCH 05/42] Toggle --- .../ui2/components/inputs/Toggle.java | 29 ++++--------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/components/inputs/Toggle.java b/src/main/java/org/saturnclient/ui2/components/inputs/Toggle.java index 5436d42..c0cfcf6 100644 --- a/src/main/java/org/saturnclient/ui2/components/inputs/Toggle.java +++ b/src/main/java/org/saturnclient/ui2/components/inputs/Toggle.java @@ -1,22 +1,12 @@ package org.saturnclient.ui2.components.inputs; import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; public class Toggle extends Element { - private static ThemeManager theme = new ThemeManager("Toggle", "hovering", "enabled"); - private static Property bgColor = theme.property("bg-color", Property.color(0xFF808080)); - private static Property fgColor = theme.property("fg-color", Property.color(0xFF909090)); - private static Property cornerRadius = theme.property("corner-radius", Property.integer(30)); - - static { - theme.propertyStateDefault("enabled", "bg-color", 0xaf8B5CF6); - theme.propertyStateDefault("enabled", "fg-color", 0xff8B5CF6); - } - private Property prop; public Toggle(Property prop) { @@ -27,19 +17,10 @@ public class Toggle extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { - theme.setState(null); - - if (prop.value) { - theme.setState("enabled"); - } - - if (ctx.isHovering()) { - theme.applyState("hovering"); - } - - renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value); - - renderScope.drawRoundedRectangle(prop.value ? 30 : 0, 0, 30, 30, 30, fgColor.value); + renderScope.drawRoundedRectangle(0, 0, width, height, height, + prop.value ? Theme.ACCENT.value : Theme.PRIMARY.value); + renderScope.drawRoundedRectangle(prop.value ? 30 : 0, 0, 30, 30, 30, + prop.value ? Theme.ACCENT.value : Theme.PRIMARY.value); } @Override From 79ceaf67a12c121ab5c53a8576778eb46d26617c Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 18:28:30 +0100 Subject: [PATCH 06/42] Cosmetic Preview --- .../ui2/components/CosmeticPreview.java | 32 ++++++------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/components/CosmeticPreview.java b/src/main/java/org/saturnclient/ui2/components/CosmeticPreview.java index 55d9e99..6056550 100644 --- a/src/main/java/org/saturnclient/ui2/components/CosmeticPreview.java +++ b/src/main/java/org/saturnclient/ui2/components/CosmeticPreview.java @@ -1,7 +1,6 @@ package org.saturnclient.ui2.components; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; @@ -10,13 +9,8 @@ import net.minecraft.client.render.RenderLayer; import net.minecraft.util.Identifier; public class CosmeticPreview extends Element { - private static ThemeManager theme = new ThemeManager("CosmeticPreview", "selected", "hovering"); - private static Property bgColor = theme.property("bg-color", Property.color(0x89000000)); - private static Property fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF)); - private static Property padding = theme.property("padding", Property.integer(14)); - private static Property cornerRadius = theme.property("corner-radius", Property.integer(10)); - - static {} + static { + } Identifier sprite; private Runnable onClick; @@ -30,25 +24,19 @@ public class CosmeticPreview extends Element { this.width = 50; this.height = 111; } - + @Override public void render(RenderScope renderScope, ElementContext ctx) { - if (ctx.isHovering()) { - theme.setState("hovering"); - } else if (isSelected) { - theme.setState("selected"); - } + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, + isSelected ? Theme.ACCENT.value : Theme.PRIMARY.value); - renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value); - renderScope.setRenderLayer(RenderLayer::getGuiTextured); - int texWidth = width - padding.value; - int texHeight = height - padding.value; - - renderScope.drawTexture(sprite, padding.value / 2, padding.value / 2, 0, 0, texWidth, texHeight, fgColor.value); + int texWidth = width - Theme.PADDING.value; + int texHeight = height - Theme.PADDING.value; - theme.setState(null); + renderScope.drawTexture(sprite, Theme.PADDING.value / 2, Theme.PADDING.value / 2, 0, 0, texWidth, texHeight, + Theme.FOREGROUND.value); } @Override From 5b37131bfd539fa1625b48660223d18363e528e5 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 18:34:12 +0100 Subject: [PATCH 07/42] Saturn module --- .../ui2/components/SaturnModule.java | 59 +++++++------------ 1 file changed, 22 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/components/SaturnModule.java b/src/main/java/org/saturnclient/ui2/components/SaturnModule.java index a9c0059..60d27e5 100644 --- a/src/main/java/org/saturnclient/ui2/components/SaturnModule.java +++ b/src/main/java/org/saturnclient/ui2/components/SaturnModule.java @@ -2,8 +2,7 @@ package org.saturnclient.ui2.components; import org.saturnclient.modules.Module; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.resources.Fonts; import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.Element; @@ -15,21 +14,12 @@ import org.saturnclient.ui2.screens.ConfigEditor; import net.minecraft.client.render.RenderLayer; public class SaturnModule extends Element { - private static ThemeManager theme = new ThemeManager("Module", "enabled", "hovering"); - private static Property bgColor = theme.property("bg", Property.color(0xFF1d202d)); - private static Property fgColor = theme.property("fg", Property.color(0xFFA1A2B8)); - private static Property iconFg = theme.property("icon-fg", Property.color(0xFFA1A2B8)); - private static Property iconBg = theme.property("icon-bg", Property.color(0xFF2e3248)); - private static Property tagBg = theme.property("tag-bg", Property.color(0xFF2e3248)); - private static Property iconRadius = theme.property("icon-radius", Property.color(10)); - private static Property font = theme.property("font", Property.font(1)); - private static Property radius = theme.property("radius", Property.color(10)); - - static { - theme.propertyStateDefault("enabled", "bg", 0xFF1d202d); - theme.propertyStateDefault("enabled", "icon-bg", 0xFF845eee); - theme.propertyStateDefault("hovering", "fg", 0xFF845eee); - } + // TODO make these states + // static { + // theme.propertyStateDefault("enabled", "bg", 0xFF1d202d); + // theme.propertyStateDefault("enabled", "icon-bg", 0xFF845eee); + // theme.propertyStateDefault("hovering", "fg", 0xFF845eee); + // } private Module mod; @@ -47,43 +37,38 @@ public class SaturnModule extends Element { renderScope.setRenderLayer(RenderLayer::getGuiTextured); + // TODO use this if (mod.isEnabled()) { - theme.setState("enabled"); } - if (ctx.isHovering(width - s - p - 5, height - s - p - 5, s + 10, s + 10)) { - settingsHover = true; - } else if (ctx.isHovering()) { - theme.applyState("hovering"); - } + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, Theme.PRIMARY.value); - renderScope.drawRoundedRectangle(0, 0, width, height, radius.value, bgColor.value); + int h = height - (p * 2); - int h = height-(p * 2); + renderScope.drawRoundedRectangle(p, p, h, h, Theme.WIDGET_RADIUS.value, Theme.PRIMARY.value); - renderScope.drawRoundedRectangle(p, p, h, h, iconRadius.value, iconBg.value); + renderScope.drawTexture(mod.getIconTexture(), p + (p / 2), p + (p / 2), 0, 0, h - p, h - p, + Theme.PRIMARY_FG.value); - renderScope.drawTexture(mod.getIconTexture(), p + (p / 2), p + (p / 2), 0, 0, h - p, h - p, iconFg.value); + renderScope.drawText(0.6f, mod.getName(), p + h + 4, p + 1, Theme.FONT.value, Theme.PRIMARY_FG.value); - renderScope.drawText(0.6f, mod.getName(), p+h+4, p + 1, font.value, fgColor.value); - - renderScope.drawText(0.35f, mod.getVersion(), width - p - (int) (Fonts.getWidth(mod.getVersion(), font.value) * 0.35f), p + 1, font.value, fgColor.value); + renderScope.drawText(0.35f, mod.getVersion(), + width - p - (int) (Fonts.getWidth(mod.getVersion(), Theme.FONT.value) * 0.35f), p + 1, Theme.FONT.value, + Theme.PRIMARY_FG.value); int xt = p + h + 4; for (String tag : mod.getTags()) { - int xtb = (int) (Fonts.getWidth(tag, font.value) * 0.4f); - renderScope.drawRoundedRectangle(xt, p + (h/2), xtb + 6, 12, 5, tagBg.value); - renderScope.drawText(0.4f, tag, xt+2, p + (h/2) + 3, font.value, fgColor.value); + int xtb = (int) (Fonts.getWidth(tag, Theme.FONT.value) * 0.4f); + renderScope.drawRoundedRectangle(xt, p + (h / 2), xtb + 6, 12, 5, Theme.ACCENT.value); + renderScope.drawText(0.4f, tag, xt + 2, p + (h / 2) + 3, Theme.FONT.value, Theme.ACCENT_FG.value); xt += xtb + 9; } + // TODO if (settingsHover) { - theme.setState("hovering"); } - renderScope.drawTexture(Textures.SETTINGS, width - s - p, height - s - p, 0, 0, s, s, fgColor.value); - - theme.setState(null); + renderScope.drawTexture(Textures.SETTINGS, width - s - p, height - s - p, 0, 0, s, s, Theme.PRIMARY_FG.value); } @Override From aab4f02dc0abdb5a6b88ef87bb3a33ec28c3fc66 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 18:40:14 +0100 Subject: [PATCH 08/42] Sidebar --- .../saturnclient/ui2/components/Sidebar.java | 62 +++++++------------ 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/components/Sidebar.java b/src/main/java/org/saturnclient/ui2/components/Sidebar.java index 36b9492..aa47d99 100644 --- a/src/main/java/org/saturnclient/ui2/components/Sidebar.java +++ b/src/main/java/org/saturnclient/ui2/components/Sidebar.java @@ -1,9 +1,8 @@ package org.saturnclient.ui2.components; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.config.Property; import org.saturnclient.saturnclient.config.SaturnClientConfig; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; @@ -18,19 +17,6 @@ import net.minecraft.client.render.RenderLayer; import net.minecraft.util.Identifier; public class Sidebar extends Element { - private static ThemeManager theme = new ThemeManager("SideBar", "hovering"); - private static Property bgColor = theme.property("bg-color", Property.color(0x90000000)); - private static Property iconFg = theme.property("icon-fg", Property.color(0xFFFFFFFF)); - private static Property iconBg = theme.property("icon-bg", Property.color(0x00000000)); - - private static Property cornerRadius = theme.property("corner-radius", Property.integer(10)); - private static Property iconRadius = theme.property("icon-radius", Property.integer(10)); - private static Property padding = theme.property("padding", Property.integer(10)); - - static { - theme.propertyStateDefault("hovering", "icon-bg", -7643914); - } - public static class SidebarComponent { Runnable onClick; boolean end; @@ -45,7 +31,7 @@ public class Sidebar extends Element { Runnable onClose; SidebarComponent[] components = { - new Sidebar.SidebarComponent(Textures.MODS_TAB, () -> { + new Sidebar.SidebarComponent(Textures.MODS_TAB, () -> { SaturnClient.client.setScreen(new ModMenu()); }, false), new Sidebar.SidebarComponent(Textures.SETTINGS, () -> { @@ -79,36 +65,33 @@ public class Sidebar extends Element { int bottomRow = 0; int gap = 5; // 5px gap between icons - int sp = 30 - padding.value + gap; - int s = 30 - (padding.value * 2); - int s2 = s + padding.value; + int padding = 10; + int sp = 30 - padding + gap; + int s = 30 - (padding * 2); + int s2 = s + padding; renderScope.setRenderLayer(RenderLayer::getGuiTextured); - renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value); + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.BG_RADIUS.value, Theme.BACKGROUND.value); int i = 0; for (SidebarComponent component : components) { if (component.end) { int y = (height - (sp * bottomRow)) - (s * 2); - if (ctx.isHovering(0, y - (padding.value / 2), s2, s2) || active == i) { - theme.setState("hovering"); - } else { - theme.setState(null); + if (ctx.isHovering(0, y - (padding / 2), s2, s2) || active == i) { } - renderScope.drawRoundedRectangle(padding.value / 2, y - (padding.value / 2), s + padding.value, s + padding.value, iconRadius.value, iconBg.value); - renderScope.drawTexture(component.sprite, padding.value, y, 0, 0, s, s, iconFg.value); + renderScope.drawRoundedRectangle(padding / 2, y - (padding / 2), s + padding, + s + padding, Theme.WIDGET_RADIUS.value, Theme.PRIMARY.value); + renderScope.drawTexture(component.sprite, padding, y, 0, 0, s, s, Theme.PRIMARY_FG.value); bottomRow += 1; } else { - int y = padding.value + (sp * topRow); - if (ctx.isHovering(0, y - (padding.value / 2), s2, s2) || active == i) { - theme.setState("hovering"); - } else { - theme.setState(null); + int y = padding + (sp * topRow); + if (ctx.isHovering(0, y - (padding / 2), s2, s2) || active == i) { } - renderScope.drawRoundedRectangle(padding.value / 2, y - (padding.value / 2), s + padding.value, s + padding.value, iconRadius.value, iconBg.value); - renderScope.drawTexture(component.sprite, padding.value, y, 0, 0, s, s, iconFg.value); + renderScope.drawRoundedRectangle(padding / 2, y - (padding / 2), s + padding, + s + padding, Theme.WIDGET_RADIUS.value, Theme.PRIMARY.value); + renderScope.drawTexture(component.sprite, padding, y, 0, 0, s, s, Theme.PRIMARY_FG.value); topRow += 1; } @@ -122,21 +105,22 @@ public class Sidebar extends Element { int bottomRow = 0; int gap = 5; // same 5px gap here - int sp = 30 - padding.value + gap; - int s = 30 - (padding.value * 2); - int s2 = s + padding.value; + int padding = 10; + int sp = 30 - padding + gap; + int s = 30 - (padding * 2); + int s2 = s + padding; for (SidebarComponent component : components) { if (component.end) { int y = (height - (sp * bottomRow)) - (s * 2); - if (Utils.isHovering(mouseX - (padding.value / 2), mouseY - (y - (padding.value / 2)), s2, s2, scale)) { + if (Utils.isHovering(mouseX - (padding / 2), mouseY - (y - (padding / 2)), s2, s2, scale)) { component.onClick.run(); break; } bottomRow += 1; } else { - int y = padding.value + (sp * topRow); - if (Utils.isHovering(mouseX - (padding.value / 2), mouseY - (y - (padding.value / 2)), s2, s2, scale)) { + int y = padding + (sp * topRow); + if (Utils.isHovering(mouseX - (padding / 2), mouseY - (y - (padding / 2)), s2, s2, scale)) { component.onClick.run(); break; } From 289a2cd78a9ebee51eb8661937b1756236450966 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 18:44:24 +0100 Subject: [PATCH 09/42] Button --- .../org/saturnclient/ui2/elements/Button.java | 27 +++++-------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/elements/Button.java b/src/main/java/org/saturnclient/ui2/elements/Button.java index 0b74643..73a1a1c 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Button.java +++ b/src/main/java/org/saturnclient/ui2/elements/Button.java @@ -1,43 +1,28 @@ package org.saturnclient.ui2.elements; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; import org.saturnclient.ui2.resources.Fonts; public class Button extends Element { - private static ThemeManager theme = new ThemeManager("Button", "hovering"); - private static Property bgColor = theme.property("bg-color", Property.color(0xFF000000)); - private static Property fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF)); - private static Property cornerRadius = theme.property("corner-radius", Property.integer(10)); - private static Property font = theme.property("font", Property.font(1)); - - static { - theme.propertyStateDefault("hovering", "fg-color", 0xFF845eee); - } - private String text; private Runnable onClick; public Button(String text, Runnable onClick) { this.text = text; this.onClick = onClick; - this.dimensions(Fonts.getWidth(text, font.value) + 50, 38); } @Override public void render(RenderScope renderScope, ElementContext ctx) { - if (ctx.isHovering()) { - theme.setState("hovering"); - } else { - theme.setState(null); - } - renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value); + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, + ctx.isHovering() ? Theme.ACCENT.value : Theme.PRIMARY.value); - // renderScope.drawText(text, (width - Fonts.getWidth(text, font)) / 2, (height - Fonts.getHeight()) / 2, bold.value, fgColor.value); - renderScope.drawText(text, Fonts.centerX(width, text, font.value), Fonts.centerY(height), font.value, fgColor.value); + renderScope.drawText(text, Fonts.centerX(width, text, Theme.FONT.value), Fonts.centerY(height), + Theme.FONT.value, + ctx.isHovering() ? Theme.ACCENT_FG.value : Theme.PRIMARY_FG.value); } @Override From e031672d72a750c9c8a0f8aa02e75411af9526f5 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 18:46:03 +0100 Subject: [PATCH 10/42] Clicakble texture --- .../ui2/elements/ClickableTexture.java | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/elements/ClickableTexture.java b/src/main/java/org/saturnclient/ui2/elements/ClickableTexture.java index 0a8aff1..877eeea 100644 --- a/src/main/java/org/saturnclient/ui2/elements/ClickableTexture.java +++ b/src/main/java/org/saturnclient/ui2/elements/ClickableTexture.java @@ -1,7 +1,6 @@ package org.saturnclient.ui2.elements; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; @@ -10,9 +9,6 @@ import net.minecraft.client.render.RenderLayer; import net.minecraft.util.Identifier; public class ClickableTexture extends Element { - private static ThemeManager theme = new ThemeManager("ClickableTexture", "hovering"); - private static Property fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF)); - Identifier sprite; private Runnable onClick; @@ -20,17 +16,12 @@ public class ClickableTexture extends Element { this.sprite = sprite; this.onClick = onClick; } - + @Override public void render(RenderScope renderScope, ElementContext ctx) { - if (ctx.isHovering()) { - theme.setState("hovering"); - } else { - theme.setState(null); - } - renderScope.setRenderLayer(RenderLayer::getGuiTextured); - renderScope.drawTexture(sprite, 0, 0, 0, 0, width, height, fgColor.value); + renderScope.drawTexture(sprite, 0, 0, 0, 0, width, height, + ctx.isHovering() ? Theme.ACCENT.value : Theme.PRIMARY.value); } @Override From 9fd79aadd549c104d47d15eb99e47949098d2ad7 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 18:47:19 +0100 Subject: [PATCH 11/42] Notification --- .../org/saturnclient/ui2/elements/Notification.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/elements/Notification.java b/src/main/java/org/saturnclient/ui2/elements/Notification.java index 61916d0..0da60c7 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Notification.java +++ b/src/main/java/org/saturnclient/ui2/elements/Notification.java @@ -1,7 +1,7 @@ package org.saturnclient.ui2.elements; import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; @@ -10,11 +10,9 @@ import org.saturnclient.ui2.resources.Fonts; import org.saturnclient.ui2.resources.Textures; public class Notification extends Element { - private static ThemeManager theme = new ThemeManager("Notification"); - private static Property bgColor = theme.property("bg-color", Property.color(0xFF000000)); - private static Property error = theme.property("error", Property.color(0xFFbf212f)); - private static Property info = theme.property("info", Property.color(0xFF264b96)); - private static Property success = theme.property("success", Property.color(0xFF27b376)); + private static Property error = Property.color(0xFFbf212f); + private static Property info = Property.color(0xFF264b96); + private static Property success = Property.color(0xFF27b376); public static enum NotificationKind { Error, @@ -40,7 +38,7 @@ public class Notification extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawRoundedRectangle(0, 0, width, height, 10, bgColor.value); + renderScope.drawRoundedRectangle(0, 0, width, height, 10, Theme.PRIMARY.value); switch (kind) { case Error: renderScope.drawTexture(Textures.CIRCLE_X, 9, 9, 0, 0, 15, 15, error.value); From 569aecde4a91da0587a6b2f1632c8a1bb0d997ea Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 18:51:58 +0100 Subject: [PATCH 12/42] Scroll --- .../org/saturnclient/ui2/elements/Scroll.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/elements/Scroll.java b/src/main/java/org/saturnclient/ui2/elements/Scroll.java index 0b0e761..7b78025 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Scroll.java +++ b/src/main/java/org/saturnclient/ui2/elements/Scroll.java @@ -4,22 +4,19 @@ import java.util.ArrayList; import java.util.List; import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; import org.saturnclient.ui2.components.ElementRenderer; public class Scroll extends Element { - private static ThemeManager theme = new ThemeManager("Scroll"); - private static Property bgColor = theme.property("bg-color", Property.color(0x90000000)); - private static Property scrollBarColor = theme.property("scrollbar-color", Property.color(-7643914)); + private static Property scrollBarColor = Property.color(-7643914); + + private static Property scrollBarRadius = Property.integer(10); + private static Property scrollBarWidth = Property.integer(5); + private static Property scrollBarPadding = Property.integer(5); - private static Property scrollBarRadius = theme.property("scrollbar-radius", Property.integer(10)); - private static Property scrollBarWidth = theme.property("scrollbar-width", Property.integer(5)); - private static Property scrollBarPadding = theme.property("scrollbar-padding", Property.integer(5)); - private static Property cornerRadius = theme.property("corner-radius", Property.integer(10)); - int padding = 0; protected List children = new ArrayList<>(); @@ -32,7 +29,7 @@ public class Scroll extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value); + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.BG_RADIUS.value, Theme.BACKGROUND.value); renderScope.enableScissor(padding, padding, width - padding, height - padding); renderScope.matrices.push(); @@ -41,7 +38,8 @@ public class Scroll extends Element { renderScope.matrices.pop(); renderScope.disableScissor(); - renderScope.drawRoundedRectangle(width - scrollBarWidth.value - scrollBarPadding.value, calculateScrollBarY(), scrollBarWidth.value, calculateScrollBarHeight(), scrollBarRadius.value, scrollBarColor.value); + renderScope.drawRoundedRectangle(width - scrollBarWidth.value - scrollBarPadding.value, calculateScrollBarY(), + scrollBarWidth.value, calculateScrollBarHeight(), scrollBarRadius.value, scrollBarColor.value); } @Override @@ -72,13 +70,16 @@ public class Scroll extends Element { } int calculateScrollBarHeight() { - if (maxScroll <= 0) return height - (scrollBarPadding.value * 2); // No scrolling needed - return Math.max(20, (height * height) / (height + maxScroll)) - (scrollBarPadding.value * 2); // At least 20px tall + if (maxScroll <= 0) + return height - (scrollBarPadding.value * 2); // No scrolling needed + return Math.max(20, (height * height) / (height + maxScroll)) - (scrollBarPadding.value * 2); // At least 20px + // tall } int calculateScrollBarY() { int scrollBarHeight = calculateScrollBarHeight(); - if (maxScroll <= 0) return scrollBarPadding.value; + if (maxScroll <= 0) + return scrollBarPadding.value; return (scroll * (height - scrollBarHeight)) / maxScroll + scrollBarPadding.value; } From 60d83530aea6289f3ce5e349f066025bf61df2d9 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 19:18:42 +0100 Subject: [PATCH 13/42] Tabmenu text and texture button --- .../saturnclient/config/Theme.java | 2 +- .../saturnclient/ui2/elements/TabMenu.java | 29 ++++++---------- .../org/saturnclient/ui2/elements/Text.java | 11 ++---- .../ui2/elements/TextureButton.java | 34 +++++-------------- 4 files changed, 23 insertions(+), 53 deletions(-) diff --git a/src/main/java/org/saturnclient/saturnclient/config/Theme.java b/src/main/java/org/saturnclient/saturnclient/config/Theme.java index 5e3ffb0..b053d95 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/Theme.java +++ b/src/main/java/org/saturnclient/saturnclient/config/Theme.java @@ -5,7 +5,7 @@ public class Theme { public static Property FOREGROUND = Property.color(0x00000000); public static Property PRIMARY = Property.color(0x00000000); public static Property PRIMARY_FG = Property.color(0x00000000); - public static Property ACCENT = Property.color(0x00000000); + public static Property ACCENT = Property.color(0xFF845eee); public static Property ACCENT_FG = Property.color(0x00000000); public static Property BG_RADIUS = Property.integer(10); public static Property WIDGET_RADIUS = Property.integer(10); diff --git a/src/main/java/org/saturnclient/ui2/elements/TabMenu.java b/src/main/java/org/saturnclient/ui2/elements/TabMenu.java index e640106..b41757b 100644 --- a/src/main/java/org/saturnclient/ui2/elements/TabMenu.java +++ b/src/main/java/org/saturnclient/ui2/elements/TabMenu.java @@ -1,7 +1,6 @@ package org.saturnclient.ui2.elements; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; @@ -10,16 +9,6 @@ import org.saturnclient.ui2.Utils; import net.minecraft.util.Identifier; public class TabMenu extends Element { - private static ThemeManager theme = new ThemeManager("TabMenu", "hovering", "selected"); - private static Property bgColor = theme.property("bg-color", Property.color(0x90000000)); - private static Property iconFg = theme.property("icon-fg", Property.color(0xFFFFFFFF)); - private static Property iconBg = theme.property("icon-bg", Property.color(0x00000000)); - private static Property cornerRadius = theme.property("corner-radius", Property.integer(10)); - - static { - theme.propertyStateDefault("hovering", "icon-bg", -7643914); - } - public static class TabMenuComponent { Runnable onClick; Identifier sprite; @@ -29,7 +18,7 @@ public class TabMenu extends Element { this.sprite = sprite; } } - + TabMenuComponent[] components; public int selectedScreen = 0; @@ -42,19 +31,21 @@ public class TabMenu extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value); + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, Theme.PRIMARY.value); int col = 0; for (TabMenuComponent component : components) { int x = 25 * col + 5; - if (ctx.isHovering(x, 5, 20, 20) || selectedScreen == col) { - theme.setState("hovering"); + + boolean hovering = ctx.isHovering(x, 5, 20, 20) || selectedScreen == col; + + if (hovering) { + renderScope.drawRoundedRectangle(x, 5, 20, 20, Theme.WIDGET_RADIUS.value, Theme.ACCENT.value); } - renderScope.drawRoundedRectangle(x, 5, 20, 20, cornerRadius.value, iconBg.value); - renderScope.drawTexture(component.sprite, x + 5, 10, 0, 0, 10, 10, iconFg.value); + renderScope.drawTexture(component.sprite, x + 5, 10, 0, 0, 10, 10, + hovering ? Theme.ACCENT_FG.value : Theme.PRIMARY_FG.value); - theme.setState(null); col++; } } diff --git a/src/main/java/org/saturnclient/ui2/elements/Text.java b/src/main/java/org/saturnclient/ui2/elements/Text.java index 8465021..285433d 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Text.java +++ b/src/main/java/org/saturnclient/ui2/elements/Text.java @@ -1,27 +1,22 @@ package org.saturnclient.ui2.elements; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; import org.saturnclient.ui2.resources.Fonts; public class Text extends Element { - private static ThemeManager theme = new ThemeManager("Text"); - private static Property fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF)); - public static Property font = theme.property("font", Property.font(1)); - private String text; public Text(String text) { this.text = text; - width = Fonts.getWidth(text, font.value); + width = Fonts.getWidth(text, Theme.FONT.value); height = Fonts.getHeight(); } @Override public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawText(this.text, 0, 0, font.value, fgColor.value); + renderScope.drawText(this.text, 0, 0, Theme.FONT.value, Theme.FOREGROUND.value); } } diff --git a/src/main/java/org/saturnclient/ui2/elements/TextureButton.java b/src/main/java/org/saturnclient/ui2/elements/TextureButton.java index d345bf3..56d8a75 100644 --- a/src/main/java/org/saturnclient/ui2/elements/TextureButton.java +++ b/src/main/java/org/saturnclient/ui2/elements/TextureButton.java @@ -1,7 +1,6 @@ package org.saturnclient.ui2.elements; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; @@ -10,17 +9,6 @@ import net.minecraft.client.render.RenderLayer; import net.minecraft.util.Identifier; public class TextureButton extends Element { - private static ThemeManager theme = new ThemeManager("TextureButton", "hovering"); - private static Property bgColor = theme.property("bg-color", Property.color(0xFF000000)); - private static Property fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF)); - private static Property padding = theme.property("padding", Property.integer(14)); - private static Property cornerRadius = theme.property("corner-radius", Property.integer(10)); - - - static { - theme.propertyStateDefault("hovering", "fg-color", 0xFF845eee); - } - Identifier sprite; private Runnable onClick; @@ -28,23 +16,19 @@ public class TextureButton extends Element { this.sprite = sprite; this.onClick = onClick; } - + @Override public void render(RenderScope renderScope, ElementContext ctx) { - if (ctx.isHovering()) { - theme.setState("hovering"); - } else { - theme.setState(null); - } + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, + ctx.isHovering() ? Theme.ACCENT.value : Theme.PRIMARY.value); - renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value); - renderScope.setRenderLayer(RenderLayer::getGuiTextured); - int texWidth = width - padding.value; - int texHeight = height - padding.value; - - renderScope.drawTexture(sprite, padding.value / 2, padding.value / 2, 0, 0, texWidth, texHeight, fgColor.value); + int texWidth = width - Theme.PADDING.value; + int texHeight = height - Theme.PADDING.value; + + renderScope.drawTexture(sprite, Theme.PADDING.value / 2, Theme.PADDING.value / 2, 0, 0, texWidth, texHeight, + ctx.isHovering() ? Theme.ACCENT_FG.value : Theme.PRIMARY_FG.value); } @Override From a7c5f0d3df9dcb0dcf109e463929a4cddaef536e Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 19:19:54 +0100 Subject: [PATCH 14/42] Fixed font stuff in screens --- .../org/saturnclient/ui2/screens/ConfigEditor.java | 14 +++++++------- .../saturnclient/ui2/screens/store/CloakStore.java | 5 +++-- .../saturnclient/ui2/screens/store/HatStore.java | 5 +++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/screens/ConfigEditor.java b/src/main/java/org/saturnclient/ui2/screens/ConfigEditor.java index e46fcb6..7b00966 100644 --- a/src/main/java/org/saturnclient/ui2/screens/ConfigEditor.java +++ b/src/main/java/org/saturnclient/ui2/screens/ConfigEditor.java @@ -4,6 +4,7 @@ import java.util.Map; import org.saturnclient.saturnclient.config.ConfigManager; import org.saturnclient.saturnclient.config.Property; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.SaturnScreen; import org.saturnclient.ui2.components.Sidebar; import org.saturnclient.ui2.components.inputs.FloatInput; @@ -59,14 +60,13 @@ public class ConfigEditor extends SaturnScreen { if (prop.getType() == Property.PropertyType.NAMESPACE) { configScroll.draw( - new Text( - propName - ).position(Fonts.centerX(520, propName, Text.font.value), modY + 1).scale(0.7f)); + new Text( + propName).position(Fonts.centerX(520, propName, Theme.FONT.value), modY + 1) + .scale(0.7f)); } else { configScroll.draw( - new Text( - propName - ).position(modX, modY + 1).scale(0.7f)); + new Text( + propName).position(modX, modY + 1).scale(0.7f)); } switch (prop.getType()) { @@ -76,7 +76,7 @@ public class ConfigEditor extends SaturnScreen { .position(modX + (w / 2) - 40, modY) .scale(0.5f)); break; - + case HEX: configScroll.draw(new HexInput((Property) prop, this).position(w / 2, modY)); break; diff --git a/src/main/java/org/saturnclient/ui2/screens/store/CloakStore.java b/src/main/java/org/saturnclient/ui2/screens/store/CloakStore.java index 1f0a056..d13b099 100644 --- a/src/main/java/org/saturnclient/ui2/screens/store/CloakStore.java +++ b/src/main/java/org/saturnclient/ui2/screens/store/CloakStore.java @@ -3,6 +3,7 @@ package org.saturnclient.ui2.screens.store; import org.saturnclient.saturnclient.SaturnClient; import org.saturnclient.saturnclient.client.ServiceClient; import org.saturnclient.saturnclient.client.player.SaturnPlayer; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; import org.saturnclient.ui2.SaturnScreen; import org.saturnclient.ui2.Utils; @@ -75,10 +76,10 @@ public class CloakStore extends SaturnScreen { String t = "100"; - scroll.draw(new Text(t).position(x + Fonts.centerX(50, t, Text.font.value), y + 113).scale(0.5f)); + scroll.draw(new Text(t).position(x + Fonts.centerX(50, t, Theme.FONT.value), y + 113).scale(0.5f)); scroll.draw(new ImageTexture(Textures.COINS).dimensions(16, 16) - .position(x + Fonts.getWidth(t, Text.font.value) - 1, y + 112).scale(0.5f)); + .position(x + Fonts.getWidth(t, Theme.FONT.value) - 1, y + 112).scale(0.5f)); if (col == 8) { col = 0; diff --git a/src/main/java/org/saturnclient/ui2/screens/store/HatStore.java b/src/main/java/org/saturnclient/ui2/screens/store/HatStore.java index 15f87b8..7a3de0a 100644 --- a/src/main/java/org/saturnclient/ui2/screens/store/HatStore.java +++ b/src/main/java/org/saturnclient/ui2/screens/store/HatStore.java @@ -3,6 +3,7 @@ package org.saturnclient.ui2.screens.store; import org.saturnclient.saturnclient.SaturnClient; import org.saturnclient.saturnclient.client.ServiceClient; import org.saturnclient.saturnclient.client.player.SaturnPlayer; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.saturnclient.cosmetics.Hats; import org.saturnclient.ui2.SaturnScreen; import org.saturnclient.ui2.Utils; @@ -75,10 +76,10 @@ public class HatStore extends SaturnScreen { String t = "50"; - scroll.draw(new Text(t).position(x + Fonts.centerX(50, t, Text.font.value), y + 53).scale(0.5f)); + scroll.draw(new Text(t).position(x + Fonts.centerX(50, t, Theme.FONT.value), y + 53).scale(0.5f)); scroll.draw(new ImageTexture(Textures.COINS).dimensions(16, 16) - .position(x + Fonts.getWidth(t, Text.font.value) + 4, y + 52).scale(0.5f)); + .position(x + Fonts.getWidth(t, Theme.FONT.value) + 4, y + 52).scale(0.5f)); if (col == 8) { col = 0; From 8d8cbc8b28f8625acdb39820b038222b8efdba9c Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 19:29:36 +0100 Subject: [PATCH 15/42] Implemenented theme --- .../saturnclient/config/Theme.java | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/saturnclient/saturnclient/config/Theme.java b/src/main/java/org/saturnclient/saturnclient/config/Theme.java index b053d95..8036644 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/Theme.java +++ b/src/main/java/org/saturnclient/saturnclient/config/Theme.java @@ -1,15 +1,30 @@ package org.saturnclient.saturnclient.config; public class Theme { - public static Property BACKGROUND = Property.color(0x00000000); - public static Property FOREGROUND = Property.color(0x00000000); - public static Property PRIMARY = Property.color(0x00000000); - public static Property PRIMARY_FG = Property.color(0x00000000); - public static Property ACCENT = Property.color(0xFF845eee); - public static Property ACCENT_FG = Property.color(0x00000000); - public static Property BG_RADIUS = Property.integer(10); + // Main UI background (slightly warm dark to match Saturn tone) + public static Property BACKGROUND = Property.color(0xFF12100D); + + // Default text color + public static Property FOREGROUND = Property.color(0xFFF2E6D2); + + // Widget default background (normal state) + public static Property PRIMARY = Property.color(0xFF1C1915); + + // Widget text color + public static Property PRIMARY_FG = Property.color(0xFFEAD9B8); + + // Saturn brand color (hovered / enabled / selected) + public static Property ACCENT = Property.color(0xFFE2BF7D); + + // Text/icons shown on accent background + public static Property ACCENT_FG = Property.color(0xFF1A140A); + + // UI metrics + public static Property BG_RADIUS = Property.integer(12); public static Property WIDGET_RADIUS = Property.integer(10); - public static Property PADDING = Property.integer(15); + public static Property PADDING = Property.integer(14); + + // Font (keeping your current system) public static Property FONT = Property.font(1); public static void init(ConfigManager parent) { From 2f93822996cac9d8aa71be6f2cf9f337b2998a97 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 19:38:19 +0100 Subject: [PATCH 16/42] Scrollbar --- .../java/org/saturnclient/saturnclient/config/Theme.java | 6 ++++++ src/main/java/org/saturnclient/ui2/elements/Scroll.java | 4 +--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/saturnclient/saturnclient/config/Theme.java b/src/main/java/org/saturnclient/saturnclient/config/Theme.java index 8036644..7471507 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/Theme.java +++ b/src/main/java/org/saturnclient/saturnclient/config/Theme.java @@ -19,6 +19,9 @@ public class Theme { // Text/icons shown on accent background public static Property ACCENT_FG = Property.color(0xFF1A140A); + // Misc colors + public static Property SCROLL = Property.color(0xFFE2BF7D); + // UI metrics public static Property BG_RADIUS = Property.integer(12); public static Property WIDGET_RADIUS = Property.integer(10); @@ -35,8 +38,11 @@ public class Theme { config.property("Primary Foreground", PRIMARY_FG); config.property("Accent", ACCENT); config.property("Accent Foreground", ACCENT_FG); + config.property("Scrollbar Color", SCROLL); + config.property("Background Radius", BG_RADIUS); config.property("Widget Radius", WIDGET_RADIUS); + config.property("Font", WIDGET_RADIUS); } } diff --git a/src/main/java/org/saturnclient/ui2/elements/Scroll.java b/src/main/java/org/saturnclient/ui2/elements/Scroll.java index 7b78025..1be2461 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Scroll.java +++ b/src/main/java/org/saturnclient/ui2/elements/Scroll.java @@ -11,8 +11,6 @@ import org.saturnclient.ui2.RenderScope; import org.saturnclient.ui2.components.ElementRenderer; public class Scroll extends Element { - private static Property scrollBarColor = Property.color(-7643914); - private static Property scrollBarRadius = Property.integer(10); private static Property scrollBarWidth = Property.integer(5); private static Property scrollBarPadding = Property.integer(5); @@ -39,7 +37,7 @@ public class Scroll extends Element { renderScope.disableScissor(); renderScope.drawRoundedRectangle(width - scrollBarWidth.value - scrollBarPadding.value, calculateScrollBarY(), - scrollBarWidth.value, calculateScrollBarHeight(), scrollBarRadius.value, scrollBarColor.value); + scrollBarWidth.value, calculateScrollBarHeight(), scrollBarRadius.value, Theme.SCROLL.value); } @Override From 52f80281bd5faf9c769f55983ac3fdce1be7adbb Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 19:46:40 +0100 Subject: [PATCH 17/42] Fixed a few issues --- .../java/org/saturnclient/saturnclient/config/Theme.java | 1 - .../org/saturnclient/ui2/components/CosmeticPreview.java | 9 ++++----- src/main/java/org/saturnclient/ui2/elements/Button.java | 1 + .../org/saturnclient/ui2/elements/TextureButton.java | 7 ++++--- .../java/org/saturnclient/ui2/screens/ShiftMenu.java | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/saturnclient/saturnclient/config/Theme.java b/src/main/java/org/saturnclient/saturnclient/config/Theme.java index 7471507..c10a139 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/Theme.java +++ b/src/main/java/org/saturnclient/saturnclient/config/Theme.java @@ -25,7 +25,6 @@ public class Theme { // UI metrics public static Property BG_RADIUS = Property.integer(12); public static Property WIDGET_RADIUS = Property.integer(10); - public static Property PADDING = Property.integer(14); // Font (keeping your current system) public static Property FONT = Property.font(1); diff --git a/src/main/java/org/saturnclient/ui2/components/CosmeticPreview.java b/src/main/java/org/saturnclient/ui2/components/CosmeticPreview.java index 6056550..49ace16 100644 --- a/src/main/java/org/saturnclient/ui2/components/CosmeticPreview.java +++ b/src/main/java/org/saturnclient/ui2/components/CosmeticPreview.java @@ -9,8 +9,7 @@ import net.minecraft.client.render.RenderLayer; import net.minecraft.util.Identifier; public class CosmeticPreview extends Element { - static { - } + static int padding = 14; Identifier sprite; private Runnable onClick; @@ -32,10 +31,10 @@ public class CosmeticPreview extends Element { renderScope.setRenderLayer(RenderLayer::getGuiTextured); - int texWidth = width - Theme.PADDING.value; - int texHeight = height - Theme.PADDING.value; + int texWidth = width - padding; + int texHeight = height - padding; - renderScope.drawTexture(sprite, Theme.PADDING.value / 2, Theme.PADDING.value / 2, 0, 0, texWidth, texHeight, + renderScope.drawTexture(sprite, padding / 2, padding / 2, 0, 0, texWidth, texHeight, Theme.FOREGROUND.value); } diff --git a/src/main/java/org/saturnclient/ui2/elements/Button.java b/src/main/java/org/saturnclient/ui2/elements/Button.java index 73a1a1c..4774f11 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Button.java +++ b/src/main/java/org/saturnclient/ui2/elements/Button.java @@ -13,6 +13,7 @@ public class Button extends Element { public Button(String text, Runnable onClick) { this.text = text; this.onClick = onClick; + this.dimensions(Fonts.getWidth(text, Theme.FONT.value) + 50, 38); } @Override diff --git a/src/main/java/org/saturnclient/ui2/elements/TextureButton.java b/src/main/java/org/saturnclient/ui2/elements/TextureButton.java index 56d8a75..ccbf1ba 100644 --- a/src/main/java/org/saturnclient/ui2/elements/TextureButton.java +++ b/src/main/java/org/saturnclient/ui2/elements/TextureButton.java @@ -11,6 +11,7 @@ import net.minecraft.util.Identifier; public class TextureButton extends Element { Identifier sprite; private Runnable onClick; + static int padding = 14; public TextureButton(Identifier sprite, Runnable onClick) { this.sprite = sprite; @@ -24,10 +25,10 @@ public class TextureButton extends Element { renderScope.setRenderLayer(RenderLayer::getGuiTextured); - int texWidth = width - Theme.PADDING.value; - int texHeight = height - Theme.PADDING.value; + int texWidth = width - padding; + int texHeight = height - padding; - renderScope.drawTexture(sprite, Theme.PADDING.value / 2, Theme.PADDING.value / 2, 0, 0, texWidth, texHeight, + renderScope.drawTexture(sprite, padding / 2, padding / 2, 0, 0, texWidth, texHeight, ctx.isHovering() ? Theme.ACCENT_FG.value : Theme.PRIMARY_FG.value); } diff --git a/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java b/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java index 92866ef..5d5448f 100644 --- a/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java +++ b/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java @@ -25,7 +25,7 @@ public class ShiftMenu extends SaturnScreen { Element button = new Button("Settings", () -> { SaturnClient.client.setScreen(new ModMenu()); - }).center(width, height); + }).center(width, height); draw(button); From 88fe53b9071e7c84b62d5f745211d8e27c81421c Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 19:57:40 +0100 Subject: [PATCH 18/42] Fixed sidebar with abstractions --- .../saturnclient/config/Theme.java | 8 ++++ .../saturnclient/ui2/components/Sidebar.java | 40 ++++++++----------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/saturnclient/saturnclient/config/Theme.java b/src/main/java/org/saturnclient/saturnclient/config/Theme.java index c10a139..8c702df 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/Theme.java +++ b/src/main/java/org/saturnclient/saturnclient/config/Theme.java @@ -44,4 +44,12 @@ public class Theme { config.property("Font", WIDGET_RADIUS); } + + public static int getBg(boolean hover) { + return hover ? ACCENT.value : PRIMARY.value; + } + + public static int getFg(boolean hover) { + return hover ? ACCENT_FG.value : PRIMARY_FG.value; + } } diff --git a/src/main/java/org/saturnclient/ui2/components/Sidebar.java b/src/main/java/org/saturnclient/ui2/components/Sidebar.java index aa47d99..7d6e002 100644 --- a/src/main/java/org/saturnclient/ui2/components/Sidebar.java +++ b/src/main/java/org/saturnclient/ui2/components/Sidebar.java @@ -77,21 +77,17 @@ public class Sidebar extends Element { int i = 0; for (SidebarComponent component : components) { + int y = component.end ? ((height - (sp * bottomRow)) - (s * 2)) : (padding + (sp * topRow)); + boolean selected = ctx.isHovering(0, y - (padding / 2), s2, s2) || active == i; + + renderScope.drawRoundedRectangle(padding / 2, y - (padding / 2), s + padding, + s + padding, Theme.WIDGET_RADIUS.value, Theme.getBg(selected)); + + renderScope.drawTexture(component.sprite, padding, y, 0, 0, s, s, Theme.getFg(selected)); + if (component.end) { - int y = (height - (sp * bottomRow)) - (s * 2); - if (ctx.isHovering(0, y - (padding / 2), s2, s2) || active == i) { - } - renderScope.drawRoundedRectangle(padding / 2, y - (padding / 2), s + padding, - s + padding, Theme.WIDGET_RADIUS.value, Theme.PRIMARY.value); - renderScope.drawTexture(component.sprite, padding, y, 0, 0, s, s, Theme.PRIMARY_FG.value); bottomRow += 1; } else { - int y = padding + (sp * topRow); - if (ctx.isHovering(0, y - (padding / 2), s2, s2) || active == i) { - } - renderScope.drawRoundedRectangle(padding / 2, y - (padding / 2), s + padding, - s + padding, Theme.WIDGET_RADIUS.value, Theme.PRIMARY.value); - renderScope.drawTexture(component.sprite, padding, y, 0, 0, s, s, Theme.PRIMARY_FG.value); topRow += 1; } @@ -104,26 +100,24 @@ public class Sidebar extends Element { int topRow = 0; int bottomRow = 0; - int gap = 5; // same 5px gap here + int gap = 5; int padding = 10; int sp = 30 - padding + gap; int s = 30 - (padding * 2); int s2 = s + padding; for (SidebarComponent component : components) { + int y = component.end ? ((height - (sp * bottomRow)) - (s * 2)) : (padding + (sp * topRow)); + boolean hovering = Utils.isHovering(mouseX - (padding / 2), mouseY - (y - (padding / 2)), s2, s2, scale); + + if (hovering) { + component.onClick.run(); + break; + } + if (component.end) { - int y = (height - (sp * bottomRow)) - (s * 2); - if (Utils.isHovering(mouseX - (padding / 2), mouseY - (y - (padding / 2)), s2, s2, scale)) { - component.onClick.run(); - break; - } bottomRow += 1; } else { - int y = padding + (sp * topRow); - if (Utils.isHovering(mouseX - (padding / 2), mouseY - (y - (padding / 2)), s2, s2, scale)) { - component.onClick.run(); - break; - } topRow += 1; } } From a49212ca646dad549c662ff5e371bd09401c71d1 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 20:02:12 +0100 Subject: [PATCH 19/42] Attempting to fix scroll --- src/main/java/org/saturnclient/ui2/elements/Scroll.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/elements/Scroll.java b/src/main/java/org/saturnclient/ui2/elements/Scroll.java index 1be2461..ee8b10e 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Scroll.java +++ b/src/main/java/org/saturnclient/ui2/elements/Scroll.java @@ -69,9 +69,8 @@ public class Scroll extends Element { int calculateScrollBarHeight() { if (maxScroll <= 0) - return height - (scrollBarPadding.value * 2); // No scrolling needed - return Math.max(20, (height * height) / (height + maxScroll)) - (scrollBarPadding.value * 2); // At least 20px - // tall + return height - (scrollBarPadding.value * 2); + return Math.max(20, (height * height) / (height + maxScroll)) - (scrollBarPadding.value * 2); } int calculateScrollBarY() { From 3ba6202b43a11d8e79b012d9cd32d3bde4ec4635 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 20:09:19 +0100 Subject: [PATCH 20/42] Improved scroll --- .../org/saturnclient/ui2/elements/Scroll.java | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/elements/Scroll.java b/src/main/java/org/saturnclient/ui2/elements/Scroll.java index ee8b10e..7a751cc 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Scroll.java +++ b/src/main/java/org/saturnclient/ui2/elements/Scroll.java @@ -27,17 +27,31 @@ public class Scroll extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawRoundedRectangle(0, 0, width, height, Theme.BG_RADIUS.value, Theme.BACKGROUND.value); + calculateMaxScroll(); + + renderScope.drawRoundedRectangle(0, 0, width, height, + Theme.BG_RADIUS.value, Theme.BACKGROUND.value); renderScope.enableScissor(padding, padding, width - padding, height - padding); renderScope.matrices.push(); - renderScope.matrices.translate(padding, (-scroll) + padding, 0); - ElementRenderer.render(children, renderScope, ctx.mouseX - padding, ctx.mouseY - padding + scroll); + renderScope.matrices.translate(padding, -scroll + padding, 0); + + ElementRenderer.render(children, renderScope, + ctx.mouseX - padding, + ctx.mouseY - padding + scroll); + renderScope.matrices.pop(); renderScope.disableScissor(); - renderScope.drawRoundedRectangle(width - scrollBarWidth.value - scrollBarPadding.value, calculateScrollBarY(), - scrollBarWidth.value, calculateScrollBarHeight(), scrollBarRadius.value, Theme.SCROLL.value); + if (maxScroll > 0) { + renderScope.drawRoundedRectangle( + width - scrollBarWidth.value - scrollBarPadding.value, + calculateScrollBarY(), + scrollBarWidth.value, + calculateScrollBarHeight(), + scrollBarRadius.value, + Theme.SCROLL.value); + } } @Override @@ -61,9 +75,13 @@ public class Scroll extends Element { @Override public Element dimensions(int width, int height) { + maxScroll = 0; + for (Element element : children) { maxScroll = Math.max(maxScroll, element.y + element.height - height); } + + maxScroll = Math.max(0, maxScroll); // never negative return super.dimensions(width, height); } @@ -80,6 +98,21 @@ public class Scroll extends Element { return (scroll * (height - scrollBarHeight)) / maxScroll + scrollBarPadding.value; } + private void calculateMaxScroll() { + maxScroll = 0; + + for (Element element : children) { + int bottom = element.y + element.height; + maxScroll = Math.max(maxScroll, bottom - height + padding); + } + + if (maxScroll > 0) { + maxScroll = maxScroll + 10; + } else { + maxScroll = 0; + } + } + @Override public void keyPressed(int keyCode, int scanCode, int modifiers) { ElementRenderer.keyPressed(children, keyCode, scanCode, modifiers); From 7683e7b91e12f8cadade33ccc3d2149e4474fbf3 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 20:18:52 +0100 Subject: [PATCH 21/42] Removed NamedProperty --- .../saturnclient/modules/ModDimensions.java | 20 +++++++++---------- .../java/org/saturnclient/modules/Module.java | 15 ++++++++------ .../saturnclient/config/NamedProperty.java | 11 ---------- .../saturnclient/config/Property.java | 9 +++++++++ 4 files changed, 28 insertions(+), 27 deletions(-) delete mode 100644 src/main/java/org/saturnclient/saturnclient/config/NamedProperty.java diff --git a/src/main/java/org/saturnclient/modules/ModDimensions.java b/src/main/java/org/saturnclient/modules/ModDimensions.java index b0bdb4f..c09b096 100644 --- a/src/main/java/org/saturnclient/modules/ModDimensions.java +++ b/src/main/java/org/saturnclient/modules/ModDimensions.java @@ -2,7 +2,7 @@ package org.saturnclient.modules; import java.util.Map; -import org.saturnclient.saturnclient.config.NamedProperty; +import org.saturnclient.saturnclient.config.Property.NamedProperty; import org.saturnclient.saturnclient.config.Property; public class ModDimensions { @@ -20,17 +20,17 @@ public class ModDimensions { public NamedProperty>> prop() { return Property.namespace(Map.of( - "X", x, - "Y", y, - "Scale", scale, - "Background Color", bgColor, - "Foreground Color", fgColor, - "Corner Radius", radius, - "Font", font - )).named("In-Game Display"); + "X", x, + "Y", y, + "Scale", scale, + "Background Color", bgColor, + "Foreground Color", fgColor, + "Corner Radius", radius, + "Font", font)).named("In-Game Display"); } - public ModDimensions() {} + public ModDimensions() { + } public ModDimensions(int width, int height) { this.width = width; diff --git a/src/main/java/org/saturnclient/modules/Module.java b/src/main/java/org/saturnclient/modules/Module.java index 87527e4..bedc306 100644 --- a/src/main/java/org/saturnclient/modules/Module.java +++ b/src/main/java/org/saturnclient/modules/Module.java @@ -1,9 +1,9 @@ package org.saturnclient.modules; import org.saturnclient.saturnclient.config.ConfigManager; -import org.saturnclient.saturnclient.config.NamedProperty; import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.RenderScope; +import org.saturnclient.saturnclient.config.Property.NamedProperty; import net.minecraft.util.Identifier; @@ -19,8 +19,11 @@ public abstract class Module { } } - public void render(RenderScope scope) {} - public void tick() {} + public void render(RenderScope scope) { + } + + public void tick() { + } public abstract boolean isEnabled(); @@ -34,7 +37,7 @@ public abstract class Module { public final String getName() { return details.name; } - + public Identifier getIconTexture() { return Textures.getModIcon(details.namespace); } @@ -46,11 +49,11 @@ public abstract class Module { public String getDescription() { return details.description; } - + public String[] getTags() { return details.tags; } - + public String getVersion() { return details.version; } diff --git a/src/main/java/org/saturnclient/saturnclient/config/NamedProperty.java b/src/main/java/org/saturnclient/saturnclient/config/NamedProperty.java deleted file mode 100644 index 3e63c31..0000000 --- a/src/main/java/org/saturnclient/saturnclient/config/NamedProperty.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.saturnclient.saturnclient.config; - -public class NamedProperty { - public String name; - public Property prop; - - public NamedProperty(String name, Property value) { - this.name = name; - this.prop = value; - } -} diff --git a/src/main/java/org/saturnclient/saturnclient/config/Property.java b/src/main/java/org/saturnclient/saturnclient/config/Property.java index 0a8aa01..6d81da7 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/Property.java +++ b/src/main/java/org/saturnclient/saturnclient/config/Property.java @@ -10,6 +10,15 @@ import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; public class Property { + public static class NamedProperty { + public String name; + public Property prop; + + public NamedProperty(String name, Property value) { + this.name = name; + this.prop = value; + } + } public enum PropertyType { BOOLEAN, From 3b0ab53d8664a3f382bceb2246f54fa3a1d45382 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 20:35:52 +0100 Subject: [PATCH 22/42] Fixed Theme issue --- .../saturnclient/config/Theme.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/saturnclient/saturnclient/config/Theme.java b/src/main/java/org/saturnclient/saturnclient/config/Theme.java index 8c702df..a5125ae 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/Theme.java +++ b/src/main/java/org/saturnclient/saturnclient/config/Theme.java @@ -2,29 +2,29 @@ package org.saturnclient.saturnclient.config; public class Theme { // Main UI background (slightly warm dark to match Saturn tone) - public static Property BACKGROUND = Property.color(0xFF12100D); + public static final Property BACKGROUND = Property.color(0xFF12100D); // Default text color - public static Property FOREGROUND = Property.color(0xFFF2E6D2); + public static final Property FOREGROUND = Property.color(0xFFF2E6D2); // Widget default background (normal state) - public static Property PRIMARY = Property.color(0xFF1C1915); + public static final Property PRIMARY = Property.color(0xFF1C1915); // Widget text color - public static Property PRIMARY_FG = Property.color(0xFFEAD9B8); + public static final Property PRIMARY_FG = Property.color(0xFFEAD9B8); // Saturn brand color (hovered / enabled / selected) - public static Property ACCENT = Property.color(0xFFE2BF7D); + public static final Property ACCENT = Property.color(0xFFE2BF7D); // Text/icons shown on accent background - public static Property ACCENT_FG = Property.color(0xFF1A140A); + public static final Property ACCENT_FG = Property.color(0xFF1A140A); // Misc colors - public static Property SCROLL = Property.color(0xFFE2BF7D); + public static final Property SCROLL = Property.color(0xFFE2BF7D); // UI metrics - public static Property BG_RADIUS = Property.integer(12); - public static Property WIDGET_RADIUS = Property.integer(10); + public static final Property BG_RADIUS = Property.integer(12); + public static final Property WIDGET_RADIUS = Property.integer(10); // Font (keeping your current system) public static Property FONT = Property.font(1); @@ -42,7 +42,7 @@ public class Theme { config.property("Background Radius", BG_RADIUS); config.property("Widget Radius", WIDGET_RADIUS); - config.property("Font", WIDGET_RADIUS); + config.property("Font", FONT); } public static int getBg(boolean hover) { From 6ee2fc3b0e373160ef27b0083c9bc3146b75a0da Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 20:42:04 +0100 Subject: [PATCH 23/42] Improved theme usability --- .../saturnclient/config/Theme.java | 22 +++++++++++++++++++ .../mixin/SplashOverlayMixin.java | 20 +++++++---------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/saturnclient/saturnclient/config/Theme.java b/src/main/java/org/saturnclient/saturnclient/config/Theme.java index a5125ae..5023458 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/Theme.java +++ b/src/main/java/org/saturnclient/saturnclient/config/Theme.java @@ -45,11 +45,33 @@ public class Theme { config.property("Font", FONT); } + /** + * primary by default, accent if true + */ public static int getBg(boolean hover) { return hover ? ACCENT.value : PRIMARY.value; } + /** + * (Foreground) primary by default, accent if true + */ public static int getFg(boolean hover) { return hover ? ACCENT_FG.value : PRIMARY_FG.value; } + + /** + * Sets alpha using 0–255 range. + */ + public static int withAlpha(int alpha, int color) { + alpha = Math.max(0, Math.min(255, alpha)); + return (color & 0x00FFFFFF) | (alpha << 24); + } + + /** + * Sets alpha using 0.0–1.0 range. + */ + public static int withAlpha(float alpha, int color) { + alpha = Math.max(0f, Math.min(1f, alpha)); + return withAlpha((int) (alpha * 255f), color); + } } diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java index 846b1cc..4570254 100644 --- a/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java +++ b/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java @@ -3,6 +3,7 @@ package org.saturnclient.saturnclient.mixin; import java.util.Optional; import java.util.function.Consumer; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.RenderScope; import org.saturnclient.ui2.resources.Textures; import org.spongepowered.asm.mixin.Mixin; @@ -40,10 +41,6 @@ public abstract class SplashOverlayMixin { @Shadow(remap = false) private float progress; - private static int withAlpha(int color, int alpha) { - return color & 0xFFFFFF | alpha << 24; - } - /** * @reason Replace vanilla splash rendering completely but keep exit logic */ @@ -80,19 +77,17 @@ public abstract class SplashOverlayMixin { if (fadeOutProgress >= 1.0F) { renderCurrentScreen(context, mouseX, mouseY, delta); int overlayAlpha = computeOverlayAlpha(fadeOutProgress - 1f); - // context.fill(0, 0, screenWidth, screenHeight, - // withAlpha(0x53389E, overlayAlpha)); scope.drawTexture(Textures.SPLASH, 0, 0, 0, 0, screenWidth, screenHeight, - withAlpha(0xFFFFFF, overlayAlpha)); + Theme.withAlpha(0xFFFFFFFF, overlayAlpha)); } else if (reloading) { if (reloadProgress < 1.0F) { renderCurrentScreen(context, mouseX, mouseY, delta); } scope.drawTexture(Textures.SPLASH, 0, 0, 0, 0, screenWidth, screenHeight, - withAlpha(0xFFFFFF, alpha)); + Theme.withAlpha(0xFFFFFFFF, alpha)); } else { scope.drawTexture(Textures.SPLASH, 0, 0, 0, 0, screenWidth, screenHeight, - withAlpha(0xFFFFFF, alpha)); + Theme.withAlpha(0xFFFFFFFF, alpha)); } float u = this.reload.getProgress(); @@ -120,18 +115,19 @@ public abstract class SplashOverlayMixin { /** Draw the main logo centered */ private void drawLogo(RenderScope scope, int screenWidth, int screenHeight, int alpha) { scope.drawTexture(Textures.LOGO, (screenWidth - 60) / 2, ((screenHeight - 60) / 2) - 20, 0, 0, 60, 60, - withAlpha(0xFFFFFF, alpha)); + Theme.withAlpha(0xFFFFFFFF, alpha)); } private void renderProgressBar(RenderScope scope, DrawContext context, int screenWidth, int screenHeight, int alpha) { int progressY = ((screenHeight - 5) / 2) + 25; - context.drawBorder((screenWidth - 120) / 2, progressY, 120, 5, withAlpha(0xFFFFFF, alpha)); + context.drawBorder((screenWidth - 120) / 2, progressY, 120, 5, Theme.withAlpha(0xFFFFFFFF, alpha)); int progressWidth = Math.min((int) (progress * 120), 120); int progressX = (screenWidth - 120) / 2; - context.fill(progressX, progressY, progressX + progressWidth, progressY + 5, withAlpha(0xFFFFFF, alpha)); + context.fill(progressX, progressY, progressX + progressWidth, progressY + 5, + Theme.withAlpha(0xFFFFFFFF, alpha)); } /** Compute overlay alpha from fade progress */ From 4403a31c936abffe091a4b1bb1b9948b2e44df16 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 20:59:07 +0100 Subject: [PATCH 24/42] Fix splashoverlay and saturnmodule --- .../saturnclient/config/Theme.java | 19 ++- .../mixin/SplashOverlayMixin.java | 12 +- .../ui2/components/SaturnModule.java | 132 +++++++++++++----- 3 files changed, 121 insertions(+), 42 deletions(-) diff --git a/src/main/java/org/saturnclient/saturnclient/config/Theme.java b/src/main/java/org/saturnclient/saturnclient/config/Theme.java index 5023458..29cb887 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/Theme.java +++ b/src/main/java/org/saturnclient/saturnclient/config/Theme.java @@ -60,18 +60,29 @@ public class Theme { } /** - * Sets alpha using 0–255 range. + * Multiplies existing alpha with 0–255 alpha. */ public static int withAlpha(int alpha, int color) { alpha = Math.max(0, Math.min(255, alpha)); - return (color & 0x00FFFFFF) | (alpha << 24); + + int originalAlpha = (color >>> 24) & 0xFF; + + // Merge (multiply) alphas + int merged = (originalAlpha * alpha) / 255; + + return (color & 0x00FFFFFF) | (merged << 24); } /** - * Sets alpha using 0.0–1.0 range. + * Multiplies existing alpha with 0.0–1.0 alpha. */ public static int withAlpha(float alpha, int color) { alpha = Math.max(0f, Math.min(1f, alpha)); - return withAlpha((int) (alpha * 255f), color); + + int originalAlpha = (color >>> 24) & 0xFF; + + int merged = (int) (originalAlpha * alpha); + + return (color & 0x00FFFFFF) | (merged << 24); } } diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java index 4570254..48b0b19 100644 --- a/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java +++ b/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java @@ -78,16 +78,16 @@ public abstract class SplashOverlayMixin { renderCurrentScreen(context, mouseX, mouseY, delta); int overlayAlpha = computeOverlayAlpha(fadeOutProgress - 1f); scope.drawTexture(Textures.SPLASH, 0, 0, 0, 0, screenWidth, screenHeight, - Theme.withAlpha(0xFFFFFFFF, overlayAlpha)); + Theme.withAlpha(overlayAlpha, 0xFFFFFFFF)); } else if (reloading) { if (reloadProgress < 1.0F) { renderCurrentScreen(context, mouseX, mouseY, delta); } scope.drawTexture(Textures.SPLASH, 0, 0, 0, 0, screenWidth, screenHeight, - Theme.withAlpha(0xFFFFFFFF, alpha)); + Theme.withAlpha(alpha, 0xFFFFFFFF)); } else { scope.drawTexture(Textures.SPLASH, 0, 0, 0, 0, screenWidth, screenHeight, - Theme.withAlpha(0xFFFFFFFF, alpha)); + Theme.withAlpha(alpha, 0xFFFFFFFF)); } float u = this.reload.getProgress(); @@ -115,19 +115,19 @@ public abstract class SplashOverlayMixin { /** Draw the main logo centered */ private void drawLogo(RenderScope scope, int screenWidth, int screenHeight, int alpha) { scope.drawTexture(Textures.LOGO, (screenWidth - 60) / 2, ((screenHeight - 60) / 2) - 20, 0, 0, 60, 60, - Theme.withAlpha(0xFFFFFFFF, alpha)); + Theme.withAlpha(alpha, 0xFFFFFFFF)); } private void renderProgressBar(RenderScope scope, DrawContext context, int screenWidth, int screenHeight, int alpha) { int progressY = ((screenHeight - 5) / 2) + 25; - context.drawBorder((screenWidth - 120) / 2, progressY, 120, 5, Theme.withAlpha(0xFFFFFFFF, alpha)); + context.drawBorder((screenWidth - 120) / 2, progressY, 120, 5, Theme.withAlpha(alpha, 0xFFFFFFFF)); int progressWidth = Math.min((int) (progress * 120), 120); int progressX = (screenWidth - 120) / 2; context.fill(progressX, progressY, progressX + progressWidth, progressY + 5, - Theme.withAlpha(0xFFFFFFFF, alpha)); + Theme.withAlpha(alpha, 0xFFFFFFFF)); } /** Compute overlay alpha from fade progress */ diff --git a/src/main/java/org/saturnclient/ui2/components/SaturnModule.java b/src/main/java/org/saturnclient/ui2/components/SaturnModule.java index 60d27e5..87da97d 100644 --- a/src/main/java/org/saturnclient/ui2/components/SaturnModule.java +++ b/src/main/java/org/saturnclient/ui2/components/SaturnModule.java @@ -14,14 +14,8 @@ import org.saturnclient.ui2.screens.ConfigEditor; import net.minecraft.client.render.RenderLayer; public class SaturnModule extends Element { - // TODO make these states - // static { - // theme.propertyStateDefault("enabled", "bg", 0xFF1d202d); - // theme.propertyStateDefault("enabled", "icon-bg", 0xFF845eee); - // theme.propertyStateDefault("hovering", "fg", 0xFF845eee); - // } - private Module mod; + private final Module mod; public SaturnModule(Module mod) { this.mod = mod; @@ -31,44 +25,111 @@ public class SaturnModule extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { - int p = 10; - int s = 14; - boolean settingsHover = false; + int p = 10; // padding + int s = 14; // settings icon size + + boolean hovered = ctx.isHovering(); + boolean enabled = mod.isEnabled(); + + boolean settingsHover = Utils.isHovering( + ctx.mouseX - (width - s - p - 5), + ctx.mouseY - (height - s - p - 5), + s + 10, + s + 10, + 1.0f); renderScope.setRenderLayer(RenderLayer::getGuiTextured); - // TODO use this - if (mod.isEnabled()) { - } + // Resolve theme colors + int bgColor = Theme.PRIMARY.value; + int fgColor = hovered && !settingsHover ? Theme.ACCENT.value : Theme.PRIMARY_FG.value; - renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, Theme.PRIMARY.value); + int iconBg = enabled ? Theme.ACCENT.value : Theme.PRIMARY.value; + int iconFg = enabled ? Theme.ACCENT_FG.value : fgColor; + + int settingsColor = settingsHover + ? Theme.ACCENT.value + : Theme.withAlpha(160, fgColor); int h = height - (p * 2); - renderScope.drawRoundedRectangle(p, p, h, h, Theme.WIDGET_RADIUS.value, Theme.PRIMARY.value); + // Main background + renderScope.drawRoundedRectangle( + 0, 0, + width, height, + Theme.WIDGET_RADIUS.value, + bgColor); - renderScope.drawTexture(mod.getIconTexture(), p + (p / 2), p + (p / 2), 0, 0, h - p, h - p, - Theme.PRIMARY_FG.value); + // Icon background + renderScope.drawRoundedRectangle( + p, p, + h, h, + Theme.WIDGET_RADIUS.value, + iconBg); - renderScope.drawText(0.6f, mod.getName(), p + h + 4, p + 1, Theme.FONT.value, Theme.PRIMARY_FG.value); + // Icon + renderScope.drawTexture( + mod.getIconTexture(), + p + (p / 2), + p + (p / 2), + 0, 0, + h - p, + h - p, + iconFg); - renderScope.drawText(0.35f, mod.getVersion(), - width - p - (int) (Fonts.getWidth(mod.getVersion(), Theme.FONT.value) * 0.35f), p + 1, Theme.FONT.value, - Theme.PRIMARY_FG.value); + // Module name + renderScope.drawText( + 0.6f, + mod.getName(), + p + h + 4, + p + 1, + Theme.FONT.value, + fgColor); + // Version (right aligned) + String version = mod.getVersion(); + int versionWidth = (int) (Fonts.getWidth(version, Theme.FONT.value) * 0.35f); + + renderScope.drawText( + 0.35f, + version, + width - p - versionWidth, + p + 1, + Theme.FONT.value, + fgColor); + + // Tags int xt = p + h + 4; for (String tag : mod.getTags()) { - int xtb = (int) (Fonts.getWidth(tag, Theme.FONT.value) * 0.4f); - renderScope.drawRoundedRectangle(xt, p + (h / 2), xtb + 6, 12, 5, Theme.ACCENT.value); - renderScope.drawText(0.4f, tag, xt + 2, p + (h / 2) + 3, Theme.FONT.value, Theme.ACCENT_FG.value); - xt += xtb + 9; + int tagWidth = (int) (Fonts.getWidth(tag, Theme.FONT.value) * 0.4f); + + renderScope.drawRoundedRectangle( + xt, + p + (h / 2), + tagWidth + 6, + 12, + 5, + Theme.ACCENT.value); + + renderScope.drawText( + 0.4f, + tag, + xt + 2, + p + (h / 2) + 3, + Theme.FONT.value, + Theme.ACCENT_FG.value); + + xt += tagWidth + 9; } - // TODO - if (settingsHover) { - } - - renderScope.drawTexture(Textures.SETTINGS, width - s - p, height - s - p, 0, 0, s, s, Theme.PRIMARY_FG.value); + // Settings icon + renderScope.drawTexture( + Textures.SETTINGS, + width - s - p, + height - s - p, + 0, 0, + s, s, + settingsColor); } @Override @@ -76,10 +137,17 @@ public class SaturnModule extends Element { int p = 10; int s = 14; - if (Utils.isHovering(mouseX - (width - s - p - 5), mouseY - (height - s - p - 5), s + 10, s + 10, 1.0f)) { + boolean settingsHover = Utils.isHovering( + mouseX - (width - s - p - 5), + mouseY - (height - s - p - 5), + s + 10, + s + 10, + 1.0f); + + if (settingsHover) { SaturnClient.client.setScreen(new ConfigEditor(mod.getConfig())); } else { mod.setEnabled(!mod.isEnabled()); } } -} +} \ No newline at end of file From bba12146ea8dad0a3c522ff921cfea74a42949c3 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 22:17:59 +0100 Subject: [PATCH 25/42] HexInput --- .../java/org/saturnclient/ui2/Element.java | 9 + .../org/saturnclient/ui2/RenderScope.java | 41 +++ .../ui2/components/dialog/ColorDialog.java | 246 ------------------ .../ui2/components/inputs/HexInput.java | 172 +++++++++++- .../ui2/screens/ConfigEditor.java | 2 +- 5 files changed, 212 insertions(+), 258 deletions(-) delete mode 100644 src/main/java/org/saturnclient/ui2/components/dialog/ColorDialog.java diff --git a/src/main/java/org/saturnclient/ui2/Element.java b/src/main/java/org/saturnclient/ui2/Element.java index 4e4e00c..ec8b110 100644 --- a/src/main/java/org/saturnclient/ui2/Element.java +++ b/src/main/java/org/saturnclient/ui2/Element.java @@ -32,6 +32,15 @@ public class Element { public void charTyped(char typedChar) { } + public void mouseClicked(double mouseX, double mouseY, int button) { + } + + public void mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + } + + public void mouseReleased(double mouseX, double mouseY, int button) { + } + public Element dimensions(int width, int height) { this.width = width; this.height = height; diff --git a/src/main/java/org/saturnclient/ui2/RenderScope.java b/src/main/java/org/saturnclient/ui2/RenderScope.java index 231428c..5cd7f59 100644 --- a/src/main/java/org/saturnclient/ui2/RenderScope.java +++ b/src/main/java/org/saturnclient/ui2/RenderScope.java @@ -398,4 +398,45 @@ public class RenderScope { sprite.getMinV(), sprite.getMaxV(), color); } } + + public void fill(int x1, int y1, int x2, int y2, int color) { + this.fill(x1, y1, x2, y2, 0, color); + } + + public void fill(int x1, int y1, int x2, int y2, int z, int color) { + this.fill(RenderLayer.getGui(), x1, y1, x2, y2, z, color); + } + + public void fill(RenderLayer layer, int x1, int y1, int x2, int y2, int color) { + this.fill(layer, x1, y1, x2, y2, 0, color); + } + + public void fill(RenderLayer layer, int x1, int y1, int x2, int y2, int z, int color) { + Matrix4f matrix4f = this.matrices.peek().getPositionMatrix(); + int i; + if (x1 < x2) { + i = x1; + x1 = x2; + x2 = i; + } + + if (y1 < y2) { + i = y1; + y1 = y2; + y2 = i; + } + + VertexConsumer vertexConsumer = this.vertexConsumers.getBuffer(layer); + vertexConsumer.vertex(matrix4f, (float) x1, (float) y1, (float) z).color(color); + vertexConsumer.vertex(matrix4f, (float) x1, (float) y2, (float) z).color(color); + vertexConsumer.vertex(matrix4f, (float) x2, (float) y2, (float) z).color(color); + vertexConsumer.vertex(matrix4f, (float) x2, (float) y1, (float) z).color(color); + } + + public void drawBorder(int x, int y, int width, int height, int color) { + this.fill(x, y, x + width, y + 1, color); + this.fill(x, y + height - 1, x + width, y + height, color); + this.fill(x, y + 1, x + 1, y + height - 1, color); + this.fill(x + width - 1, y + 1, x + width, y + height - 1, color); + } } diff --git a/src/main/java/org/saturnclient/ui2/components/dialog/ColorDialog.java b/src/main/java/org/saturnclient/ui2/components/dialog/ColorDialog.java deleted file mode 100644 index 9567218..0000000 --- a/src/main/java/org/saturnclient/ui2/components/dialog/ColorDialog.java +++ /dev/null @@ -1,246 +0,0 @@ -package org.saturnclient.ui2.components.dialog; - -import java.awt.Color; - -import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.mixin.DrawContextAccessor; -import org.saturnclient.ui2.RenderScope; -import org.saturnclient.ui2.SaturnScreen; - -import net.minecraft.client.gui.DrawContext; - -public class ColorDialog extends SaturnScreen { - private Property prop; - private SaturnScreen parent; - private static final int PICKER_WIDTH = 200; - private static final int PICKER_HEIGHT = 200; - private static final int SLIDER_WIDTH = 200; - private static final int SLIDER_HEIGHT = 10; - private static final int HUE_SLIDER_HEIGHT = 10; - private float hue = 0.0f; - - private int selectedX = 0; - private int selectedY = 0; - - private float opacity = 1.0f; - private boolean dragging = false; - - public ColorDialog(Property prop , SaturnScreen parent) { - super("Color Dialog"); - this.prop = prop; - this.parent = parent; - - int alpha = (prop.value >> 24) & 0xFF; - if (alpha == 0) alpha = 255; // fallback if no alpha specified - this.opacity = alpha / 255.0f; - syncFromColor(); - } - - @Override - public void ui() {} - - @Override - public void close() { - SaturnClient.client.setScreen(parent); - } - - @Override - public void render(DrawContext context, int mouseX, int mouseY, float delta) { - super.render(context, mouseX, mouseY, delta); - RenderScope renderScope = new RenderScope(context.getMatrices(), - ((DrawContextAccessor) context).getVertexConsumers()); - - renderScope.matrices.push(); - - renderScope.matrices.scale(0.5f, 0.5f, 0.5f); - - int xStart = (width - PICKER_WIDTH) / 2; - int yStart = (height - PICKER_HEIGHT) / 2; - - // Draw the HSV saturation/value square (with current hue) - for (int x = 0; x < PICKER_WIDTH; x++) { - for (int y = 0; y < PICKER_HEIGHT; y++) { - float saturation = x / (float) PICKER_WIDTH; - float value = 1.0f - y / (float) PICKER_HEIGHT; - int color = Color.HSBtoRGB(hue, saturation, value); - context.fill(xStart + x, yStart + y, xStart + x + 1, yStart + y + 1, 0xFF000000 | color); - } - } - - int x = (xStart + selectedX) - 4; - int y = (yStart + selectedY) - 4; - context.fill(x, y, x+8, y+8, 0xFF000000 | prop.value); - context.drawBorder(x, y, 8, 8, 0xFFffffff); - - renderSlider(context, mouseX, mouseY, delta); - renderHueSlider(context); - - renderScope.matrices.pop(); - } - - public void renderSlider(DrawContext context, int mouseX, int mouseY, float delta) { - int xStart = (width - SLIDER_WIDTH) / 2; - int yStart = (height - SLIDER_HEIGHT - PICKER_HEIGHT) / 2 - 10; - - // Draw slider background (left = transparent, right = white) - for (int x = 0; x < SLIDER_WIDTH; x++) { - float localOpacity = x / (float) SLIDER_WIDTH; - int alpha = (int)(localOpacity * 255) & 0xFF; - int color = (alpha << 24) | (prop.value & 0xFFFFFF); - context.fill(xStart + x, yStart, xStart + x + 1, yStart + SLIDER_HEIGHT, color); - } - - // Draw current value as a marker (thin black line) - int knobX = xStart + (int)(opacity * SLIDER_WIDTH); - context.fill(knobX - 1, yStart - 2, knobX + 1, yStart + SLIDER_HEIGHT + 2, 0xFF000000); - - // Draw opacity text - // context.drawText(textRenderer, String.format("Opacity: %.2f", opacity), xStart, yStart - 15, 0xFFFFFF, false); - } - - private void renderHueSlider(DrawContext context) { - int xStart = (width - SLIDER_WIDTH) / 2; - int yStart = (height + PICKER_HEIGHT) / 2 + 10; - - for (int x = 0; x < SLIDER_WIDTH; x++) { - float localHue = x / (float) SLIDER_WIDTH; - int color = Color.HSBtoRGB(localHue, 1.0f, 1.0f); - context.fill(xStart + x, yStart, xStart + x + 1, yStart + HUE_SLIDER_HEIGHT, 0xFF000000 | color); - } - - int knobX = xStart + (int)(hue * SLIDER_WIDTH); - context.fill(knobX - 1, yStart - 2, knobX + 1, yStart + HUE_SLIDER_HEIGHT + 2, 0xFF000000); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - mouseX *= 2; - mouseY *= 2; - - int xStart = (width - PICKER_WIDTH) / 2; - int yStart = (height - PICKER_HEIGHT) / 2; - - int relX = (int) mouseX - xStart; - int relY = (int) mouseY - yStart; - - if (relX >= 0 && relX < PICKER_WIDTH && relY >= 0 && relY < PICKER_HEIGHT) { - float saturation = relX / (float) PICKER_WIDTH; - float value = 1.0f - relY / (float) PICKER_HEIGHT; - prop.value = Color.HSBtoRGB(hue, saturation, value); - - int alpha = (int)(opacity * 255) & 0xFF; - prop.value = (alpha << 24) | (prop.value & 0xFFFFFF); - - selectedX = relX; - selectedY = relY; - - return true; - } else if (isInSlider(mouseX, mouseY)) { - updateOpacity(mouseX); - dragging = true; - return true; - } else if (isInHueSlider(mouseX, mouseY)) { - updateHue(mouseX); - return true; - } - - return super.mouseClicked(mouseX, mouseY, button); - } - - @Override - public boolean mouseReleased(double mouseX, double mouseY, int button) { - dragging = false; - return super.mouseReleased(mouseX, mouseY, button); - } - - @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - mouseX *= 2; - mouseY *= 2; - - if (isInHueSlider(mouseX, mouseY)) { - updateHue(mouseX); - return true; - } else if (dragging) { - updateOpacity(mouseX); - return true; - } else { - int xStart = (width - PICKER_WIDTH) / 2; - int yStart = (height - PICKER_HEIGHT) / 2; - - int relX = (int) mouseX - xStart; - int relY = (int) mouseY - yStart; - - if (relX >= 0 && relX < PICKER_WIDTH && relY >= 0 && relY < PICKER_HEIGHT) { - float saturation = relX / (float) PICKER_WIDTH; - float value = 1.0f - relY / (float) PICKER_HEIGHT; - prop.value = Color.HSBtoRGB(hue, saturation, value); - - int alpha = (int)(opacity * 255) & 0xFF; - prop.value = (alpha << 24) | (prop.value & 0xFFFFFF); - - selectedX = relX; - selectedY = relY; - - return true; - } - } - - return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); - } - - private boolean isInSlider(double mouseX, double mouseY) { - int xStart = (width - SLIDER_WIDTH) / 2; - int yStart = (height - SLIDER_HEIGHT - PICKER_HEIGHT) / 2 - 10; - return mouseX >= xStart && mouseX <= xStart + SLIDER_WIDTH && - mouseY >= yStart && mouseY <= yStart + SLIDER_HEIGHT; - } - - private boolean isInHueSlider(double mouseX, double mouseY) { - int xStart = (width - SLIDER_WIDTH) / 2; - int yStart = (height + PICKER_HEIGHT) / 2 + 10; - return mouseX >= xStart && mouseX <= xStart + SLIDER_WIDTH && - mouseY >= yStart && mouseY <= yStart + HUE_SLIDER_HEIGHT; - } - - private void updateOpacity(double mouseX) { - int xStart = (width - SLIDER_WIDTH) / 2; - float newOpacity = (float)((mouseX - xStart) / SLIDER_WIDTH); - opacity = Math.max(0.0f, Math.min(1.0f, newOpacity)); - - int alpha = (int)(opacity * 255) & 0xFF; - prop.value = (alpha << 24) | (prop.value & 0xFFFFFF); - } - - private void updateHue(double mouseX) { - int xStart = (width - SLIDER_WIDTH) / 2; - float newHue = (float)((mouseX - xStart) / SLIDER_WIDTH); - hue = Math.max(0.0f, Math.min(1.0f, newHue)); - - float saturation = selectedX / (float) PICKER_WIDTH; - float value = 1.0f - selectedY / (float) PICKER_HEIGHT; - prop.value = Color.HSBtoRGB(hue, saturation, value); - - int alpha = (int)(opacity * 255) & 0xFF; - prop.value = (alpha << 24) | (prop.value & 0xFFFFFF); - } - - private void syncFromColor() { - int rgb = prop.value & 0xFFFFFF; - float[] hsb = Color.RGBtoHSB((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF, null); - - this.hue = hsb[0]; - - float saturation = hsb[1]; - float value = hsb[2]; - - this.selectedX = (int)(saturation * PICKER_WIDTH); - this.selectedY = (int)((1.0f - value) * PICKER_HEIGHT); - - // Extract alpha and convert to opacity float - int alpha = (prop.value >> 24) & 0xFF; - if (alpha == 0) alpha = 255; - this.opacity = alpha / 255.0f; - } -} diff --git a/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java b/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java index 025bfd9..8a1864e 100644 --- a/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java +++ b/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java @@ -1,32 +1,182 @@ package org.saturnclient.ui2.components.inputs; -import org.saturnclient.saturnclient.SaturnClient; +import java.awt.Color; + import org.saturnclient.saturnclient.config.Property; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; -import org.saturnclient.ui2.SaturnScreen; -import org.saturnclient.ui2.components.dialog.ColorDialog; public class HexInput extends Element { public Property prop; - public SaturnScreen screen; - public HexInput(Property prop, SaturnScreen screen) { + // Picker state + private boolean open = false; + private float hue = 0f; + private float opacity = 1f; + private int selectedX = 0; + private int selectedY = 0; + + private boolean draggingOpacity = false; + + // Dimensions + private static final int PICKER_WIDTH = 200; + private static final int PICKER_HEIGHT = 200; + private static final int SLIDER_WIDTH = 200; + private static final int SLIDER_HEIGHT = 10; + private static final int HUE_SLIDER_HEIGHT = 10; + + public HexInput(Property prop) { + this.prop = prop; this.width = 58; this.height = 20; - this.prop = prop; - this.scale = 0.8f; - this.screen = screen; + syncFromColor(); } @Override public void click(int mouseX, int mouseY) { - SaturnClient.client.setScreen(new ColorDialog(prop, screen)); + open = !open; + } + + @Override + public void mouseClicked(double mouseX, double mouseY, int button) { + if (open && mouseX >= width + 8 && mouseX <= width && mouseY >= 0 && mouseY <= height) { + handlePickerClick(mouseX - width, mouseY); + } + } + + @Override + public void mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + if (open) + handlePickerDrag(mouseX - width, mouseY); + } + + @Override + public void mouseReleased(double mouseX, double mouseY, int button) { + draggingOpacity = false; } @Override public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawRoundedRectangle(0, 0, width, height, 17, prop.value); + // Draw the main color rectangle + renderScope.drawRoundedRectangle(0, 0, width, height, 6, prop.value); + + if (!open) + return; + + // Draw the picker relative to (width + 8, 0) + int pickerX = width + 8; + int pickerY = 0; + + renderColorSquare(renderScope, pickerX, pickerY); + renderOpacitySlider(renderScope, pickerX, pickerY - SLIDER_HEIGHT - 10); + renderHueSlider(renderScope, pickerX, pickerY + PICKER_HEIGHT + 10); } -} + + private void renderColorSquare(RenderScope renderScope, int xStart, int yStart) { + for (int x = 0; x < PICKER_WIDTH; x++) { + for (int y = 0; y < PICKER_HEIGHT; y++) { + float saturation = x / (float) PICKER_WIDTH; + float value = 1f - y / (float) PICKER_HEIGHT; + int color = Color.HSBtoRGB(hue, saturation, value); + int alpha = (int) (opacity * 255) & 0xFF; + color = (alpha << 24) | (color & 0xFFFFFF); + renderScope.fill(xStart + x, yStart + y, xStart + x + 1, yStart + y + 1, color); + } + } + + // Draw selection square + int selX = xStart + selectedX - 4; + int selY = yStart + selectedY - 4; + renderScope.fill(selX, selY, selX + 8, selY + 8, 0xFF000000 | prop.value); + renderScope.drawBorder(selX, selY, 8, 8, 0xFFFFFFFF); + } + + private void renderOpacitySlider(RenderScope renderScope, int xStart, int yStart) { + for (int x = 0; x < SLIDER_WIDTH; x++) { + float localOpacity = x / (float) SLIDER_WIDTH; + int alpha = (int) (localOpacity * 255) & 0xFF; + int color = (alpha << 24) | (prop.value & 0xFFFFFF); + renderScope.fill(xStart + x, yStart, xStart + x + 1, yStart + SLIDER_HEIGHT, color); + } + + int knobX = xStart + (int) (opacity * SLIDER_WIDTH); + renderScope.fill(knobX - 1, yStart - 2, knobX + 1, yStart + SLIDER_HEIGHT + 2, 0xFF000000); + } + + private void renderHueSlider(RenderScope renderScope, int xStart, int yStart) { + for (int x = 0; x < SLIDER_WIDTH; x++) { + float localHue = x / (float) SLIDER_WIDTH; + int color = Color.HSBtoRGB(localHue, 1f, 1f); + renderScope.fill(xStart + x, yStart, xStart + x + 1, yStart + HUE_SLIDER_HEIGHT, 0xFF000000 | color); + } + + int knobX = xStart + (int) (hue * SLIDER_WIDTH); + renderScope.fill(knobX - 1, yStart - 2, knobX + 1, yStart + HUE_SLIDER_HEIGHT + 2, 0xFF000000); + } + + private void handlePickerClick(double mouseX, double mouseY) { + // Color square + if (mouseX >= 0 && mouseX < PICKER_WIDTH && mouseY >= 0 && mouseY < PICKER_HEIGHT) { + selectedX = (int) mouseX; + selectedY = (int) mouseY; + updateColorFromSelection(); + } + + // Opacity slider + int opY = -SLIDER_HEIGHT - 10; + if (mouseX >= 0 && mouseX < SLIDER_WIDTH && mouseY >= opY && mouseY <= opY + SLIDER_HEIGHT) { + updateOpacity(mouseX); + draggingOpacity = true; + } + + // Hue slider + int hueY = PICKER_HEIGHT + 10; + if (mouseX >= 0 && mouseX < SLIDER_WIDTH && mouseY >= hueY && mouseY <= hueY + HUE_SLIDER_HEIGHT) { + updateHue(mouseX); + } + } + + private void handlePickerDrag(double mouseX, double mouseY) { + // Opacity + if (draggingOpacity) + updateOpacity(mouseX); + + // Color square + if (mouseX >= 0 && mouseX < PICKER_WIDTH && mouseY >= 0 && mouseY < PICKER_HEIGHT) { + selectedX = (int) mouseX; + selectedY = (int) mouseY; + updateColorFromSelection(); + } + } + + private void updateColorFromSelection() { + float saturation = selectedX / (float) PICKER_WIDTH; + float value = 1f - selectedY / (float) PICKER_HEIGHT; + int color = Color.HSBtoRGB(hue, saturation, value); + int alpha = (int) (opacity * 255) & 0xFF; + prop.value = (alpha << 24) | (color & 0xFFFFFF); + } + + private void updateHue(double mouseX) { + hue = (float) Math.max(0, Math.min(1, mouseX / SLIDER_WIDTH)); + updateColorFromSelection(); + } + + private void updateOpacity(double mouseX) { + opacity = (float) Math.max(0, Math.min(1, mouseX / SLIDER_WIDTH)); + updateColorFromSelection(); + } + + private void syncFromColor() { + int rgb = prop.value & 0xFFFFFF; + float[] hsb = Color.RGBtoHSB((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF, null); + hue = hsb[0]; + selectedX = (int) (hsb[1] * PICKER_WIDTH); + selectedY = (int) ((1f - hsb[2]) * PICKER_HEIGHT); + int alpha = (prop.value >> 24) & 0xFF; + if (alpha == 0) + alpha = 255; + opacity = alpha / 255f; + } +} \ No newline at end of file diff --git a/src/main/java/org/saturnclient/ui2/screens/ConfigEditor.java b/src/main/java/org/saturnclient/ui2/screens/ConfigEditor.java index 7b00966..c56ed4a 100644 --- a/src/main/java/org/saturnclient/ui2/screens/ConfigEditor.java +++ b/src/main/java/org/saturnclient/ui2/screens/ConfigEditor.java @@ -78,7 +78,7 @@ public class ConfigEditor extends SaturnScreen { break; case HEX: - configScroll.draw(new HexInput((Property) prop, this).position(w / 2, modY)); + configScroll.draw(new HexInput((Property) prop).position(w / 2, modY)); break; case INTEGER: From 3db44bab85f4f9e0903befbd9ce444933682e623 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 22:37:56 +0100 Subject: [PATCH 26/42] Fixed HexInput and stuff --- .../org/saturnclient/ui2/SaturnScreen.java | 20 ++++++++++ .../ui2/components/ElementRenderer.java | 39 +++++++++++++------ .../ui2/components/inputs/HexInput.java | 9 +++-- .../org/saturnclient/ui2/elements/Scroll.java | 10 +++++ 4 files changed, 63 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/SaturnScreen.java b/src/main/java/org/saturnclient/ui2/SaturnScreen.java index 05bde40..c6af321 100644 --- a/src/main/java/org/saturnclient/ui2/SaturnScreen.java +++ b/src/main/java/org/saturnclient/ui2/SaturnScreen.java @@ -129,6 +129,26 @@ public abstract class SaturnScreen extends Screen { return false; } + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + mouseX *= 2; + mouseY *= 2; + + ElementRenderer.mouseDragged(elements, mouseX, mouseY, button, deltaX, deltaY); + + return super.mouseReleased(mouseX, mouseY, button); + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + mouseX *= 2; + mouseY *= 2; + + ElementRenderer.mouseReleased(elements, mouseX, mouseY, button); + + return super.mouseReleased(mouseX, mouseY, button); + } + @Override public boolean mouseScrolled( double mouseX, diff --git a/src/main/java/org/saturnclient/ui2/components/ElementRenderer.java b/src/main/java/org/saturnclient/ui2/components/ElementRenderer.java index d7b9a02..ee165da 100644 --- a/src/main/java/org/saturnclient/ui2/components/ElementRenderer.java +++ b/src/main/java/org/saturnclient/ui2/components/ElementRenderer.java @@ -14,7 +14,7 @@ public class ElementRenderer { synchronized (elements) { elements.add(element); } - + if (element.animation != null) { element.animation.init(element); @@ -44,7 +44,10 @@ public class ElementRenderer { int adjustedMouseX = (int) mouseX - element.x; int adjustedMouseY = (int) mouseY - element.y; - if (element.opacity > 0 && Utils.isHovering(adjustedMouseX, adjustedMouseY, element.width, element.height, element.scale)) { + element.mouseClicked(adjustedMouseX * element.scale, adjustedMouseY * element.scale, button); + + if (element.opacity > 0 && Utils.isHovering(adjustedMouseX, adjustedMouseY, element.width, + element.height, element.scale)) { element.focused = true; element.click((int) (adjustedMouseX * element.scale), (int) (adjustedMouseY * element.scale)); } @@ -58,16 +61,17 @@ public class ElementRenderer { double mouseY, double horizontalAmount, double verticalAmount) { - for (Element element : new ArrayList<>(elements)) { - if (Utils.isHovering((int) mouseX - element.x, (int) mouseY - element.y, element.width, element.height, element.scale)) { - element.scroll( - (int) mouseX - element.x, - (int) mouseY - element.y, - horizontalAmount, - verticalAmount); - } - } + for (Element element : new ArrayList<>(elements)) { + if (Utils.isHovering((int) mouseX - element.x, (int) mouseY - element.y, element.width, element.height, + element.scale)) { + element.scroll( + (int) mouseX - element.x, + (int) mouseY - element.y, + horizontalAmount, + verticalAmount); } + } + } public static void keyPressed(List elements, int keyCode, int scanCode, int modifiers) { for (Element element : new ArrayList<>(elements)) { @@ -81,4 +85,17 @@ public class ElementRenderer { } } } + + public static void mouseDragged(List elements, double mouseX, double mouseY, int button, double deltaX, + double deltaY) { + for (Element element : new ArrayList<>(elements)) { + element.mouseDragged(mouseX - element.x, mouseY - element.y, button, deltaX, deltaY); + } + } + + public static void mouseReleased(List elements, double mouseX, double mouseY, int button) { + for (Element element : new ArrayList<>(elements)) { + element.mouseReleased(mouseX - element.x, mouseY - element.y, button); + } + } } diff --git a/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java b/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java index 8a1864e..f46e28a 100644 --- a/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java +++ b/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java @@ -40,15 +40,16 @@ public class HexInput extends Element { @Override public void mouseClicked(double mouseX, double mouseY, int button) { - if (open && mouseX >= width + 8 && mouseX <= width && mouseY >= 0 && mouseY <= height) { - handlePickerClick(mouseX - width, mouseY); + if (open) { + handlePickerClick(mouseX - width - 8, mouseY); } } @Override public void mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - if (open) - handlePickerDrag(mouseX - width, mouseY); + if (open) { + handlePickerDrag(mouseX - width - 8, mouseY); + } } @Override diff --git a/src/main/java/org/saturnclient/ui2/elements/Scroll.java b/src/main/java/org/saturnclient/ui2/elements/Scroll.java index 7a751cc..4ebd219 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Scroll.java +++ b/src/main/java/org/saturnclient/ui2/elements/Scroll.java @@ -117,4 +117,14 @@ public class Scroll extends Element { public void keyPressed(int keyCode, int scanCode, int modifiers) { ElementRenderer.keyPressed(children, keyCode, scanCode, modifiers); } + + @Override + public void mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + ElementRenderer.mouseDragged(children, mouseX - padding, mouseY - padding + scroll, button, deltaX, deltaY); + } + + @Override + public void mouseReleased(double mouseX, double mouseY, int button) { + ElementRenderer.mouseReleased(children, mouseX - padding, mouseY - padding + scroll, button); + } } From 2096925a0280713933c593afa3ea0d1d625e43dd Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 22:42:21 +0100 Subject: [PATCH 27/42] Smaller HexInput --- .../org/saturnclient/ui2/components/inputs/HexInput.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java b/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java index f46e28a..aa49018 100644 --- a/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java +++ b/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java @@ -20,9 +20,9 @@ public class HexInput extends Element { private boolean draggingOpacity = false; // Dimensions - private static final int PICKER_WIDTH = 200; - private static final int PICKER_HEIGHT = 200; - private static final int SLIDER_WIDTH = 200; + private static final int PICKER_WIDTH = 100; + private static final int PICKER_HEIGHT = 100; + private static final int SLIDER_WIDTH = 100; private static final int SLIDER_HEIGHT = 10; private static final int HUE_SLIDER_HEIGHT = 10; From d3258edbc7d0e37326b08ee72d56450429c59a6d Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 22:55:47 +0100 Subject: [PATCH 28/42] Cleaner Config --- .../saturnclient/config/ConfigManager.java | 178 +++++++++++------- .../saturnclient/config/Property.java | 9 + 2 files changed, 118 insertions(+), 69 deletions(-) diff --git a/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java b/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java index 4123bbf..87aab0e 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java +++ b/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java @@ -1,107 +1,86 @@ package org.saturnclient.saturnclient.config; import com.google.gson.*; +import org.saturnclient.saturnclient.SaturnClient; + import java.io.File; import java.io.IOException; import java.nio.file.Files; -import java.util.*; -import org.saturnclient.saturnclient.SaturnClient; +import java.util.LinkedHashMap; +import java.util.Map; public class ConfigManager { - private static final File configFile = new File(SaturnClient.client.runDirectory, "saturn.json"); - private static final Map>> properties = new HashMap<>(); - private static JsonObject cachedThemeJson = null; + + private static final File configFile = + new File(SaturnClient.client.runDirectory, "saturn.json"); + + // SINGLE ROOT TREE + private static final Map> ROOT = new LinkedHashMap<>(); + + private static JsonObject cachedJson = null; private final Map> currentMap; - private final String namespace; + /** + * Creates a root namespace + */ public ConfigManager(String namespace) { - this.namespace = namespace; this.currentMap = new LinkedHashMap<>(); - properties.put(namespace, currentMap); - System.out.println("Created namespace: " + namespace); + ROOT.put(namespace, Property.namespace(currentMap)); } + /** + * Creates a sub-namespace inside a parent + */ public ConfigManager(ConfigManager parent, String namespace) { - this.namespace = namespace; this.currentMap = new LinkedHashMap<>(); - Property>> nsProp = Property.namespace(currentMap); - parent.property(namespace, nsProp); - System.out.println("Created sub-namespace: " + namespace); - } - - public void sub(String name) { - property(name, Property.namespace(new LinkedHashMap<>())); + parent.property(namespace, Property.namespace(currentMap)); } + /** + * Add a property + */ public Property property(String name, Property value) { currentMap.put(name, value); - loadProp(name, value); + loadSingleProperty(name, value); return value; } - private void loadProp(String name, Property prop) { - JsonObject source = cachedThemeJson != null ? cachedThemeJson : loadAndCache(); - if (source == null) - return; - - JsonElement namespaceJson = source.get(namespace); - if (namespaceJson == null || !namespaceJson.isJsonObject()) - return; - - JsonElement value = namespaceJson.getAsJsonObject().get(name); - if (value != null) - prop.loadFromJson(value); - } - - private static JsonObject loadAndCache() { - try { - if (!configFile.exists()) { - Files.writeString(configFile.toPath(), "{}"); - return new JsonObject(); - } - String json = Files.readString(configFile.toPath()); - cachedThemeJson = JsonParser.parseString(json).getAsJsonObject(); - return cachedThemeJson; - } catch (IOException e) { - SaturnClient.LOGGER.error("Error reading config file", e); - return null; - } + /** + * Add empty namespace + */ + public ConfigManager sub(String name) { + return new ConfigManager(this, name); } + /** + * Load entire config + */ public static void load() { SaturnClient.LOGGER.info("Loading config..."); + JsonObject json = loadAndCache(); if (json == null) return; - properties.forEach((namespace, map) -> { - JsonElement nsElement = json.get(namespace); - if (nsElement != null && nsElement.isJsonObject()) { - loadProperties(nsElement.getAsJsonObject(), map); - } - }); - } - - private static void loadProperties(JsonObject json, Map> props) { - props.forEach((name, prop) -> { - JsonElement el = json.get(name); - if (el != null) - prop.loadFromJson(el); - }); + loadRecursive(json, ROOT); } + /** + * Save entire config + */ public static void save() { SaturnClient.LOGGER.info("Saving config..."); - JsonObject root = new JsonObject(); - properties.forEach((namespace, map) -> { - JsonObject nsJson = new JsonObject(); - saveProperties(nsJson, map); - root.add(namespace, nsJson); - }); + + JsonObject rootJson = new JsonObject(); + saveRecursive(rootJson, ROOT); try { - String formatted = new GsonBuilder().setPrettyPrinting().create().toJson(root); + String formatted = new GsonBuilder() + .setPrettyPrinting() + .create() + .toJson(rootJson); + Files.writeString(configFile.toPath(), formatted); SaturnClient.LOGGER.info("Config saved successfully."); } catch (IOException e) { @@ -109,11 +88,72 @@ public class ConfigManager { } } - private static void saveProperties(JsonObject json, Map> props) { - props.forEach((name, prop) -> json.add(name, prop.toJson())); + /** + * Recursive save + */ + private static void saveRecursive(JsonObject json, Map> map) { + map.forEach((name, prop) -> { + if (prop.isNamespace()) { + JsonObject child = new JsonObject(); + saveRecursive(child, prop.getNamespaceMap()); + json.add(name, child); + } else { + json.add(name, prop.toJson()); + } + }); + } + + /** + * Recursive load + */ + private static void loadRecursive(JsonObject json, Map> map) { + map.forEach((name, prop) -> { + JsonElement element = json.get(name); + if (element == null) + return; + + if (prop.isNamespace() && element.isJsonObject()) { + loadRecursive(element.getAsJsonObject(), prop.getNamespaceMap()); + } else { + prop.loadFromJson(element); + } + }); + } + + /** + * Load only a single property immediately after creation + */ + private void loadSingleProperty(String name, Property prop) { + JsonObject source = cachedJson != null ? cachedJson : loadAndCache(); + if (source == null) + return; + + JsonElement element = source.get(name); + if (element != null) + prop.loadFromJson(element); + } + + /** + * Reads file and caches json + */ + private static JsonObject loadAndCache() { + try { + if (!configFile.exists()) { + Files.writeString(configFile.toPath(), "{}"); + return new JsonObject(); + } + + String json = Files.readString(configFile.toPath()); + cachedJson = JsonParser.parseString(json).getAsJsonObject(); + return cachedJson; + + } catch (IOException e) { + SaturnClient.LOGGER.error("Error reading config file", e); + return null; + } } public Map> getProperties() { return currentMap; } -} +} \ No newline at end of file diff --git a/src/main/java/org/saturnclient/saturnclient/config/Property.java b/src/main/java/org/saturnclient/saturnclient/config/Property.java index 6d81da7..2d7dd2e 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/Property.java +++ b/src/main/java/org/saturnclient/saturnclient/config/Property.java @@ -286,4 +286,13 @@ public class Property { if (value != null) this.loadFromJson(value); } + + public boolean isNamespace() { + return type == PropertyType.NAMESPACE; + } + + @SuppressWarnings("unchecked") + public Map> getNamespaceMap() { + return isNamespace() ? (Map>) (Object) value : null; + } } From e62da29a4960c4692c9f2b06580349342ac981fa Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 21 Feb 2026 23:11:22 +0100 Subject: [PATCH 29/42] Sub namespace loading --- .../saturnclient/config/ConfigManager.java | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java b/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java index 87aab0e..bc628b1 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java +++ b/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java @@ -11,8 +11,7 @@ import java.util.Map; public class ConfigManager { - private static final File configFile = - new File(SaturnClient.client.runDirectory, "saturn.json"); + private static final File configFile = new File(SaturnClient.client.runDirectory, "saturn.json"); // SINGLE ROOT TREE private static final Map> ROOT = new LinkedHashMap<>(); @@ -21,11 +20,14 @@ public class ConfigManager { private final Map> currentMap; + private final String[] path; + /** * Creates a root namespace */ public ConfigManager(String namespace) { this.currentMap = new LinkedHashMap<>(); + this.path = new String[] { namespace }; // Path is just ["namespace"] ROOT.put(namespace, Property.namespace(currentMap)); } @@ -34,6 +36,12 @@ public class ConfigManager { */ public ConfigManager(ConfigManager parent, String namespace) { this.currentMap = new LinkedHashMap<>(); + + // Build new path: parent path + current namespace + this.path = new String[parent.path.length + 1]; + System.arraycopy(parent.path, 0, this.path, 0, parent.path.length); + this.path[this.path.length - 1] = namespace; + parent.property(namespace, Property.namespace(currentMap)); } @@ -121,16 +129,30 @@ public class ConfigManager { } /** - * Load only a single property immediately after creation + * Load only a single property immediately after creation, + * traversing the JSON tree based on this manager's path. */ private void loadSingleProperty(String name, Property prop) { JsonObject source = cachedJson != null ? cachedJson : loadAndCache(); if (source == null) return; - JsonElement element = source.get(name); - if (element != null) + // Traverse the tree to the correct namespace + JsonObject currentScope = source; + for (String segment : path) { + JsonElement next = currentScope.get(segment); + if (next != null && next.isJsonObject()) { + currentScope = next.getAsJsonObject(); + } else { + return; // Path doesn't exist in config yet + } + } + + // Now look for the property inside the correctly nested object + JsonElement element = currentScope.get(name); + if (element != null) { prop.loadFromJson(element); + } } /** From f952fa70958980436921f7f7ca7cd63a6d7d23d7 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 22 Feb 2026 00:12:13 +0100 Subject: [PATCH 30/42] Better animation system --- .../java/org/saturnclient/ui2/Element.java | 6 ++ .../org/saturnclient/ui2/ElementContext.java | 4 +- .../org/saturnclient/ui2/SaturnScreen.java | 47 +++----------- .../org/saturnclient/ui2/anim/Animation.java | 64 +------------------ .../java/org/saturnclient/ui2/anim/Fade.java | 4 +- .../org/saturnclient/ui2/anim/FadeOut.java | 4 +- .../org/saturnclient/ui2/anim/SlideX.java | 2 +- .../saturnclient/ui2/anim/SlideXAbsolute.java | 2 +- .../org/saturnclient/ui2/anim/SlideY.java | 2 +- .../ui2/components/ElementRenderer.java | 11 ++-- .../org/saturnclient/ui2/elements/Scroll.java | 2 +- 11 files changed, 33 insertions(+), 115 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/Element.java b/src/main/java/org/saturnclient/ui2/Element.java index ec8b110..296ec7f 100644 --- a/src/main/java/org/saturnclient/ui2/Element.java +++ b/src/main/java/org/saturnclient/ui2/Element.java @@ -41,6 +41,12 @@ public class Element { public void mouseReleased(double mouseX, double mouseY, int button) { } + public void playAnimationFrame(long elapsed) { + if (this.animation != null) { + this.animation.tick(this.curve.apply(Math.min(1.0, (double) elapsed / this.animation.duration)), this); + } + } + public Element dimensions(int width, int height) { this.width = width; this.height = height; diff --git a/src/main/java/org/saturnclient/ui2/ElementContext.java b/src/main/java/org/saturnclient/ui2/ElementContext.java index 8f3f898..def84dd 100644 --- a/src/main/java/org/saturnclient/ui2/ElementContext.java +++ b/src/main/java/org/saturnclient/ui2/ElementContext.java @@ -4,13 +4,15 @@ public class ElementContext { public int mouseX, mouseY; public int elementWidth, elementHeight; public float elementScale; + public long elapsed; - public ElementContext(int mouseX, int mouseY, Element e) { + public ElementContext(long elapsed, int mouseX, int mouseY, Element e) { this.mouseX = mouseX - e.x; this.mouseY = mouseY - e.y; this.elementWidth = e.width; this.elementHeight = e.height; this.elementScale = e.scale; + this.elapsed = elapsed; } public boolean isHovering() { diff --git a/src/main/java/org/saturnclient/ui2/SaturnScreen.java b/src/main/java/org/saturnclient/ui2/SaturnScreen.java index c6af321..f88cbe6 100644 --- a/src/main/java/org/saturnclient/ui2/SaturnScreen.java +++ b/src/main/java/org/saturnclient/ui2/SaturnScreen.java @@ -1,11 +1,11 @@ package org.saturnclient.ui2; +import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.List; import org.saturnclient.saturnclient.mixin.DrawContextAccessor; -import org.saturnclient.ui2.anim.Animation; -import org.saturnclient.ui2.anim.SlideXAbsolute; import org.saturnclient.ui2.components.ElementRenderer; import net.minecraft.client.MinecraftClient; @@ -23,6 +23,7 @@ public abstract class SaturnScreen extends Screen { private final Pool pool = new Pool(3); protected List elements = new ArrayList<>(); protected float backgroundOpacity = 1.0f; + protected Instant start = null; public int blurDuration = 700; public float blurProgress = 0.0f; public int backgroundBlur = 10; @@ -41,36 +42,7 @@ public abstract class SaturnScreen extends Screen { } public void draw(Element element) { - synchronized (elements) { - elements.add(element); - } - - if (element.animation != null) { - element.animation.init(element); - - Animation.execute((Float progress) -> { - element.animation.tick(progress, element); - }, element.animation.duration); - } - - if (element.duration != null) { - new Thread(() -> { - try { - Animation fadeOut = new SlideXAbsolute(700, -(width - element.x)); - Thread.sleep(element.duration); - fadeOut.init(element); - Animation.executeSync((Float progress) -> { - fadeOut.tick(progress, element); - }, fadeOut.duration); - synchronized (elements) { - elements.remove(element); - } - - } catch (InterruptedException e) { - e.printStackTrace(); - } - }).start(); - } + ElementRenderer.draw(elements, element); } @Override @@ -79,10 +51,6 @@ public abstract class SaturnScreen extends Screen { width *= 2; height *= 2; ui(); // abstraction to render the saturn ui and also render extra stuff here - - Animation.execute((Float progress) -> { - blurProgress = progress; - }, blurDuration); } public abstract void ui(); @@ -90,6 +58,11 @@ public abstract class SaturnScreen extends Screen { @SuppressWarnings("deprecation") @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { + if (start == null) { + start = Instant.now(); + } + long elapsed = Duration.between(start, Instant.now()).toMillis(); + mouseX *= 2; mouseY *= 2; @@ -114,7 +87,7 @@ public abstract class SaturnScreen extends Screen { renderScope.matrices.scale(0.5f, 0.5f, 0.5f); - ElementRenderer.render(new ArrayList<>(elements), renderScope, mouseX, mouseY); + ElementRenderer.render(new ArrayList<>(elements), elapsed, renderScope, mouseX, mouseY); renderScope.matrices.pop(); } diff --git a/src/main/java/org/saturnclient/ui2/anim/Animation.java b/src/main/java/org/saturnclient/ui2/anim/Animation.java index d1ed85d..269cbcf 100644 --- a/src/main/java/org/saturnclient/ui2/anim/Animation.java +++ b/src/main/java/org/saturnclient/ui2/anim/Animation.java @@ -1,8 +1,5 @@ package org.saturnclient.ui2.anim; -import java.util.function.Consumer; -import java.util.function.Function; - import org.saturnclient.ui2.Element; public abstract class Animation { @@ -12,64 +9,7 @@ public abstract class Animation { this.duration = duration; } - public abstract void tick(float progress, Element element); + public abstract void tick(double progress, Element element); + public abstract void init(Element element); - - public static void execute(Consumer tick, int duration) { - new Thread(() -> { - Function curveFunction = Curve::easeInOutCubic; - float progress = 0.0f; - double incremental = (1000 - duration) / 10000.0; - - for (int i = 0; i <= 100; i++) { - float newProgress = (float) (double) curveFunction.apply(i / 100.0); - - while (Math.abs(newProgress - progress) > 1e-6) { - if (progress < newProgress) { - progress += incremental; - if (progress > newProgress) progress = newProgress; - } else { - progress -= incremental; - if (progress < newProgress) progress = newProgress; - } - - tick.accept(newProgress); - - try { - Thread.sleep(duration / 100); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - }).start(); - } - - public static void executeSync(Consumer tick, int duration) { - Function curveFunction = Curve::easeInOutCubic; - float progress = 0.0f; - double incremental = (1000 - duration) / 10000.0; - - for (int i = 0; i <= 100; i++) { - float newProgress = (float) (double) curveFunction.apply(i / 100.0); - - while (Math.abs(newProgress - progress) > 1e-6) { - if (progress < newProgress) { - progress += incremental; - if (progress > newProgress) progress = newProgress; - } else { - progress -= incremental; - if (progress < newProgress) progress = newProgress; - } - - tick.accept(newProgress); - - try { - Thread.sleep(duration / 100); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } } diff --git a/src/main/java/org/saturnclient/ui2/anim/Fade.java b/src/main/java/org/saturnclient/ui2/anim/Fade.java index 47dfd65..b20bade 100644 --- a/src/main/java/org/saturnclient/ui2/anim/Fade.java +++ b/src/main/java/org/saturnclient/ui2/anim/Fade.java @@ -10,8 +10,8 @@ public class Fade extends Animation { } @Override - public void tick(float progress, Element element) { - element.opacity = targetOpacity * progress; + public void tick(double progress, Element element) { + element.opacity = targetOpacity * (float) progress; } @Override diff --git a/src/main/java/org/saturnclient/ui2/anim/FadeOut.java b/src/main/java/org/saturnclient/ui2/anim/FadeOut.java index a1fb42a..77d93f6 100644 --- a/src/main/java/org/saturnclient/ui2/anim/FadeOut.java +++ b/src/main/java/org/saturnclient/ui2/anim/FadeOut.java @@ -10,8 +10,8 @@ public class FadeOut extends Animation { } @Override - public void tick(float progress, Element element) { - element.opacity = targetOpacity - progress; + public void tick(double progress, Element element) { + element.opacity = targetOpacity - (float) progress; } @Override diff --git a/src/main/java/org/saturnclient/ui2/anim/SlideX.java b/src/main/java/org/saturnclient/ui2/anim/SlideX.java index 595c412..58d5e8c 100644 --- a/src/main/java/org/saturnclient/ui2/anim/SlideX.java +++ b/src/main/java/org/saturnclient/ui2/anim/SlideX.java @@ -24,7 +24,7 @@ public class SlideX extends Animation { } @Override - public void tick(float progress, Element element) { + public void tick(double progress, Element element) { element.x = elementX + (int) (offset * progress); } diff --git a/src/main/java/org/saturnclient/ui2/anim/SlideXAbsolute.java b/src/main/java/org/saturnclient/ui2/anim/SlideXAbsolute.java index ace746f..75a3121 100644 --- a/src/main/java/org/saturnclient/ui2/anim/SlideXAbsolute.java +++ b/src/main/java/org/saturnclient/ui2/anim/SlideXAbsolute.java @@ -24,7 +24,7 @@ public class SlideXAbsolute extends Animation { } @Override - public void tick(float progress, Element element) { + public void tick(double progress, Element element) { element.x = elementX + (int) (offset * progress); } diff --git a/src/main/java/org/saturnclient/ui2/anim/SlideY.java b/src/main/java/org/saturnclient/ui2/anim/SlideY.java index 48ca61b..9d91f3b 100644 --- a/src/main/java/org/saturnclient/ui2/anim/SlideY.java +++ b/src/main/java/org/saturnclient/ui2/anim/SlideY.java @@ -26,7 +26,7 @@ public class SlideY extends Animation { } @Override - public void tick(float progress, Element element) { + public void tick(double progress, Element element) { element.y = elementY + (int) (offset * progress); } diff --git a/src/main/java/org/saturnclient/ui2/components/ElementRenderer.java b/src/main/java/org/saturnclient/ui2/components/ElementRenderer.java index ee165da..30842a1 100644 --- a/src/main/java/org/saturnclient/ui2/components/ElementRenderer.java +++ b/src/main/java/org/saturnclient/ui2/components/ElementRenderer.java @@ -7,7 +7,6 @@ import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; import org.saturnclient.ui2.Utils; -import org.saturnclient.ui2.anim.Animation; public class ElementRenderer { public static void draw(List elements, Element element) { @@ -17,20 +16,18 @@ public class ElementRenderer { if (element.animation != null) { element.animation.init(element); - - Animation.execute((Float progress) -> { - element.animation.tick(progress, element); - }, element.animation.duration); } } - public static void render(List elements, RenderScope renderScope, int mouseX, int mouseY) { + public static void render(List elements, long elapsed, RenderScope renderScope, int mouseX, int mouseY) { for (Element element : elements) { + element.playAnimationFrame(elapsed); + renderScope.matrices.push(); renderScope.setOpacity(element.opacity); renderScope.matrices.translate(element.x, element.y, 0); renderScope.matrices.scale(element.scale, element.scale, 1.0f); - element.render(renderScope, new ElementContext(mouseX, mouseY, element)); + element.render(renderScope, new ElementContext(elapsed, mouseX, mouseY, element)); renderScope.matrices.pop(); renderScope.setRenderLayer(null); } diff --git a/src/main/java/org/saturnclient/ui2/elements/Scroll.java b/src/main/java/org/saturnclient/ui2/elements/Scroll.java index 4ebd219..e02e379 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Scroll.java +++ b/src/main/java/org/saturnclient/ui2/elements/Scroll.java @@ -36,7 +36,7 @@ public class Scroll extends Element { renderScope.matrices.push(); renderScope.matrices.translate(padding, -scroll + padding, 0); - ElementRenderer.render(children, renderScope, + ElementRenderer.render(children, ctx.elapsed, renderScope, ctx.mouseX - padding, ctx.mouseY - padding + scroll); From 7de3d5c9bc0d516d2f86ef72e5c5080d93a793d1 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 22 Feb 2026 00:20:04 +0100 Subject: [PATCH 31/42] Fixed keybinding crashing when invalid --- .../saturnclient/mixin/SplashOverlayMixin.java | 1 + .../ui2/components/inputs/KeybindingSelector.java | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java index 48b0b19..b5c0c3b 100644 --- a/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java +++ b/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java @@ -42,6 +42,7 @@ public abstract class SplashOverlayMixin { private float progress; /** + * @author SaturnClient * @reason Replace vanilla splash rendering completely but keep exit logic */ @Overwrite diff --git a/src/main/java/org/saturnclient/ui2/components/inputs/KeybindingSelector.java b/src/main/java/org/saturnclient/ui2/components/inputs/KeybindingSelector.java index d65ebfd..f85d76e 100644 --- a/src/main/java/org/saturnclient/ui2/components/inputs/KeybindingSelector.java +++ b/src/main/java/org/saturnclient/ui2/components/inputs/KeybindingSelector.java @@ -21,9 +21,12 @@ public class KeybindingSelector extends Element { public void render(RenderScope renderScope, ElementContext ctx) { int textColor = focused ? 0xFFFFFF : 0xAAAAAA; renderScope.drawRoundedRectangle(0, 0, width, height, 10, 0xFF000000); - renderScope.drawText(0.6f, prop.value == -1 ? "" : - GLFW.glfwGetKeyName(prop.value, GLFW.glfwGetKeyScancode(prop.value)).toUpperCase(), - 4, 4, Theme.FONT.value, textColor); + String name = GLFW.glfwGetKeyName(prop.value, GLFW.glfwGetKeyScancode(prop.value)); + + renderScope.drawText(0.6f, + prop.value == -1 ? "" + : name != null ? name.toUpperCase() : "", + 4, 4, Theme.FONT.value, textColor); } @Override From 2747ad366eed5686206a77b0041070df75e39fdd Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 22 Feb 2026 01:06:33 +0100 Subject: [PATCH 32/42] Fixed title menu freezing --- .../saturnclient/SaturnClient.java | 4 ++++ .../org/saturnclient/ui2/SaturnScreen.java | 20 +++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/saturnclient/saturnclient/SaturnClient.java b/src/main/java/org/saturnclient/saturnclient/SaturnClient.java index 7a6c803..1894a58 100644 --- a/src/main/java/org/saturnclient/saturnclient/SaturnClient.java +++ b/src/main/java/org/saturnclient/saturnclient/SaturnClient.java @@ -41,6 +41,10 @@ public class SaturnClient implements ModInitializer { SaturnClientConfig.init(); ModManager.init(); + client.execute(() -> { + SaturnScreen.preload(client); + }); + ClientLifecycleEvents.CLIENT_STOPPING.register(_o -> ConfigManager.save()); SpecialModelLoaderEvents.LOAD_SCOPE.register(() -> { diff --git a/src/main/java/org/saturnclient/ui2/SaturnScreen.java b/src/main/java/org/saturnclient/ui2/SaturnScreen.java index f88cbe6..ac39d7f 100644 --- a/src/main/java/org/saturnclient/ui2/SaturnScreen.java +++ b/src/main/java/org/saturnclient/ui2/SaturnScreen.java @@ -15,6 +15,8 @@ import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.RotatingCubeMapRenderer; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.render.DefaultFramebufferSet; +import net.minecraft.client.texture.ResourceTexture; +import net.minecraft.client.texture.TextureManager; import net.minecraft.client.util.Pool; import net.minecraft.text.Text; import net.minecraft.util.Identifier; @@ -28,8 +30,9 @@ public abstract class SaturnScreen extends Screen { public float blurProgress = 0.0f; public int backgroundBlur = 10; - protected static final CubeMapRenderer PANORAMA_RENDERER = new CubeMapRenderer( - Identifier.of("saturnclient", "textures/gui/title/background/panorama")); + protected static final Identifier PANORAMA = Identifier.of("saturnclient", + "textures/gui/title/background/panorama"); + protected static final CubeMapRenderer PANORAMA_RENDERER = new CubeMapRenderer(PANORAMA); public static final RotatingCubeMapRenderer ROTATING_PANORAMA_RENDERER; @@ -37,6 +40,18 @@ public abstract class SaturnScreen extends Screen { ROTATING_PANORAMA_RENDERER = new RotatingCubeMapRenderer(PANORAMA_RENDERER); } + public static void preload(MinecraftClient client) { + TextureManager textureManager = client.getTextureManager(); + + // Force upload each texture to GPU + for (int i = 0; i < 6; i++) { + String var10001 = PANORAMA.getPath(); + Identifier tex = PANORAMA.withPath(var10001 + "_" + i + ".png"); + ResourceTexture resourceTexture = new ResourceTexture(tex); + textureManager.registerTexture(tex, resourceTexture); + } + } + public SaturnScreen(String title) { super(Text.literal(title)); } @@ -73,6 +88,7 @@ public abstract class SaturnScreen extends Screen { PostEffectProcessor postEffectProcessor = this.client.getShaderLoader().loadPostEffect( Identifier.ofVanilla("blur"), DefaultFramebufferSet.MAIN_ONLY); + if (postEffectProcessor != null) { postEffectProcessor.setUniforms("Radius", backgroundBlur * blurProgress); postEffectProcessor.render(this.client.getFramebuffer(), this.pool); From 37ec729d1df2acde740bf46c3554444ef0e63825 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 22 Feb 2026 01:11:12 +0100 Subject: [PATCH 33/42] Blurring --- src/main/java/org/saturnclient/ui2/SaturnScreen.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/SaturnScreen.java b/src/main/java/org/saturnclient/ui2/SaturnScreen.java index ac39d7f..29651de 100644 --- a/src/main/java/org/saturnclient/ui2/SaturnScreen.java +++ b/src/main/java/org/saturnclient/ui2/SaturnScreen.java @@ -26,8 +26,6 @@ public abstract class SaturnScreen extends Screen { protected List elements = new ArrayList<>(); protected float backgroundOpacity = 1.0f; protected Instant start = null; - public int blurDuration = 700; - public float blurProgress = 0.0f; public int backgroundBlur = 10; protected static final Identifier PANORAMA = Identifier.of("saturnclient", @@ -90,7 +88,7 @@ public abstract class SaturnScreen extends Screen { DefaultFramebufferSet.MAIN_ONLY); if (postEffectProcessor != null) { - postEffectProcessor.setUniforms("Radius", backgroundBlur * blurProgress); + postEffectProcessor.setUniforms("Radius", backgroundBlur * Math.min((float) elapsed / 700, 1.0f)); postEffectProcessor.render(this.client.getFramebuffer(), this.pool); } From 049c92785d4ba28e299fb2ebfa9fcbfc95524cec Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 22 Feb 2026 01:25:22 +0100 Subject: [PATCH 34/42] Fixed bugs and restructured roles --- .../saturnclient/client/player/Roles.java | 59 +++++++++++++++++++ .../client/player/SaturnPlayer.java | 4 ++ .../config/SaturnClientConfig.java | 53 ----------------- .../cosmetics/CloakFeatureRenderer.java | 8 ++- .../saturnclient/mixin/NameTagMixin.java | 10 ++-- .../saturnclient/mixin/TabListMixin.java | 6 +- 6 files changed, 77 insertions(+), 63 deletions(-) create mode 100644 src/main/java/org/saturnclient/saturnclient/client/player/Roles.java diff --git a/src/main/java/org/saturnclient/saturnclient/client/player/Roles.java b/src/main/java/org/saturnclient/saturnclient/client/player/Roles.java new file mode 100644 index 0000000..8771960 --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/client/player/Roles.java @@ -0,0 +1,59 @@ +package org.saturnclient.saturnclient.client.player; + +import java.util.Map; +import java.util.UUID; + +import org.saturnclient.saturnclient.config.SaturnClientConfig; + +import net.minecraft.util.Formatting; + +public class Roles { + static enum Role { + OWNER, + ADMIN, + PARTNER, + CONTRIBUTOR + } + + private static final Map ROLES = Map.of( + UUID.fromString("d362a042-28bd-49e1-a807-ae74dbe8aba9"), + Role.OWNER); + + /* + * Gets the icon color of a specific individual, here are the different colors + * + * - Owner: Dark Red + * - Admin: Red + * - Partners: Gold + * - Contributor: Aqua + * - Other/player: White + */ + public static Formatting getIconColor(UUID uuid) { + Role role = ROLES.get(uuid); + + if (role == null) { + return Formatting.WHITE; + } + + switch (role) { + case OWNER: + return Formatting.DARK_RED; + + case ADMIN: + return Formatting.RED; + + case PARTNER: + return Formatting.GOLD; + + case CONTRIBUTOR: + return Formatting.AQUA; + + default: + return Formatting.WHITE; + } + } + + public static String getSaturnIndicator() { + return SaturnClientConfig.realisticLogo.value ? "" : ""; + } +} diff --git a/src/main/java/org/saturnclient/saturnclient/client/player/SaturnPlayer.java b/src/main/java/org/saturnclient/saturnclient/client/player/SaturnPlayer.java index 5f18c51..a6caf95 100644 --- a/src/main/java/org/saturnclient/saturnclient/client/player/SaturnPlayer.java +++ b/src/main/java/org/saturnclient/saturnclient/client/player/SaturnPlayer.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; +import org.jetbrains.annotations.Nullable; import org.saturnclient.saturnclient.client.ServiceClient; public class SaturnPlayer { @@ -22,14 +23,17 @@ public class SaturnPlayer { this.name = name; } + @Nullable public static SaturnPlayer get() { return PLAYERS.get(ServiceClient.uuid); } + @Nullable public static SaturnPlayer get(UUID uuid) { return PLAYERS.get(uuid); } + @Nullable public static SaturnPlayer get(String name) { UUID uuid = PLAYER_NAMES.get(name); if (uuid == null) diff --git a/src/main/java/org/saturnclient/saturnclient/config/SaturnClientConfig.java b/src/main/java/org/saturnclient/saturnclient/config/SaturnClientConfig.java index cd09f65..5f35a38 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/SaturnClientConfig.java +++ b/src/main/java/org/saturnclient/saturnclient/config/SaturnClientConfig.java @@ -1,12 +1,8 @@ package org.saturnclient.saturnclient.config; -import java.util.Map; -import java.util.UUID; - import org.lwjgl.glfw.GLFW; import org.saturnclient.ui2.resources.Textures; -import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; public class SaturnClientConfig { @@ -17,59 +13,10 @@ public class SaturnClientConfig { public static Property bendyCloaks = Property.bool(true); public static Property openEmoteWheel = Property.keybinding(GLFW.GLFW_KEY_B); - static enum Role { - OWNER, - ADMIN, - PARTNER, - CONTRIBUTOR - } - - private static final Map ROLES = Map.of( - UUID.fromString("d362a042-28bd-49e1-a807-ae74dbe8aba9"), - Role.OWNER); - public static Identifier getLogo() { return realisticLogo.value ? Textures.REALISTIC_LOGO : Textures.LOGO; } - public static String getSaturnIndicator() { - return realisticLogo.value ? "" : ""; - } - - /* - * Gets the icon color of a specific individual, here are the different colors - * - * - Owner: Dark Red - * - Admin: Red - * - Partners: Gold - * - Contributor: Aqua - * - Other/player: White - */ - public static Formatting getIconColor(UUID uuid) { - Role role = ROLES.get(uuid); - - if (role == null) { - return Formatting.WHITE; - } - - switch (role) { - case OWNER: - return Formatting.DARK_RED; - - case ADMIN: - return Formatting.RED; - - case PARTNER: - return Formatting.GOLD; - - case CONTRIBUTOR: - return Formatting.AQUA; - - default: - return Formatting.WHITE; - } - } - public static void init() { config = new ConfigManager("Saturn Client"); config.property("Realistic logo", realisticLogo); diff --git a/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java b/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java index 9f4344f..bafc998 100644 --- a/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java +++ b/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java @@ -283,14 +283,16 @@ public class CloakFeatureRenderer extends FeatureRenderer { UUID uuid = isSaturn(state); if (uuid != null) { - MutableText iconText = Text.literal(SaturnClientConfig.getSaturnIndicator()) - .styled(style -> style.withColor(SaturnClientConfig.getIconColor(uuid))); + MutableText iconText = Text.literal(Roles.getSaturnIndicator()) + .styled(style -> style.withColor(Roles.getIconColor(uuid))); Text nameText = text.copy().styled(style -> style.withColor(Formatting.WHITE)); @@ -59,7 +59,9 @@ public abstract class NameTagMixin { if (state instanceof PlayerEntityRenderState) { String name = ((PlayerEntityRenderState) state).name; SaturnPlayer player = SaturnPlayer.get(name); - return player.uuid; + if (player != null) { + return player.uuid; + } } return null; diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java index 93513cc..e830a3e 100644 --- a/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java +++ b/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java @@ -7,8 +7,8 @@ import net.minecraft.util.Formatting; import java.util.UUID; import org.jetbrains.annotations.Nullable; +import org.saturnclient.saturnclient.client.player.Roles; import org.saturnclient.saturnclient.client.player.SaturnPlayer; -import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; @@ -34,8 +34,8 @@ public abstract class TabListMixin { UUID uuid = profile.getId(); if (SaturnPlayer.get(uuid) != null) { - return Text.literal(SaturnClientConfig.getSaturnIndicator()) - .styled(style -> style.withColor(SaturnClientConfig.getIconColor(uuid))) + return Text.literal(Roles.getSaturnIndicator()) + .styled(style -> style.withColor(Roles.getIconColor(uuid))) .append(Text.literal(name).styled(style -> style.withColor(Formatting.WHITE))); } return Text.literal(name); From f46f9c474edec53bb665b7a65107c25b4a16d550 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 22 Feb 2026 01:34:54 +0100 Subject: [PATCH 35/42] Animation Stagger element --- .../ui2/elements/AnimationStagger.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java diff --git a/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java b/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java new file mode 100644 index 0000000..ce2e1cd --- /dev/null +++ b/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java @@ -0,0 +1,52 @@ +package org.saturnclient.ui2.elements; + +import java.util.ArrayList; +import java.util.List; + +import org.saturnclient.ui2.Element; +import org.saturnclient.ui2.ElementContext; +import org.saturnclient.ui2.RenderScope; +import org.saturnclient.ui2.components.ElementRenderer; + +public class AnimationStagger extends Element { + protected List children = new ArrayList<>(); + public int duration; + + public AnimationStagger(int duration) { + this.duration = duration; + } + + @Override + public void render(RenderScope renderScope, ElementContext ctx) { + ElementRenderer.render(children, ctx.elapsed, renderScope, + ctx.mouseX, + ctx.mouseY); + } + + @Override + public void click(int mouseX, int mouseY) { + ElementRenderer.mouseClicked(children, mouseX, mouseY, 0); + } + + public void draw(Element element) { + if (element.animation != null) { + element.animation.duration = duration * (children.size() + 1); + } + children.add(element); + } + + @Override + public void keyPressed(int keyCode, int scanCode, int modifiers) { + ElementRenderer.keyPressed(children, keyCode, scanCode, modifiers); + } + + @Override + public void mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + ElementRenderer.mouseDragged(children, mouseX, mouseY, button, deltaX, deltaY); + } + + @Override + public void mouseReleased(double mouseX, double mouseY, int button) { + ElementRenderer.mouseReleased(children, mouseX, mouseY, button); + } +} From 265b44187b2aca48e878e23ef42b14a54109c992 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 22 Feb 2026 01:38:30 +0100 Subject: [PATCH 36/42] Animation stagger delay --- src/main/java/org/saturnclient/ui2/Element.java | 2 +- src/main/java/org/saturnclient/ui2/anim/Animation.java | 1 + .../org/saturnclient/ui2/elements/AnimationStagger.java | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/Element.java b/src/main/java/org/saturnclient/ui2/Element.java index 296ec7f..1d41d3d 100644 --- a/src/main/java/org/saturnclient/ui2/Element.java +++ b/src/main/java/org/saturnclient/ui2/Element.java @@ -42,7 +42,7 @@ public class Element { } public void playAnimationFrame(long elapsed) { - if (this.animation != null) { + if (this.animation != null && elapsed >= this.animation.delay) { this.animation.tick(this.curve.apply(Math.min(1.0, (double) elapsed / this.animation.duration)), this); } } diff --git a/src/main/java/org/saturnclient/ui2/anim/Animation.java b/src/main/java/org/saturnclient/ui2/anim/Animation.java index 269cbcf..5fa328b 100644 --- a/src/main/java/org/saturnclient/ui2/anim/Animation.java +++ b/src/main/java/org/saturnclient/ui2/anim/Animation.java @@ -4,6 +4,7 @@ import org.saturnclient.ui2.Element; public abstract class Animation { public int duration; + public int delay = 0; Animation(int duration) { this.duration = duration; diff --git a/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java b/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java index ce2e1cd..5cd6e93 100644 --- a/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java +++ b/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java @@ -10,10 +10,10 @@ import org.saturnclient.ui2.components.ElementRenderer; public class AnimationStagger extends Element { protected List children = new ArrayList<>(); - public int duration; + public int delay; - public AnimationStagger(int duration) { - this.duration = duration; + public AnimationStagger(int delay) { + this.delay = delay; } @Override @@ -30,7 +30,7 @@ public class AnimationStagger extends Element { public void draw(Element element) { if (element.animation != null) { - element.animation.duration = duration * (children.size() + 1); + element.animation.delay = delay * (children.size() + 1); } children.add(element); } From 53732c5df35a37b589cf7f03e5bc09678f126e4f Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 22 Feb 2026 02:19:04 +0100 Subject: [PATCH 37/42] Animation stagger and a few slide fixes --- .../java/org/saturnclient/ui2/Element.java | 3 +- .../java/org/saturnclient/ui2/anim/Fade.java | 4 +-- .../org/saturnclient/ui2/anim/SlideFade.java | 32 +++++++++++++++++++ .../org/saturnclient/ui2/anim/SlideY.java | 17 +++++----- .../ui2/elements/AnimationStagger.java | 4 +-- .../saturnclient/ui2/screens/TitleMenu.java | 24 ++++++++------ 6 files changed, 62 insertions(+), 22 deletions(-) create mode 100644 src/main/java/org/saturnclient/ui2/anim/SlideFade.java diff --git a/src/main/java/org/saturnclient/ui2/Element.java b/src/main/java/org/saturnclient/ui2/Element.java index 1d41d3d..d00b80f 100644 --- a/src/main/java/org/saturnclient/ui2/Element.java +++ b/src/main/java/org/saturnclient/ui2/Element.java @@ -43,7 +43,8 @@ public class Element { public void playAnimationFrame(long elapsed) { if (this.animation != null && elapsed >= this.animation.delay) { - this.animation.tick(this.curve.apply(Math.min(1.0, (double) elapsed / this.animation.duration)), this); + this.animation.tick(this.curve + .apply(Math.min(1.0, (double) (elapsed - this.animation.delay) / this.animation.duration)), this); } } diff --git a/src/main/java/org/saturnclient/ui2/anim/Fade.java b/src/main/java/org/saturnclient/ui2/anim/Fade.java index b20bade..db75ae6 100644 --- a/src/main/java/org/saturnclient/ui2/anim/Fade.java +++ b/src/main/java/org/saturnclient/ui2/anim/Fade.java @@ -11,12 +11,12 @@ public class Fade extends Animation { @Override public void tick(double progress, Element element) { - element.opacity = targetOpacity * (float) progress; + element.opacity = Math.max(0.1f, targetOpacity * (float) progress); } @Override public void init(Element element) { targetOpacity = element.opacity; - element.opacity = 0; + element.opacity = 0.1f; } } diff --git a/src/main/java/org/saturnclient/ui2/anim/SlideFade.java b/src/main/java/org/saturnclient/ui2/anim/SlideFade.java new file mode 100644 index 0000000..c407cc0 --- /dev/null +++ b/src/main/java/org/saturnclient/ui2/anim/SlideFade.java @@ -0,0 +1,32 @@ +package org.saturnclient.ui2.anim; + +import org.saturnclient.ui2.Element; + +public class SlideFade extends Animation { + public Fade fade; + public SlideY slideY; + + public SlideFade(int duration, int offset) { + super(duration); + this.fade = new Fade(duration); + this.slideY = new SlideY(duration, offset); + } + + @Override + public void tick(double progress, Element element) { + fade.delay = this.delay; + fade.duration = this.duration; + + slideY.delay = this.delay; + slideY.duration = this.duration; + + fade.tick(progress, element); + slideY.tick(progress, element); + } + + @Override + public void init(Element element) { + fade.init(element); + slideY.init(element); + } +} diff --git a/src/main/java/org/saturnclient/ui2/anim/SlideY.java b/src/main/java/org/saturnclient/ui2/anim/SlideY.java index 9d91f3b..5ca5a97 100644 --- a/src/main/java/org/saturnclient/ui2/anim/SlideY.java +++ b/src/main/java/org/saturnclient/ui2/anim/SlideY.java @@ -5,7 +5,7 @@ import org.saturnclient.ui2.Element; public class SlideY extends Animation { int offset = 20; int maxOffset = 20; - int elementY; + double startY; public SlideY(int duration) { super(duration); @@ -24,15 +24,16 @@ public class SlideY extends Animation { this.offset = offset; this.maxOffset = offset; } - - @Override - public void tick(double progress, Element element) { - element.y = elementY + (int) (offset * progress); - } @Override public void init(Element element) { - element.y -= offset; - elementY = element.y; + startY = element.y - offset; + element.y = (int) startY; + } + + @Override + public void tick(double progress, Element element) { + double currentY = startY + offset * progress; + element.y = (int) currentY; } } diff --git a/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java b/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java index 5cd6e93..b716b9c 100644 --- a/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java +++ b/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java @@ -30,9 +30,9 @@ public class AnimationStagger extends Element { public void draw(Element element) { if (element.animation != null) { - element.animation.delay = delay * (children.size() + 1); + element.animation.delay = delay * children.size(); } - children.add(element); + ElementRenderer.draw(children, element); } @Override diff --git a/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java b/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java index 7f0636a..aa17223 100644 --- a/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java +++ b/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java @@ -7,7 +7,9 @@ import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.screens.cosmetics.CloakMenu; import org.saturnclient.ui2.SaturnScreen; import org.saturnclient.ui2.anim.Fade; +import org.saturnclient.ui2.anim.SlideFade; import org.saturnclient.ui2.anim.SlideY; +import org.saturnclient.ui2.elements.AnimationStagger; import org.saturnclient.ui2.elements.Button; import org.saturnclient.ui2.elements.ImageTexture; import org.saturnclient.ui2.elements.TextureButton; @@ -19,7 +21,7 @@ import net.minecraft.client.gui.screen.world.SelectWorldScreen; public class TitleMenu extends SaturnScreen { public TitleMenu() { - super("Tile Menu"); + super("Title Menu"); } @Override @@ -31,21 +33,25 @@ public class TitleMenu extends SaturnScreen { draw(new ImageTexture(SaturnClientConfig.getLogo()).dimensions(98, 98).centerOffset(width, height, 0, -82) .animation(new SlideY(700, -20))); - draw(new Button("SINGLEPLAYER", () -> { + AnimationStagger stagger = new AnimationStagger(120); + + stagger.draw(new Button("SINGLEPLAYER", () -> { client.setScreen(new SelectWorldScreen(new TitleMenu())); - }).scale(0.69f).dimensions(420, 52).centerOffset(width, height, 0, 0)); + }).scale(0.69f).dimensions(420, 52).position(0, 0).animation(new SlideFade(1000, -10))); - draw(new Button("MULTIPLAYER", () -> { + stagger.draw(new Button("MULTIPLAYER", () -> { client.setScreen(new MultiplayerScreen(new TitleMenu())); - }).scale(0.69f).dimensions(420, 52).centerOffset(width, height, 0, 40)); + }).scale(0.69f).dimensions(420, 52).position(0, 40).animation(new SlideFade(1000, -10))); - draw(new Button("OPTIONS", () -> { + stagger.draw(new Button("OPTIONS", () -> { client.setScreen(new OptionsScreen(new TitleMenu(), SaturnClient.client.options)); - }).scale(0.69f).dimensions(206, 52).centerOffset(width, height, -73, 80)); + }).scale(0.69f).dimensions(206, 52).position(0, 80).animation(new SlideFade(1000, -10))); - draw(new Button("QUIT", () -> { + stagger.draw(new Button("QUIT", () -> { client.scheduleStop(); - }).scale(0.69f).dimensions(206, 52).centerOffset(width, height, 73, 80)); + }).scale(0.69f).dimensions(206, 52).position(146, 80).animation(new SlideFade(1000, -10))); + + draw(stagger.dimensions(289, 143).centerOffset(width, height, 0, 60)); int s = Fonts.getHeight() + 20; From 44d7aa3641a3d7ebe7a01b6808cb9497427ec9d5 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 22 Feb 2026 02:31:56 +0100 Subject: [PATCH 38/42] Hoo lee sheet --- .../saturnclient/ui2/screens/TitleMenu.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java b/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java index aa17223..ebffa12 100644 --- a/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java +++ b/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java @@ -33,38 +33,42 @@ public class TitleMenu extends SaturnScreen { draw(new ImageTexture(SaturnClientConfig.getLogo()).dimensions(98, 98).centerOffset(width, height, 0, -82) .animation(new SlideY(700, -20))); - AnimationStagger stagger = new AnimationStagger(120); + AnimationStagger mainButtonStagger = new AnimationStagger(120); - stagger.draw(new Button("SINGLEPLAYER", () -> { + mainButtonStagger.draw(new Button("SINGLEPLAYER", () -> { client.setScreen(new SelectWorldScreen(new TitleMenu())); }).scale(0.69f).dimensions(420, 52).position(0, 0).animation(new SlideFade(1000, -10))); - stagger.draw(new Button("MULTIPLAYER", () -> { + mainButtonStagger.draw(new Button("MULTIPLAYER", () -> { client.setScreen(new MultiplayerScreen(new TitleMenu())); }).scale(0.69f).dimensions(420, 52).position(0, 40).animation(new SlideFade(1000, -10))); - stagger.draw(new Button("OPTIONS", () -> { + mainButtonStagger.draw(new Button("OPTIONS", () -> { client.setScreen(new OptionsScreen(new TitleMenu(), SaturnClient.client.options)); }).scale(0.69f).dimensions(206, 52).position(0, 80).animation(new SlideFade(1000, -10))); - stagger.draw(new Button("QUIT", () -> { + mainButtonStagger.draw(new Button("QUIT", () -> { client.scheduleStop(); }).scale(0.69f).dimensions(206, 52).position(146, 80).animation(new SlideFade(1000, -10))); - draw(stagger.dimensions(289, 143).centerOffset(width, height, 0, 60)); + draw(mainButtonStagger.dimensions(289, 143).centerOffset(width, height, 0, 60)); int s = Fonts.getHeight() + 20; - draw(new TextureButton(Textures.HUD_ICON, () -> { + AnimationStagger saturnStagger = new AnimationStagger(180); + + saturnStagger.draw(new TextureButton(Textures.HUD_ICON, () -> { client.setScreen(new HudEditor()); - }).dimensions(s, s).centerHorizontal(width, height, -(s + 2), 8).animation(new SlideY(700, s + 8))); + }).dimensions(s, s).position(0, 0).animation(new SlideFade(1000, s + 8))); - draw(new TextureButton(Textures.SETTINGS, () -> { + saturnStagger.draw(new TextureButton(Textures.SETTINGS, () -> { SaturnClient.client.setScreen(new ModMenu()); - }).dimensions(s, s).centerHorizontal(width, height, 0, 8).animation(new SlideY(700, s + 8))); + }).dimensions(s, s).position(s + 2, 0).animation(new SlideFade(1000, s + 8))); - draw(new TextureButton(Textures.CLOAK, () -> { + saturnStagger.draw(new TextureButton(Textures.CLOAK, () -> { client.setScreen(new CloakMenu()); - }).dimensions(s, s).centerHorizontal(width, height, s + 2, 8).animation(new SlideY(700, s + 8))); + }).dimensions(s, s).position((s + 2) * 2, 0).animation(new SlideFade(1000, s + 8))); + + draw(saturnStagger.dimensions(((s + 2) * 2) + s, s).centerHorizontal(width, height, 0, 8)); } } From 85d4a1de389479e521a81aad6b0f8e64c3bdd2d2 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 22 Feb 2026 02:44:58 +0100 Subject: [PATCH 39/42] Animated mods --- .../ui2/elements/AnimationStagger.java | 18 +++++++++--------- .../org/saturnclient/ui2/elements/Scroll.java | 18 +++++++++--------- .../org/saturnclient/ui2/screens/ModMenu.java | 9 ++++++++- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java b/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java index b716b9c..d72d62a 100644 --- a/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java +++ b/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java @@ -16,6 +16,13 @@ public class AnimationStagger extends Element { this.delay = delay; } + public void draw(Element element) { + if (element.animation != null) { + element.animation.delay = delay * children.size(); + } + ElementRenderer.draw(children, element); + } + @Override public void render(RenderScope renderScope, ElementContext ctx) { ElementRenderer.render(children, ctx.elapsed, renderScope, @@ -24,15 +31,8 @@ public class AnimationStagger extends Element { } @Override - public void click(int mouseX, int mouseY) { - ElementRenderer.mouseClicked(children, mouseX, mouseY, 0); - } - - public void draw(Element element) { - if (element.animation != null) { - element.animation.delay = delay * children.size(); - } - ElementRenderer.draw(children, element); + public void mouseClicked(double mouseX, double mouseY, int button) { + ElementRenderer.mouseClicked(children, mouseX, mouseY, button); } @Override diff --git a/src/main/java/org/saturnclient/ui2/elements/Scroll.java b/src/main/java/org/saturnclient/ui2/elements/Scroll.java index e02e379..b39616a 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Scroll.java +++ b/src/main/java/org/saturnclient/ui2/elements/Scroll.java @@ -25,6 +25,10 @@ public class Scroll extends Element { this.padding = padding; } + public void draw(Element element) { + ElementRenderer.draw(children, element); + } + @Override public void render(RenderScope renderScope, ElementContext ctx) { calculateMaxScroll(); @@ -64,15 +68,6 @@ public class Scroll extends Element { } } - @Override - public void click(int mouseX, int mouseY) { - ElementRenderer.mouseClicked(children, mouseX - padding, mouseY - padding + scroll, 0); - } - - public void draw(Element element) { - children.add(element); - } - @Override public Element dimensions(int width, int height) { maxScroll = 0; @@ -118,6 +113,11 @@ public class Scroll extends Element { ElementRenderer.keyPressed(children, keyCode, scanCode, modifiers); } + @Override + public void mouseClicked(double mouseX, double mouseY, int button) { + ElementRenderer.mouseClicked(children, mouseX, mouseY, button); + } + @Override public void mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { ElementRenderer.mouseDragged(children, mouseX - padding, mouseY - padding + scroll, button, deltaX, deltaY); diff --git a/src/main/java/org/saturnclient/ui2/screens/ModMenu.java b/src/main/java/org/saturnclient/ui2/screens/ModMenu.java index 8b414a6..83041b1 100644 --- a/src/main/java/org/saturnclient/ui2/screens/ModMenu.java +++ b/src/main/java/org/saturnclient/ui2/screens/ModMenu.java @@ -3,8 +3,10 @@ package org.saturnclient.ui2.screens; import org.saturnclient.modules.ModManager; import org.saturnclient.modules.Module; import org.saturnclient.ui2.SaturnScreen; +import org.saturnclient.ui2.anim.SlideFade; import org.saturnclient.ui2.components.SaturnModule; import org.saturnclient.ui2.components.Sidebar; +import org.saturnclient.ui2.elements.AnimationStagger; import org.saturnclient.ui2.elements.ImageTexture; import org.saturnclient.ui2.elements.Scroll; import org.saturnclient.ui2.resources.Textures; @@ -24,8 +26,11 @@ public class ModMenu extends SaturnScreen { int row = 0; int col = 0; + AnimationStagger moduleStagger = new AnimationStagger(80); + for (Module mod : ModManager.ALL_MODS) { - scroll.draw(new SaturnModule(mod).position((160 + g) * col, (50 + g) * row)); + moduleStagger.draw( + new SaturnModule(mod).position((160 + g) * col, (50 + g) * row).animation(new SlideFade(600, -12))); if (col == 2) { col = 0; @@ -35,6 +40,8 @@ public class ModMenu extends SaturnScreen { } } + scroll.draw(moduleStagger); + int scrollWidth = 480 + 10 + (g * 2) + (p * 2); draw(scroll.dimensions(scrollWidth, 350).center(width, height)); From 377031c0a9696d6072afd8bf6fa5036802108dc5 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 22 Feb 2026 03:20:16 +0100 Subject: [PATCH 40/42] Fixed click bugs --- .../ui2/components/SaturnModule.java | 48 ++++++++++++------- .../ui2/components/inputs/Toggle.java | 2 +- .../org/saturnclient/ui2/elements/Scroll.java | 2 +- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/components/SaturnModule.java b/src/main/java/org/saturnclient/ui2/components/SaturnModule.java index 87da97d..21c8b1c 100644 --- a/src/main/java/org/saturnclient/ui2/components/SaturnModule.java +++ b/src/main/java/org/saturnclient/ui2/components/SaturnModule.java @@ -17,6 +17,10 @@ public class SaturnModule extends Element { private final Module mod; + static int p = 10; // padding + static int s = 14; // settings icon size + static int expand = 5; // settings icon click area + public SaturnModule(Module mod) { this.mod = mod; this.width = 160; @@ -25,18 +29,17 @@ public class SaturnModule extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { - int p = 10; // padding - int s = 14; // settings icon size - boolean hovered = ctx.isHovering(); boolean enabled = mod.isEnabled(); - boolean settingsHover = Utils.isHovering( - ctx.mouseX - (width - s - p - 5), - ctx.mouseY - (height - s - p - 5), - s + 10, - s + 10, - 1.0f); + int iconX = width - s - p; + int iconY = height - s - p; + + boolean settingsHover = ctx.isHovering( + getSettingsX(), + getSettingsY(), + getSettingsHitBox(), + getSettingsHitBox()); renderScope.setRenderLayer(RenderLayer::getGuiTextured); @@ -125,8 +128,8 @@ public class SaturnModule extends Element { // Settings icon renderScope.drawTexture( Textures.SETTINGS, - width - s - p, - height - s - p, + iconX, + iconY, 0, 0, s, s, settingsColor); @@ -134,14 +137,11 @@ public class SaturnModule extends Element { @Override public void click(int mouseX, int mouseY) { - int p = 10; - int s = 14; - boolean settingsHover = Utils.isHovering( - mouseX - (width - s - p - 5), - mouseY - (height - s - p - 5), - s + 10, - s + 10, + mouseX - getSettingsX(), + mouseY - getSettingsY(), + getSettingsHitBox(), + getSettingsHitBox(), 1.0f); if (settingsHover) { @@ -150,4 +150,16 @@ public class SaturnModule extends Element { mod.setEnabled(!mod.isEnabled()); } } + + private int getSettingsX() { + return width - s - p - expand; + } + + private int getSettingsY() { + return height - s - p - expand; + } + + private int getSettingsHitBox() { + return s + expand * 2; + } } \ No newline at end of file diff --git a/src/main/java/org/saturnclient/ui2/components/inputs/Toggle.java b/src/main/java/org/saturnclient/ui2/components/inputs/Toggle.java index c0cfcf6..e692ad9 100644 --- a/src/main/java/org/saturnclient/ui2/components/inputs/Toggle.java +++ b/src/main/java/org/saturnclient/ui2/components/inputs/Toggle.java @@ -18,7 +18,7 @@ public class Toggle extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { renderScope.drawRoundedRectangle(0, 0, width, height, height, - prop.value ? Theme.ACCENT.value : Theme.PRIMARY.value); + Theme.withAlpha(0.5f, prop.value ? Theme.ACCENT.value : Theme.PRIMARY.value)); renderScope.drawRoundedRectangle(prop.value ? 30 : 0, 0, 30, 30, 30, prop.value ? Theme.ACCENT.value : Theme.PRIMARY.value); } diff --git a/src/main/java/org/saturnclient/ui2/elements/Scroll.java b/src/main/java/org/saturnclient/ui2/elements/Scroll.java index b39616a..68bde0b 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Scroll.java +++ b/src/main/java/org/saturnclient/ui2/elements/Scroll.java @@ -115,7 +115,7 @@ public class Scroll extends Element { @Override public void mouseClicked(double mouseX, double mouseY, int button) { - ElementRenderer.mouseClicked(children, mouseX, mouseY, button); + ElementRenderer.mouseClicked(children, mouseX - padding, mouseY - padding + scroll, button); } @Override From cd5cac7f6923697d1b5a1ba347ba0dac4db145af Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 22 Feb 2026 03:36:39 +0100 Subject: [PATCH 41/42] Shift menu animations --- .../saturnclient/ui2/screens/ShiftMenu.java | 45 ++++++++++++++----- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java b/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java index 5d5448f..350a6a1 100644 --- a/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java +++ b/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java @@ -5,8 +5,8 @@ import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.saturnclient.menus.HudEditor; import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.screens.cosmetics.CloakMenu; -import org.saturnclient.ui2.Element; import org.saturnclient.ui2.SaturnScreen; +import org.saturnclient.ui2.elements.AnimationStagger; import org.saturnclient.ui2.elements.Button; import org.saturnclient.ui2.elements.ImageTexture; import org.saturnclient.ui2.elements.TextureButton; @@ -20,21 +20,42 @@ public class ShiftMenu extends SaturnScreen { @Override public void ui() { - draw(new ImageTexture(Textures.LOGO_TEXT).dimensions(98, 10).centerOffset(width, height, 0, -36).animation(new Fade(700))); - draw(new ImageTexture(SaturnClientConfig.getLogo()).dimensions(98, 98).centerOffset(width, height, 0, -80).animation(new SlideY(700, -20))); + // Logo animations (unchanged) + draw(new ImageTexture(Textures.LOGO_TEXT) + .dimensions(98, 10) + .centerOffset(width, height, 0, -36) + .animation(new Fade(700))); - Element button = new Button("Settings", () -> { - SaturnClient.client.setScreen(new ModMenu()); - }).center(width, height); + draw(new ImageTexture(SaturnClientConfig.getLogo()) + .dimensions(98, 98) + .centerOffset(width, height, 0, -80) + .animation(new SlideY(700, -20))); - draw(button); + // Spacing and sizes + int btnWidth = 120; + int btnHeight = 40; + int spacing = 4; - draw(new TextureButton(Textures.COSMETICS, () -> { - client.setScreen(new CloakMenu()); - }).dimensions(button.height, button.height).centerOffset(width, height, (button.width / 2) + (button.height / 2) + 4, 0)); + // Create stagger + AnimationStagger stagger = new AnimationStagger(120); - draw(new TextureButton(Textures.HUD_ICON, () -> { + stagger.draw(new TextureButton(Textures.HUD_ICON, () -> { client.setScreen(new HudEditor()); - }).dimensions(button.height, button.height).centerOffset(width, height, -((button.width / 2) + (button.height / 2) + 4), 0)); + }).dimensions(btnHeight, btnHeight).position(0, 0) + .animation(new Fade(300))); + + stagger.draw(new Button("Settings", () -> { + SaturnClient.client.setScreen(new ModMenu()); + }).dimensions(btnWidth, btnHeight).position(btnHeight + spacing, 0) + .animation(new Fade(300))); + + stagger.draw(new TextureButton(Textures.COSMETICS, () -> { + client.setScreen(new CloakMenu()); + }).dimensions(btnHeight, btnHeight).position(btnWidth + btnHeight + (spacing * 2), 0) + .animation(new Fade(300))); + + // Draw the stagger at the absolute center of the screen + draw(stagger.dimensions(btnWidth + (btnHeight * 2) + (spacing * 2), btnHeight).centerOffset(width, height, 0, + 0)); } } From cd84866ee809c220f703772505b1aba44d50e3c6 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 22 Feb 2026 03:44:22 +0100 Subject: [PATCH 42/42] Optional staggering --- .../saturnclient/config/SaturnClientConfig.java | 2 ++ .../org/saturnclient/ui2/elements/AnimationStagger.java | 6 ++++++ src/main/java/org/saturnclient/ui2/elements/Scroll.java | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/saturnclient/saturnclient/config/SaturnClientConfig.java b/src/main/java/org/saturnclient/saturnclient/config/SaturnClientConfig.java index 5f35a38..0b9a628 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/SaturnClientConfig.java +++ b/src/main/java/org/saturnclient/saturnclient/config/SaturnClientConfig.java @@ -12,6 +12,7 @@ public class SaturnClientConfig { public static Property saturnTitleScreen = Property.bool(true); public static Property bendyCloaks = Property.bool(true); public static Property openEmoteWheel = Property.keybinding(GLFW.GLFW_KEY_B); + public static Property stagger = Property.bool(true); public static Identifier getLogo() { return realisticLogo.value ? Textures.REALISTIC_LOGO : Textures.LOGO; @@ -23,6 +24,7 @@ public class SaturnClientConfig { config.property("Saturn client title screen", saturnTitleScreen); config.property("Open Emote Wheel", openEmoteWheel); config.property("Bendy Cloaks", bendyCloaks); + config.property("Stagger Animations", stagger); // Initialize a sub namespace for theme Theme.init(config); diff --git a/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java b/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java index d72d62a..3865481 100644 --- a/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java +++ b/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java @@ -3,6 +3,7 @@ package org.saturnclient.ui2.elements; import java.util.ArrayList; import java.util.List; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; @@ -17,9 +18,14 @@ public class AnimationStagger extends Element { } public void draw(Element element) { + if (!SaturnClientConfig.stagger.value) { + element.animation = null; + } + if (element.animation != null) { element.animation.delay = delay * children.size(); } + ElementRenderer.draw(children, element); } diff --git a/src/main/java/org/saturnclient/ui2/elements/Scroll.java b/src/main/java/org/saturnclient/ui2/elements/Scroll.java index 68bde0b..3114af6 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Scroll.java +++ b/src/main/java/org/saturnclient/ui2/elements/Scroll.java @@ -83,7 +83,7 @@ public class Scroll extends Element { int calculateScrollBarHeight() { if (maxScroll <= 0) return height - (scrollBarPadding.value * 2); - return Math.max(20, (height * height) / (height + maxScroll)) - (scrollBarPadding.value * 2); + return Math.max(20, (height * height) / (height + maxScroll + 10)) - (scrollBarPadding.value * 2); } int calculateScrollBarY() {