Redesign the mod menu, settings and cosmetics screens #6
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user