Redesign the mod menu, settings and cosmetics screens #6
@@ -1,24 +1,54 @@
|
|||||||
package org.saturnclient.ui;
|
package org.saturnclient.ui;
|
||||||
|
|
||||||
public class ElementContext {
|
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;
|
public int mouseX, mouseY;
|
||||||
/** The element's top-left corner on the screen, for placing popups next to it */
|
/** The element's top-left corner on the screen, for placing popups next to it */
|
||||||
public int originX, originY;
|
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 int elementWidth, elementHeight;
|
||||||
public float elementScale;
|
public float elementScale;
|
||||||
public long elapsed;
|
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.mouseX = mouseX - e.x;
|
||||||
this.mouseY = mouseY - e.y;
|
this.mouseY = mouseY - e.y;
|
||||||
this.originX = parentX + e.x;
|
this.originX = frame.x() + e.x;
|
||||||
this.originY = parentY + e.y;
|
this.originY = frame.y() + e.y;
|
||||||
|
this.visibleTop = frame.visibleTop();
|
||||||
|
this.visibleBottom = frame.visibleBottom();
|
||||||
this.elementWidth = e.width;
|
this.elementWidth = e.width;
|
||||||
this.elementHeight = e.height;
|
this.elementHeight = e.height;
|
||||||
this.elementScale = e.scale;
|
this.elementScale = e.scale;
|
||||||
this.elapsed = elapsed;
|
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() {
|
public boolean isHovering() {
|
||||||
return Utils.isHovering(mouseX, mouseY, elementWidth, elementHeight, elementScale);
|
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) {
|
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
|
* Renders a container's children within its {@code frame}.
|
||||||
* ({@code parentX}, {@code parentY}) on the screen.
|
|
||||||
*/
|
*/
|
||||||
public static void render(List<Element> elements, long elapsed, RenderScope renderScope, int mouseX, int mouseY,
|
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) {
|
for (Element element : elements) {
|
||||||
element.playAnimationFrame(elapsed);
|
element.playAnimationFrame(elapsed);
|
||||||
|
|
||||||
@@ -31,7 +30,7 @@ public class ElementRenderer {
|
|||||||
renderScope.setOpacity(element.opacity);
|
renderScope.setOpacity(element.opacity);
|
||||||
renderScope.getMatrixStack().translate(element.x, element.y);
|
renderScope.getMatrixStack().translate(element.x, element.y);
|
||||||
renderScope.getMatrixStack().scale(element.scale, element.scale);
|
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();
|
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
|
* Opens {@code popup} just below its owner if it fits in the part of the
|
||||||
* room below.
|
* 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 ownerContext the owner's context from its last render
|
||||||
* @param originY
|
|
||||||
*/
|
*/
|
||||||
public static void openBelow(Element owner, Element popup, int originX, int originY) {
|
public static void openBelow(Element owner, Element popup, ElementContext ownerContext) {
|
||||||
int y = originY + owner.height + OWNER_GAP;
|
int top = Math.max(ownerContext.visibleTop, SCREEN_MARGIN);
|
||||||
|
int bottom = Math.min(ownerContext.visibleBottom, screenHeight - SCREEN_MARGIN);
|
||||||
|
|
||||||
if (y + popup.height > screenHeight - SCREEN_MARGIN) {
|
int below = ownerContext.originY + owner.height + OWNER_GAP;
|
||||||
y = originY - OWNER_GAP - popup.height;
|
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() {
|
public static void close() {
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ public class Select extends Element {
|
|||||||
|
|
||||||
private final SelectProperty prop;
|
private final SelectProperty prop;
|
||||||
|
|
||||||
/** Where this was last drawn on the screen, to open the list under it */
|
/** The context this was last drawn with, to open the list next to it */
|
||||||
private int originX, originY;
|
private ElementContext lastContext;
|
||||||
|
|
||||||
public Select(SelectProperty prop) {
|
public Select(SelectProperty prop) {
|
||||||
this.prop = prop;
|
this.prop = prop;
|
||||||
@@ -32,8 +32,7 @@ public class Select extends Element {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(RenderScope renderScope, ElementContext ctx) {
|
public void render(RenderScope renderScope, ElementContext ctx) {
|
||||||
originX = ctx.originX;
|
lastContext = ctx;
|
||||||
originY = ctx.originY;
|
|
||||||
boolean open = Popup.isOpenFor(this);
|
boolean open = Popup.isOpenFor(this);
|
||||||
|
|
||||||
Field.drawBox(renderScope, width, height, ctx.isHovering(), open);
|
Field.drawBox(renderScope, width, height, ctx.isHovering(), open);
|
||||||
@@ -55,6 +54,6 @@ public class Select extends Element {
|
|||||||
Popup.close();
|
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,
|
ElementRenderer.render(children, ctx.elapsed, renderScope,
|
||||||
ctx.mouseX,
|
ctx.mouseX,
|
||||||
ctx.mouseY,
|
ctx.mouseY,
|
||||||
ctx.originX,
|
ctx.childFrame());
|
||||||
ctx.originY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -81,8 +81,7 @@ public class Scroll extends Element {
|
|||||||
ElementRenderer.render(children, ctx.elapsed, renderScope,
|
ElementRenderer.render(children, ctx.elapsed, renderScope,
|
||||||
ctx.mouseX - padding,
|
ctx.mouseX - padding,
|
||||||
ctx.mouseY - padding + offset,
|
ctx.mouseY - padding + offset,
|
||||||
ctx.originX + padding,
|
ctx.childFrame(padding, padding - offset, padding, height - padding));
|
||||||
ctx.originY + padding - offset);
|
|
||||||
|
|
||||||
renderScope.getMatrixStack().pop();
|
renderScope.getMatrixStack().pop();
|
||||||
renderScope.disableScissor();
|
renderScope.disableScissor();
|
||||||
|
|||||||
Reference in New Issue
Block a user