Redesign the mod menu
The mod menu is now a translucent panel beside a navigation rail, with a header showing how many mods are enabled, a search box, category filters built from the mods' tags and a three-column grid of mod cards. Each card shows the mod's icon, name and description with a settings button and an on/off switch. The layout shrinks to fit smaller windows. New reusable pieces: Panel, Label, ChipGroup, SearchInput, Toggle.drawSwitch, Theme helpers for panel, border, muted text and body font, and Fonts.ellipsize. The sidebar and card icons are Lucide SVGs, and seven mod icons were redrawn in the same style. Scroll can skip its background and be cleared, and no longer passes clicks outside its bounds to children scrolled out of view. Input checks overflow and places the cursor at the scale its text is drawn at. Screens that are not redesigned yet move the wider sidebar so it keeps its gap. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user