The world or panorama keeps its animated background blur, while glass behind menus and behind widgets (buttons, the dock, the account chip) each get a fixed blur of their own. Glass is left out when its blur is 0. Co-Authored-By: Claude Opus 5.5 <[email protected]>
182 lines
6.5 KiB
Java
182 lines
6.5 KiB
Java
package org.saturnclient.ui.screens;
|
|
|
|
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.property.FloatProperty;
|
|
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.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.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 {
|
|
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");
|
|
}
|
|
|
|
@Override
|
|
protected FloatProperty getScaleSetting() {
|
|
return Config.hudMenuScale;
|
|
}
|
|
|
|
@Override
|
|
public void ui() {
|
|
List<String> emotes = Emotes.availableEmotes;
|
|
int left = (width - GRID) / 2;
|
|
int top = (height - GRID) / 2 + LOGO / 2;
|
|
|
|
draw(new ImageTexture(Config.getLogo())
|
|
.dimensions(LOGO, LOGO)
|
|
.position((width - LOGO) / 2, top - 20 - LOGO)
|
|
.animation(new SlideY(AnimationConfig.logo, -12)));
|
|
|
|
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;
|
|
}
|
|
|
|
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.drawGlassRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, Config.widgetBlur.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;
|
|
}
|
|
}
|
|
}
|