Redesign the mod menu, settings and cosmetics screens #6

Merged
selimaj-dev merged 13 commits from ui-redesign into master 2026-09-27 16:27:35 +00:00
6 changed files with 58 additions and 27 deletions
Showing only changes of commit 8b58fe919d - Show all commits
@@ -1,24 +1,54 @@
package org.saturnclient.ui;
public class ElementContext {
/**
* Where a container's children are drawn: the screen position of their
* (0, 0), and the part of the screen, top to bottom, where they can be seen.
*/
public record Frame(int x, int y, int visibleTop, int visibleBottom) {
/** The whole screen, for top-level elements */
public static final Frame SCREEN = new Frame(0, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
public int mouseX, mouseY;
/** The element's top-left corner on the screen, for placing popups next to it */
public int originX, originY;
/** The part of the screen, top to bottom, where the element can be seen */
public int visibleTop, visibleBottom;
public int elementWidth, elementHeight;
public float elementScale;
public long elapsed;
public ElementContext(long elapsed, int mouseX, int mouseY, int parentX, int parentY, Element e) {
public ElementContext(long elapsed, int mouseX, int mouseY, Frame frame, Element e) {
this.mouseX = mouseX - e.x;
this.mouseY = mouseY - e.y;
this.originX = parentX + e.x;
this.originY = parentY + e.y;
this.originX = frame.x() + e.x;
this.originY = frame.y() + e.y;
this.visibleTop = frame.visibleTop();
this.visibleBottom = frame.visibleBottom();
this.elementWidth = e.width;
this.elementHeight = e.height;
this.elementScale = e.scale;
this.elapsed = elapsed;
}
/**
* The frame for this element's children, drawn {@code dx}, {@code dy} from
* its corner and seen only between {@code clipTop} and {@code clipBottom}
* (relative to its corner).
*/
public Frame childFrame(int dx, int dy, int clipTop, int clipBottom) {
return new Frame(originX + dx, originY + dy,
Math.max(visibleTop, originY + clipTop), Math.min(visibleBottom, originY + clipBottom));
}
/**
* The frame for children drawn at this element's corner and not clipped.
*/
public Frame childFrame() {
return new Frame(originX, originY, visibleTop, visibleBottom);
}
public boolean isHovering() {
return Utils.isHovering(mouseX, mouseY, elementWidth, elementHeight, elementScale);
}
@@ -15,15 +15,14 @@ public class ElementRenderer {
}
public static void render(List<Element> elements, long elapsed, RenderScope renderScope, int mouseX, int mouseY) {
render(elements, elapsed, renderScope, mouseX, mouseY, 0, 0);
render(elements, elapsed, renderScope, mouseX, mouseY, ElementContext.Frame.SCREEN);
}
/**
* Renders elements whose parent's top-left corner is at
* ({@code parentX}, {@code parentY}) on the screen.
* Renders a container's children within its {@code frame}.
*/
public static void render(List<Element> elements, long elapsed, RenderScope renderScope, int mouseX, int mouseY,
int parentX, int parentY) {
ElementContext.Frame frame) {
for (Element element : elements) {
element.playAnimationFrame(elapsed);
@@ -31,7 +30,7 @@ public class ElementRenderer {
renderScope.setOpacity(element.opacity);
renderScope.getMatrixStack().translate(element.x, element.y);
renderScope.getMatrixStack().scale(element.scale, element.scale);
element.render(renderScope, new ElementContext(elapsed, mouseX, mouseY, parentX, parentY, element));
element.render(renderScope, new ElementContext(elapsed, mouseX, mouseY, frame, element));
renderScope.getMatrixStack().pop();
}
}
+15 -10
View File
@@ -37,20 +37,25 @@ public final class Popup {
}
/**
* Opens {@code popup} just below its owner, or above it when there isn't
* room below.
* Opens {@code popup} just below its owner if it fits in the part of the
* screen where the owner can be seen, such as a scroll's box; otherwise
* above it if it fits there, or else on the side with more room.
*
* @param originX the owner's top-left corner on the screen
* @param originY
* @param ownerContext the owner's context from its last render
*/
public static void openBelow(Element owner, Element popup, int originX, int originY) {
int y = originY + owner.height + OWNER_GAP;
public static void openBelow(Element owner, Element popup, ElementContext ownerContext) {
int top = Math.max(ownerContext.visibleTop, SCREEN_MARGIN);
int bottom = Math.min(ownerContext.visibleBottom, screenHeight - SCREEN_MARGIN);
if (y + popup.height > screenHeight - SCREEN_MARGIN) {
y = originY - OWNER_GAP - popup.height;
}
int below = ownerContext.originY + owner.height + OWNER_GAP;
int above = ownerContext.originY - OWNER_GAP - popup.height;
open(owner, popup, originX, y);
boolean fitsBelow = below + popup.height <= bottom;
boolean fitsAbove = above >= top;
boolean moreRoomBelow = bottom - below >= ownerContext.originY - OWNER_GAP - top;
int y = fitsBelow || (!fitsAbove && moreRoomBelow) ? below : above;
open(owner, popup, ownerContext.originX, y);
}
public static void close() {
@@ -21,8 +21,8 @@ public class Select extends Element {
private final SelectProperty prop;
/** Where this was last drawn on the screen, to open the list under it */
private int originX, originY;
/** The context this was last drawn with, to open the list next to it */
private ElementContext lastContext;
public Select(SelectProperty prop) {
this.prop = prop;
@@ -32,8 +32,7 @@ public class Select extends Element {
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
originX = ctx.originX;
originY = ctx.originY;
lastContext = ctx;
boolean open = Popup.isOpenFor(this);
Field.drawBox(renderScope, width, height, ctx.isHovering(), open);
@@ -55,6 +54,6 @@ public class Select extends Element {
Popup.close();
});
Popup.openBelow(this, list, originX, originY);
Popup.openBelow(this, list, lastContext);
}
}
@@ -42,8 +42,7 @@ public class AnimationStagger extends Element {
ElementRenderer.render(children, ctx.elapsed, renderScope,
ctx.mouseX,
ctx.mouseY,
ctx.originX,
ctx.originY);
ctx.childFrame());
}
@Override
@@ -81,8 +81,7 @@ public class Scroll extends Element {
ElementRenderer.render(children, ctx.elapsed, renderScope,
ctx.mouseX - padding,
ctx.mouseY - padding + offset,
ctx.originX + padding,
ctx.originY + padding - offset);
ctx.childFrame(padding, padding - offset, padding, height - padding));
renderScope.getMatrixStack().pop();
renderScope.disableScissor();