Fix UI bugs and bring the remaining screens into the new style #7
@@ -7,32 +7,27 @@ import org.saturnclient.config.Theme;
|
|||||||
import org.saturnclient.ui.Element;
|
import org.saturnclient.ui.Element;
|
||||||
import org.saturnclient.ui.ElementContext;
|
import org.saturnclient.ui.ElementContext;
|
||||||
import org.saturnclient.ui.RenderScope;
|
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 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;
|
public static final int HEIGHT = 52;
|
||||||
|
|
||||||
private static final int PADDING = 6;
|
private static final int PADDING = 6;
|
||||||
private static final int ITEM_HEIGHT = HEIGHT - PADDING * 2;
|
private static final int ITEM = HEIGHT - PADDING * 2;
|
||||||
private static final int ITEM_PADDING = 14;
|
private static final int ICON = 18;
|
||||||
private static final int ICON = 17;
|
|
||||||
private static final int ICON_GAP = 8;
|
|
||||||
private static final int GAP = 4;
|
private static final int GAP = 4;
|
||||||
private static final float TEXT_SCALE = 0.7f;
|
|
||||||
|
|
||||||
private final List<Item> items;
|
private final List<Item> items;
|
||||||
|
|
||||||
public Dock(List<Item> items) {
|
public Dock(List<Item> items) {
|
||||||
this.items = items;
|
this.items = items;
|
||||||
this.height = HEIGHT;
|
this.height = HEIGHT;
|
||||||
this.width = getItemX(items.size()) - GAP + PADDING;
|
this.width = PADDING * 2 + items.size() * ITEM + (items.size() - 1) * GAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -41,22 +36,17 @@ public class Dock extends Element {
|
|||||||
Theme.withAlpha(0.1f, Theme.FOREGROUND.value));
|
Theme.withAlpha(0.1f, Theme.FOREGROUND.value));
|
||||||
|
|
||||||
for (int i = 0; i < items.size(); i++) {
|
for (int i = 0; i < items.size(); i++) {
|
||||||
Item item = items.get(i);
|
|
||||||
int x = getItemX(i);
|
int x = getItemX(i);
|
||||||
int itemWidth = getItemWidth(item);
|
boolean hovered = ctx.isHovering(x, PADDING, ITEM, ITEM);
|
||||||
boolean hovered = ctx.isHovering(x, PADDING, itemWidth, ITEM_HEIGHT);
|
|
||||||
|
|
||||||
if (hovered) {
|
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));
|
Theme.withAlpha(0.08f, Theme.FOREGROUND.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
int color = hovered ? Theme.ACCENT.value : Theme.PRIMARY_FG.value;
|
int offset = (ITEM - ICON) / 2;
|
||||||
renderScope.drawTexture(item.icon(), x + ITEM_PADDING, PADDING + (ITEM_HEIGHT - ICON) / 2, 0, 0, ICON,
|
renderScope.drawTexture(items.get(i).icon(), x + offset, PADDING + offset, 0, 0, ICON, ICON,
|
||||||
ICON, color);
|
hovered ? Theme.ACCENT.value : Theme.PRIMARY_FG.value);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,22 +54,14 @@ public class Dock extends Element {
|
|||||||
public void click(int mouseX, int mouseY) {
|
public void click(int mouseX, int mouseY) {
|
||||||
for (int i = 0; i < items.size(); i++) {
|
for (int i = 0; i < items.size(); i++) {
|
||||||
int x = getItemX(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();
|
items.get(i).onClick().run();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getItemX(int index) {
|
private static int getItemX(int index) {
|
||||||
int x = PADDING;
|
return PADDING + index * (ITEM + GAP);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ import org.saturnclient.ui.RenderScope;
|
|||||||
import org.saturnclient.ui.resources.Fonts;
|
import org.saturnclient.ui.resources.Fonts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A text button: primary (filled with the accent color) for the main action,
|
* A text button: a translucent, outlined surface that brightens on hover.
|
||||||
* or secondary (a translucent, outlined surface) for the rest.
|
|
||||||
*/
|
*/
|
||||||
public class Button extends Element {
|
public class Button extends Element {
|
||||||
public static final int HEIGHT = 40;
|
public static final int HEIGHT = 40;
|
||||||
@@ -16,12 +15,10 @@ public class Button extends Element {
|
|||||||
private static final float TEXT_SCALE = 0.72f;
|
private static final float TEXT_SCALE = 0.72f;
|
||||||
|
|
||||||
private final String text;
|
private final String text;
|
||||||
private final boolean primary;
|
|
||||||
private final Runnable onClick;
|
private final Runnable onClick;
|
||||||
|
|
||||||
public Button(String text, boolean primary, Runnable onClick) {
|
public Button(String text, Runnable onClick) {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.primary = primary;
|
|
||||||
this.onClick = onClick;
|
this.onClick = onClick;
|
||||||
this.width = (int) (Fonts.getWidth(text, Theme.FONT.value) * TEXT_SCALE) + 48;
|
this.width = (int) (Fonts.getWidth(text, Theme.FONT.value) * TEXT_SCALE) + 48;
|
||||||
this.height = HEIGHT;
|
this.height = HEIGHT;
|
||||||
@@ -30,29 +27,21 @@ public class Button extends Element {
|
|||||||
@Override
|
@Override
|
||||||
public void render(RenderScope renderScope, ElementContext ctx) {
|
public void render(RenderScope renderScope, ElementContext ctx) {
|
||||||
boolean hovered = ctx.isHovering();
|
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;
|
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,
|
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}.
|
* The button's surface, shared with {@link IconButton}.
|
||||||
*/
|
*/
|
||||||
static void drawSurface(RenderScope renderScope, int width, int height, boolean primary, boolean hovered) {
|
static void drawSurface(RenderScope renderScope, int width, int height, 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,
|
renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, 1,
|
||||||
hovered ? Theme.withAlpha(0.9f, Theme.PRIMARY.value) : Theme.getPanelBg(),
|
hovered ? Theme.withAlpha(0.9f, Theme.PRIMARY.value) : Theme.getPanelBg(),
|
||||||
Theme.withAlpha(hovered ? 0.25f : 0.1f, Theme.FOREGROUND.value));
|
Theme.withAlpha(hovered ? 0.25f : 0.1f, Theme.FOREGROUND.value));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void click(int mouseX, int mouseY) {
|
public void click(int mouseX, int mouseY) {
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import org.saturnclient.ui.ElementContext;
|
|||||||
import org.saturnclient.ui.RenderScope;
|
import org.saturnclient.ui.RenderScope;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A square secondary {@link Button} showing an icon, which turns the accent
|
* A square {@link Button} showing an icon, which turns the accent color on
|
||||||
* color on hover.
|
* hover.
|
||||||
*/
|
*/
|
||||||
public class IconButton extends Element {
|
public class IconButton extends Element {
|
||||||
private static final float ICON_RATIO = 0.48f;
|
private static final float ICON_RATIO = 0.48f;
|
||||||
@@ -26,7 +26,7 @@ public class IconButton extends Element {
|
|||||||
@Override
|
@Override
|
||||||
public void render(RenderScope renderScope, ElementContext ctx) {
|
public void render(RenderScope renderScope, ElementContext ctx) {
|
||||||
boolean hovered = ctx.isHovering();
|
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);
|
int size = (int) (Math.min(width, height) * ICON_RATIO);
|
||||||
renderScope.drawTexture(icon, (width - size) / 2, (height - size) / 2, 0, 0, size, size,
|
renderScope.drawTexture(icon, (width - size) / 2, (height - size) / 2, 0, 0, size, size,
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class ShiftMenu extends SaturnScreen {
|
|||||||
.position(x, 0).animation(new Fade(AnimationConfig.shiftMenu)));
|
.position(x, 0).animation(new Fade(AnimationConfig.shiftMenu)));
|
||||||
x += Button.HEIGHT + GAP;
|
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)
|
.dimensions(MODS_WIDTH, Button.HEIGHT)
|
||||||
.position(x, 0).animation(new Fade(AnimationConfig.shiftMenu)));
|
.position(x, 0).animation(new Fade(AnimationConfig.shiftMenu)));
|
||||||
x += MODS_WIDTH + GAP;
|
x += MODS_WIDTH + GAP;
|
||||||
|
|||||||
@@ -61,16 +61,16 @@ public class TitleMenu extends SaturnScreen {
|
|||||||
int halfWidth = (COLUMN_WIDTH - GAP) / 2;
|
int halfWidth = (COLUMN_WIDTH - GAP) / 2;
|
||||||
AnimationStagger menus = new AnimationStagger(AnimationConfig.mainMenu);
|
AnimationStagger menus = new AnimationStagger(AnimationConfig.mainMenu);
|
||||||
|
|
||||||
addMenuButton(menus, new Button("Singleplayer", true,
|
addMenuButton(menus, new Button("Singleplayer",
|
||||||
() -> Providers.saturn.getClient().setScreen(MinecraftScreen.SelectWorld))
|
() -> Providers.saturn.getClient().setScreen(MinecraftScreen.SelectWorld))
|
||||||
.dimensions(COLUMN_WIDTH, BUTTON_HEIGHT).position(0, 0));
|
.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))
|
() -> Providers.saturn.getClient().setScreen(MinecraftScreen.Multiplayer))
|
||||||
.dimensions(COLUMN_WIDTH, BUTTON_HEIGHT).position(0, rowHeight));
|
.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))
|
() -> Providers.saturn.getClient().setScreen(MinecraftScreen.Options))
|
||||||
.dimensions(halfWidth, BUTTON_HEIGHT).position(0, rowHeight * 2));
|
.dimensions(halfWidth, BUTTON_HEIGHT).position(0, rowHeight * 2));
|
||||||
addMenuButton(menus, new Button("Quit", false,
|
addMenuButton(menus, new Button("Quit",
|
||||||
() -> Providers.saturn.getClient().scheduleStop())
|
() -> Providers.saturn.getClient().scheduleStop())
|
||||||
.dimensions(halfWidth, BUTTON_HEIGHT).position(COLUMN_WIDTH - halfWidth, rowHeight * 2));
|
.dimensions(halfWidth, BUTTON_HEIGHT).position(COLUMN_WIDTH - halfWidth, rowHeight * 2));
|
||||||
|
|
||||||
@@ -82,11 +82,10 @@ public class TitleMenu extends SaturnScreen {
|
|||||||
.animation(new Fade(AnimationConfig.mainMenu)));
|
.animation(new Fade(AnimationConfig.mainMenu)));
|
||||||
|
|
||||||
Dock dock = new Dock(List.of(
|
Dock dock = new Dock(List.of(
|
||||||
new Dock.Item(Textures.ICON_MODS, "Mods",
|
new Dock.Item(Textures.ICON_MODS, () -> Providers.saturn.getClient().setScreen(new ModMenu())),
|
||||||
() -> Providers.saturn.getClient().setScreen(new ModMenu())),
|
new Dock.Item(Textures.ICON_COSMETICS,
|
||||||
new Dock.Item(Textures.ICON_COSMETICS, "Cosmetics",
|
|
||||||
() -> Providers.saturn.getClient().setScreen(new CosmeticsMenu())),
|
() -> 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()))));
|
() -> Providers.saturn.getClient().setScreen(new HudEditor()))));
|
||||||
draw(dock.position((width - dock.width) / 2, height - EDGE - Dock.HEIGHT)
|
draw(dock.position((width - dock.width) / 2, height - EDGE - Dock.HEIGHT)
|
||||||
.animation(new SlideFade(AnimationConfig.mainMenu, 12)));
|
.animation(new SlideFade(AnimationConfig.mainMenu, 12)));
|
||||||
|
|||||||
Reference in New Issue
Block a user