diff --git a/src/main/java/org/saturnclient/config/Theme.java b/src/main/java/org/saturnclient/config/Theme.java index 70ad3af..8a9af41 100644 --- a/src/main/java/org/saturnclient/config/Theme.java +++ b/src/main/java/org/saturnclient/config/Theme.java @@ -64,6 +64,35 @@ public class Theme { return hover ? ACCENT_FG.value : PRIMARY_FG.value; } + /** + * Translucent background for panels drawn over the world + */ + public static int getPanelBg() { + return withAlpha(0.82f, BACKGROUND.value); + } + + /** + * Faint outline for panels, cards and inputs + */ + public static int getBorder() { + return withAlpha(0.08f, FOREGROUND.value); + } + + /** + * Secondary text: descriptions, counts and placeholders + */ + public static int getMutedFg() { + return withAlpha(0.65f, FOREGROUND.value); + } + + /** + * Font for secondary text. Inter bold is too heavy there, so it becomes + * regular Inter; other fonts are kept. + */ + public static int getBodyFont() { + return FONT.value == 2 ? 1 : FONT.value; + } + /** * Multiplies existing alpha with 0–255 alpha. */ diff --git a/src/main/java/org/saturnclient/ui/components/SaturnModule.java b/src/main/java/org/saturnclient/ui/components/SaturnModule.java index 3a753e3..1af513f 100644 --- a/src/main/java/org/saturnclient/ui/components/SaturnModule.java +++ b/src/main/java/org/saturnclient/ui/components/SaturnModule.java @@ -7,141 +7,100 @@ import org.saturnclient.mod.Mod; import org.saturnclient.ui.Element; import org.saturnclient.ui.ElementContext; import org.saturnclient.ui.RenderScope; -import org.saturnclient.ui.Utils; +import org.saturnclient.ui.components.inputs.Toggle; import org.saturnclient.ui.resources.Fonts; import org.saturnclient.ui.resources.Textures; import org.saturnclient.ui.screens.ConfigEditor; +/** + * A mod's card in the mod menu: icon, name, description, a settings button and + * an on/off switch. Clicking anywhere but the settings button toggles the mod. + */ public class SaturnModule extends Element { + public static final int HEIGHT = 76; + + private static final int PADDING = 12; + private static final int ICON_TILE = 44; + private static final int ICON = 22; + private static final int SETTINGS = 32; + private static final int SETTINGS_ICON = 17; + private static final int GAP = 12; + private static final float NAME_SCALE = 0.74f; + private static final float DESCRIPTION_SCALE = 0.64f; private final Mod mod; - static int p = 10; // padding - static int s = 14; // settings icon size - static int expand = 5; // settings icon click area - - public SaturnModule(Mod mod) { + public SaturnModule(Mod mod, int width) { this.mod = mod; - this.width = 160; - this.height = 50; + this.width = width; + this.height = HEIGHT; } @Override public void render(RenderScope renderScope, ElementContext ctx) { - boolean hovered = ctx.isHovering(); boolean enabled = mod.isEnabled(); + boolean settingsHovered = ctx.isHovering(getSettingsX(), getSettingsY(), SETTINGS, SETTINGS); + boolean hovered = ctx.isHovering() && !settingsHovered; - int iconX = width - s - p; - int iconY = height - s - p; + int border = enabled ? Theme.withAlpha(hovered ? 0.7f : 0.4f, Theme.ACCENT.value) + : Theme.withAlpha(hovered ? 0.22f : 0.06f, Theme.FOREGROUND.value); - boolean settingsHover = ctx.isHovering( - getSettingsX(), - getSettingsY(), - getSettingsHitBox(), - getSettingsHitBox()); + // Card + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, 1, + Theme.withAlpha(0.72f, Theme.PRIMARY.value), border); - // Resolve theme colors - int bgColor = Theme.PRIMARY.value; - int fgColor = hovered && !settingsHover ? Theme.ACCENT.value : Theme.PRIMARY_FG.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); - - // Main background - renderScope.drawRoundedRectangle( - 0, 0, - width, height, - Theme.WIDGET_RADIUS.value, - bgColor); - - // Icon background - renderScope.drawRoundedRectangle( - p, p, - h, h, - Theme.WIDGET_RADIUS.value, - iconBg); - - // Icon - renderScope.drawTexture( - mod.getIconTexture(), - p + (p / 2), - p + (p / 2), - 0, 0, - h - p, - h - p, - iconFg); - - // 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 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; + if (enabled) { + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, + Theme.withAlpha(0.06f, Theme.ACCENT.value)); } - // Settings icon - renderScope.drawTexture( - Textures.SETTINGS, - iconX, - iconY, - 0, 0, - s, s, - settingsColor); + // Icon + int tileY = (height - ICON_TILE) / 2; + renderScope.drawRoundedRectangle(PADDING, tileY, ICON_TILE, ICON_TILE, Theme.WIDGET_RADIUS.value, + enabled ? Theme.withAlpha(0.18f, Theme.ACCENT.value) : Theme.withAlpha(0.06f, Theme.FOREGROUND.value)); + + renderScope.drawTexture(mod.getIconTexture(), + PADDING + (ICON_TILE - ICON) / 2, tileY + (ICON_TILE - ICON) / 2, + 0, 0, ICON, ICON, Theme.PRIMARY_FG.value); + + // Name and description + int textX = PADDING + ICON_TILE + GAP; + int textWidth = getSettingsX() - GAP - textX; + int nameHeight = (int) (Fonts.getHeight() * NAME_SCALE); + int descriptionHeight = (int) (Fonts.getHeight() * DESCRIPTION_SCALE); + int nameY = (height - nameHeight - 5 - descriptionHeight) / 2; + + renderScope.drawText(NAME_SCALE, + Fonts.ellipsize(mod.getName(), Theme.FONT.value, NAME_SCALE, textWidth), + textX, nameY, Theme.FONT.value, Theme.FOREGROUND.value); + + String description = mod.getDescription() == null ? "" : mod.getDescription(); + renderScope.drawText(DESCRIPTION_SCALE, + Fonts.ellipsize(description, Theme.getBodyFont(), DESCRIPTION_SCALE, textWidth), + textX, nameY + nameHeight + 5, Theme.getBodyFont(), Theme.getMutedFg()); + + // Settings button + if (settingsHovered) { + renderScope.drawRoundedRectangle(getSettingsX(), getSettingsY(), SETTINGS, SETTINGS, + Theme.WIDGET_RADIUS.value, Theme.withAlpha(0.08f, Theme.FOREGROUND.value)); + } + + int settingsIconOffset = (SETTINGS - SETTINGS_ICON) / 2; + renderScope.drawTexture(Textures.ICON_SLIDERS, + getSettingsX() + settingsIconOffset, getSettingsY() + settingsIconOffset, + 0, 0, SETTINGS_ICON, SETTINGS_ICON, + settingsHovered ? Theme.ACCENT.value : Theme.getMutedFg()); + + // Switch + Toggle.drawSwitch(renderScope, getSwitchX(), (height - Toggle.SWITCH_HEIGHT) / 2, enabled); } @Override public void click(int mouseX, int mouseY) { - boolean settingsHover = Utils.isHovering( - mouseX - getSettingsX(), - mouseY - getSettingsY(), - getSettingsHitBox(), - getSettingsHitBox(), - 1.0f); + boolean settingsClicked = mouseX >= getSettingsX() && mouseX <= getSettingsX() + SETTINGS + && mouseY >= getSettingsY() && mouseY <= getSettingsY() + SETTINGS; - if (settingsHover) { + if (settingsClicked) { if (mod instanceof HudMod h) { Providers.saturn.getClient().setScreen(new ConfigEditor(mod.getConfig(), h)); } else { @@ -152,15 +111,15 @@ public class SaturnModule extends Element { } } + private int getSwitchX() { + return width - PADDING - Toggle.SWITCH_WIDTH; + } + private int getSettingsX() { - return width - s - p - expand; + return getSwitchX() - 8 - SETTINGS; } private int getSettingsY() { - return height - s - p - expand; + return (height - SETTINGS) / 2; } - - private int getSettingsHitBox() { - return s + expand * 2; - } -} \ No newline at end of file +} diff --git a/src/main/java/org/saturnclient/ui/components/Sidebar.java b/src/main/java/org/saturnclient/ui/components/Sidebar.java index 006b5a5..e263189 100644 --- a/src/main/java/org/saturnclient/ui/components/Sidebar.java +++ b/src/main/java/org/saturnclient/ui/components/Sidebar.java @@ -7,51 +7,48 @@ import org.saturnclient.config.Theme; import org.saturnclient.ui.Element; import org.saturnclient.ui.ElementContext; import org.saturnclient.ui.RenderScope; -import org.saturnclient.ui.Utils; +import org.saturnclient.ui.elements.Panel; import org.saturnclient.ui.resources.Textures; import org.saturnclient.ui.screens.ConfigEditor; +import org.saturnclient.ui.screens.HudEditor; import org.saturnclient.ui.screens.ModMenu; import org.saturnclient.ui.screens.cosmetics.CloakMenu; -import org.saturnclient.ui.screens.store.CloakStore; +/** + * The navigation rail beside Saturn's screens: the logo, one button per screen, + * and a close button at the bottom. + */ public class Sidebar extends Element { - public static class SidebarComponent { - Runnable onClick; - boolean end; - IdentifierRef sprite; + public static final int WIDTH = 60; - public SidebarComponent(IdentifierRef sprite, Runnable onClick, boolean end) { - this.onClick = onClick; - this.end = end; - this.sprite = sprite; - } + // Values for the constructor's `active` + public static final int MODS = 0; + public static final int COSMETICS = 1; + public static final int HUD_EDITOR = 2; + public static final int SETTINGS = 3; + + private static final int LOGO = 32; + private static final int BUTTON = 44; + private static final int ICON = 22; + private static final int GAP = 8; + private static final int PADDING = 12; + + private record Item(IdentifierRef icon, Runnable onClick) { } - Runnable onClose; - SidebarComponent[] components = { - new Sidebar.SidebarComponent(Textures.MODS_TAB, () -> { - Providers.saturn.getClient().setScreen(new ModMenu()); - }, false), - new Sidebar.SidebarComponent(Textures.SETTINGS, () -> { - Providers.saturn.getClient().setScreen(new ConfigEditor(Config.config)); - }, false), - - new Sidebar.SidebarComponent(Textures.SHIRT, () -> { - Providers.saturn.getClient().setScreen(new CloakMenu()); - }, false), - - new Sidebar.SidebarComponent(Textures.CLOSE, () -> { - onClose.run(); - }, true), - - new Sidebar.SidebarComponent(Textures.STORE, () -> { - Providers.saturn.getClient().setScreen(new CloakStore()); - }, true), + private final Item[] items = { + new Item(Textures.ICON_MODS, () -> Providers.saturn.getClient().setScreen(new ModMenu())), + new Item(Textures.ICON_COSMETICS, () -> Providers.saturn.getClient().setScreen(new CloakMenu())), + new Item(Textures.ICON_HUD_EDITOR, () -> Providers.saturn.getClient().setScreen(new HudEditor())), + new Item(Textures.ICON_SETTINGS, + () -> Providers.saturn.getClient().setScreen(new ConfigEditor(Config.config))), }; - int active = 0; + + private final int active; + private final Runnable onClose; public Sidebar(int active, Runnable onClose) { - this.width = 30; + this.width = WIDTH; this.height = 350; this.active = active; this.onClose = onClose; @@ -59,63 +56,75 @@ public class Sidebar extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { - int topRow = 0; - int bottomRow = 0; + Panel.drawBackground(renderScope, width, height); - int gap = 5; // 5px gap between icons - int padding = 10; - int sp = 30 - padding + gap; - int s = 30 - (padding * 2); - int s2 = s + padding; + renderScope.drawTexture(Textures.LOGO, (width - LOGO) / 2, PADDING, 0, 0, LOGO, LOGO); - renderScope.drawRoundedRectangle(0, 0, width, height, Theme.BG_RADIUS.value, Theme.BACKGROUND.value); + int x = getButtonX(); - int i = 0; + for (int i = 0; i < items.length; i++) { + int y = getItemY(i); + boolean selected = i == active; + boolean hovered = ctx.isHovering(x, y, BUTTON, BUTTON); - 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) { - bottomRow += 1; - } else { - topRow += 1; + if (selected) { + renderScope.drawRoundedRectangle(x, y, BUTTON, BUTTON, Theme.WIDGET_RADIUS.value, Theme.ACCENT.value); + } else if (hovered) { + renderScope.drawRoundedRectangle(x, y, BUTTON, BUTTON, Theme.WIDGET_RADIUS.value, + Theme.withAlpha(0.08f, Theme.FOREGROUND.value)); } - i++; + drawIcon(renderScope, items[i].icon(), x, y, + selected ? Theme.ACCENT_FG.value + : hovered ? Theme.FOREGROUND.value : Theme.withAlpha(0.8f, Theme.FOREGROUND.value)); } + + int closeY = getCloseY(); + boolean closeHovered = ctx.isHovering(x, closeY, BUTTON, BUTTON); + + renderScope.drawRoundedRectangle(x, closeY, BUTTON, BUTTON, Theme.WIDGET_RADIUS.value, + Theme.withAlpha(closeHovered ? 0.12f : 0.06f, Theme.FOREGROUND.value)); + + drawIcon(renderScope, Textures.ICON_CLOSE, x, closeY, + closeHovered ? Theme.FOREGROUND.value : Theme.withAlpha(0.8f, Theme.FOREGROUND.value)); } @Override public void click(int mouseX, int mouseY) { - int topRow = 0; - int bottomRow = 0; + int x = getButtonX(); - int gap = 5; - int padding = 10; - int sp = 30 - padding + gap; - int s = 30 - (padding * 2); - int s2 = s + padding; + if (mouseX < x || mouseX > x + BUTTON) { + return; + } - 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); + for (int i = 0; i < items.length; i++) { + int y = getItemY(i); - if (hovering) { - component.onClick.run(); - break; - } - - if (component.end) { - bottomRow += 1; - } else { - topRow += 1; + if (mouseY >= y && mouseY <= y + BUTTON) { + items[i].onClick().run(); + return; } } + + if (mouseY >= getCloseY() && mouseY <= getCloseY() + BUTTON) { + onClose.run(); + } + } + + private static void drawIcon(RenderScope renderScope, IdentifierRef icon, int x, int y, int color) { + int offset = (BUTTON - ICON) / 2; + renderScope.drawTexture(icon, x + offset, y + offset, 0, 0, ICON, ICON, color); + } + + private int getButtonX() { + return (width - BUTTON) / 2; + } + + private int getItemY(int index) { + return PADDING + LOGO + 14 + index * (BUTTON + GAP); + } + + private int getCloseY() { + return height - PADDING - BUTTON; } } diff --git a/src/main/java/org/saturnclient/ui/components/inputs/Input.java b/src/main/java/org/saturnclient/ui/components/inputs/Input.java index 8947416..421c759 100644 --- a/src/main/java/org/saturnclient/ui/components/inputs/Input.java +++ b/src/main/java/org/saturnclient/ui/components/inputs/Input.java @@ -11,6 +11,11 @@ public abstract class Input extends Element { String text = ""; public int cursorPosition = 0; + /** Scale the text is drawn at */ + protected float textScale = 0.6f; + /** Horizontal inset of the text on both sides */ + protected int textX = 4; + public abstract void checkReset(); public abstract void backspace(); @@ -41,6 +46,7 @@ public abstract class Input extends Element { @Override public void click(int mouseX, int mouseY) { + mouseX -= textX; int scrollOffset = getScrollOffset(); String visibleText = text.substring(scrollOffset); @@ -48,7 +54,7 @@ public abstract class Input extends Element { float textWidth = 0; for (int i = 0; i < visibleText.length(); i++) { - textWidth = Fonts.getWidth(visibleText.substring(0, i + 1), Theme.FONT.value) * 0.6f; + textWidth = Fonts.getWidth(visibleText.substring(0, i + 1), Theme.FONT.value) * textScale; if (textWidth > mouseX) { break; @@ -68,24 +74,32 @@ public abstract class Input extends Element { int scrollOffset = getScrollOffset(); String visibleText = getVisibleText(scrollOffset); - renderScope.drawText(0.6f, visibleText, 4, 4, Theme.FONT.value, Theme.PRIMARY_FG.value); + renderScope.drawText(textScale, visibleText, textX, 4, Theme.FONT.value, Theme.PRIMARY_FG.value); if (focused) { - int cursorX = 4 + - (int) (Fonts.getWidth(visibleText.substring(0, cursorPosition - scrollOffset), Theme.FONT.value) - * 0.6f); + int cursorX = getCursorX(visibleText, scrollOffset); renderScope.drawRectangle(cursorX, 2, 1, height - 4, Theme.ACCENT.value); } } + protected int getCursorX(String visibleText, int scrollOffset) { + return textX + (int) (Fonts.getWidth(visibleText.substring(0, cursorPosition - scrollOffset), + Theme.FONT.value) * textScale); + } + + /** Width available to the text, in unscaled font units */ + private float getTextSpace() { + return (width - textX * 2) / textScale; + } + protected int getScrollOffset() { if (text.isEmpty()) { return 0; } int offset = 0; - int maxWidth = width - 4; // Available width for text + float maxWidth = getTextSpace(); while (offset < cursorPosition) { // Ensure cursor remains visible String visibleText = text.substring(offset, cursorPosition); if (Fonts.getWidth(visibleText, Theme.FONT.value) > maxWidth) { @@ -102,7 +116,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), Theme.FONT.value) > width - 4) { + if (Fonts.getWidth(visibleText.substring(0, i), Theme.FONT.value) > getTextSpace()) { return visibleText.substring(0, i - 1); // Trim overflow } } diff --git a/src/main/java/org/saturnclient/ui/components/inputs/SearchInput.java b/src/main/java/org/saturnclient/ui/components/inputs/SearchInput.java new file mode 100644 index 0000000..f515408 --- /dev/null +++ b/src/main/java/org/saturnclient/ui/components/inputs/SearchInput.java @@ -0,0 +1,79 @@ +package org.saturnclient.ui.components.inputs; + +import java.util.function.Consumer; + +import org.saturnclient.config.Theme; +import org.saturnclient.ui.ElementContext; +import org.saturnclient.ui.RenderScope; +import org.saturnclient.ui.resources.Fonts; +import org.saturnclient.ui.resources.Textures; + +/** + * A free-text search box with an icon and placeholder, reporting every change. + */ +public class SearchInput extends Input { + private static final int ICON_SIZE = 16; + private static final int ICON_X = 12; + + private final String placeholder; + private final Consumer onChange; + + public SearchInput(String placeholder, Consumer onChange) { + this.placeholder = placeholder; + this.onChange = onChange; + this.textScale = 0.68f; + this.textX = ICON_X + ICON_SIZE + 8; + this.width = 240; + this.height = 36; + } + + @Override + public void charTyped(char chr) { + if (text.length() >= 64) { + return; + } + + text = text.substring(0, cursorPosition) + chr + text.substring(cursorPosition); + cursorPosition++; + onChange.accept(text); + } + + @Override + public void backspace() { + onChange.accept(text); + } + + @Override + public void checkReset() { + } + + @Override + public void render(RenderScope renderScope, ElementContext ctx) { + int border = focused ? Theme.withAlpha(0.6f, Theme.ACCENT.value) + : ctx.isHovering() ? Theme.withAlpha(0.25f, Theme.FOREGROUND.value) + : Theme.withAlpha(0.1f, Theme.FOREGROUND.value); + + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, 1, + Theme.withAlpha(0.06f, Theme.FOREGROUND.value), border); + + renderScope.drawTexture(Textures.ICON_SEARCH, ICON_X, (height - ICON_SIZE) / 2, 0, 0, + ICON_SIZE, ICON_SIZE, Theme.getMutedFg()); + + int textHeight = (int) (Fonts.getHeight() * textScale); + int textY = (height - textHeight) / 2; + + if (text.isEmpty() && !focused) { + renderScope.drawText(textScale, placeholder, textX, textY, Theme.getBodyFont(), Theme.getMutedFg()); + return; + } + + int scrollOffset = getScrollOffset(); + String visibleText = getVisibleText(scrollOffset); + renderScope.drawText(textScale, visibleText, textX, textY, Theme.FONT.value, Theme.FOREGROUND.value); + + if (focused) { + renderScope.drawRectangle(getCursorX(visibleText, scrollOffset), textY - 1, 1, textHeight + 2, + Theme.ACCENT.value); + } + } +} diff --git a/src/main/java/org/saturnclient/ui/components/inputs/Toggle.java b/src/main/java/org/saturnclient/ui/components/inputs/Toggle.java index c55f940..0987723 100644 --- a/src/main/java/org/saturnclient/ui/components/inputs/Toggle.java +++ b/src/main/java/org/saturnclient/ui/components/inputs/Toggle.java @@ -23,6 +23,26 @@ public class Toggle extends Element { prop.value ? Theme.ACCENT.value : Theme.PRIMARY.value); } + public static final int SWITCH_WIDTH = 42; + public static final int SWITCH_HEIGHT = 24; + + /** + * Draws an on/off switch: a pill track with a round knob on the right when on. + */ + public static void drawSwitch(RenderScope renderScope, int x, int y, boolean on) { + int inset = 3; + int knob = SWITCH_HEIGHT - inset * 2; + + renderScope.drawRoundedRectangle(x, y, SWITCH_WIDTH, SWITCH_HEIGHT, SWITCH_HEIGHT / 2, + on ? Theme.ACCENT.value : Theme.withAlpha(0.16f, Theme.FOREGROUND.value)); + + renderScope.drawRoundedRectangle( + on ? x + SWITCH_WIDTH - inset - knob : x + inset, + y + inset, + knob, knob, knob / 2, + on ? Theme.ACCENT_FG.value : Theme.withAlpha(0.8f, Theme.PRIMARY_FG.value)); + } + @Override public void click(int mouseX, int mouseY) { prop.value = !prop.value; diff --git a/src/main/java/org/saturnclient/ui/elements/ChipGroup.java b/src/main/java/org/saturnclient/ui/elements/ChipGroup.java new file mode 100644 index 0000000..6f23659 --- /dev/null +++ b/src/main/java/org/saturnclient/ui/elements/ChipGroup.java @@ -0,0 +1,85 @@ +package org.saturnclient.ui.elements; + +import java.util.List; +import java.util.function.Consumer; + +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; + +/** + * A row of pill buttons where exactly one is selected, such as category filters. + */ +public class ChipGroup extends Element { + private static final int HEIGHT = 28; + private static final int PADDING = 14; + private static final int GAP = 8; + private static final float TEXT_SCALE = 0.62f; + + private final List options; + private final Consumer onSelect; + private String selected; + + public ChipGroup(List options, String selected, Consumer onSelect) { + this.options = options; + this.selected = selected; + this.onSelect = onSelect; + this.height = HEIGHT; + this.width = chipX(options.size()) - GAP; + } + + @Override + public void render(RenderScope renderScope, ElementContext ctx) { + int font = Theme.FONT.value; + int textY = (HEIGHT - (int) (Fonts.getHeight() * TEXT_SCALE)) / 2; + + for (int i = 0; i < options.size(); i++) { + String option = options.get(i); + int x = chipX(i); + int w = chipWidth(option); + boolean active = option.equals(selected); + boolean hovered = ctx.isHovering(x, 0, w, HEIGHT); + + if (active) { + renderScope.drawRoundedRectangle(x, 0, w, HEIGHT, HEIGHT / 2, Theme.ACCENT.value); + } else { + renderScope.drawRoundedRectangle(x, 0, w, HEIGHT, HEIGHT / 2, 1, + Theme.withAlpha(0.05f, Theme.FOREGROUND.value), + hovered ? Theme.withAlpha(0.25f, Theme.FOREGROUND.value) : Theme.getBorder()); + } + + renderScope.drawText(TEXT_SCALE, option, x + PADDING, textY, font, + active ? Theme.ACCENT_FG.value : Theme.PRIMARY_FG.value); + } + } + + @Override + public void click(int mouseX, int mouseY) { + for (int i = 0; i < options.size(); i++) { + String option = options.get(i); + int x = chipX(i); + + if (mouseX >= x && mouseX <= x + chipWidth(option)) { + if (!option.equals(selected)) { + selected = option; + onSelect.accept(option); + } + return; + } + } + } + + private int chipX(int index) { + int x = 0; + for (int i = 0; i < index; i++) { + x += chipWidth(options.get(i)) + GAP; + } + return x; + } + + private static int chipWidth(String option) { + return (int) (Fonts.getWidth(option, Theme.FONT.value) * TEXT_SCALE) + PADDING * 2; + } +} diff --git a/src/main/java/org/saturnclient/ui/elements/Label.java b/src/main/java/org/saturnclient/ui/elements/Label.java new file mode 100644 index 0000000..a0be75a --- /dev/null +++ b/src/main/java/org/saturnclient/ui/elements/Label.java @@ -0,0 +1,33 @@ +package org.saturnclient.ui.elements; + +import java.util.function.IntSupplier; +import java.util.function.Supplier; + +import org.saturnclient.ui.Element; +import org.saturnclient.ui.ElementContext; +import org.saturnclient.ui.RenderScope; +import org.saturnclient.ui.resources.Fonts; + +/** + * A line of text whose content, font and color are read on every frame, so it + * follows state and theme changes without rebuilding the screen. + */ +public class Label extends Element { + private final Supplier text; + private final float textScale; + private final IntSupplier font; + private final IntSupplier color; + + public Label(Supplier text, float textScale, IntSupplier font, IntSupplier color) { + this.text = text; + this.textScale = textScale; + this.font = font; + this.color = color; + this.height = (int) (Fonts.getHeight() * textScale); + } + + @Override + public void render(RenderScope renderScope, ElementContext ctx) { + renderScope.drawText(textScale, text.get(), 0, 0, font.getAsInt(), color.getAsInt()); + } +} diff --git a/src/main/java/org/saturnclient/ui/elements/Panel.java b/src/main/java/org/saturnclient/ui/elements/Panel.java new file mode 100644 index 0000000..2b3369e --- /dev/null +++ b/src/main/java/org/saturnclient/ui/elements/Panel.java @@ -0,0 +1,22 @@ +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; + +/** + * The translucent, outlined surface that screens lay their content on. + */ +public class Panel extends Element { + + @Override + public void render(RenderScope renderScope, ElementContext ctx) { + drawBackground(renderScope, width, height); + } + + public static void drawBackground(RenderScope renderScope, int width, int height) { + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.BG_RADIUS.value, 1, + Theme.getPanelBg(), Theme.getBorder()); + } +} diff --git a/src/main/java/org/saturnclient/ui/elements/Scroll.java b/src/main/java/org/saturnclient/ui/elements/Scroll.java index 31daaa3..fe6fcf3 100644 --- a/src/main/java/org/saturnclient/ui/elements/Scroll.java +++ b/src/main/java/org/saturnclient/ui/elements/Scroll.java @@ -17,6 +17,7 @@ public class Scroll extends Element { private static IntProperty scrollBarPadding = Property.integer(5); int padding = 0; + boolean background = true; protected List children = new ArrayList<>(); int scroll = 0; @@ -30,12 +31,31 @@ public class Scroll extends Element { ElementRenderer.draw(children, element); } + /** + * Skips the scroll's own background, for when it sits on a {@link Panel}. + */ + public Scroll noBackground() { + this.background = false; + return this; + } + + /** + * Removes every child and scrolls back to the top. + */ + public void clear() { + children.clear(); + scroll = 0; + maxScroll = 0; + } + @Override public void render(RenderScope renderScope, ElementContext ctx) { calculateMaxScroll(); - renderScope.drawRoundedRectangle(0, 0, width, height, - Theme.BG_RADIUS.value, Theme.BACKGROUND.value); + if (background) { + renderScope.drawRoundedRectangle(0, 0, width, height, + Theme.BG_RADIUS.value, Theme.BACKGROUND.value); + } renderScope.enableScissor(padding, padding, width - padding, height - padding); renderScope.getMatrixStack().push(); @@ -117,6 +137,15 @@ public class Scroll extends Element { @Override public void mouseClicked(double mouseX, double mouseY, int button) { + // Children scrolled out of view still have positions under the rest of the + // screen, so only clicks inside the scroll's own bounds may reach them. + if (mouseX < 0 || mouseY < 0 || mouseX > width || mouseY > height) { + for (Element child : children) { + child.focused = false; + } + return; + } + ElementRenderer.mouseClicked(children, mouseX - padding, mouseY - padding + scroll, button); } diff --git a/src/main/java/org/saturnclient/ui/resources/Fonts.java b/src/main/java/org/saturnclient/ui/resources/Fonts.java index 4c66770..def6d4b 100644 --- a/src/main/java/org/saturnclient/ui/resources/Fonts.java +++ b/src/main/java/org/saturnclient/ui/resources/Fonts.java @@ -44,6 +44,24 @@ public class Fonts { return 18; } + /** + * Shortens {@code text} with a trailing "…" so it fits in {@code maxWidth} + * when drawn at {@code scale}. + */ + public static String ellipsize(String text, int font, float scale, int maxWidth) { + if (getWidth(text, font) * scale <= maxWidth) { + return text; + } + + String ellipsis = "…"; + int end = text.length(); + while (end > 0 && getWidth(text.substring(0, end).stripTrailing() + ellipsis, font) * scale > maxWidth) { + end--; + } + + return text.substring(0, end).stripTrailing() + ellipsis; + } + public static int centerX(int w, String text, int font) { return (w - Fonts.getWidth(text, font)) / 2; } diff --git a/src/main/java/org/saturnclient/ui/resources/Textures.java b/src/main/java/org/saturnclient/ui/resources/Textures.java index 6058e95..68bb46b 100644 --- a/src/main/java/org/saturnclient/ui/resources/Textures.java +++ b/src/main/java/org/saturnclient/ui/resources/Textures.java @@ -25,6 +25,15 @@ public class Textures { 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"); + public static final IdentifierRef ICON_COSMETICS = IdentifierRef.ofSaturn("textures/gui/components/cosmetics.svg"); + public static final IdentifierRef ICON_HUD_EDITOR = IdentifierRef.ofSaturn("textures/gui/components/hud_editor.svg"); + public static final IdentifierRef ICON_SETTINGS = IdentifierRef.ofSaturn("textures/gui/components/settings.svg"); + public static final IdentifierRef ICON_CLOSE = IdentifierRef.ofSaturn("textures/gui/components/close.svg"); + public static final IdentifierRef ICON_SEARCH = IdentifierRef.ofSaturn("textures/gui/components/search.svg"); + public static final IdentifierRef ICON_SLIDERS = IdentifierRef.ofSaturn("textures/gui/components/sliders.svg"); + public static final IdentifierRef LOGO = IdentifierRef.ofSaturn("textures/logo/logo.png"); public static final IdentifierRef REALISTIC_LOGO = IdentifierRef.ofSaturn("textures/logo/realistic.png"); public static final IdentifierRef LOGO_TEXT = IdentifierRef.ofSaturn("textures/logo/text.png"); diff --git a/src/main/java/org/saturnclient/ui/screens/ConfigEditor.java b/src/main/java/org/saturnclient/ui/screens/ConfigEditor.java index e21245a..fb31348 100644 --- a/src/main/java/org/saturnclient/ui/screens/ConfigEditor.java +++ b/src/main/java/org/saturnclient/ui/screens/ConfigEditor.java @@ -63,7 +63,7 @@ public class ConfigEditor extends SaturnScreen { draw(scroll.dimensions(scrollWidth, 350).center(width, height)); - draw(new Sidebar(1, this.provider::close).center(width, height, -(scrollWidth / 2 + 20), 0)); + draw(new Sidebar(Sidebar.SETTINGS, this.provider::close).center(width, height, -(scrollWidth / 2 + 35), 0)); } private int drawProperties(Scroll configScroll, Map properties, int row, int col, int w) { diff --git a/src/main/java/org/saturnclient/ui/screens/ModMenu.java b/src/main/java/org/saturnclient/ui/screens/ModMenu.java index a531eca..ef6eadb 100644 --- a/src/main/java/org/saturnclient/ui/screens/ModMenu.java +++ b/src/main/java/org/saturnclient/ui/screens/ModMenu.java @@ -1,56 +1,171 @@ package org.saturnclient.ui.screens; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + import org.saturnclient.config.AnimationConfig; +import org.saturnclient.config.Theme; import org.saturnclient.mod.Mod; import org.saturnclient.mod.ModManager; import org.saturnclient.ui.SaturnScreen; import org.saturnclient.ui.anim.SlideFade; import org.saturnclient.ui.components.SaturnModule; import org.saturnclient.ui.components.Sidebar; +import org.saturnclient.ui.components.inputs.SearchInput; import org.saturnclient.ui.elements.AnimationStagger; +import org.saturnclient.ui.elements.ChipGroup; import org.saturnclient.ui.elements.ImageTexture; +import org.saturnclient.ui.elements.Label; +import org.saturnclient.ui.elements.Panel; import org.saturnclient.ui.elements.Scroll; +import org.saturnclient.ui.resources.Fonts; import org.saturnclient.ui.resources.Textures; public class ModMenu extends SaturnScreen { + private static final String ALL = "All"; + + private static final int MAX_WIDTH = 900; + private static final int MAX_HEIGHT = 580; + private static final int MARGIN = 40; + private static final int GAP = 12; + private static final int PADDING = 20; + private static final int COLUMNS = 3; + private static final int CARD_GAP = 10; + private static final int SCROLLBAR_SPACE = 14; + + private String category = ALL; + private String query = ""; + + private Scroll scroll; + private int gridWidth; + public ModMenu() { super("Mod Menu"); } @Override public void ui() { - int p = 10; - int g = 10; + // The search box starts empty after a resize, so the query does too. + query = ""; - Scroll scroll = new Scroll(p); + int panelWidth = Math.min(MAX_WIDTH, width - MARGIN * 2 - Sidebar.WIDTH - GAP); + int panelHeight = Math.min(MAX_HEIGHT, height - MARGIN * 2); + int left = (width - (Sidebar.WIDTH + GAP + panelWidth)) / 2; + int top = (height - panelHeight) / 2; + int panelX = left + Sidebar.WIDTH + GAP; + int contentX = panelX + PADDING; + gridWidth = panelWidth - PADDING * 2; - int row = 0; - int col = 0; + draw(new Sidebar(Sidebar.MODS, this.provider::close) + .dimensions(Sidebar.WIDTH, panelHeight) + .position(left, top)); - AnimationStagger moduleStagger = new AnimationStagger(AnimationConfig.modMenu); + draw(new Panel().dimensions(panelWidth, panelHeight).position(panelX, top)); - for (Mod mod : ModManager.MODS) { - moduleStagger.draw( - new SaturnModule(mod) - .position((160 + g) * col, (50 + g) * row) - .animation(new SlideFade(AnimationConfig.modMenu, -12))); + // Header + draw(new Label(() -> "Mods", 1.15f, () -> Theme.FONT.value, () -> Theme.FOREGROUND.value) + .position(contentX, top + PADDING + 2)); - if (col == 2) { - col = 0; - row++; - } else { - col++; - } - } + draw(new Label(this::getEnabledSummary, 0.66f, Theme::getBodyFont, Theme::getMutedFg) + .position(contentX, top + PADDING + 28)); - scroll.draw(moduleStagger); + SearchInput search = new SearchInput("Search mods", text -> { + query = text; + refresh(false); + }); + draw(search.position(panelX + panelWidth - PADDING - search.width, top + PADDING + 2)); - int scrollWidth = 480 + 10 + (g * 2) + (p * 2); + // Categories + int chipsY = top + PADDING + 56; + ChipGroup categories = new ChipGroup(getCategories(), category, selected -> { + category = selected; + refresh(false); + }); + draw(categories.position(contentX, chipsY)); - draw(scroll.dimensions(scrollWidth, 350).center(width, height)); - - draw(new Sidebar(0, this.provider::close).center(width, height, -(scrollWidth / 2 + 20), 0)); + // Mods + int scrollY = chipsY + categories.height + 14; + scroll = new Scroll(0).noBackground(); + scroll.dimensions(gridWidth + SCROLLBAR_SPACE, top + panelHeight - 12 - scrollY); + refresh(true); + draw(scroll.position(contentX, scrollY)); draw(new ImageTexture(Textures.LOGO_TEXT_BIG).dimensions(180, 18).position(width - 180 - 20, height - 18 - 20)); } + + /** + * Fills the grid with the mods that match the category and search query. + */ + private void refresh(boolean animate) { + scroll.clear(); + + List mods = ModManager.MODS.stream().filter(this::matches).toList(); + + if (mods.isEmpty()) { + String message = "No mods match “" + query + "”"; + float scale = 0.7f; + int x = (gridWidth - (int) (Fonts.getWidth(message, Theme.getBodyFont()) * scale)) / 2; + + scroll.draw(new Label(() -> message, scale, Theme::getBodyFont, Theme::getMutedFg).position(x, 60)); + return; + } + + int cardWidth = (gridWidth - CARD_GAP * (COLUMNS - 1)) / COLUMNS; + AnimationStagger grid = new AnimationStagger(AnimationConfig.modMenu); + + for (int i = 0; i < mods.size(); i++) { + int col = i % COLUMNS; + int row = i / COLUMNS; + + SaturnModule card = new SaturnModule(mods.get(i), cardWidth); + card.position((cardWidth + CARD_GAP) * col, (SaturnModule.HEIGHT + CARD_GAP) * row); + + if (animate) { + card.animation(new SlideFade(AnimationConfig.modMenu, -12)); + } + + grid.draw(card); + } + + scroll.draw(grid); + } + + private boolean matches(Mod mod) { + if (!category.equals(ALL) && !List.of(mod.getTags()).contains(category)) { + return false; + } + + String q = query.trim().toLowerCase(Locale.ROOT); + if (q.isEmpty()) { + return true; + } + + String description = mod.getDescription() == null ? "" : mod.getDescription(); + return mod.getName().toLowerCase(Locale.ROOT).contains(q) + || description.toLowerCase(Locale.ROOT).contains(q); + } + + /** + * "All", then every mod tag in the order it first appears. + */ + private static List getCategories() { + List categories = new ArrayList<>(); + categories.add(ALL); + + for (Mod mod : ModManager.MODS) { + for (String tag : mod.getTags()) { + if (!categories.contains(tag)) { + categories.add(tag); + } + } + } + + return categories; + } + + private String getEnabledSummary() { + long enabled = ModManager.MODS.stream().filter(Mod::isEnabled).count(); + return enabled + " of " + ModManager.MODS.size() + " enabled"; + } } diff --git a/src/main/java/org/saturnclient/ui/screens/cosmetics/CloakMenu.java b/src/main/java/org/saturnclient/ui/screens/cosmetics/CloakMenu.java index db0b936..79699d5 100644 --- a/src/main/java/org/saturnclient/ui/screens/cosmetics/CloakMenu.java +++ b/src/main/java/org/saturnclient/ui/screens/cosmetics/CloakMenu.java @@ -68,8 +68,8 @@ public class CloakMenu extends SaturnScreen { .position(scroll.x + (scrollWidth - 220), scroll.y + 40) .animation(new Fade(500))); - draw(new Sidebar(2, this.provider::close) - .center(width, height, -(scrollWidth / 2 + 20), 0)); + draw(new Sidebar(Sidebar.COSMETICS, this.provider::close) + .center(width, height, -(scrollWidth / 2 + 35), 0)); draw(new TabMenu(0, new TabMenuComponent(Textures.CLOAK, () -> { diff --git a/src/main/java/org/saturnclient/ui/screens/cosmetics/HatMenu.java b/src/main/java/org/saturnclient/ui/screens/cosmetics/HatMenu.java index 6493e23..1d2244d 100644 --- a/src/main/java/org/saturnclient/ui/screens/cosmetics/HatMenu.java +++ b/src/main/java/org/saturnclient/ui/screens/cosmetics/HatMenu.java @@ -68,8 +68,8 @@ public class HatMenu extends SaturnScreen { .position(scroll.x + (scrollWidth - 220), scroll.y + 40) .animation(new Fade(500))); - draw(new Sidebar(2, this.provider::close) - .center(width, height, -(scrollWidth / 2 + 20), 0)); + draw(new Sidebar(Sidebar.COSMETICS, this.provider::close) + .center(width, height, -(scrollWidth / 2 + 35), 0)); draw(new TabMenu(1, new TabMenuComponent(Textures.CLOAK, () -> { diff --git a/src/main/java/org/saturnclient/ui/screens/store/CloakStore.java b/src/main/java/org/saturnclient/ui/screens/store/CloakStore.java index bc62890..c6c2e7d 100644 --- a/src/main/java/org/saturnclient/ui/screens/store/CloakStore.java +++ b/src/main/java/org/saturnclient/ui/screens/store/CloakStore.java @@ -98,8 +98,8 @@ public class CloakStore extends SaturnScreen { .dimensions(scrollWidth, 350) .center(width, height, 15, 0)); - draw(new Sidebar(5, this.provider::close) - .center(width, height, -((scrollWidth - 30) / 2 + 20), 0)); + draw(new Sidebar(Sidebar.COSMETICS, this.provider::close) + .center(width, height, -((scrollWidth - 30) / 2 + 35), 0)); draw(new TabMenu(0, new TabMenuComponent(Textures.CLOAK, () -> { diff --git a/src/main/java/org/saturnclient/ui/screens/store/HatStore.java b/src/main/java/org/saturnclient/ui/screens/store/HatStore.java index c2540ec..aec83e8 100644 --- a/src/main/java/org/saturnclient/ui/screens/store/HatStore.java +++ b/src/main/java/org/saturnclient/ui/screens/store/HatStore.java @@ -98,8 +98,8 @@ public class HatStore extends SaturnScreen { .dimensions(scrollWidth, 350) .center(width, height, 15, 0)); - draw(new Sidebar(5, this.provider::close) - .center(width, height, -((scrollWidth - 30) / 2 + 20), 0)); + draw(new Sidebar(Sidebar.COSMETICS, this.provider::close) + .center(width, height, -((scrollWidth - 30) / 2 + 35), 0)); draw(new TabMenu(1, new TabMenuComponent(Textures.CLOAK, () -> { diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/close.svg b/src/main/resources/assets/saturnclient/textures/gui/components/close.svg new file mode 100644 index 0000000..c509233 --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/components/close.svg @@ -0,0 +1 @@ + diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/cosmetics.svg b/src/main/resources/assets/saturnclient/textures/gui/components/cosmetics.svg new file mode 100644 index 0000000..8eca3bb --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/components/cosmetics.svg @@ -0,0 +1 @@ + diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/hud_editor.svg b/src/main/resources/assets/saturnclient/textures/gui/components/hud_editor.svg new file mode 100644 index 0000000..3978faf --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/components/hud_editor.svg @@ -0,0 +1 @@ + diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/mods.svg b/src/main/resources/assets/saturnclient/textures/gui/components/mods.svg new file mode 100644 index 0000000..65d3912 --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/components/mods.svg @@ -0,0 +1 @@ + diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/search.svg b/src/main/resources/assets/saturnclient/textures/gui/components/search.svg new file mode 100644 index 0000000..8c7fb8d --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/components/search.svg @@ -0,0 +1 @@ + diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/settings.svg b/src/main/resources/assets/saturnclient/textures/gui/components/settings.svg new file mode 100644 index 0000000..75ba448 --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/components/settings.svg @@ -0,0 +1 @@ + diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/sliders.svg b/src/main/resources/assets/saturnclient/textures/gui/components/sliders.svg new file mode 100644 index 0000000..a433070 --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/components/sliders.svg @@ -0,0 +1 @@ + diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/clock.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/clock.svg index c928bd6..a260617 100644 --- a/src/main/resources/assets/saturnclient/textures/gui/mod/clock.svg +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/clock.svg @@ -1,7 +1 @@ - - - - - - - \ No newline at end of file + diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/crosshair.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/crosshair.svg index bb0cb50..572ac84 100644 --- a/src/main/resources/assets/saturnclient/textures/gui/mod/crosshair.svg +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/crosshair.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/nametags.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/nametags.svg index 876a0f0..233afdd 100644 --- a/src/main/resources/assets/saturnclient/textures/gui/mod/nametags.svg +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/nametags.svg @@ -1,7 +1 @@ - - - - - - - \ No newline at end of file + diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/ping.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/ping.svg index 6eaafc9..a230b11 100644 --- a/src/main/resources/assets/saturnclient/textures/gui/mod/ping.svg +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/ping.svg @@ -1,7 +1 @@ - - - - - - - \ No newline at end of file + diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/sprint.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/sprint.svg index 35e91e7..11515b0 100644 --- a/src/main/resources/assets/saturnclient/textures/gui/mod/sprint.svg +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/sprint.svg @@ -1,35 +1 @@ - - - - -Created by potrace 1.15, written by Peter Selinger 2001-2017 - - - - - - + diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/tps.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/tps.svg index f2ad6c9..7c5fed6 100644 --- a/src/main/resources/assets/saturnclient/textures/gui/mod/tps.svg +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/tps.svg @@ -1,7 +1 @@ - - - - - - performance_line - \ No newline at end of file + diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/zoom.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/zoom.svg index 320a59d..e0c3ce8 100644 --- a/src/main/resources/assets/saturnclient/textures/gui/mod/zoom.svg +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/zoom.svg @@ -1 +1 @@ - \ No newline at end of file +