From 05dbec028a0c167aa3c5a235812fdc0d15e0363f Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 27 Sep 2026 18:43:27 +0200 Subject: [PATCH 1/5] Fix and restyle the emote wheel The slot index was taken before the middle slot was skipped, so page one showed emotes 0-4 and 6-8: emote 5 never appeared and emote 8 showed on two pages. Emotes now fill the eight cells around the middle in order, and slots past the last emote aren't drawn, so they can't play a null emote. Emotes show as EmoteTiles: the preview in its own colors (it was tinted, almost black on hover), the name under it, an accent outline on hover, and an icon when an emote has no preview. The middle cell holds the page and its arrows when there's more than one page. Emote names and cosmetic names share Utils.nameFromId. Co-Authored-By: Claude Opus 5.5 --- .../org/saturnclient/cosmetics/Emotes.java | 8 + src/main/java/org/saturnclient/ui/Utils.java | 18 ++ .../saturnclient/ui/components/EmoteTile.java | 68 ++++++ .../saturnclient/ui/resources/Textures.java | 17 ++ .../ui/screens/CosmeticsMenu.java | 14 +- .../saturnclient/ui/screens/EmoteWheel.java | 219 ++++++++++++------ .../textures/gui/components/emote.svg | 1 + 7 files changed, 256 insertions(+), 89 deletions(-) create mode 100644 src/main/java/org/saturnclient/ui/components/EmoteTile.java create mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/emote.svg diff --git a/src/main/java/org/saturnclient/cosmetics/Emotes.java b/src/main/java/org/saturnclient/cosmetics/Emotes.java index b4f00dd..f245f64 100644 --- a/src/main/java/org/saturnclient/cosmetics/Emotes.java +++ b/src/main/java/org/saturnclient/cosmetics/Emotes.java @@ -8,6 +8,7 @@ import java.util.Optional; import org.saturnclient.common.provider.Providers; import org.saturnclient.emotes.core.Emote; import org.saturnclient.emotes.core.EmoteRegistry; +import org.saturnclient.ui.Utils; /** * Saturn's emotes, loaded from {@code assets/saturnclient/player_animations/.json} (Emotecraft @@ -23,6 +24,13 @@ public class Emotes { /** The emotes that loaded, in wheel order. */ public static List availableEmotes = new ArrayList<>(); + /** + * The emote's name as shown to players. + */ + public static String getName(String id) { + return id.equals("tpose") ? "T-Pose" : Utils.nameFromId(id); + } + public static void initialize() { for (String id : IDS) { String path = "/assets/saturnclient/player_animations/" + id + ".json"; diff --git a/src/main/java/org/saturnclient/ui/Utils.java b/src/main/java/org/saturnclient/ui/Utils.java index 5be5f4d..b9287dc 100644 --- a/src/main/java/org/saturnclient/ui/Utils.java +++ b/src/main/java/org/saturnclient/ui/Utils.java @@ -47,6 +47,24 @@ public class Utils { }; } + /** + * A display name from an id: each underscore-separated word capitalized, so + * "black_hole_white" becomes "Black Hole White". + */ + public static String nameFromId(String id) { + StringBuilder builder = new StringBuilder(); + for (String word : id.split("_")) { + if (word.isEmpty()) { + continue; + } + if (!builder.isEmpty()) { + builder.append(' '); + } + builder.append(Character.toUpperCase(word.charAt(0))).append(word.substring(1)); + } + return builder.toString(); + } + public static T getOrNull(List list, int index) { return (index >= 0 && index < list.size()) ? list.get(index) : null; } diff --git a/src/main/java/org/saturnclient/ui/components/EmoteTile.java b/src/main/java/org/saturnclient/ui/components/EmoteTile.java new file mode 100644 index 0000000..ede8058 --- /dev/null +++ b/src/main/java/org/saturnclient/ui/components/EmoteTile.java @@ -0,0 +1,68 @@ +package org.saturnclient.ui.components; + +import org.saturnclient.common.ref.asset.IdentifierRef; +import org.saturnclient.config.Theme; +import org.saturnclient.cosmetics.Emotes; +import org.saturnclient.ui.Element; +import org.saturnclient.ui.ElementContext; +import org.saturnclient.ui.RenderScope; +import org.saturnclient.ui.resources.Fonts; +import org.saturnclient.ui.resources.Textures; + +/** + * One emote in the emote wheel: its preview in its own colors and its name. + * An emote without a preview shows an icon instead. + */ +public class EmoteTile extends Element { + public static final int SIZE = 86; + + private static final int INSET = 6; + private static final int NAME_AREA = 20; + private static final int PLACEHOLDER = 26; + private static final float NAME_SCALE = 0.56f; + + private final String name; + /** The preview, or null when the emote has none */ + private final IdentifierRef preview; + private final Runnable onPlay; + + public EmoteTile(String emote, Runnable onPlay) { + IdentifierRef texture = Textures.getEmotePreview(emote); + + this.name = Emotes.getName(emote); + this.preview = Textures.exists(texture) ? texture : null; + this.onPlay = onPlay; + this.width = SIZE; + this.height = SIZE; + } + + @Override + public void render(RenderScope renderScope, ElementContext ctx) { + boolean hovered = ctx.isHovering(); + + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, hovered ? 2 : 1, + Theme.withAlpha(0.72f, Theme.PRIMARY.value), + hovered ? Theme.ACCENT.value : Theme.withAlpha(0.06f, Theme.FOREGROUND.value)); + + int imageSize = height - INSET * 2 - NAME_AREA; + + if (preview != null) { + renderScope.drawTexture(preview, (width - imageSize) / 2, INSET, 0, 0, imageSize, imageSize); + } else { + int iconY = INSET + (imageSize - PLACEHOLDER) / 2; + renderScope.drawTexture(Textures.ICON_EMOTE, (width - PLACEHOLDER) / 2, iconY, 0, 0, PLACEHOLDER, + PLACEHOLDER, Theme.getMutedFg()); + } + + String text = Fonts.ellipsize(name, Theme.FONT.value, NAME_SCALE, width - INSET * 2); + int textX = (width - (int) (Fonts.getWidth(text, Theme.FONT.value) * NAME_SCALE)) / 2; + int textY = height - INSET - NAME_AREA + (NAME_AREA - (int) (Fonts.getHeight() * NAME_SCALE)) / 2; + renderScope.drawText(NAME_SCALE, text, textX, textY, Theme.FONT.value, + hovered ? Theme.FOREGROUND.value : Theme.PRIMARY_FG.value); + } + + @Override + public void click(int mouseX, int mouseY) { + onPlay.run(); + } +} diff --git a/src/main/java/org/saturnclient/ui/resources/Textures.java b/src/main/java/org/saturnclient/ui/resources/Textures.java index 8372396..8ecd804 100644 --- a/src/main/java/org/saturnclient/ui/resources/Textures.java +++ b/src/main/java/org/saturnclient/ui/resources/Textures.java @@ -1,5 +1,9 @@ package org.saturnclient.ui.resources; +import java.io.IOException; +import java.io.InputStream; + +import org.saturnclient.common.provider.Providers; import org.saturnclient.common.ref.asset.IdentifierRef; public class Textures { @@ -43,6 +47,7 @@ public class Textures { .ofSaturn("textures/gui/components/chevron_right.svg"); public static final IdentifierRef ICON_CHEVRON_DOWN = IdentifierRef .ofSaturn("textures/gui/components/chevron_down.svg"); + public static final IdentifierRef ICON_EMOTE = IdentifierRef.ofSaturn("textures/gui/components/emote.svg"); public static final IdentifierRef ICON_CHECK = IdentifierRef.ofSaturn("textures/gui/components/check.svg"); public static final IdentifierRef LOGO = IdentifierRef.ofSaturn("textures/logo/logo.png"); @@ -61,6 +66,18 @@ public class Textures { public static final IdentifierRef MOD = IdentifierRef.ofSaturn("textures/gui/components/mod.png"); public static final IdentifierRef MOD_BG = IdentifierRef.ofSaturn("textures/gui/components/mod_bg.png"); + /** + * Whether a texture file is in the resources, for falling back when an + * optional one (like an emote's preview) is missing. + */ + public static boolean exists(IdentifierRef texture) { + try (InputStream in = Providers.saturn.getClient().getResource(texture)) { + return in != null; + } catch (IOException e) { + return false; + } + } + public static IdentifierRef getCloakPreview(String cloak) { return IdentifierRef.ofSaturn("textures/gui/cloak/" + (cloak.isEmpty() ? "none" : cloak) + ".png"); } diff --git a/src/main/java/org/saturnclient/ui/screens/CosmeticsMenu.java b/src/main/java/org/saturnclient/ui/screens/CosmeticsMenu.java index 8fa0556..5e95bef 100644 --- a/src/main/java/org/saturnclient/ui/screens/CosmeticsMenu.java +++ b/src/main/java/org/saturnclient/ui/screens/CosmeticsMenu.java @@ -19,6 +19,7 @@ import org.saturnclient.ui.Element; import org.saturnclient.ui.ElementContext; import org.saturnclient.ui.PanelScreen; import org.saturnclient.ui.RenderScope; +import org.saturnclient.ui.Utils; import org.saturnclient.ui.anim.SlideFade; import org.saturnclient.ui.components.CosmeticTile; import org.saturnclient.ui.components.Sidebar; @@ -193,18 +194,7 @@ public class CosmeticsMenu extends PanelScreen { private static String getName(String id) { String name = NAMES.get(id); - if (name != null) { - return name; - } - - StringBuilder builder = new StringBuilder(); - for (String word : id.split("_")) { - if (!builder.isEmpty()) { - builder.append(' '); - } - builder.append(Character.toUpperCase(word.charAt(0))).append(word.substring(1)); - } - return builder.toString(); + return name != null ? name : Utils.nameFromId(id); } /** diff --git a/src/main/java/org/saturnclient/ui/screens/EmoteWheel.java b/src/main/java/org/saturnclient/ui/screens/EmoteWheel.java index 2a870ec..771fd40 100644 --- a/src/main/java/org/saturnclient/ui/screens/EmoteWheel.java +++ b/src/main/java/org/saturnclient/ui/screens/EmoteWheel.java @@ -1,21 +1,43 @@ package org.saturnclient.ui.screens; -import org.saturnclient.cosmetics.Emotes; +import java.util.List; + import org.saturnclient.client.ServiceClient; import org.saturnclient.common.provider.Providers; +import org.saturnclient.common.ref.asset.IdentifierRef; import org.saturnclient.config.AnimationConfig; import org.saturnclient.config.Config; +import org.saturnclient.config.Theme; +import org.saturnclient.cosmetics.Emotes; +import org.saturnclient.ui.Element; +import org.saturnclient.ui.ElementContext; +import org.saturnclient.ui.RenderScope; import org.saturnclient.ui.SaturnScreen; -import org.saturnclient.ui.Utils; import org.saturnclient.ui.anim.Fade; import org.saturnclient.ui.anim.SlideY; +import org.saturnclient.ui.components.EmoteTile; import org.saturnclient.ui.elements.AnimationStagger; import org.saturnclient.ui.elements.ImageTexture; -import org.saturnclient.ui.elements.TextureButton; +import org.saturnclient.ui.elements.Label; +import org.saturnclient.ui.resources.Fonts; import org.saturnclient.ui.resources.Textures; +/** + * A 3x3 wheel of emotes to play, with the page controls in the middle. The + * emote wheel key opens and closes it (in the version's key handler). + */ public class EmoteWheel extends SaturnScreen { - int page = 1; + private static final int GAP = 10; + private static final int GRID = EmoteTile.SIZE * 3 + GAP * 2; + private static final int LOGO = 48; + + /** The grid's cells in the order emotes fill them, around the middle one */ + private static final int[][] SLOTS = { + { 0, 0 }, { 1, 0 }, { 2, 0 }, + { 0, 1 }, { 2, 1 }, + { 0, 2 }, { 1, 2 }, { 2, 2 } }; + + private int page = 0; public EmoteWheel() { super("Emote Wheel"); @@ -23,88 +45,131 @@ public class EmoteWheel extends SaturnScreen { @Override public void ui() { - int row = 0; - int col = 0; - - // ============================= - // Logo - // ============================= - - draw(new ImageTexture(Textures.LOGO_TEXT) - .dimensions(98, 10) - .center(width, height, 0, -105) - .animation(new Fade(AnimationConfig.logo.duration.value))); + List emotes = Emotes.availableEmotes; + int left = (width - GRID) / 2; + int top = (height - GRID) / 2 + LOGO / 2; draw(new ImageTexture(Config.getLogo()) - .dimensions(98, 98) - .center(width, height, 0, -149) - .animation(new SlideY(AnimationConfig.logo, -20))); + .dimensions(LOGO, LOGO) + .position((width - LOGO) / 2, top - 20 - LOGO) + .animation(new SlideY(AnimationConfig.logo, -12))); - // ============================= - // Navigation Buttons - // ============================= - - draw(new TextureButton(Textures.LEFT, () -> { - if (page > 1) { - page--; - elements.clear(); - ui(); - } - }).dimensions(30, 30) - .center(width, height, -50, 105) - .animation(new Fade(500))); - - draw(new TextureButton(Textures.RIGHT, () -> { - if ((page * 8) < Emotes.availableEmotes.size()) { - page++; - elements.clear(); - ui(); - } - }).dimensions(30, 30) - .center(width, height, 50, 105) - .animation(new Fade(500))); - - // ============================= - // Emote Grid (Staggered) - // ============================= - - AnimationStagger emoteStagger = new AnimationStagger(AnimationConfig.emoteWheel); - - while (row < 3) { - - int idx = (row * 3 + col) + ((page - 1) * 8); - - if (row == 1 && col == 1) { - col++; - } - - String emote = Utils.getOrNull(Emotes.availableEmotes, idx); - - emoteStagger.draw( - new TextureButton(Textures.getEmotePreview(emote), () -> { - Providers.saturn.playEmote(ServiceClient.uuid, emote); - ServiceClient.emote(emote); - provider.close(); - }) - .dimensions(70, 70) - .center(width, height, - -80 + (col * 80), - -35 + (row * 80)) - .animation(new SlideY(AnimationConfig.emoteWheel, 12))); - - if (col < 2) { - col++; - } else { - col = 0; - row++; - } + if (emotes.isEmpty()) { + String message = "No emotes available"; + int x = (width - (int) (Fonts.getWidth(message, Theme.getBodyFont()) * 0.7f)) / 2; + draw(new Label(() -> message, 0.7f, Theme::getBodyFont, Theme::getMutedFg).position(x, top + GRID / 2)); + return; } - draw(emoteStagger); + int pages = (emotes.size() + SLOTS.length - 1) / SLOTS.length; + page = Math.min(page, pages - 1); + + AnimationStagger grid = new AnimationStagger(AnimationConfig.emoteWheel); + + for (int slot = 0; slot < SLOTS.length; slot++) { + int index = page * SLOTS.length + slot; + if (index >= emotes.size()) { + break; + } + + String emote = emotes.get(index); + grid.draw(new EmoteTile(emote, () -> play(emote)) + .position(SLOTS[slot][0] * (EmoteTile.SIZE + GAP), SLOTS[slot][1] * (EmoteTile.SIZE + GAP)) + .animation(new SlideY(AnimationConfig.emoteWheel, 12))); + } + + draw(grid.position(left, top)); + + draw(new PageControl(page, pages, () -> turnPage(-1), () -> turnPage(1)) + .position(left + EmoteTile.SIZE + GAP, top + EmoteTile.SIZE + GAP) + .animation(new Fade(AnimationConfig.emoteWheel))); + } + + private void play(String emote) { + Providers.saturn.playEmote(ServiceClient.uuid, emote); + ServiceClient.emote(emote); + provider.close(); + } + + private void turnPage(int direction) { + page += direction; + init(); } @Override public boolean shouldPause() { return false; } + + /** + * The middle of the wheel: "Emotes", and the page with arrows to turn it + * when there's more than one. + */ + private static class PageControl extends Element { + private static final int ARROW = 16; + private static final int ARROW_AREA = 26; + + private final int page; + private final int pages; + private final Runnable onPrevious; + private final Runnable onNext; + + PageControl(int page, int pages, Runnable onPrevious, Runnable onNext) { + this.page = page; + this.pages = pages; + this.onPrevious = onPrevious; + this.onNext = onNext; + this.width = EmoteTile.SIZE; + this.height = EmoteTile.SIZE; + } + + @Override + public void render(RenderScope renderScope, ElementContext ctx) { + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, 1, + Theme.getPanelBg(), Theme.getBorder()); + + float titleScale = 0.54f; + drawCentered(renderScope, "EMOTES", titleScale, pages > 1 ? 24 : (height - 10) / 2, Theme.getMutedFg()); + + if (pages <= 1) { + return; + } + + drawCentered(renderScope, (page + 1) + " / " + pages, 0.66f, 48, Theme.FOREGROUND.value); + + int arrowY = 48 + ((int) (Fonts.getHeight() * 0.66f) - ARROW) / 2; + drawArrow(renderScope, ctx, Textures.ICON_CHEVRON_LEFT, 4, arrowY, canGoBack()); + drawArrow(renderScope, ctx, Textures.ICON_CHEVRON_RIGHT, width - 4 - ARROW, arrowY, canGoForward()); + } + + private void drawArrow(RenderScope renderScope, ElementContext ctx, IdentifierRef icon, int x, int y, + boolean enabled) { + boolean hovered = enabled && ctx.isHovering(x - 5, 0, ARROW_AREA, height); + int color = !enabled ? Theme.withAlpha(0.2f, Theme.FOREGROUND.value) + : hovered ? Theme.ACCENT.value : Theme.getMutedFg(); + renderScope.drawTexture(icon, x, y, 0, 0, ARROW, ARROW, color); + } + + private void drawCentered(RenderScope renderScope, String text, float scale, int y, int color) { + int x = (width - (int) (Fonts.getWidth(text, Theme.FONT.value) * scale)) / 2; + renderScope.drawText(scale, text, x, y, Theme.FONT.value, color); + } + + @Override + public void click(int mouseX, int mouseY) { + if (mouseX < ARROW_AREA && canGoBack()) { + onPrevious.run(); + } else if (mouseX > width - ARROW_AREA && canGoForward()) { + onNext.run(); + } + } + + private boolean canGoBack() { + return page > 0; + } + + private boolean canGoForward() { + return page < pages - 1; + } + } } diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/emote.svg b/src/main/resources/assets/saturnclient/textures/gui/components/emote.svg new file mode 100644 index 0000000..912c98c --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/components/emote.svg @@ -0,0 +1 @@ + From 2f4ea77e6f29d1feb2a33560cee21cdca92ae938 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 27 Sep 2026 19:01:42 +0200 Subject: [PATCH 2/5] Restyle buttons, the Shift menu and the title screen Button is now primary (accent fill) or secondary (a translucent outlined surface), and IconButton is a square secondary button with a Lucide icon, replacing the PNG TextureButtons. Neither is scaled with Element.scale any more, which multiplied click positions instead of dividing them. The Shift menu is the HUD editor, the mod menu (its button was labelled "Settings") and cosmetics. The title screen centers the logo over a compact stack of the game's menus, with the player, a dock of Saturn's screens and the version along the bottom. The player chip shows the player's face from their skin and whether they're connected to Saturn. Co-Authored-By: Claude Opus 5.5 --- .../common/provider/SaturnProvider.java | 6 + .../ui/components/AccountChip.java | 54 ++++++++ .../org/saturnclient/ui/components/Dock.java | 85 +++++++++++++ .../org/saturnclient/ui/elements/Button.java | 46 +++++-- .../saturnclient/ui/elements/IconButton.java | 40 ++++++ .../saturnclient/ui/screens/ShiftMenu.java | 46 ++++--- .../saturnclient/ui/screens/TitleMenu.java | 119 ++++++++++++------ 7 files changed, 323 insertions(+), 73 deletions(-) create mode 100644 src/main/java/org/saturnclient/ui/components/AccountChip.java create mode 100644 src/main/java/org/saturnclient/ui/components/Dock.java create mode 100644 src/main/java/org/saturnclient/ui/elements/IconButton.java diff --git a/src/main/java/org/saturnclient/common/provider/SaturnProvider.java b/src/main/java/org/saturnclient/common/provider/SaturnProvider.java index 5efbf2e..4d63eec 100644 --- a/src/main/java/org/saturnclient/common/provider/SaturnProvider.java +++ b/src/main/java/org/saturnclient/common/provider/SaturnProvider.java @@ -22,6 +22,12 @@ public interface SaturnProvider { /** The Saturn Client mod version, e.g. {@code 0.1.0-beta3+1.21.11}. */ public String getModVersion(); + /** + * The signed-in player's 64x64 skin texture, or the default skin until + * theirs has loaded. + */ + public IdentifierRef getPlayerSkin(); + /** Shows a warning toast. Safe to call from any thread. */ public void showWarning(String title, String message); } diff --git a/src/main/java/org/saturnclient/ui/components/AccountChip.java b/src/main/java/org/saturnclient/ui/components/AccountChip.java new file mode 100644 index 0000000..554f9c6 --- /dev/null +++ b/src/main/java/org/saturnclient/ui/components/AccountChip.java @@ -0,0 +1,54 @@ +package org.saturnclient.ui.components; + +import org.saturnclient.client.ServiceClient; +import org.saturnclient.common.provider.Providers; +import org.saturnclient.common.ref.asset.IdentifierRef; +import org.saturnclient.config.Theme; +import org.saturnclient.ui.Element; +import org.saturnclient.ui.ElementContext; +import org.saturnclient.ui.RenderScope; +import org.saturnclient.ui.elements.Field; +import org.saturnclient.ui.resources.Fonts; + +/** + * The signed-in player: their skin's face, their name, and a dot that's green + * while connected to Saturn. + */ +public class AccountChip extends Element { + public static final int HEIGHT = 40; + + private static final int HEAD = 28; + private static final int PADDING = 6; + private static final int DOT = 7; + private static final float NAME_SCALE = 0.7f; + private static final int CONNECTED = 0xFF7FD1A8; + + private final String name; + + public AccountChip() { + String username = Providers.saturn.getClient().getUsername(); + this.name = username != null ? username : "Player"; + this.height = HEIGHT; + this.width = PADDING + HEAD + 10 + (int) (Fonts.getWidth(name, Theme.FONT.value) * NAME_SCALE) + 10 + DOT + 12; + } + + @Override + public void render(RenderScope renderScope, ElementContext ctx) { + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, 1, Theme.getPanelBg(), + Theme.getBorder()); + + // The face, then the hat layer over it, from the 64x64 skin + IdentifierRef skin = Providers.saturn.getPlayerSkin(); + int headY = (height - HEAD) / 2; + renderScope.drawTexture(skin, PADDING, headY, 8, 8, HEAD, HEAD, 8, 8, 64, 64); + renderScope.drawTexture(skin, PADDING, headY, 40, 8, HEAD, HEAD, 8, 8, 64, 64); + + int nameX = PADDING + HEAD + 10; + renderScope.drawText(NAME_SCALE, name, nameX, Field.textY(height, NAME_SCALE), Theme.FONT.value, + Theme.FOREGROUND.value); + + int dotX = nameX + (int) (Fonts.getWidth(name, Theme.FONT.value) * NAME_SCALE) + 10; + renderScope.drawRoundedRectangle(dotX, (height - DOT) / 2, DOT, DOT, DOT / 2, + ServiceClient.isConnected() ? CONNECTED : Theme.withAlpha(0.3f, Theme.FOREGROUND.value)); + } +} diff --git a/src/main/java/org/saturnclient/ui/components/Dock.java b/src/main/java/org/saturnclient/ui/components/Dock.java new file mode 100644 index 0000000..7f6d881 --- /dev/null +++ b/src/main/java/org/saturnclient/ui/components/Dock.java @@ -0,0 +1,85 @@ +package org.saturnclient.ui.components; + +import java.util.List; + +import org.saturnclient.common.ref.asset.IdentifierRef; +import org.saturnclient.config.Theme; +import org.saturnclient.ui.Element; +import org.saturnclient.ui.ElementContext; +import org.saturnclient.ui.RenderScope; +import org.saturnclient.ui.elements.Field; +import org.saturnclient.ui.resources.Fonts; + +/** + * A glass bar of buttons, each an icon with its label. + */ +public class Dock extends Element { + public record Item(IdentifierRef icon, String label, Runnable onClick) { + } + + public static final int HEIGHT = 52; + + private static final int PADDING = 6; + private static final int ITEM_HEIGHT = HEIGHT - PADDING * 2; + private static final int ITEM_PADDING = 14; + private static final int ICON = 17; + private static final int ICON_GAP = 8; + private static final int GAP = 4; + private static final float TEXT_SCALE = 0.7f; + + private final List items; + + public Dock(List items) { + this.items = items; + this.height = HEIGHT; + this.width = getItemX(items.size()) - GAP + PADDING; + } + + @Override + public void render(RenderScope renderScope, ElementContext ctx) { + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value + 4, 1, Theme.getPanelBg(), + Theme.withAlpha(0.1f, Theme.FOREGROUND.value)); + + for (int i = 0; i < items.size(); i++) { + Item item = items.get(i); + int x = getItemX(i); + int itemWidth = getItemWidth(item); + boolean hovered = ctx.isHovering(x, PADDING, itemWidth, ITEM_HEIGHT); + + if (hovered) { + renderScope.drawRoundedRectangle(x, PADDING, itemWidth, ITEM_HEIGHT, Theme.WIDGET_RADIUS.value, + Theme.withAlpha(0.08f, Theme.FOREGROUND.value)); + } + + int color = hovered ? Theme.ACCENT.value : Theme.PRIMARY_FG.value; + renderScope.drawTexture(item.icon(), x + ITEM_PADDING, PADDING + (ITEM_HEIGHT - ICON) / 2, 0, 0, ICON, + ICON, color); + renderScope.drawText(TEXT_SCALE, item.label(), x + ITEM_PADDING + ICON + ICON_GAP, + PADDING + Field.textY(ITEM_HEIGHT, TEXT_SCALE), Theme.FONT.value, + hovered ? Theme.FOREGROUND.value : Theme.PRIMARY_FG.value); + } + } + + @Override + public void click(int mouseX, int mouseY) { + for (int i = 0; i < items.size(); i++) { + int x = getItemX(i); + if (mouseX >= x && mouseX <= x + getItemWidth(items.get(i))) { + items.get(i).onClick().run(); + return; + } + } + } + + private int getItemX(int index) { + int x = PADDING; + for (int i = 0; i < index; i++) { + x += getItemWidth(items.get(i)) + GAP; + } + return x; + } + + private static int getItemWidth(Item item) { + return ITEM_PADDING * 2 + ICON + ICON_GAP + (int) (Fonts.getWidth(item.label(), Theme.FONT.value) * TEXT_SCALE); + } +} diff --git a/src/main/java/org/saturnclient/ui/elements/Button.java b/src/main/java/org/saturnclient/ui/elements/Button.java index 3c0d5ed..714514e 100644 --- a/src/main/java/org/saturnclient/ui/elements/Button.java +++ b/src/main/java/org/saturnclient/ui/elements/Button.java @@ -6,24 +6,52 @@ import org.saturnclient.ui.ElementContext; import org.saturnclient.ui.RenderScope; import org.saturnclient.ui.resources.Fonts; +/** + * A text button: primary (filled with the accent color) for the main action, + * or secondary (a translucent, outlined surface) for the rest. + */ public class Button extends Element { - private String text; - private Runnable onClick; + public static final int HEIGHT = 40; - public Button(String text, Runnable onClick) { + private static final float TEXT_SCALE = 0.72f; + + private final String text; + private final boolean primary; + private final Runnable onClick; + + public Button(String text, boolean primary, Runnable onClick) { this.text = text; + this.primary = primary; this.onClick = onClick; - this.dimensions(Fonts.getWidth(text, Theme.FONT.value) + 50, 38); + this.width = (int) (Fonts.getWidth(text, Theme.FONT.value) * TEXT_SCALE) + 48; + this.height = HEIGHT; } @Override public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, - ctx.isHovering() ? Theme.ACCENT.value : Theme.PRIMARY.value); + boolean hovered = ctx.isHovering(); + drawSurface(renderScope, width, height, primary, hovered); - 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); + int textX = (width - (int) (Fonts.getWidth(text, Theme.FONT.value) * TEXT_SCALE)) / 2; + renderScope.drawText(TEXT_SCALE, text, textX, Field.textY(height, TEXT_SCALE), Theme.FONT.value, + primary ? Theme.ACCENT_FG.value : hovered ? Theme.FOREGROUND.value : Theme.PRIMARY_FG.value); + } + + /** + * The button's surface, shared with {@link IconButton}. + */ + static void drawSurface(RenderScope renderScope, int width, int height, boolean primary, boolean hovered) { + if (primary) { + // Lighten the accent on hover by laying white over it + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, Theme.ACCENT.value); + if (hovered) { + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, 0x26FFFFFF); + } + } else { + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, 1, + hovered ? Theme.withAlpha(0.9f, Theme.PRIMARY.value) : Theme.getPanelBg(), + Theme.withAlpha(hovered ? 0.25f : 0.1f, Theme.FOREGROUND.value)); + } } @Override diff --git a/src/main/java/org/saturnclient/ui/elements/IconButton.java b/src/main/java/org/saturnclient/ui/elements/IconButton.java new file mode 100644 index 0000000..764d297 --- /dev/null +++ b/src/main/java/org/saturnclient/ui/elements/IconButton.java @@ -0,0 +1,40 @@ +package org.saturnclient.ui.elements; + +import org.saturnclient.common.ref.asset.IdentifierRef; +import org.saturnclient.config.Theme; +import org.saturnclient.ui.Element; +import org.saturnclient.ui.ElementContext; +import org.saturnclient.ui.RenderScope; + +/** + * A square secondary {@link Button} showing an icon, which turns the accent + * color on hover. + */ +public class IconButton extends Element { + private static final float ICON_RATIO = 0.48f; + + private final IdentifierRef icon; + private final Runnable onClick; + + public IconButton(IdentifierRef icon, Runnable onClick) { + this.icon = icon; + this.onClick = onClick; + this.width = Button.HEIGHT; + this.height = Button.HEIGHT; + } + + @Override + public void render(RenderScope renderScope, ElementContext ctx) { + boolean hovered = ctx.isHovering(); + Button.drawSurface(renderScope, width, height, false, hovered); + + int size = (int) (Math.min(width, height) * ICON_RATIO); + renderScope.drawTexture(icon, (width - size) / 2, (height - size) / 2, 0, 0, size, size, + hovered ? Theme.ACCENT.value : Theme.PRIMARY_FG.value); + } + + @Override + public void click(int mouseX, int mouseY) { + onClick.run(); + } +} diff --git a/src/main/java/org/saturnclient/ui/screens/ShiftMenu.java b/src/main/java/org/saturnclient/ui/screens/ShiftMenu.java index 2915e68..6b1770b 100644 --- a/src/main/java/org/saturnclient/ui/screens/ShiftMenu.java +++ b/src/main/java/org/saturnclient/ui/screens/ShiftMenu.java @@ -8,18 +8,24 @@ import org.saturnclient.ui.anim.Fade; import org.saturnclient.ui.anim.SlideY; import org.saturnclient.ui.elements.AnimationStagger; import org.saturnclient.ui.elements.Button; +import org.saturnclient.ui.elements.IconButton; import org.saturnclient.ui.elements.ImageTexture; -import org.saturnclient.ui.elements.TextureButton; import org.saturnclient.ui.resources.Textures; +/** + * The in-game quick menu: the logo over the HUD editor, mod menu and + * cosmetics. + */ public class ShiftMenu extends SaturnScreen { + private static final int MODS_WIDTH = 120; + private static final int GAP = 6; + public ShiftMenu() { super("Shift Menu"); } @Override public void ui() { - // Logo animations (unchanged) draw(new ImageTexture(Textures.LOGO_TEXT) .dimensions(98, 10) .center(width, height, 0, -36) @@ -30,32 +36,24 @@ public class ShiftMenu extends SaturnScreen { .center(width, height, 0, -80) .animation(new SlideY(AnimationConfig.logo, -20))); - // Spacing and sizes - int btnWidth = 120; - int btnHeight = 40; - int spacing = 4; - - // Create stagger - AnimationStagger stagger = new AnimationStagger(AnimationConfig.shiftMenu.stagger.value); + int x = 0; - stagger.draw(new TextureButton(Textures.HUD_ICON, () -> { - Providers.saturn.getClient().setScreen(new HudEditor()); - }).dimensions(btnHeight, btnHeight).position(0, 0) - .animation(new Fade(AnimationConfig.shiftMenu))); + stagger.draw(new IconButton(Textures.ICON_HUD_EDITOR, + () -> Providers.saturn.getClient().setScreen(new HudEditor())) + .position(x, 0).animation(new Fade(AnimationConfig.shiftMenu))); + x += Button.HEIGHT + GAP; - stagger.draw(new Button("Settings", () -> { - Providers.saturn.getClient().setScreen(new ModMenu()); - }).dimensions(btnWidth, btnHeight).position(btnHeight + spacing, 0) - .animation(new Fade(AnimationConfig.shiftMenu))); + stagger.draw(new Button("Mods", true, () -> Providers.saturn.getClient().setScreen(new ModMenu())) + .dimensions(MODS_WIDTH, Button.HEIGHT) + .position(x, 0).animation(new Fade(AnimationConfig.shiftMenu))); + x += MODS_WIDTH + GAP; - stagger.draw(new TextureButton(Textures.COSMETICS, () -> { - Providers.saturn.getClient().setScreen(new CosmeticsMenu()); - }).dimensions(btnHeight, btnHeight).position(btnWidth + btnHeight + (spacing * 2), 0) - .animation(new Fade(AnimationConfig.shiftMenu))); + stagger.draw(new IconButton(Textures.ICON_COSMETICS, + () -> Providers.saturn.getClient().setScreen(new CosmeticsMenu())) + .position(x, 0).animation(new Fade(AnimationConfig.shiftMenu))); + x += Button.HEIGHT; - // Draw the stagger at the absolute center of the screen - draw(stagger.dimensions(btnWidth + (btnHeight * 2) + (spacing * 2), btnHeight).center(width, height, 0, - 0)); + draw(stagger.position((width - x) / 2, (height - Button.HEIGHT) / 2)); } } diff --git a/src/main/java/org/saturnclient/ui/screens/TitleMenu.java b/src/main/java/org/saturnclient/ui/screens/TitleMenu.java index d134334..781a007 100644 --- a/src/main/java/org/saturnclient/ui/screens/TitleMenu.java +++ b/src/main/java/org/saturnclient/ui/screens/TitleMenu.java @@ -1,21 +1,40 @@ package org.saturnclient.ui.screens; +import java.util.List; + import org.saturnclient.common.provider.Providers; import org.saturnclient.common.ref.game.MinecraftClientRef.MinecraftScreen; import org.saturnclient.config.AnimationConfig; import org.saturnclient.config.Config; +import org.saturnclient.config.Theme; +import org.saturnclient.ui.Element; import org.saturnclient.ui.SaturnScreen; import org.saturnclient.ui.anim.Fade; import org.saturnclient.ui.anim.SlideFade; import org.saturnclient.ui.anim.SlideY; +import org.saturnclient.ui.components.AccountChip; +import org.saturnclient.ui.components.Dock; import org.saturnclient.ui.elements.AnimationStagger; import org.saturnclient.ui.elements.Button; import org.saturnclient.ui.elements.ImageTexture; -import org.saturnclient.ui.elements.TextureButton; +import org.saturnclient.ui.elements.Label; import org.saturnclient.ui.resources.Fonts; import org.saturnclient.ui.resources.Textures; +/** + * Saturn's title screen: the logo over the game's menus in the middle, and + * along the bottom the player, a dock of Saturn's screens and the version. + */ public class TitleMenu extends SaturnScreen { + private static final int LOGO = 88; + private static final int WORDMARK_WIDTH = 200; + private static final int WORDMARK_HEIGHT = 20; + private static final int COLUMN_WIDTH = 280; + private static final int BUTTON_HEIGHT = 36; + private static final int GAP = 8; + private static final int EDGE = 28; + private static final float VERSION_SCALE = 0.62f; + public TitleMenu() { super("Title Menu"); } @@ -24,53 +43,73 @@ public class TitleMenu extends SaturnScreen { public void ui() { blurBackground = false; - draw(new ImageTexture(Textures.LOGO_TEXT).dimensions(98, 10).center(width, height, 0, -40) - .animation(new Fade(AnimationConfig.logo.duration.value))); - draw(new ImageTexture(Config.getLogo()).dimensions(98, 98).center(width, height, 0, -84) + // Logo and menus, centered together a little above the middle + int menusHeight = BUTTON_HEIGHT * 3 + GAP * 2; + int blockHeight = LOGO + 16 + WORDMARK_HEIGHT + 36 + menusHeight; + int top = (height - blockHeight) / 2 - 20; + + draw(new ImageTexture(Config.getLogo()) + .dimensions(LOGO, LOGO) + .position((width - LOGO) / 2, top) .animation(new SlideY(AnimationConfig.logo, -20))); + draw(new ImageTexture(Textures.LOGO_TEXT_BIG) + .dimensions(WORDMARK_WIDTH, WORDMARK_HEIGHT) + .position((width - WORDMARK_WIDTH) / 2, top + LOGO + 16) + .animation(new Fade(AnimationConfig.logo.duration.value))); - AnimationStagger mainButtonStagger = new AnimationStagger(AnimationConfig.mainMenu); + int rowHeight = BUTTON_HEIGHT + GAP; + int halfWidth = (COLUMN_WIDTH - GAP) / 2; + AnimationStagger menus = new AnimationStagger(AnimationConfig.mainMenu); - mainButtonStagger.draw(new Button("SINGLEPLAYER", () -> { - Providers.saturn.getClient().setScreen(MinecraftScreen.SelectWorld); - }).scale(0.69f).dimensions(420, 52).position(0, 0) - .animation(new SlideFade(AnimationConfig.mainMenu, -10))); + addMenuButton(menus, new Button("Singleplayer", true, + () -> Providers.saturn.getClient().setScreen(MinecraftScreen.SelectWorld)) + .dimensions(COLUMN_WIDTH, BUTTON_HEIGHT).position(0, 0)); + addMenuButton(menus, new Button("Multiplayer", false, + () -> Providers.saturn.getClient().setScreen(MinecraftScreen.Multiplayer)) + .dimensions(COLUMN_WIDTH, BUTTON_HEIGHT).position(0, rowHeight)); + addMenuButton(menus, new Button("Options", false, + () -> Providers.saturn.getClient().setScreen(MinecraftScreen.Options)) + .dimensions(halfWidth, BUTTON_HEIGHT).position(0, rowHeight * 2)); + addMenuButton(menus, new Button("Quit", false, + () -> Providers.saturn.getClient().scheduleStop()) + .dimensions(halfWidth, BUTTON_HEIGHT).position(COLUMN_WIDTH - halfWidth, rowHeight * 2)); - mainButtonStagger.draw(new Button("MULTIPLAYER", () -> { - Providers.saturn.getClient().setScreen(MinecraftScreen.Multiplayer); - }).scale(0.69f).dimensions(420, 52).position(0, 40) - .animation(new SlideFade(AnimationConfig.mainMenu, -10))); + draw(menus.position((width - COLUMN_WIDTH) / 2, top + LOGO + 16 + WORDMARK_HEIGHT + 36)); - mainButtonStagger.draw(new Button("OPTIONS", () -> { - Providers.saturn.getClient().setScreen(MinecraftScreen.Options); - }).scale(0.69f).dimensions(206, 52).position(0, 80) - .animation(new SlideFade(AnimationConfig.mainMenu, -10))); + // Along the bottom: the player, Saturn's screens, the version + draw(new AccountChip() + .position(EDGE, height - EDGE - AccountChip.HEIGHT) + .animation(new Fade(AnimationConfig.mainMenu))); - mainButtonStagger.draw(new Button("QUIT", () -> { - Providers.saturn.getClient().scheduleStop(); - }).scale(0.69f).dimensions(206, 52).position(146, 80) - .animation(new SlideFade(AnimationConfig.mainMenu, -10))); + Dock dock = new Dock(List.of( + new Dock.Item(Textures.ICON_MODS, "Mods", + () -> Providers.saturn.getClient().setScreen(new ModMenu())), + new Dock.Item(Textures.ICON_COSMETICS, "Cosmetics", + () -> Providers.saturn.getClient().setScreen(new CosmeticsMenu())), + new Dock.Item(Textures.ICON_HUD_EDITOR, "HUD editor", + () -> Providers.saturn.getClient().setScreen(new HudEditor())))); + draw(dock.position((width - dock.width) / 2, height - EDGE - Dock.HEIGHT) + .animation(new SlideFade(AnimationConfig.mainMenu, 12))); - draw(mainButtonStagger.dimensions(289, 143).center(width, height, 0, 50)); + String version = getVersionText(); + int versionWidth = (int) (Fonts.getWidth(version, Theme.getBodyFont()) * VERSION_SCALE); + int versionHeight = (int) (Fonts.getHeight() * VERSION_SCALE); + draw(new Label(() -> version, VERSION_SCALE, Theme::getBodyFont, Theme::getMutedFg) + .position(width - EDGE - versionWidth, height - EDGE - (AccountChip.HEIGHT + versionHeight) / 2) + .animation(new Fade(AnimationConfig.mainMenu))); + } - int s = Fonts.getHeight() + 20; + /** + * "Saturn Client 0.1.0 · Minecraft 1.21.11", from the mod version + * "0.1.0+1.21.11". + */ + private static String getVersionText() { + String[] version = Providers.saturn.getModVersion().split("\\+", 2); + String text = "Saturn Client " + version[0]; + return version.length > 1 ? text + " · Minecraft " + version[1] : text; + } - AnimationStagger saturnStagger = new AnimationStagger(AnimationConfig.mainMenu.stagger.value); - - saturnStagger.draw(new TextureButton(Textures.HUD_ICON, () -> { - Providers.saturn.getClient().setScreen(new HudEditor()); - }).dimensions(s, s).position(0, 0).animation(new SlideFade(AnimationConfig.mainMenu, s + 8))); - - saturnStagger.draw(new TextureButton(Textures.SETTINGS, () -> { - Providers.saturn.getClient().setScreen(new ModMenu()); - }).dimensions(s, s).position(s + 2, 0) - .animation(new SlideFade(AnimationConfig.mainMenu, s + 8))); - - saturnStagger.draw(new TextureButton(Textures.CLOAK, () -> { - Providers.saturn.getClient().setScreen(new CosmeticsMenu()); - }).dimensions(s, s).position((s + 2) * 2, 0) - .animation(new SlideFade(AnimationConfig.mainMenu, s + 8))); - - draw(saturnStagger.dimensions(((s + 2) * 2) + s, s).centerHorizontal(width, height, 0, 8)); + private static void addMenuButton(AnimationStagger stagger, Element button) { + stagger.draw(button.animation(new SlideFade(AnimationConfig.mainMenu, -10))); } } From f0971ff1282f942fd84eff2399dff0f27c7ea012 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 27 Sep 2026 19:06:01 +0200 Subject: [PATCH 3/5] Use one button style and an icon-only dock Buttons no longer have a primary style: every button is the translucent outlined surface that brightens on hover, and only an icon button's icon takes the accent color. The title screen's dock shows just its icons. Co-Authored-By: Claude Opus 5.5 --- .../org/saturnclient/ui/components/Dock.java | 44 ++++++------------- .../org/saturnclient/ui/elements/Button.java | 27 ++++-------- .../saturnclient/ui/elements/IconButton.java | 6 +-- .../saturnclient/ui/screens/ShiftMenu.java | 2 +- .../saturnclient/ui/screens/TitleMenu.java | 15 +++---- 5 files changed, 32 insertions(+), 62 deletions(-) diff --git a/src/main/java/org/saturnclient/ui/components/Dock.java b/src/main/java/org/saturnclient/ui/components/Dock.java index 7f6d881..e5d174e 100644 --- a/src/main/java/org/saturnclient/ui/components/Dock.java +++ b/src/main/java/org/saturnclient/ui/components/Dock.java @@ -7,32 +7,27 @@ import org.saturnclient.config.Theme; import org.saturnclient.ui.Element; import org.saturnclient.ui.ElementContext; import org.saturnclient.ui.RenderScope; -import org.saturnclient.ui.elements.Field; -import org.saturnclient.ui.resources.Fonts; /** - * A glass bar of buttons, each an icon with its label. + * A glass bar of square icon buttons. */ public class Dock extends Element { - public record Item(IdentifierRef icon, String label, Runnable onClick) { + public record Item(IdentifierRef icon, Runnable onClick) { } public static final int HEIGHT = 52; private static final int PADDING = 6; - private static final int ITEM_HEIGHT = HEIGHT - PADDING * 2; - private static final int ITEM_PADDING = 14; - private static final int ICON = 17; - private static final int ICON_GAP = 8; + private static final int ITEM = HEIGHT - PADDING * 2; + private static final int ICON = 18; private static final int GAP = 4; - private static final float TEXT_SCALE = 0.7f; private final List items; public Dock(List items) { this.items = items; this.height = HEIGHT; - this.width = getItemX(items.size()) - GAP + PADDING; + this.width = PADDING * 2 + items.size() * ITEM + (items.size() - 1) * GAP; } @Override @@ -41,22 +36,17 @@ public class Dock extends Element { Theme.withAlpha(0.1f, Theme.FOREGROUND.value)); for (int i = 0; i < items.size(); i++) { - Item item = items.get(i); int x = getItemX(i); - int itemWidth = getItemWidth(item); - boolean hovered = ctx.isHovering(x, PADDING, itemWidth, ITEM_HEIGHT); + boolean hovered = ctx.isHovering(x, PADDING, ITEM, ITEM); if (hovered) { - renderScope.drawRoundedRectangle(x, PADDING, itemWidth, ITEM_HEIGHT, Theme.WIDGET_RADIUS.value, + renderScope.drawRoundedRectangle(x, PADDING, ITEM, ITEM, Theme.WIDGET_RADIUS.value, Theme.withAlpha(0.08f, Theme.FOREGROUND.value)); } - int color = hovered ? Theme.ACCENT.value : Theme.PRIMARY_FG.value; - renderScope.drawTexture(item.icon(), x + ITEM_PADDING, PADDING + (ITEM_HEIGHT - ICON) / 2, 0, 0, ICON, - ICON, color); - renderScope.drawText(TEXT_SCALE, item.label(), x + ITEM_PADDING + ICON + ICON_GAP, - PADDING + Field.textY(ITEM_HEIGHT, TEXT_SCALE), Theme.FONT.value, - hovered ? Theme.FOREGROUND.value : Theme.PRIMARY_FG.value); + int offset = (ITEM - ICON) / 2; + renderScope.drawTexture(items.get(i).icon(), x + offset, PADDING + offset, 0, 0, ICON, ICON, + hovered ? Theme.ACCENT.value : Theme.PRIMARY_FG.value); } } @@ -64,22 +54,14 @@ public class Dock extends Element { public void click(int mouseX, int mouseY) { for (int i = 0; i < items.size(); i++) { int x = getItemX(i); - if (mouseX >= x && mouseX <= x + getItemWidth(items.get(i))) { + if (mouseX >= x && mouseX <= x + ITEM) { items.get(i).onClick().run(); return; } } } - private int getItemX(int index) { - int x = PADDING; - for (int i = 0; i < index; i++) { - x += getItemWidth(items.get(i)) + GAP; - } - return x; - } - - private static int getItemWidth(Item item) { - return ITEM_PADDING * 2 + ICON + ICON_GAP + (int) (Fonts.getWidth(item.label(), Theme.FONT.value) * TEXT_SCALE); + private static int getItemX(int index) { + return PADDING + index * (ITEM + GAP); } } diff --git a/src/main/java/org/saturnclient/ui/elements/Button.java b/src/main/java/org/saturnclient/ui/elements/Button.java index 714514e..e884242 100644 --- a/src/main/java/org/saturnclient/ui/elements/Button.java +++ b/src/main/java/org/saturnclient/ui/elements/Button.java @@ -7,8 +7,7 @@ import org.saturnclient.ui.RenderScope; import org.saturnclient.ui.resources.Fonts; /** - * A text button: primary (filled with the accent color) for the main action, - * or secondary (a translucent, outlined surface) for the rest. + * A text button: a translucent, outlined surface that brightens on hover. */ public class Button extends Element { public static final int HEIGHT = 40; @@ -16,12 +15,10 @@ public class Button extends Element { private static final float TEXT_SCALE = 0.72f; private final String text; - private final boolean primary; private final Runnable onClick; - public Button(String text, boolean primary, Runnable onClick) { + public Button(String text, Runnable onClick) { this.text = text; - this.primary = primary; this.onClick = onClick; this.width = (int) (Fonts.getWidth(text, Theme.FONT.value) * TEXT_SCALE) + 48; this.height = HEIGHT; @@ -30,28 +27,20 @@ public class Button extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { boolean hovered = ctx.isHovering(); - drawSurface(renderScope, width, height, primary, hovered); + drawSurface(renderScope, width, height, hovered); int textX = (width - (int) (Fonts.getWidth(text, Theme.FONT.value) * TEXT_SCALE)) / 2; renderScope.drawText(TEXT_SCALE, text, textX, Field.textY(height, TEXT_SCALE), Theme.FONT.value, - primary ? Theme.ACCENT_FG.value : hovered ? Theme.FOREGROUND.value : Theme.PRIMARY_FG.value); + hovered ? Theme.FOREGROUND.value : Theme.PRIMARY_FG.value); } /** * The button's surface, shared with {@link IconButton}. */ - static void drawSurface(RenderScope renderScope, int width, int height, boolean primary, boolean hovered) { - if (primary) { - // Lighten the accent on hover by laying white over it - renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, Theme.ACCENT.value); - if (hovered) { - renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, 0x26FFFFFF); - } - } else { - renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, 1, - hovered ? Theme.withAlpha(0.9f, Theme.PRIMARY.value) : Theme.getPanelBg(), - Theme.withAlpha(hovered ? 0.25f : 0.1f, Theme.FOREGROUND.value)); - } + static void drawSurface(RenderScope renderScope, int width, int height, boolean hovered) { + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, 1, + hovered ? Theme.withAlpha(0.9f, Theme.PRIMARY.value) : Theme.getPanelBg(), + Theme.withAlpha(hovered ? 0.25f : 0.1f, Theme.FOREGROUND.value)); } @Override diff --git a/src/main/java/org/saturnclient/ui/elements/IconButton.java b/src/main/java/org/saturnclient/ui/elements/IconButton.java index 764d297..8264913 100644 --- a/src/main/java/org/saturnclient/ui/elements/IconButton.java +++ b/src/main/java/org/saturnclient/ui/elements/IconButton.java @@ -7,8 +7,8 @@ import org.saturnclient.ui.ElementContext; import org.saturnclient.ui.RenderScope; /** - * A square secondary {@link Button} showing an icon, which turns the accent - * color on hover. + * A square {@link Button} showing an icon, which turns the accent color on + * hover. */ public class IconButton extends Element { private static final float ICON_RATIO = 0.48f; @@ -26,7 +26,7 @@ public class IconButton extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { boolean hovered = ctx.isHovering(); - Button.drawSurface(renderScope, width, height, false, hovered); + Button.drawSurface(renderScope, width, height, hovered); int size = (int) (Math.min(width, height) * ICON_RATIO); renderScope.drawTexture(icon, (width - size) / 2, (height - size) / 2, 0, 0, size, size, diff --git a/src/main/java/org/saturnclient/ui/screens/ShiftMenu.java b/src/main/java/org/saturnclient/ui/screens/ShiftMenu.java index 6b1770b..3f2d512 100644 --- a/src/main/java/org/saturnclient/ui/screens/ShiftMenu.java +++ b/src/main/java/org/saturnclient/ui/screens/ShiftMenu.java @@ -44,7 +44,7 @@ public class ShiftMenu extends SaturnScreen { .position(x, 0).animation(new Fade(AnimationConfig.shiftMenu))); x += Button.HEIGHT + GAP; - stagger.draw(new Button("Mods", true, () -> Providers.saturn.getClient().setScreen(new ModMenu())) + stagger.draw(new Button("Mods", () -> Providers.saturn.getClient().setScreen(new ModMenu())) .dimensions(MODS_WIDTH, Button.HEIGHT) .position(x, 0).animation(new Fade(AnimationConfig.shiftMenu))); x += MODS_WIDTH + GAP; diff --git a/src/main/java/org/saturnclient/ui/screens/TitleMenu.java b/src/main/java/org/saturnclient/ui/screens/TitleMenu.java index 781a007..3821d69 100644 --- a/src/main/java/org/saturnclient/ui/screens/TitleMenu.java +++ b/src/main/java/org/saturnclient/ui/screens/TitleMenu.java @@ -61,16 +61,16 @@ public class TitleMenu extends SaturnScreen { int halfWidth = (COLUMN_WIDTH - GAP) / 2; AnimationStagger menus = new AnimationStagger(AnimationConfig.mainMenu); - addMenuButton(menus, new Button("Singleplayer", true, + addMenuButton(menus, new Button("Singleplayer", () -> Providers.saturn.getClient().setScreen(MinecraftScreen.SelectWorld)) .dimensions(COLUMN_WIDTH, BUTTON_HEIGHT).position(0, 0)); - addMenuButton(menus, new Button("Multiplayer", false, + addMenuButton(menus, new Button("Multiplayer", () -> Providers.saturn.getClient().setScreen(MinecraftScreen.Multiplayer)) .dimensions(COLUMN_WIDTH, BUTTON_HEIGHT).position(0, rowHeight)); - addMenuButton(menus, new Button("Options", false, + addMenuButton(menus, new Button("Options", () -> Providers.saturn.getClient().setScreen(MinecraftScreen.Options)) .dimensions(halfWidth, BUTTON_HEIGHT).position(0, rowHeight * 2)); - addMenuButton(menus, new Button("Quit", false, + addMenuButton(menus, new Button("Quit", () -> Providers.saturn.getClient().scheduleStop()) .dimensions(halfWidth, BUTTON_HEIGHT).position(COLUMN_WIDTH - halfWidth, rowHeight * 2)); @@ -82,11 +82,10 @@ public class TitleMenu extends SaturnScreen { .animation(new Fade(AnimationConfig.mainMenu))); Dock dock = new Dock(List.of( - new Dock.Item(Textures.ICON_MODS, "Mods", - () -> Providers.saturn.getClient().setScreen(new ModMenu())), - new Dock.Item(Textures.ICON_COSMETICS, "Cosmetics", + new Dock.Item(Textures.ICON_MODS, () -> Providers.saturn.getClient().setScreen(new ModMenu())), + new Dock.Item(Textures.ICON_COSMETICS, () -> Providers.saturn.getClient().setScreen(new CosmeticsMenu())), - new Dock.Item(Textures.ICON_HUD_EDITOR, "HUD editor", + new Dock.Item(Textures.ICON_HUD_EDITOR, () -> Providers.saturn.getClient().setScreen(new HudEditor())))); draw(dock.position((width - dock.width) / 2, height - EDGE - Dock.HEIGHT) .animation(new SlideFade(AnimationConfig.mainMenu, 12))); From 25d288da92c4915b2cfda99d03aba664abad6aef Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 27 Sep 2026 19:09:06 +0200 Subject: [PATCH 4/5] Rework the HUD editor HUDs are drawn as they are in game, background included, through the new HudModPreview.draw, and the world behind the editor isn't blurred. Each has an outline that turns the accent color with the mod's name while hovered or dragged, and a visible resize handle that's easier to grab. Scale stays within its range and HUDs stay on screen, and a hint says how to use the editor. Co-Authored-By: Claude Opus 5.5 --- .../ui/components/HudModPreview.java | 12 +- .../saturnclient/ui/screens/HudEditor.java | 186 ++++++++++++------ 2 files changed, 141 insertions(+), 57 deletions(-) diff --git a/src/main/java/org/saturnclient/ui/components/HudModPreview.java b/src/main/java/org/saturnclient/ui/components/HudModPreview.java index a4e803a..ba1754d 100644 --- a/src/main/java/org/saturnclient/ui/components/HudModPreview.java +++ b/src/main/java/org/saturnclient/ui/components/HudModPreview.java @@ -15,13 +15,21 @@ public class HudModPreview extends Element { @Override public void render(RenderScope scope, ElementContext ctx) { - ModLayout layout = feature.getDimensions(); + draw(scope, feature); + } + + /** + * Draws a HUD mod with sample content and the background it has in game, + * at the origin and its layout's unscaled size. + */ + public static void draw(RenderScope scope, HudMod mod) { + ModLayout layout = mod.getDimensions(); if (layout.renderBackground) { scope.drawRoundedRectangle(0, 0, layout.width, layout.height, layout.radius.value, layout.bgColor.value); } - feature.renderDummy(scope); + mod.renderDummy(scope); } } diff --git a/src/main/java/org/saturnclient/ui/screens/HudEditor.java b/src/main/java/org/saturnclient/ui/screens/HudEditor.java index 7047b26..8f10f80 100644 --- a/src/main/java/org/saturnclient/ui/screens/HudEditor.java +++ b/src/main/java/org/saturnclient/ui/screens/HudEditor.java @@ -1,59 +1,71 @@ package org.saturnclient.ui.screens; -import org.saturnclient.common.ref.render.MatrixStackRef; +import java.util.ArrayList; +import java.util.List; + import org.saturnclient.config.ConfigManager; +import org.saturnclient.config.Theme; import org.saturnclient.mod.HudMod; import org.saturnclient.mod.Mod; import org.saturnclient.mod.ModLayout; import org.saturnclient.mod.ModManager; import org.saturnclient.ui.RenderScope; import org.saturnclient.ui.SaturnScreen; +import org.saturnclient.ui.components.HudModPreview; +import org.saturnclient.ui.resources.Fonts; -import java.util.ArrayList; -import java.util.List; - +/** + * Moves and resizes the enabled HUD mods, drawn as they are in game. Drag one + * to move it, or drag its corner handle to resize it. + * + * Unlike other Saturn screens this works in GUI pixels, like the HUD itself: + * it draws without the half scale and takes the mouse unscaled. + */ public class HudEditor extends SaturnScreen { + private static final String HINT = "Drag to move · Drag the corner to resize · Esc when done"; + + /** Size of the resize handle, and how far around it still grabs it */ + private static final int HANDLE = 4; + private static final int HANDLE_REACH = 4; + private static final float LABEL_SCALE = 0.4f; + private static final float HINT_SCALE = 0.45f; + private final List hudMods = new ArrayList<>(); + private HudMod draggingMod = null; private boolean resizing = false; private int offsetX, offsetY; - private static final int RESIZE_MARGIN = 3; public HudEditor() { super("HUD Editor"); for (Mod m : ModManager.ENABLED_MODS) { - if (m.isEnabled() && m instanceof HudMod) { - hudMods.add((HudMod) m); + if (m.isEnabled() && m instanceof HudMod hudMod) { + hudMods.add(hudMod); } } } + @Override + public void ui() { + // Placing HUDs needs a clear view of the game. + blurBackground = false; + } + @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { if (button == 0) { - for (int m = hudMods.size() - 1; m >= 0; m--) { - HudMod mod = hudMods.get(m); + HudMod mod = getModAt(mouseX, mouseY); + + if (mod != null) { ModLayout dim = mod.getDimensions(); - - // Check if clicking the corner for resizing - if (isCorner(mouseX, mouseY, dim)) { - draggingMod = mod; - resizing = true; - offsetX = (int) (mouseX - (dim.x.value + dim.width * dim.scale.value)); - offsetY = (int) (mouseY - (dim.y.value + dim.height * dim.scale.value)); - return true; - } - - // Check if clicking inside the mod - if (isInside(mouseX, mouseY, dim)) { - draggingMod = mod; - resizing = false; - offsetX = (int) (mouseX - dim.x.value); - offsetY = (int) (mouseY - dim.y.value); - return true; - } + draggingMod = mod; + resizing = isOnHandle(mouseX, mouseY, dim); + offsetX = (int) (mouseX - (resizing ? right(dim) : dim.x.value)); + offsetY = (int) (mouseY - (resizing ? bottom(dim) : dim.y.value)); + return true; } } + return super.mouseClicked(mouseX, mouseY, button); } @@ -72,57 +84,121 @@ public class HudEditor extends SaturnScreen { ModLayout dim = draggingMod.getDimensions(); if (resizing) { - // Scale based on cursor movement - float newScale = Math.max(0.5f, ((float) (mouseX - dim.x.value) / dim.width)); - dim.scale.value = newScale; + // The handle follows the cursor: the scale is the new width over the unscaled width. + float scale = (float) (mouseX - offsetX - dim.x.value) / dim.width; + float min = dim.scale.min != null ? dim.scale.min : 0.5f; + float max = dim.scale.max != null ? dim.scale.max : 4f; + dim.scale.value = Math.max(min, Math.min(max, scale)); } else { - // Move the mod dim.x.value = (int) mouseX - offsetX; dim.y.value = (int) mouseY - offsetY; } + + keepOnScreen(dim); } + return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); } - @Override - public void ui() { - } - @Override public void render(RenderScope renderScope, int mouseX, int mouseY, float delta, long elapsed) { + // The screen hands over the mouse in Saturn units, twice GUI pixels. + int guiMouseX = mouseX / 2; + int guiMouseY = mouseY / 2; + HudMod hovered = draggingMod != null ? draggingMod : getModAt(guiMouseX, guiMouseY); + for (HudMod mod : hudMods) { ModLayout dim = mod.getDimensions(); - MatrixStackRef matrices = renderScope.getMatrixStack(); - matrices.push(); + boolean active = mod == hovered; - matrices.translate(dim.x.value, dim.y.value); - matrices.scale(dim.scale.value, dim.scale.value); + renderScope.getMatrixStack().push(); + renderScope.getMatrixStack().translate(dim.x.value, dim.y.value); + renderScope.getMatrixStack().scale(dim.scale.value, dim.scale.value); + HudModPreview.draw(renderScope, mod); + renderScope.getMatrixStack().pop(); - // Render the mod - mod.renderDummy(renderScope); + drawFrame(renderScope, mod, dim, active); + } - matrices.pop(); + drawHint(renderScope); + } - // Draw border around mod - int borderX = dim.x.value; - int borderY = dim.y.value; - int borderW = (int) (dim.width * dim.scale.value); - int borderH = (int) (dim.height * dim.scale.value); + /** + * The outline around a HUD, its resize handle, and its name while it's + * hovered or dragged. + */ + private void drawFrame(RenderScope renderScope, HudMod mod, ModLayout dim, boolean active) { + int x = dim.x.value; + int y = dim.y.value; + int w = right(dim) - x; + int h = bottom(dim) - y; + int color = active ? Theme.ACCENT.value : Theme.withAlpha(0.45f, Theme.FOREGROUND.value); - renderScope.drawBorder(borderX, borderY, borderW, borderH, 0xFFFFFFFF); // White border + if (active) { + renderScope.drawRectangle(x, y, w, h, Theme.withAlpha(0.08f, Theme.ACCENT.value)); + } + + renderScope.drawBorder(x - 1, y - 1, w + 2, h + 2, color); + renderScope.drawRectangle(x + w - HANDLE / 2, y + h - HANDLE / 2, HANDLE, HANDLE, color); + + if (active && mod instanceof Mod named) { + int labelHeight = (int) (Fonts.getHeight() * LABEL_SCALE); + int labelY = y - labelHeight - 4 < 0 ? y + h + 4 : y - labelHeight - 4; + renderScope.drawText(LABEL_SCALE, named.getName(), x, labelY, Theme.FONT.value, Theme.FOREGROUND.value); } } - private boolean isInside(double mouseX, double mouseY, ModLayout dim) { - return mouseX >= dim.x.value && mouseX <= dim.x.value + (dim.width * dim.scale.value) && - mouseY >= dim.y.value && mouseY <= dim.y.value + (dim.height * dim.scale.value); + private void drawHint(RenderScope renderScope) { + int guiWidth = width / 2; + int textWidth = (int) (Fonts.getWidth(HINT, Theme.getBodyFont()) * HINT_SCALE); + int textHeight = (int) (Fonts.getHeight() * HINT_SCALE); + int pillWidth = textWidth + 20; + int pillHeight = textHeight + 10; + int x = (guiWidth - pillWidth) / 2; + int y = 8; + + renderScope.drawRoundedRectangle(x, y, pillWidth, pillHeight, pillHeight / 2, 1, Theme.getPanelBg(), + Theme.getBorder()); + renderScope.drawText(HINT_SCALE, HINT, x + 10, y + 5, Theme.getBodyFont(), Theme.PRIMARY_FG.value); } - private boolean isCorner(double mouseX, double mouseY, ModLayout dim) { - float rightX = dim.x.value + dim.width * dim.scale.value; - float bottomY = dim.y.value + dim.height * dim.scale.value; + /** + * The HUD under the mouse, preferring the one drawn on top, or null. + */ + private HudMod getModAt(double mouseX, double mouseY) { + for (int i = hudMods.size() - 1; i >= 0; i--) { + ModLayout dim = hudMods.get(i).getDimensions(); + if (isOnHandle(mouseX, mouseY, dim) || isInside(mouseX, mouseY, dim)) { + return hudMods.get(i); + } + } + return null; + } - return Math.abs(mouseX - rightX) < RESIZE_MARGIN && Math.abs(mouseY - bottomY) < RESIZE_MARGIN; + private void keepOnScreen(ModLayout dim) { + int guiWidth = width / 2; + int guiHeight = height / 2; + int w = right(dim) - dim.x.value; + int h = bottom(dim) - dim.y.value; + + dim.x.value = Math.max(0, Math.min(dim.x.value, guiWidth - w)); + dim.y.value = Math.max(0, Math.min(dim.y.value, guiHeight - h)); + } + + private static int right(ModLayout dim) { + return dim.x.value + (int) (dim.width * dim.scale.value); + } + + private static int bottom(ModLayout dim) { + return dim.y.value + (int) (dim.height * dim.scale.value); + } + + private static boolean isInside(double mouseX, double mouseY, ModLayout dim) { + return mouseX >= dim.x.value && mouseX <= right(dim) && mouseY >= dim.y.value && mouseY <= bottom(dim); + } + + private static boolean isOnHandle(double mouseX, double mouseY, ModLayout dim) { + return Math.abs(mouseX - right(dim)) <= HANDLE_REACH && Math.abs(mouseY - bottom(dim)) <= HANDLE_REACH; } @Override From 136621cc8d332f3a600bdd2ffdd4cb01e26f9711 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 27 Sep 2026 19:14:17 +0200 Subject: [PATCH 5/5] Remove UI code and icons nothing uses TextureButton, ClickableTexture, Text, Notification and the FadeOut and SlideX animations only Notification used, Utils.getOrNull and the commented-out notify, Element.duration, the 17 PNG icons the Lucide SVGs replaced, and the Textures constants for them and for files that don't exist. Co-Authored-By: Claude Opus 5.5 --- .../java/org/saturnclient/ui/Element.java | 1 - src/main/java/org/saturnclient/ui/Utils.java | 16 ----- .../org/saturnclient/ui/anim/FadeOut.java | 27 -------- .../java/org/saturnclient/ui/anim/SlideX.java | 39 ------------ .../ui/elements/ClickableTexture.java | 30 --------- .../ui/elements/Notification.java | 59 ------------------ .../org/saturnclient/ui/elements/Text.java | 22 ------- .../ui/elements/TextureButton.java | 37 ----------- .../saturnclient/ui/resources/Textures.java | 29 --------- .../textures/gui/components/check.png | Bin 1571 -> 0 bytes .../textures/gui/components/circle_x.png | Bin 1609 -> 0 bytes .../textures/gui/components/cloak.png | Bin 3205 -> 0 bytes .../textures/gui/components/close.png | Bin 322 -> 0 bytes .../textures/gui/components/coins.png | Bin 1684 -> 0 bytes .../textures/gui/components/cosmetics.png | Bin 3563 -> 0 bytes .../textures/gui/components/hat.png | Bin 2808 -> 0 bytes .../textures/gui/components/hud.png | Bin 645 -> 0 bytes .../textures/gui/components/info.png | Bin 1497 -> 0 bytes .../textures/gui/components/left.png | Bin 374 -> 0 bytes .../textures/gui/components/mods_tab.png | Bin 2589 -> 0 bytes .../textures/gui/components/reset.png | Bin 771 -> 0 bytes .../textures/gui/components/right.png | Bin 357 -> 0 bytes .../textures/gui/components/search.png | Bin 523 -> 0 bytes .../textures/gui/components/settings.png | Bin 2121 -> 0 bytes .../textures/gui/components/shirt.png | Bin 884 -> 0 bytes .../textures/gui/components/store.png | Bin 958 -> 0 bytes 26 files changed, 260 deletions(-) delete mode 100644 src/main/java/org/saturnclient/ui/anim/FadeOut.java delete mode 100644 src/main/java/org/saturnclient/ui/anim/SlideX.java delete mode 100644 src/main/java/org/saturnclient/ui/elements/ClickableTexture.java delete mode 100644 src/main/java/org/saturnclient/ui/elements/Notification.java delete mode 100644 src/main/java/org/saturnclient/ui/elements/Text.java delete mode 100644 src/main/java/org/saturnclient/ui/elements/TextureButton.java delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/check.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/circle_x.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/cloak.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/close.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/coins.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/cosmetics.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/hat.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/hud.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/info.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/left.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/mods_tab.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/reset.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/right.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/search.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/settings.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/shirt.png delete mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/store.png diff --git a/src/main/java/org/saturnclient/ui/Element.java b/src/main/java/org/saturnclient/ui/Element.java index 41f90e7..6677713 100644 --- a/src/main/java/org/saturnclient/ui/Element.java +++ b/src/main/java/org/saturnclient/ui/Element.java @@ -11,7 +11,6 @@ public class Element { public boolean focused; public Animation animation; public float scale = 1.0f; - public Integer duration = null; // Element duration, will fade out if not null public void render(RenderScope renderScope, ElementContext ctx) { } diff --git a/src/main/java/org/saturnclient/ui/Utils.java b/src/main/java/org/saturnclient/ui/Utils.java index b9287dc..8b85ad4 100644 --- a/src/main/java/org/saturnclient/ui/Utils.java +++ b/src/main/java/org/saturnclient/ui/Utils.java @@ -1,7 +1,5 @@ package org.saturnclient.ui; -import java.util.List; - import org.saturnclient.common.provider.GLFWProvider; public class Utils { @@ -64,18 +62,4 @@ public class Utils { } return builder.toString(); } - - public static T getOrNull(List list, int index) { - return (index >= 0 && index < list.size()) ? list.get(index) : null; - } - - // public static void notify(NotificationKind kind, String title, String toast) - // { - // if (SaturnClient.client.currentScreen instanceof SaturnScreen) { - // ((SaturnScreen) SaturnClient.client.currentScreen) - // .draw(new Notification(SaturnClient.client.currentScreen.width, - // SaturnClient.client.currentScreen.height, kind, - // title, toast)); - // } - // } } diff --git a/src/main/java/org/saturnclient/ui/anim/FadeOut.java b/src/main/java/org/saturnclient/ui/anim/FadeOut.java deleted file mode 100644 index 4172883..0000000 --- a/src/main/java/org/saturnclient/ui/anim/FadeOut.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.saturnclient.ui.anim; - -import org.saturnclient.config.AnimationConfig; -import org.saturnclient.ui.Element; - -public class FadeOut extends Animation { - float targetOpacity; - - public FadeOut(int duration) { - super(duration); - } - - public FadeOut(AnimationConfig config) { - super(config); - } - - @Override - public void tick(double progress, Element element) { - element.opacity = targetOpacity - (float) progress; - } - - @Override - public void init(Element element) { - targetOpacity = element.opacity; - // element.opacity = 1.0f; - } -} diff --git a/src/main/java/org/saturnclient/ui/anim/SlideX.java b/src/main/java/org/saturnclient/ui/anim/SlideX.java deleted file mode 100644 index 82792ba..0000000 --- a/src/main/java/org/saturnclient/ui/anim/SlideX.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.saturnclient.ui.anim; - -import org.saturnclient.config.AnimationConfig; -import org.saturnclient.ui.Element; - -public class SlideX extends Animation { - int offset = 20; - double startX; - - public SlideX(AnimationConfig config) { - super(config); - } - - public SlideX(AnimationConfig config, int offset) { - super(config); - this.offset = offset; - } - - public SlideX(int duration) { - super(duration); - } - - public SlideX(int duration, int offset) { - super(duration); - this.offset = offset; - } - - @Override - public void init(Element element) { - startX = element.x - offset; - element.x = (int) startX; - } - - @Override - public void tick(double progress, Element element) { - double currentX = startX + offset * progress; - element.x = (int) currentX; - } -} diff --git a/src/main/java/org/saturnclient/ui/elements/ClickableTexture.java b/src/main/java/org/saturnclient/ui/elements/ClickableTexture.java deleted file mode 100644 index 5936fcb..0000000 --- a/src/main/java/org/saturnclient/ui/elements/ClickableTexture.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.saturnclient.ui.elements; - -import org.saturnclient.common.ref.asset.IdentifierRef; -import org.saturnclient.config.Theme; -import org.saturnclient.ui.Element; -import org.saturnclient.ui.ElementContext; -import org.saturnclient.ui.RenderScope; - -public class ClickableTexture extends Element { - IdentifierRef sprite; - private Runnable onClick; - - public ClickableTexture(IdentifierRef sprite, Runnable onClick) { - this.sprite = sprite; - this.onClick = onClick; - } - - @Override - public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawTexture(sprite, 0, 0, 0, 0, width, height, - ctx.isHovering() ? Theme.ACCENT.value : Theme.PRIMARY.value); - } - - @Override - public void click(int mouseX, int mouseY) { - if (onClick != null) { - onClick.run(); - } - } -} diff --git a/src/main/java/org/saturnclient/ui/elements/Notification.java b/src/main/java/org/saturnclient/ui/elements/Notification.java deleted file mode 100644 index 0e0b471..0000000 --- a/src/main/java/org/saturnclient/ui/elements/Notification.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.saturnclient.ui.elements; - -import org.saturnclient.config.Theme; -import org.saturnclient.config.property.ColorProperty; -import org.saturnclient.config.property.Property; -import org.saturnclient.ui.Element; -import org.saturnclient.ui.ElementContext; -import org.saturnclient.ui.RenderScope; -import org.saturnclient.ui.anim.SlideX; -import org.saturnclient.ui.resources.Fonts; -import org.saturnclient.ui.resources.Textures; - -public class Notification extends Element { - private static ColorProperty error = Property.color(0xFFbf212f); - private static ColorProperty info = Property.color(0xFF264b96); - private static ColorProperty success = Property.color(0xFF27b376); - - public static enum NotificationKind { - Error, - Info, - Success, - } - - NotificationKind kind; - String text; - String title; - - public Notification(int width, int height, NotificationKind kind, String title, String text) { - this.kind = kind; - this.text = text; - this.title = title; - this.width = (int) Math.max(Fonts.getWidth(text, 1) * 0.6f, Fonts.getWidth(title, 1)) + 20; - this.height = 50; - this.x = width - this.width - 15; - this.y = height - this.height - 15; - this.animation = new SlideX(700, -width); - this.duration = 3000; - } - - @Override - public void render(RenderScope renderScope, ElementContext ctx) { - 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); - break; - - case Info: - renderScope.drawTexture(Textures.INFO, 9, 9, 0, 0, 15, 15, info.value); - break; - - case Success: - renderScope.drawTexture(Textures.CHECK, 9, 9, 0, 0, 15, 15, success.value); - break; - } - renderScope.drawText(0.7f, title, 32, 10, 1, -1); - renderScope.drawText(0.5f, text, 32, 28, 1, -1); - } -} diff --git a/src/main/java/org/saturnclient/ui/elements/Text.java b/src/main/java/org/saturnclient/ui/elements/Text.java deleted file mode 100644 index 7de1737..0000000 --- a/src/main/java/org/saturnclient/ui/elements/Text.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.saturnclient.ui.elements; - -import org.saturnclient.config.Theme; -import org.saturnclient.ui.Element; -import org.saturnclient.ui.ElementContext; -import org.saturnclient.ui.RenderScope; -import org.saturnclient.ui.resources.Fonts; - -public class Text extends Element { - private String text; - - public Text(String text) { - this.text = text; - width = Fonts.getWidth(text, Theme.FONT.value); - height = Fonts.getHeight(); - } - - @Override - public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawText(this.text, 0, 0, Theme.FONT.value, Theme.FOREGROUND.value); - } -} diff --git a/src/main/java/org/saturnclient/ui/elements/TextureButton.java b/src/main/java/org/saturnclient/ui/elements/TextureButton.java deleted file mode 100644 index 25c63b5..0000000 --- a/src/main/java/org/saturnclient/ui/elements/TextureButton.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.saturnclient.ui.elements; - -import org.saturnclient.common.ref.asset.IdentifierRef; -import org.saturnclient.config.Theme; -import org.saturnclient.ui.Element; -import org.saturnclient.ui.ElementContext; -import org.saturnclient.ui.RenderScope; - -public class TextureButton extends Element { - IdentifierRef sprite; - private Runnable onClick; - static int padding = 14; - - public TextureButton(IdentifierRef sprite, Runnable onClick) { - this.sprite = sprite; - this.onClick = onClick; - } - - @Override - public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, - ctx.isHovering() ? Theme.ACCENT.value : Theme.PRIMARY.value); - - int texWidth = width - padding; - int texHeight = height - padding; - - renderScope.drawTexture(sprite, padding / 2, padding / 2, 0, 0, texWidth, texHeight, - ctx.isHovering() ? Theme.ACCENT_FG.value : Theme.PRIMARY_FG.value); - } - - @Override - public void click(int mouseX, int mouseY) { - if (onClick != null) { - onClick.run(); - } - } -} diff --git a/src/main/java/org/saturnclient/ui/resources/Textures.java b/src/main/java/org/saturnclient/ui/resources/Textures.java index 8ecd804..01398ca 100644 --- a/src/main/java/org/saturnclient/ui/resources/Textures.java +++ b/src/main/java/org/saturnclient/ui/resources/Textures.java @@ -9,25 +9,6 @@ import org.saturnclient.common.ref.asset.IdentifierRef; public class Textures { public static final IdentifierRef CROSSHAIR_RANGE = IdentifierRef .ofSaturn("textures/gui/hud/crosshair_range.png"); - public static final IdentifierRef COSMETICS = IdentifierRef.ofSaturn("textures/gui/components/cosmetics.png"); - public static final IdentifierRef HUD_ICON = IdentifierRef.ofSaturn("textures/gui/components/hud.png"); - public static final IdentifierRef SEARCH = IdentifierRef.ofSaturn("textures/gui/components/search.png"); - public static final IdentifierRef CLOSE = IdentifierRef.ofSaturn("textures/gui/components/close.png"); - public static final IdentifierRef MODS_TAB = IdentifierRef.ofSaturn("textures/gui/components/mods_tab.png"); - public static final IdentifierRef SETTINGS = IdentifierRef.ofSaturn("textures/gui/components/settings.png"); - public static final IdentifierRef CLOAK = IdentifierRef.ofSaturn("textures/gui/components/cloak.png"); - public static final IdentifierRef HAT = IdentifierRef.ofSaturn("textures/gui/components/hat.png"); - public static final IdentifierRef RESET = IdentifierRef.ofSaturn("textures/gui/components/reset.png"); - public static final IdentifierRef TOGGLE_INDICATOR = IdentifierRef - .ofSaturn("textures/gui/components/toggle_indicator.png"); - public static final IdentifierRef LEFT = IdentifierRef.ofSaturn("textures/gui/components/left.png"); - public static final IdentifierRef RIGHT = IdentifierRef.ofSaturn("textures/gui/components/right.png"); - public static final IdentifierRef STORE = IdentifierRef.ofSaturn("textures/gui/components/store.png"); - public static final IdentifierRef COINS = IdentifierRef.ofSaturn("textures/gui/components/coins.png"); - public static final IdentifierRef SHIRT = IdentifierRef.ofSaturn("textures/gui/components/shirt.png"); - public static final IdentifierRef CIRCLE_X = IdentifierRef.ofSaturn("textures/gui/components/circle_x.png"); - public static final IdentifierRef INFO = IdentifierRef.ofSaturn("textures/gui/components/info.png"); - public static final IdentifierRef CHECK = IdentifierRef.ofSaturn("textures/gui/components/check.png"); // Lucide icons (SVG, drawn in white so they can be tinted) public static final IdentifierRef ICON_MODS = IdentifierRef.ofSaturn("textures/gui/components/mods.svg"); @@ -56,16 +37,6 @@ public class Textures { public static final IdentifierRef LOGO_TEXT_BIG = IdentifierRef.ofSaturn("textures/logo/text_big.png"); public static final IdentifierRef SPLASH = IdentifierRef.ofSaturn("textures/gui/splash.png"); - // Widgets - public static final IdentifierRef BUTTON_BORDER = IdentifierRef.ofSaturn("button_border"); - public static final IdentifierRef BUTTON = IdentifierRef.ofSaturn("button"); - public static final IdentifierRef BUTTON_OP = IdentifierRef.ofSaturn("button_op"); - public static final IdentifierRef SETTINGS_BG = IdentifierRef.ofSaturn("settings_bg"); - public static final IdentifierRef RECT = IdentifierRef.ofSaturn("rect"); - public static final IdentifierRef RECT_BORDER = IdentifierRef.ofSaturn("rect_border"); - public static final IdentifierRef MOD = IdentifierRef.ofSaturn("textures/gui/components/mod.png"); - public static final IdentifierRef MOD_BG = IdentifierRef.ofSaturn("textures/gui/components/mod_bg.png"); - /** * Whether a texture file is in the resources, for falling back when an * optional one (like an emote's preview) is missing. diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/check.png b/src/main/resources/assets/saturnclient/textures/gui/components/check.png deleted file mode 100644 index 039befb30ccfc0e46a71a270be1088f5ca406c19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1571 zcmV+;2Hg3HP)X4m}L~DmX=A26;?_{VMv;3kr5P$El^1tnGqC}5lJu07D5do zGtBnYq-Zb7dTsPaduh@7`h1^rhx5B{?#!K;-}^n@fy2!2&bjA&zjyB3Irq%3F`%DI zqo3m+&@uvDU0q`t4CzpGPjrt&HAY{dUna*-IKJFyG+t@N;MF1k=t}@`GI|8MbxAL;&EY@2Y{lexLFCQiwcO)?XGT4+ zh3Wh==cnNCr8=V?>Pt*LACICt8k@g4A0K*eWD>y95IVi#ITHAhIQq0Vz&oGB-k0;W z=nf{17KFoy{kb1IMBqgXkMu@i91dRVP4I@qnB?x;>9mIU#}yJ_1Wv$cm1lSsogZok zcthe`&hPPJY7jNJsr0x55O{~HBaF=xbW*y|b^(h9QUmH_Em%ee3DDsTE4uC3_~&_QdvRsts-7@yO2{^Wc+aQ&sW^bSBkte!N6-(s{|tHBdTqp1|43%!gOD~n># zN4eE5#_o9fX|^;GP~M^Z-pL}2<`g+Ea~&WTV6SY}iPrU@#L=@B6#CuG#o5L{xz{|O zz-k)oIy)1id&>YU0O5m|c_%s~f`Gt_gp*bDImsvR77Yg*qX`&^RBd4dbtjdz`ZARm z4;KZXzrfn5wvK)yeFECI?rxk7$LPZd=M%A6fND-Jpw9!gPY!r(Tox7i*L8g8y`=Y( zlTP|}?*{EdtfyNmk&}TK{gD>{$D4CqxzS$6E(Mk`=bc$J_=JFxJLN-8Hh^tgpTGth zwlPM7FxnVFKrgw$o}GL6?E_m0d_rIl$KOnhjbKw-(;ZmP?|qDsRtL4^N?^|r>Qidu zofBfHRAaM&^GL@vZ%)*UGtBRvC0VWho@6V;Wvvt|1X zsH8E;7)`-wd7<~jAZNbIqSDBlJK*PN%fP16P7{Io{I>hgn=sO5K3W1KYJpd9{4V4$ z*8sT+Y}fk)w1rfq%t^XbMKjnGY!(MMRRrG8>C3q5w#BC^9x7Kl(avyP6M@7~+s5sU z;Rp;>@98rEyk4$)$vXK3OzC#hPp9=(JkuC2##kfTX99r^f=@R9mVzlwuYCfl&8#uT zeZ8UCA1v>q7H8A8GHXluEFH!h5-VY>bfN9S=s!o$qfOw|V3}ZnWD(Gw)2}|vqGMiN zwB_Ui@0L;EP`M|SP+3KpUw68i$iEzQ>!Mz4b=d%Z96p{wZCOR%5mXdzk`MuXUC~z3 z?t+v|jmAlD7q<3GW`M2EeNWpV#Qr*pfQ%RgeJ;}TU`vZX@p~eU?E9kbfT#VFkyl3G zmlnskbw8RwLgH+W_j#RE+?|cXj+P+%Mw@cTe=Cp0>t{qbE~Q{GhN1BY_0^8x^8;M2eRJxrqrBqWq-Yt;3* zC`;a^QL9(_i3tGTa0ds{raA3CF{yB%(YEDF>rW+=NwLpaG=YSKRwZSDN-zAmns=vT zu4$=O3~(4xfmVR2;-lXa_#eo< V1y7nv`se@v002ovPDHLkV1kDv`5*uQ diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/circle_x.png b/src/main/resources/assets/saturnclient/textures/gui/components/circle_x.png deleted file mode 100644 index 11401deddf697b462a1e396a4fdc30d91fe3a3c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1609 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 diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/coins.png b/src/main/resources/assets/saturnclient/textures/gui/components/coins.png deleted file mode 100644 index 0946546c6c5b36c749c8f26194d10b32dac86807..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1684 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 N69WtVdRa!(iU*J0TNUr>vnx8T*heLdYOuM6Zx_ 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 diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/hud.png b/src/main/resources/assets/saturnclient/textures/gui/components/hud.png deleted file mode 100644 index a71c97143db1a6262a251e307b89cf5c89829c6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 645 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz07Sip>6gA}f5OZp5{_TJOQF(iWX z?R4v)!v+FvxpJBhr9=#37}qgKdN`jKEMnFOX0#2R(WvckkX1sXsOifECxiQZ(>|S^ zCOo^MP3h*$-mu?4!lOK=O;S1Sm$`-^a@yNP_ZzQ2;F-51^Or;P>;o2uDrL9H-2cGQ zV}2`3X$3R?LkZqh%Ff&enLRy{&9Q{=>;l>&~t_Y*)IVj#Fah)W4?YdoIKs z3fpBi?ZC86{O=FDRWE&-zz};Q@cs4md*d6b`Q~hUJs~%xFJ#-y?Y>PyEjbtNR^+k3;6|nsB1ezu?Y`_yhH- zw@=Jt(0uqi_`zN-Cdc%9$ z=*q0$W|9t}n_9oDW?Z9XP|m#baf*BPy5e^io=E)r-L7$ixo6Lpl_^2jOVi~(?hcCO zxgXB3c<;k^pBs|x7XIVyIIFkV`G(&5AFh+wFWpG}!fF39HKcX@_JyogL6#>QzoZq{ z`9>Z6vPrLTJ=+Q`b5Enw;f8zHFn8>WNK-W1;#&MtsE1|4`B{pd{ew>gTe~DWM4f8TJcK diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/info.png b/src/main/resources/assets/saturnclient/textures/gui/components/info.png deleted file mode 100644 index 81686b13728f161f73f502ad02443b60a199b535..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1497 zcmV;~1t$85P)o;)D(Z1X-Q4b?|X0Wn|1fQ=iIaR*-!IUvU1MdcMadS&$;`oz0Pe68sO3x z;P?k+BhcO5J(kIk4n_AscXz5e`U?Hh9Y5jtN~6(uHOJ)DA^_;i0C5U>B)U~3px?27 z4SfPKw?_Il&65ZK{7fR;gzlA^IPm+7&zD2w@z{7#1OR?83GQ&WN^Gtw_Ag*G3nCv@ zF_ukb0)U^6{lb#K@9TCzpFzJve?)(9_B(Oh5#0qn4m}M$uq4)0NZenAL?r@%zmi}# z6a>7T@dYIOqDn$6b^ND{=nSUt(f}ex)gF%45`8>PM%FzxGxh`e=W^}XQ`zhpFR79eX00ED{=|yyN zhF!RgH)kid^5(5L+Y-p3^OzMQW@ zw>NpTARJEa&%@kB1YW}Ms9+Yx5#aUy1aC-;aaZ5oPAkcOd`AMzz=;?w4-C)6dGY@N z-jKL}^Lv7vnnX=*Q~F#12)xU;BaF?HIH_ES65^bN!+hs-H8CEE3V<;&G?AK6FRO?% zx{!cN`mizhm-AsbsQ`--VrhBZ-#M)z#;~XWy#x;8@Lu3|2C*LVV=Y$z2d(W|3A}V+ ze12?V+2_LfP`Bx_$#`lF+L3Aw-O1|zJ(ltQ5@ee7&dagEx7*F zSn~=%K&+lJhTmeeYYO<>K44RAwX=zP0@!r7v=C6;q59s-ofyr^4JIWX1n$Ofrtwwn zH76vnf&shEPRHopl!Uo`ARzD};bl44P7VpY&A=hXXaYtewaEnn0=vurSq-+4Apz}M zcQZ!AG5RPKeU9gV&rK{nm-Kw{vJPxLyFvRS)~{PDk(a?3{ZWHJ?dO0YpyE#TkeBsf z+a@Hio`J26(GZL_)F9ApeTmg^?@^SCD=>ubely>1Ae_cpuE1J8?`@2RVx+MoA!$wm zYSq|kU@h1*)Xlc^)tCq9qpr;^^V3hpd-hz|`DshUN4_Se(?z(c2E!sSHOuRefO<14jq#@5&>R4k4^WG^jk z#CV>($C%tJz%s#NX-7bN&anG11IMzyXe_^u_JCI@uePO?QQ%O!rzu5k6;*yc<*Ji^ zIO@_RKiE1VHU@wn$H!+;+g8zg1T}?Qq=B@P0)~j*Z%uZpSFkanTW$%u6yU0NlB5;^n~|%cw>qbz>O!kM z>yi)$PT2_L0Fx49z!Ufn-(mt!z3FYi00000NkvXXu0mjfs1Veb diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/left.png b/src/main/resources/assets/saturnclient/textures/gui/components/left.png deleted file mode 100644 index 073a7488e50fd8583b5862430b5e22af77edc091..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 374 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 diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/reset.png b/src/main/resources/assets/saturnclient/textures/gui/components/reset.png deleted file mode 100644 index fa62098f1b0c3c8ff022aae1290320751dcad66f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 771 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(M@AAusjfMPXED3en zvHH%t2ku;JS-0;z66EYt$nI3y@H&$@rorceOU~K{Ge0QI_xPgX!|W_>#p$(iZG-)> zgO4qL2)(%eZ{i6R$xoBwj69nzaBkbOuR*8Pj79YM?zDm__9wG1h?p?`70>%s?pT(@ zlk}VCRa1@5UyjFR&v*sCFHil;C`F=D%(B zhrZ80y^5QS96+iLv z#gbWltGj*(YTVp^#A5ni^~5~e#{1O=?{9chU%H5C)0;%!?5YQoJ%xTPGGm;vn}KJo zRIOs)=33X<4SyF$J#w6MT6oQAKaJ!s{0)E3Z$4GmWV86#^hNKF7_6M6I!*kf+yvXD zp1XE(*EO~;kmh0j{bcz~G3^(NmF+h0$~0{FVzg_O%*2&>+m3Ku|5*KsLvU}`kxRan wX>S=mZ?SU!$MwYFt82XL9L0ABY+oFx|73QeHKzSVJSYKry85}Sb4q9e0CL?$4gdfE diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/right.png b/src/main/resources/assets/saturnclient/textures/gui/components/right.png deleted file mode 100644 index fa6ee7c37c249b0d46130402779feda1ebcd806c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 357 zcmV-r0h<1aP)9U5CzZ%f5*p<=|&MBxNzlTp$Ph6qTuhu8|b2h=pr+BNFjv~C?p(ir%6-S^z3py z^EMUCequG@nsAgrEs3H_!h632aDjGn&YjrUFn@MQ06W6?R|ok3dd5aez!Tt}5s;3~ z1_vlo4rQ>4&{rfK%7k)>z%BZYerlDp7;KGJ0b8Qgz*cBgumxHj%tlkdOf(JLqA%#@ z(UNz>I=#(Zq^aN^NqgKM0{zKBTY&d~?a&4t;27X{abRrSsggJYyUxLeF|>q%rEJ+0 zFbhjbn2A*fv$3jR3#=O03abLP#EQYd9x%x!T2sqBA|+1E!Cmel6yW&OOvh@JM1Ovy z4BeHqb(00000NkvXXu0mjf DT_&7` diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/search.png b/src/main/resources/assets/saturnclient/textures/gui/components/search.png deleted file mode 100644 index ac032901af483000ff429ab309c168caeca04c30..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 523 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgftkl!RF~o!S z>XeOshaGs@^jA!2e|g{vqoUd|ubjERgk&Qt*~;P?SVMh0dNzdc@N}>zI(t0)KdHE6 z*Oy6B8?RiFw@&|GR~k&O>2?EzB`ldpPDzd;|EKUfW_gt8VOoAwmI17 zsctV#V$o)r{(oEalay?MDE+$1b82QqOMXR{P7$!sJ>jPQc(Lj6`G#e}%DV3EKHLQ& z6Q_smoOf)aOzoyyzZbfnT=HHvuJN+LRONmj>l3yAKg|<+(595Ww#c?O+0yFMI;Q7y z%j*wYG_%goJu&s$vPewBa0oZHttl}tZ`%w>m=oMN`HiR?G(PpqNj8qjW^!-&XVU%`#mmQ uSus=Gu&G){!tlCORkY~Nlh^tG{}rEo^Xr8JioI2!i12jvb6Mw<&;$U!i_6pi diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/settings.png b/src/main/resources/assets/saturnclient/textures/gui/components/settings.png deleted file mode 100644 index 93074e02b0a391ecb6df8694cbcf85f646ad40df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2121 zcmV-P2)6f$P)V!8n2^?|f_n?_Rlw zH$Yc)_spna!97O@F+KfJO?_@v_lVr!1~-@^7UT-?@#Dv$-|xRTIXQWbe+zsDwdTWx zg@yg&vJr? zAFb1eNhV|y(C5#et4MVT5ZpE*+3?Y$M+^M$J1)Obh8q0%@uRU8rlK#IK=Z)U_ca|p ze*E~HX1TCFf=T|(eiu7n91441G9a4<;YWGR0s?qrbn~{s(chO$$R5QmEuh!S&TUeV zQ$SCB7r~TEtpl`cs$9RmK8O+I=g*(Zaz0!i!m%D|DZ$sTU)RxIC_|RYb>W!MFkjOm z$9(YM!G5>M`V%Z>7aFlq3CgkN zO?-W>3|k^<4aEQ)^?{}_zWHw5y0znT>{_1?q6CCRE@D!$*dpeBCYiXOLNrYQ!hVT` z?ppVN9*ps4T{@Vrh7x^NA3l6|7`ibiAg2WfqG(ME1huDvr9~|;g^*T4LNc8+%?iSK zCvy-Ev}YyuW|+jP7{00@2DFM0D>ns1pCgfGm4KOWQffTB*9kPbPb3Ni95ekYd?cYTqiJA`Q$)9+wkB0T$eOn> z_?oW`6Te1!uvPu}-=UCz5)nlc~meWy@>LkMWe*GCl)!t1H;Iy3F7tP!_?qbmo#HdYaQ*OQra zm%^#YC!Z==ul#Q=48dgQd$>O7YEFi9JouzO$r=QQ_E+1wa17(EBbEJH^J;-d(;zF% zm%fY0aW-nd+A^g+Ll{g+T(*t7JJ5`_LS=*Xx9;+h9rUsCZm}&Bc20j z(k91{M9}xpL5q?T(ww!vmVmZI$4pfrs2KiJEs}}uSXzQ(q-YZ7rDL`7a37<=5Y8y@pl9`P%eR@S#@)Mj$Cmmz?1b_eIAofIb`Oc& z22+WuXb+H+Sf$tjoxIUrJ(Q3+UaE&*L@=9o1u`zi(iD}622vI?FLQnAI|^UB6;Yu* zjFKZ!z!C|zvsXhAIaqS#0Qm8%tli*WZLl@b7orL_l(g28RPVf2q6y(>^D^~$4NkNY zLsz0}(kyJTexfuF7%99H^m@;H*U4>Sc#XSfTN%S!=SHMk7R96?@TGbl8A4Lgo=lXg zsWf{9WE8qW0pJYyQTxi+MdJ0nRI-`8tARzwgCvA<-HDdUzT{RDPwD9>b*`j zZ3x?oXaQA8rqVps`~(*DUg@(I!-gH<8~NH;4)I-g{!QDJeM^Qdkq8QiMA22^)Fcy6 za-#JInbSh*Y{$eBQjI8j!CH~%(4r&-zQf-X^MHZ^0vUT3C{2`BvPUvzP=guEChM)M zK6wnYcBiq0uVaWuxd)^ADE=lM2Mnc2W~zZjZ-!2V#q5sGVe^ss+fshDSx5PeS*^STabvhAa89MY*NX2z`(_2>$CMS;!0g5P<@aNfd9nU8@7_xPIBKB|D+ zw$GyH`Z9MjAn`Y~MV=kc1F<~Eb#QO#UTbQ-@mIlZJaV^U6g!{W-54oD?rC$WCgy6< zR7WknAjkOT4oQwAf&}tJM!(;B@=QAXrf%_Ue!*WI5Gis^>A-ZDyNBMbJC&QE&>=fBFsDkl2Kn&DZ2IhtAQH;mlq*($?Hoq#FkzGJEHB$W)Q{lbnv(i<;Ed|+4 ztPWSS=lfqzFGQ@VE84Ttw|f(1N5DV>00000NkvXXu0mjfte@(% diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/shirt.png b/src/main/resources/assets/saturnclient/textures/gui/components/shirt.png deleted file mode 100644 index 96a85f1f843ba6c204dc8dd4f8fc7d703393b04a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 884 zcmV-)1B?8LP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NE-bqA3RA>e5SG#T$K@hwnaOBL8 zIB)tYQJWkUsG1;SqJ8hF4Ri-7*P0dgF`9Y|h`dEihsT%+tZv|BW zVnz|oGgEufUN7DNYjR9yRn2e>9Q=92vd8g_4v;ZaDNe7E;Y4>&J*|~$?J0eX!4UH`uksa z8zwmmZak_5;JSdd$104pWyrTGy;Y0;{;#U|8Y*#PCN1{1>@yTz0JbKvFy2WrMKGi$ zFk3;?01hB8Aip5)3L=UCxkWCW?18;Bzkk5r53NBii^X5k;9Q&6rccYSuhBOCKh~cI zSoG246UZl!xC8kLC2nAHdOm^VElecHCy=;-$?5q7lD9CCAfG_u1}3NfS10hpZWsQ8 zx@GMY9b7jhzgA0PH8bV}Ue+>uy}elsQ8d3N+^@t=H&N&zp*ca3L+St+@5~Vnn0O+)T7&EmAK04J9cu*J2Dw$`%&O z1rnPJ7i61@k(58j=Qr;;{T%0<_j#Xlp5uMvS8vZbXV3HfeLv5i_j%rTv7(4aEaLu) zk^u2|d>Jr@xaOrm_42(w7K>dEBdi9vfx+b&OuhwRYS;m8VX!ib$#Nhbh7H1G3MD)@ z0B}6C0I9}U6ZQOdO#R*lz`7^_EX3>sWw;lB*--)*f!WVoBbDiKKzs}nMAm(PX>=d6 z<;rkX*lwqO07o(3pa5C`*cYV{Sc}<<%5Vn&E29K36SJ}thbf+5W+xqaM@;#ig;)pg zsW&-H1jEJ&Q-G^ftPUFheoA2IHyMGwRBj0wzyRilXN3vC3hH$zfNmPgCReav8gC}q z8I|xd9#)$I6jO0XHU7%y(FlAi6afHd$yKZJ?I!<0BLJy{zzd2}B~XEYY;pw&@;@h0 znM$^l{C9%@oTu^zCD4d~Y;w*6^J7V(k1s#?K8E~Xf&gr%@(Jbk5(2WxIS&A;NYbtn z^^iOH)abj2y(zSSvRjGtAu`Lk`(M+ym7-bYIz{eniSMQWf9+%nz-`RR^LipS0&pP^ zfHw+Vlod*-1|dDPc^?qWO9#u5ev}d~CGSfcfFm^8p@doyl1o4v&I%6^g=HQRt_f zqy)+klugb_0PqT7eYdM5pDgNR7*8P&;0mQ4!a4*`yKs;B>FB;m(Jm(6r(6IUX?$1- zycQrtpXCz*^V86i*POEM67iTk^HcK#9f1-A-f;zLmnXO;00io{2yBGjkyGHVJee|; zk@L?K00wdf@YaIgdsI_nruAwue=c3+z$1_lVI(&3c?;JJE?3XYkI>$Vc`4I|HGpZ? zxvuvgz;zG%>HnJ}zye-H&opt(@p|Yf<$+v}*EYI=M}Q=9l#nAux~K-?n%}Ue`@5~K z4L~Ob7G*Hm1;AoU04rS^0C__oZwk`I2LL8o0?00#sqG-T`V^c@VFNHo>j@43taNPv z?qNRDH0h+LmROE}m97mywnc3HFDRcyoKZJ0fb_1HY>#&v{Z1**19BU+x&tLf%tqG= gz-EfLY7=>YpVzBGK>G&vo&W#<07*qoM6N<$g1OA7n*aa+