Add layers to Gui API so specific elements can be drawn on top of others and react to mouse clicks first
This commit is contained in:
@@ -45,10 +45,6 @@ public class OffsetGuiRenderer implements GuiRenderer {
|
|||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
if (size.getHeight() > renderer.getSize().getHeight()
|
|
||||||
|| size.getWidth() > renderer.getSize().getWidth()) {
|
|
||||||
throw new IllegalArgumentException("Size must not be larger than size of renderer.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -31,9 +31,14 @@ public class RenderInfo {
|
|||||||
public final float partialTick;
|
public final float partialTick;
|
||||||
public final int mouseX;
|
public final int mouseX;
|
||||||
public final int mouseY;
|
public final int mouseY;
|
||||||
|
public final int layer;
|
||||||
|
|
||||||
public RenderInfo offsetMouse(int minusX, int minusY) {
|
public RenderInfo offsetMouse(int minusX, int minusY) {
|
||||||
return new RenderInfo(partialTick, mouseX - minusX, mouseY - minusY);
|
return new RenderInfo(partialTick, mouseX - minusX, mouseY - minusY, layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenderInfo layer(int layer) {
|
||||||
|
return new RenderInfo(partialTick, mouseX, mouseY, layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addTo(CrashReport crashReport) {
|
public void addTo(CrashReport crashReport) {
|
||||||
@@ -41,5 +46,6 @@ public class RenderInfo {
|
|||||||
category.addCrashSection("Partial Tick", partialTick);
|
category.addCrashSection("Partial Tick", partialTick);
|
||||||
category.addCrashSection("Mouse X", mouseX);
|
category.addCrashSection("Mouse X", mouseX);
|
||||||
category.addCrashSection("Mouse Y", mouseY);
|
category.addCrashSection("Mouse Y", mouseY);
|
||||||
|
category.addCrashSection("Layer", layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import de.johni0702.minecraft.gui.GuiRenderer;
|
|||||||
import de.johni0702.minecraft.gui.OffsetGuiRenderer;
|
import de.johni0702.minecraft.gui.OffsetGuiRenderer;
|
||||||
import de.johni0702.minecraft.gui.RenderInfo;
|
import de.johni0702.minecraft.gui.RenderInfo;
|
||||||
import de.johni0702.minecraft.gui.element.AbstractComposedGuiElement;
|
import de.johni0702.minecraft.gui.element.AbstractComposedGuiElement;
|
||||||
|
import de.johni0702.minecraft.gui.element.ComposedGuiElement;
|
||||||
import de.johni0702.minecraft.gui.element.GuiElement;
|
import de.johni0702.minecraft.gui.element.GuiElement;
|
||||||
import de.johni0702.minecraft.gui.layout.Layout;
|
import de.johni0702.minecraft.gui.layout.Layout;
|
||||||
import de.johni0702.minecraft.gui.layout.LayoutData;
|
import de.johni0702.minecraft.gui.layout.LayoutData;
|
||||||
@@ -129,6 +130,16 @@ public abstract class AbstractGuiContainer<T extends AbstractGuiContainer<T>>
|
|||||||
throw new ReportedException(crashReport);
|
throw new ReportedException(crashReport);
|
||||||
}
|
}
|
||||||
for (final Map.Entry<GuiElement, Pair<ReadablePoint, ReadableDimension>> e : layedOutElements.entrySet()) {
|
for (final Map.Entry<GuiElement, Pair<ReadablePoint, ReadableDimension>> e : layedOutElements.entrySet()) {
|
||||||
|
GuiElement element = e.getKey();
|
||||||
|
if (element instanceof ComposedGuiElement) {
|
||||||
|
if (((ComposedGuiElement) element).getMaxLayer() < renderInfo.layer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (element.getLayer() != renderInfo.layer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
final ReadablePoint ePosition = e.getValue().getLeft();
|
final ReadablePoint ePosition = e.getValue().getLeft();
|
||||||
final ReadableDimension eSize = e.getValue().getRight();
|
final ReadableDimension eSize = e.getValue().getRight();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -67,67 +67,70 @@ public abstract class AbstractGuiScreen<T extends AbstractGuiScreen<T>> extends
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
|
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
|
||||||
if (drawBackground) {
|
if (renderInfo.layer == 0) {
|
||||||
wrapped.drawDefaultBackground();
|
if (drawBackground) {
|
||||||
}
|
wrapped.drawDefaultBackground();
|
||||||
if (title != null) {
|
}
|
||||||
ReadableDimension titleSize = title.getMinSize();
|
if (title != null) {
|
||||||
int x = screenSize.getWidth() / 2 - titleSize.getWidth() / 2;
|
ReadableDimension titleSize = title.getMinSize();
|
||||||
OffsetGuiRenderer eRenderer = new OffsetGuiRenderer(renderer, new Point(x, 10), new Dimension(0, 0));
|
int x = screenSize.getWidth() / 2 - titleSize.getWidth() / 2;
|
||||||
title.draw(eRenderer, titleSize, null);
|
OffsetGuiRenderer eRenderer = new OffsetGuiRenderer(renderer, new Point(x, 10), new Dimension(0, 0));
|
||||||
|
title.draw(eRenderer, titleSize, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
super.draw(renderer, size, renderInfo);
|
super.draw(renderer, size, renderInfo);
|
||||||
|
if (renderInfo.layer == getMaxLayer()) {
|
||||||
final GuiElement tooltip = forEach(GuiElement.class).getTooltip(renderInfo);
|
final GuiElement tooltip = forEach(GuiElement.class).getTooltip(renderInfo);
|
||||||
if (tooltip != null) {
|
if (tooltip != null) {
|
||||||
final ReadableDimension tooltipSize = tooltip.getMinSize();
|
final ReadableDimension tooltipSize = tooltip.getMinSize();
|
||||||
int dx, dy;
|
int dx, dy;
|
||||||
if (renderInfo.mouseX + 8 + tooltipSize.getWidth() < screenSize.getWidth()) {
|
if (renderInfo.mouseX + 8 + tooltipSize.getWidth() < screenSize.getWidth()) {
|
||||||
dx = 8;
|
dx = 8;
|
||||||
} else {
|
} else {
|
||||||
dx = -8;
|
dx = -8;
|
||||||
}
|
}
|
||||||
if (renderInfo.mouseY + 8 + tooltipSize.getHeight() < screenSize.getHeight()) {
|
if (renderInfo.mouseY + 8 + tooltipSize.getHeight() < screenSize.getHeight()) {
|
||||||
dy = 8;
|
dy = 8;
|
||||||
} else {
|
} else {
|
||||||
dy = -8;
|
dy = -8;
|
||||||
}
|
}
|
||||||
final ReadablePoint position = new Point(renderInfo.mouseX + dx, renderInfo.mouseY + dy);
|
final ReadablePoint position = new Point(renderInfo.mouseX + dx, renderInfo.mouseY + dy);
|
||||||
try {
|
try {
|
||||||
OffsetGuiRenderer eRenderer = new OffsetGuiRenderer(renderer, position, tooltipSize);
|
OffsetGuiRenderer eRenderer = new OffsetGuiRenderer(renderer, position, tooltipSize);
|
||||||
tooltip.draw(eRenderer, tooltipSize, renderInfo.offsetMouse(position.getX(), position.getY()));
|
tooltip.draw(eRenderer, tooltipSize, renderInfo.offsetMouse(position.getX(), position.getY()));
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
CrashReport crashReport = CrashReport.makeCrashReport(ex, "Rendering Gui Tooltip");
|
CrashReport crashReport = CrashReport.makeCrashReport(ex, "Rendering Gui Tooltip");
|
||||||
renderInfo.addTo(crashReport);
|
renderInfo.addTo(crashReport);
|
||||||
CrashReportCategory category = crashReport.makeCategory("Gui container details");
|
CrashReportCategory category = crashReport.makeCategory("Gui container details");
|
||||||
category.addCrashSectionCallable("Container", new Callable() {
|
category.addCrashSectionCallable("Container", new Callable() {
|
||||||
@Override
|
@Override
|
||||||
public Object call() throws Exception {
|
public Object call() throws Exception {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
category.addCrashSection("Width", size.getWidth());
|
category.addCrashSection("Width", size.getWidth());
|
||||||
category.addCrashSection("Height", size.getHeight());
|
category.addCrashSection("Height", size.getHeight());
|
||||||
category = crashReport.makeCategory("Tooltip details");
|
category = crashReport.makeCategory("Tooltip details");
|
||||||
category.addCrashSectionCallable("Element", new Callable() {
|
category.addCrashSectionCallable("Element", new Callable() {
|
||||||
@Override
|
@Override
|
||||||
public Object call() throws Exception {
|
public Object call() throws Exception {
|
||||||
return tooltip;
|
return tooltip;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
category.addCrashSectionCallable("Position", new Callable() {
|
category.addCrashSectionCallable("Position", new Callable() {
|
||||||
@Override
|
@Override
|
||||||
public Object call() throws Exception {
|
public Object call() throws Exception {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
category.addCrashSectionCallable("Size", new Callable() {
|
category.addCrashSectionCallable("Size", new Callable() {
|
||||||
@Override
|
@Override
|
||||||
public Object call() throws Exception {
|
public Object call() throws Exception {
|
||||||
return tooltipSize;
|
return tooltipSize;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
throw new ReportedException(crashReport);
|
throw new ReportedException(crashReport);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,7 +162,10 @@ public abstract class AbstractGuiScreen<T extends AbstractGuiScreen<T>> extends
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
|
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
|
||||||
draw(renderer, screenSize, new RenderInfo(partialTicks, mouseX, mouseY));
|
int layers = getMaxLayer();
|
||||||
|
for (int layer = 0; layer <= layers; layer++) {
|
||||||
|
draw(renderer, screenSize, new RenderInfo(partialTicks, mouseX, mouseY, layer));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ import net.minecraft.util.ReportedException;
|
|||||||
import java.lang.reflect.InvocationHandler;
|
import java.lang.reflect.InvocationHandler;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
public abstract class AbstractComposedGuiElement<T extends AbstractComposedGuiElement<T>>
|
public abstract class AbstractComposedGuiElement<T extends AbstractComposedGuiElement<T>>
|
||||||
@@ -41,19 +43,103 @@ public abstract class AbstractComposedGuiElement<T extends AbstractComposedGuiEl
|
|||||||
super(container);
|
super(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxLayer() {
|
||||||
|
int maxLayer = getLayer();
|
||||||
|
for (GuiElement element : getChildren()) {
|
||||||
|
int elementMaxLayer;
|
||||||
|
if (element instanceof ComposedGuiElement) {
|
||||||
|
elementMaxLayer = ((ComposedGuiElement) element).getMaxLayer();
|
||||||
|
} else {
|
||||||
|
elementMaxLayer = element.getLayer();
|
||||||
|
}
|
||||||
|
if (elementMaxLayer > maxLayer) {
|
||||||
|
maxLayer = elementMaxLayer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxLayer;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <C> C forEach(final Class<C> ofType) {
|
public <C> C forEach(final Class<C> ofType) {
|
||||||
|
int maxLayer = getMaxLayer();
|
||||||
|
final List<C> layers = new ArrayList<C>(maxLayer + 1);
|
||||||
|
for (int i = 0; i <= maxLayer; i++) {
|
||||||
|
layers.add(forEach(i, ofType));
|
||||||
|
}
|
||||||
return (C) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{ofType}, new InvocationHandler() {
|
return (C) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{ofType}, new InvocationHandler() {
|
||||||
@Override
|
@Override
|
||||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||||
boolean isGetter = method.getName().startsWith("get");
|
boolean isGetter = method.getName().startsWith("get");
|
||||||
Object handled = null;
|
Object handled = method.getReturnType().equals(Boolean.class) ? false : null;
|
||||||
|
for (final C layer : layers) {
|
||||||
|
handled = method.invoke(layer, args);
|
||||||
|
if (handled != null) {
|
||||||
|
if (handled instanceof Boolean) {
|
||||||
|
if (Boolean.TRUE.equals(handled)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (isGetter) {
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <C> C forEach(final int layer, final Class<C> ofType) {
|
||||||
|
return (C) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{ofType}, new InvocationHandler() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||||
|
boolean isGetter = method.getName().startsWith("get");
|
||||||
|
Object handled = method.getReturnType().equals(boolean.class) ? false : null;
|
||||||
|
final AbstractComposedGuiElement self = AbstractComposedGuiElement.this;
|
||||||
|
if (ofType.isInstance(self) && self.getLayer() == layer) {
|
||||||
|
try {
|
||||||
|
handled = method.invoke(self, args);
|
||||||
|
} catch (Exception e) {
|
||||||
|
CrashReport crash = CrashReport.makeCrashReport(e, "Calling Gui method");
|
||||||
|
CrashReportCategory category = crash.makeCategory("Gui");
|
||||||
|
category.addCrashSection("Method", method);
|
||||||
|
category.addCrashSectionCallable("ComposedElement", new Callable() {
|
||||||
|
@Override
|
||||||
|
public Object call() throws Exception {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
category.addCrashSectionCallable("Element", new Callable() {
|
||||||
|
@Override
|
||||||
|
public Object call() throws Exception {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
throw new ReportedException(crash);
|
||||||
|
}
|
||||||
|
if (handled != null) {
|
||||||
|
if (handled instanceof Boolean) {
|
||||||
|
if (Boolean.TRUE.equals(handled)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (isGetter) {
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
for (final GuiElement element : getChildren()) {
|
for (final GuiElement element : getChildren()) {
|
||||||
try {
|
try {
|
||||||
if (element instanceof ComposedGuiElement) {
|
if (element instanceof ComposedGuiElement) {
|
||||||
handled = method.invoke(((ComposedGuiElement) element).forEach(ofType), args);
|
ComposedGuiElement composed = (ComposedGuiElement) element;
|
||||||
} else if (ofType.isInstance(element)) {
|
if (layer <= composed.getMaxLayer()) {
|
||||||
|
Object elementProxy = composed.forEach(layer, ofType);
|
||||||
|
handled = method.invoke(elementProxy, args);
|
||||||
|
}
|
||||||
|
} else if (ofType.isInstance(element) && element.getLayer() == layer) {
|
||||||
handled = method.invoke(element, args);
|
handled = method.invoke(element, args);
|
||||||
}
|
}
|
||||||
if (handled != null) {
|
if (handled != null) {
|
||||||
|
|||||||
@@ -147,6 +147,10 @@ public abstract class AbstractGuiElement<T extends AbstractGuiElement<T>> implem
|
|||||||
return getThis();
|
return getThis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getLayer() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ReadableDimension getMaxSize() {
|
public ReadableDimension getMaxSize() {
|
||||||
return maxSize == null ? getPreferredSize() : maxSize;
|
return maxSize == null ? getPreferredSize() : maxSize;
|
||||||
|
|||||||
@@ -28,4 +28,13 @@ public interface ComposedGuiElement<T extends ComposedGuiElement<T>> extends Gui
|
|||||||
Collection<GuiElement> getChildren();
|
Collection<GuiElement> getChildren();
|
||||||
|
|
||||||
<C> C forEach(Class<C> ofType);
|
<C> C forEach(Class<C> ofType);
|
||||||
|
<C> C forEach(int layer, Class<C> ofType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the highest layer this element or any of its children take part in.
|
||||||
|
* Events will be called for this composed gui element for all layers between
|
||||||
|
* layer 0 (inclusive) and the returned maximum layer (inclusive).
|
||||||
|
* @return Highest layer relevant to this element
|
||||||
|
*/
|
||||||
|
int getMaxLayer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,4 +52,11 @@ public interface GuiElement<T extends GuiElement<T>> {
|
|||||||
GuiElement getTooltip(RenderInfo renderInfo);
|
GuiElement getTooltip(RenderInfo renderInfo);
|
||||||
T setTooltip(GuiElement tooltip);
|
T setTooltip(GuiElement tooltip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the layer this element takes part in.
|
||||||
|
* The standard layer is layer 0. Event handlers will be called for this layer.
|
||||||
|
* @return The layer of this element
|
||||||
|
*/
|
||||||
|
int getLayer();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user