Split mod into core, recording, replay, render[todo], paths[todo] and extras[wip] modules

Move everything to com.replaymod package
Add KeyBindingRegistry and SettingsRegistry
Recreate settings GUI with new GUI API and dynamically from SettingsRegistry
Use ReplayFile from ReplayStudio
ReplayHandler is now object oriented
Add GuiOverlay, GuiSlider and GuiTexturedButton to GUI API
Rewrite both overlays to use new GUI API
Fix size capping in vertical and horizontal layout
Allow CustomLayouts to have parents
Fix tooltip rendering when close to screen border
Allow changing of columns in GridLayout
This commit is contained in:
johni0702
2015-10-03 17:36:03 +02:00
parent 8bd051eb27
commit f925d56ca2
141 changed files with 6294 additions and 5582 deletions

View File

@@ -0,0 +1,239 @@
/*
* Copyright (c) 2015 johni0702
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.johni0702.minecraft.gui.container;
import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.MinecraftGuiRenderer;
import de.johni0702.minecraft.gui.OffsetGuiRenderer;
import de.johni0702.minecraft.gui.RenderInfo;
import de.johni0702.minecraft.gui.element.GuiElement;
import de.johni0702.minecraft.gui.function.*;
import eu.crushedpixel.replaymod.utils.MouseUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.util.ReportedException;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.Point;
import org.lwjgl.util.ReadableDimension;
import org.lwjgl.util.ReadablePoint;
import java.io.IOException;
import java.util.concurrent.Callable;
public abstract class AbstractGuiOverlay<T extends AbstractGuiOverlay<T>> extends AbstractGuiContainer<T> {
private final UserInputGuiScreen userInputGuiScreen = new UserInputGuiScreen();
private final EventHandler eventHandler = new EventHandler();
private boolean visible;
private Dimension screenSize;
private boolean mouseVisible;
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
if (this.visible != visible) {
if (visible) {
MinecraftForge.EVENT_BUS.register(eventHandler);
} else {
forEach(Closeable.class).close();
MinecraftForge.EVENT_BUS.unregister(eventHandler);
}
updateUserInputGui();
}
this.visible = visible;
}
public boolean isMouseVisible() {
return mouseVisible;
}
public void setMouseVisible(boolean mouseVisible) {
this.mouseVisible = mouseVisible;
updateUserInputGui();
}
private void updateUserInputGui() {
Minecraft mc = getMinecraft();
if (visible) {
if (mouseVisible) {
if (mc.currentScreen != userInputGuiScreen) {
mc.displayGuiScreen(userInputGuiScreen);
}
} else {
if (mc.currentScreen == userInputGuiScreen) {
mc.displayGuiScreen(null);
}
}
}
}
@Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
super.draw(renderer, size, renderInfo);
if (mouseVisible && renderInfo.layer == getMaxLayer()) {
final GuiElement tooltip = forEach(GuiElement.class).getTooltip(renderInfo);
if (tooltip != null) {
final ReadableDimension tooltipSize = tooltip.getMinSize();
int x, y;
if (renderInfo.mouseX + 8 + tooltipSize.getWidth() < screenSize.getWidth()) {
x = renderInfo.mouseX + 8;
} else {
x = screenSize.getWidth() - tooltipSize.getWidth() - 1;
}
if (renderInfo.mouseY + 8 + tooltipSize.getHeight() < screenSize.getHeight()) {
y = renderInfo.mouseY + 8;
} else {
y = screenSize.getHeight() - tooltipSize.getHeight() - 1;
}
final ReadablePoint position = new Point(x, y);
try {
OffsetGuiRenderer eRenderer = new OffsetGuiRenderer(renderer, position, tooltipSize);
tooltip.draw(eRenderer, tooltipSize, renderInfo);
} catch (Exception ex) {
CrashReport crashReport = CrashReport.makeCrashReport(ex, "Rendering Gui Tooltip");
renderInfo.addTo(crashReport);
CrashReportCategory category = crashReport.makeCategory("Gui container details");
category.addCrashSectionCallable("Container", new Callable() {
@Override
public Object call() throws Exception {
return this;
}
});
category.addCrashSection("Width", size.getWidth());
category.addCrashSection("Height", size.getHeight());
category = crashReport.makeCategory("Tooltip details");
category.addCrashSectionCallable("Element", new Callable() {
@Override
public Object call() throws Exception {
return tooltip;
}
});
category.addCrashSectionCallable("Position", new Callable() {
@Override
public Object call() throws Exception {
return position;
}
});
category.addCrashSectionCallable("Size", new Callable() {
@Override
public Object call() throws Exception {
return tooltipSize;
}
});
throw new ReportedException(crashReport);
}
}
}
}
@Override
public ReadableDimension getMinSize() {
return screenSize;
}
@Override
public ReadableDimension getMaxSize() {
return screenSize;
}
private class EventHandler {
private MinecraftGuiRenderer renderer;
@SubscribeEvent
public void renderOverlay(RenderGameOverlayEvent.Post event) {
if (event.type == RenderGameOverlayEvent.ElementType.ALL) {
updateRenderer();
int layers = getMaxLayer();
int mouseX = -1, mouseY = -1;
if (mouseVisible) {
Point mouse = MouseUtils.getMousePos();
mouseX = mouse.getX();
mouseY = mouse.getY();
}
for (int layer = 0; layer <= layers; layer++) {
draw(renderer, screenSize, new RenderInfo(event.partialTicks, mouseX, mouseY, layer));
}
}
}
@SubscribeEvent
public void tickOverlay(TickEvent.ClientTickEvent event) {
if (event.phase == TickEvent.Phase.START) {
forEach(Tickable.class).tick();
}
}
private void updateRenderer() {
Minecraft mc = getMinecraft();
ScaledResolution res = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
if (screenSize == null
|| screenSize.getWidth() != res.getScaledWidth()
|| screenSize.getHeight() != res.getScaledHeight()) {
screenSize = new Dimension(res.getScaledWidth(), res.getScaledHeight());
renderer = new MinecraftGuiRenderer(screenSize);
}
}
}
protected class UserInputGuiScreen extends net.minecraft.client.gui.GuiScreen {
@Override
protected void keyTyped(char typedChar, int keyCode) throws IOException {
forEach(Typeable.class).typeKey(MouseUtils.getMousePos(), keyCode, typedChar, isCtrlKeyDown(), isShiftKeyDown());
super.keyTyped(typedChar, keyCode);
}
@Override
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
forEach(Clickable.class).mouseClick(new Point(mouseX, mouseY), mouseButton);
}
@Override
protected void mouseReleased(int mouseX, int mouseY, int mouseButton) {
forEach(Draggable.class).mouseClick(new Point(mouseX, mouseY), mouseButton);
}
@Override
protected void mouseClickMove(int mouseX, int mouseY, int mouseButton, long timeSinceLastClick) {
forEach(Draggable.class).mouseDrag(new Point(mouseX, mouseY), mouseButton, timeSinceLastClick);
}
@Override
public void updateScreen() {
forEach(Tickable.class).tick();
}
@Override
public void onGuiClosed() {
mouseVisible = false;
}
}
}

View File

@@ -83,21 +83,21 @@ public abstract class AbstractGuiScreen<T extends AbstractGuiScreen<T>> extends
final GuiElement tooltip = forEach(GuiElement.class).getTooltip(renderInfo);
if (tooltip != null) {
final ReadableDimension tooltipSize = tooltip.getMinSize();
int dx, dy;
int x, y;
if (renderInfo.mouseX + 8 + tooltipSize.getWidth() < screenSize.getWidth()) {
dx = 8;
x = renderInfo.mouseX + 8;
} else {
dx = -8;
x = screenSize.getWidth() - tooltipSize.getWidth() - 1;
}
if (renderInfo.mouseY + 8 + tooltipSize.getHeight() < screenSize.getHeight()) {
dy = 8;
y = renderInfo.mouseY + 8;
} else {
dy = -8;
y = screenSize.getHeight() - tooltipSize.getHeight() - 1;
}
final ReadablePoint position = new Point(renderInfo.mouseX + dx, renderInfo.mouseY + dy);
final ReadablePoint position = new Point(x, y);
try {
OffsetGuiRenderer eRenderer = new OffsetGuiRenderer(renderer, position, tooltipSize);
tooltip.draw(eRenderer, tooltipSize, renderInfo.offsetMouse(position.getX(), position.getY()));
tooltip.draw(eRenderer, tooltipSize, renderInfo);
} catch (Exception ex) {
CrashReport crashReport = CrashReport.makeCrashReport(ex, "Rendering Gui Tooltip");
renderInfo.addTo(crashReport);

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2015 johni0702
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.johni0702.minecraft.gui.container;
public class GuiOverlay extends AbstractGuiOverlay<GuiOverlay> {
@Override
protected GuiOverlay getThis() {
return this;
}
}

View File

@@ -26,11 +26,14 @@ import de.johni0702.minecraft.gui.RenderInfo;
import de.johni0702.minecraft.gui.container.GuiContainer;
import lombok.Getter;
import net.minecraft.client.Minecraft;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.Point;
import org.lwjgl.util.ReadableDimension;
public abstract class AbstractGuiElement<T extends AbstractGuiElement<T>> implements GuiElement<T> {
protected static final ResourceLocation TEXTURE = new ResourceLocation("guiapi", "gui.png");
@Getter
private final Minecraft minecraft = Minecraft.getMinecraft();

View File

@@ -0,0 +1,189 @@
/*
* Copyright (c) 2015 johni0702
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.johni0702.minecraft.gui.element;
import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.RenderInfo;
import de.johni0702.minecraft.gui.container.GuiContainer;
import de.johni0702.minecraft.gui.function.Clickable;
import de.johni0702.minecraft.gui.function.Draggable;
import net.minecraft.client.resources.I18n;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.Point;
import org.lwjgl.util.ReadableDimension;
import org.lwjgl.util.ReadablePoint;
// TODO: Currently assumes a height of 20
public abstract class AbstractGuiSlider<T extends AbstractGuiSlider<T>> extends AbstractGuiElement<T> implements Clickable, Draggable, IGuiSlider<T> {
private Runnable onValueChanged;
private ReadableDimension size;
private int value;
private int steps;
private String text = "";
private boolean dragging;
public AbstractGuiSlider() {
}
public AbstractGuiSlider(GuiContainer container) {
super(container);
}
@Override
protected ReadableDimension calcMinSize() {
return new Dimension(0, 0);
}
@Override
public boolean mouseClick(ReadablePoint position, int button) {
Point pos = new Point(position);
if (getContainer() != null) {
getContainer().convertFor(this, pos);
}
if (isMouseHovering(pos) && isEnabled()) {
updateValue(pos);
dragging = true;
return true;
}
return false;
}
@Override
public boolean mouseDrag(ReadablePoint position, int button, long timeSinceLastCall) {
if (dragging) {
Point pos = new Point(position);
if (getContainer() != null) {
getContainer().convertFor(this, pos);
}
updateValue(pos);
}
return dragging;
}
@Override
public boolean mouseRelease(ReadablePoint position, int button) {
if (dragging) {
dragging = false;
Point pos = new Point(position);
if (getContainer() != null) {
getContainer().convertFor(this, pos);
}
updateValue(pos);
return true;
} else {
return false;
}
}
protected boolean isMouseHovering(ReadablePoint pos) {
return pos.getX() > 0 && pos.getY() > 0
&& pos.getX() < size.getWidth() && pos.getY() < size.getHeight();
}
@Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
this.size = size;
int width = size.getWidth();
int height = size.getHeight();
renderer.bindTexture(GuiButton.WIDGETS_TEXTURE);
// Draw background
renderer.drawTexturedRect(0, 0, 0, 46, width / 2, height);
renderer.drawTexturedRect(width / 2, 0, 200 - width / 2, 46, width / 2, height);
// Draw slider
int sliderX = (width - 8) * value / steps;
renderer.drawTexturedRect(sliderX, 0, 0, 66, 4, 20);
renderer.drawTexturedRect(sliderX + 4, 0, 196, 66, 4, 20);
// Draw text
int color = 0xe0e0e0;
if (!isEnabled()) {
color = 0xa0a0a0;
} else if (isMouseHovering(new Point(renderInfo.mouseX, renderInfo.mouseY))) {
color = 0xffffa0;
}
renderer.drawCenteredString(width / 2, height / 2 - 4, color, text);
}
protected void updateValue(ReadablePoint position) {
if (size == null) {
return;
}
int width = size.getWidth() - 8;
int pos = Math.max(0, Math.min(width, position.getX() - 4));
setValue(steps * pos / width);
}
public void onValueChanged() {
if (onValueChanged != null) {
onValueChanged.run();
}
}
@Override
public T setText(String text) {
this.text = text;
return getThis();
}
@Override
public T setI18nText(String text, Object... args) {
return setText(I18n.format(text, args));
}
@Override
public T setValue(int value) {
this.value = value;
onValueChanged();
return getThis();
}
@Override
public int getValue() {
return value;
}
@Override
public int getSteps() {
return steps;
}
@Override
public T setSteps(int steps) {
this.steps = steps;
return getThis();
}
@Override
public T onValueChanged(Runnable runnable) {
this.onValueChanged = runnable;
return getThis();
}
}

View File

@@ -0,0 +1,218 @@
/*
* Copyright (c) 2015 johni0702
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.johni0702.minecraft.gui.element;
import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.RenderInfo;
import de.johni0702.minecraft.gui.container.GuiContainer;
import de.johni0702.minecraft.gui.function.Clickable;
import lombok.Getter;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.util.*;
import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA;
import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA;
public abstract class AbstractGuiTexturedButton<T extends AbstractGuiTexturedButton<T>> extends AbstractGuiClickable<T> implements Clickable, IGuiTexturedButton<T> {
protected static final ResourceLocation BUTTON_SOUND = new ResourceLocation("gui.button.press");
@Getter
private ResourceLocation texture;
@Getter
private ReadableDimension textureSize = new ReadableDimension() {
@Override
public int getWidth() {
return getMaxSize().getWidth();
}
@Override
public int getHeight() {
return getMaxSize().getHeight();
}
@Override
public void getSize(WritableDimension dest) {
getMaxSize().getSize(dest);
}
};
@Getter
private ReadableDimension textureTotalSize;
@Getter
private ReadablePoint textureNormal;
@Getter
private ReadablePoint textureHover;
@Getter
private ReadablePoint textureDisabled;
public AbstractGuiTexturedButton() {
}
public AbstractGuiTexturedButton(GuiContainer container) {
super(container);
}
@Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
super.draw(renderer, size, renderInfo);
renderer.bindTexture(texture);
ReadablePoint texture = textureNormal;
if (!isEnabled()) {
texture = textureDisabled;
} else if (isMouseHovering(new Point(renderInfo.mouseX, renderInfo.mouseY))) {
texture = textureHover;
}
if (texture == null) { // Button is disabled but we have no texture for that
GlStateManager.color(0.5f, 0.5f, 0.5f, 1);
texture = textureNormal;
}
GlStateManager.enableBlend();
GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 1, 0);
GlStateManager.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
renderer.drawTexturedRect(0, 0, texture.getX(), texture.getY(), size.getWidth(), size.getHeight(),
textureSize.getWidth(), textureSize.getHeight(),
textureTotalSize.getWidth(), textureTotalSize.getHeight());
}
@Override
public ReadableDimension calcMinSize() {
return new Dimension(0, 0);
}
@Override
public void onClick() {
getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.create(BUTTON_SOUND, 1.0F));
super.onClick();
}
@Override
public T setTexture(ResourceLocation resourceLocation, int size) {
return setTexture(resourceLocation, size, size);
}
@Override
public T setTexture(ResourceLocation resourceLocation, int width, int height) {
this.texture = resourceLocation;
this.textureTotalSize = new Dimension(width, height);
return getThis();
}
@Override
public T setTextureSize(int size) {
return setTextureSize(size, size);
}
@Override
public T setTextureSize(int width, int height) {
this.textureSize = new Dimension(width, height);
return getThis();
}
@Override
public T setTexturePosH(final int x, final int y) {
return setTexturePosH(new Point(x, y));
}
@Override
public T setTexturePosV(final int x, final int y) {
return setTexturePosV(new Point(x, y));
}
@Override
public T setTexturePosH(final ReadablePoint pos) {
this.textureNormal = pos;
this.textureHover = new ReadablePoint() {
@Override
public int getX() {
return pos.getX() + textureSize.getWidth();
}
@Override
public int getY() {
return pos.getY();
}
@Override
public void getLocation(WritablePoint dest) {
dest.setLocation(getX(), getY());
}
};
return getThis();
}
@Override
public T setTexturePosV(final ReadablePoint pos) {
this.textureNormal = pos;
this.textureHover = new ReadablePoint() {
@Override
public int getX() {
return pos.getX();
}
@Override
public int getY() {
return pos.getY() + textureSize.getHeight();
}
@Override
public void getLocation(WritablePoint dest) {
dest.setLocation(getX(), getY());
}
};
return getThis();
}
@Override
public T setTexturePos(int normalX, int normalY, int hoverX, int hoverY) {
return setTexturePos(new Point(normalX, normalY), new Point(hoverX, hoverY));
}
@Override
public T setTexturePos(ReadablePoint normal, ReadablePoint hover) {
this.textureNormal = normal;
this.textureHover = hover;
return getThis();
}
@Override
public T setTexturePos(int normalX, int normalY, int hoverX, int hoverY, int disabledX, int disabledY) {
return setTexturePos(new Point(normalX, normalY), new Point(hoverX, hoverY), new Point(disabledX, disabledY));
}
@Override
public T setTexturePos(ReadablePoint normal, ReadablePoint hover, ReadablePoint disabled) {
this.textureDisabled = disabled;
return setTexturePos(normal, hover);
}
}

View File

@@ -47,7 +47,7 @@ public abstract class AbstractGuiToggleButton<V, T extends AbstractGuiToggleButt
@Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
String orgLabel = getLabel();
setLabel(orgLabel + values[selected]);
setLabel(orgLabel + ": " + values[selected]);
super.draw(renderer, size, renderInfo);
setLabel(orgLabel);
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2015 johni0702
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.johni0702.minecraft.gui.element;
import de.johni0702.minecraft.gui.container.GuiContainer;
public class GuiSlider extends AbstractGuiSlider<GuiSlider> {
public GuiSlider() {
}
public GuiSlider(GuiContainer container) {
super(container);
}
@Override
protected GuiSlider getThis() {
return this;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2015 johni0702
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.johni0702.minecraft.gui.element;
import de.johni0702.minecraft.gui.container.GuiContainer;
public class GuiTexturedButton extends AbstractGuiTexturedButton<GuiTexturedButton> {
public GuiTexturedButton() {
}
public GuiTexturedButton(GuiContainer container) {
super(container);
}
@Override
protected GuiTexturedButton getThis() {
return this;
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2015 johni0702
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.johni0702.minecraft.gui.element;
public interface IGuiSlider<T extends IGuiSlider<T>> extends GuiElement<T> {
T setText(String text);
T setI18nText(String text, Object... args);
T setValue(int value);
int getValue();
int getSteps();
T setSteps(int steps);
T onValueChanged(Runnable runnable);
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2015 johni0702
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.johni0702.minecraft.gui.element;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.util.ReadableDimension;
import org.lwjgl.util.ReadablePoint;
public interface IGuiTexturedButton<T extends IGuiTexturedButton<T>> extends IGuiClickable<T> {
ResourceLocation getTexture();
ReadableDimension getTextureTotalSize();
T setTexture(ResourceLocation resourceLocation, int size);
T setTexture(ResourceLocation resourceLocation, int width, int height);
ReadableDimension getTextureSize();
T setTextureSize(int size);
T setTextureSize(int width, int height);
ReadablePoint getTextureNormal();
ReadablePoint getTextureHover();
ReadablePoint getTextureDisabled();
T setTexturePosH(int x, int y);
T setTexturePosV(int x, int y);
T setTexturePosH(ReadablePoint pos);
T setTexturePosV(ReadablePoint pos);
T setTexturePos(int normalX, int normalY, int hoverX, int hoverY);
T setTexturePos(ReadablePoint normal, ReadablePoint hover);
T setTexturePos(int normalX, int normalY, int hoverX, int hoverY, int disabledX, int disabledY);
T setTexturePos(ReadablePoint normal, ReadablePoint hover, ReadablePoint disabled);
}

View File

@@ -0,0 +1,253 @@
/*
* Copyright (c) 2015 johni0702
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.johni0702.minecraft.gui.element.advanced;
import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.RenderInfo;
import de.johni0702.minecraft.gui.container.GuiContainer;
import de.johni0702.minecraft.gui.element.AbstractGuiElement;
import de.johni0702.minecraft.gui.element.GuiTooltip;
import de.johni0702.minecraft.gui.function.Clickable;
import net.minecraft.util.MathHelper;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.Point;
import org.lwjgl.util.ReadableDimension;
import org.lwjgl.util.ReadablePoint;
public abstract class AbstractGuiTimeline<T extends AbstractGuiTimeline<T>> extends AbstractGuiElement<T> implements IGuiTimeline<T>, Clickable {
protected static final int TEXTURE_WIDTH = 64;
protected static final int TEXTURE_HEIGHT = 22;
protected static final int TEXTURE_X = 0;
protected static final int TEXTURE_Y = 16;
protected static final int BORDER_LEFT = 4;
protected static final int BORDER_RIGHT = 4;
protected static final int BORDER_TOP = 4;
protected static final int BORDER_BOTTOM = 3;
protected static final int BODY_WIDTH = TEXTURE_WIDTH - BORDER_LEFT - BORDER_RIGHT;
protected static final int BODY_HEIGHT = TEXTURE_HEIGHT - BORDER_TOP - BORDER_BOTTOM;
private OnClick onClick;
private int length;
private int cursorPosition;
private double zoom = 1;
private int offset;
private ReadableDimension size;
public AbstractGuiTimeline() {
}
public AbstractGuiTimeline(GuiContainer container) {
super(container);
}
{
setTooltip(new GuiTooltip(){
@Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
int ms = getTimeAt(renderInfo.mouseX, renderInfo.mouseY);
int s = ms / 1000 % 60;
int m = ms / 1000 / 60;
setText(String.format("%02d:%02d", m, s));
super.draw(renderer, size, renderInfo);
}
}.setText("00:00"));
}
@Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
this.size = size;
int width = size.getWidth();
int height = size.getHeight();
// We have to increase the border size as there is one pixel row which is part of the border while drawing
// but isn't during position calculations due to shadows
int BORDER_LEFT = GuiTimeline.BORDER_LEFT + 1;
int BODY_WIDTH = GuiTimeline.BODY_WIDTH - 1;
renderer.bindTexture(TEXTURE);
// Left and right borders
for (int pass = 0; pass < 2; pass++) {
int x = pass == 0 ? 0 : width - BORDER_RIGHT;
int textureX = pass == 0 ? TEXTURE_X : TEXTURE_X + TEXTURE_WIDTH - BORDER_RIGHT;
// Border
for (int y = BORDER_TOP; y < height - BORDER_BOTTOM; y += BODY_HEIGHT) {
int segmentHeight = Math.min(BODY_HEIGHT, height - BORDER_BOTTOM - y);
renderer.drawTexturedRect(x, y, textureX, TEXTURE_Y + BORDER_TOP, BORDER_LEFT, segmentHeight);
}
// Top corner
renderer.drawTexturedRect(x, 0, textureX, TEXTURE_Y, BORDER_LEFT, BORDER_TOP);
// Bottom corner
renderer.drawTexturedRect(x, height - BORDER_BOTTOM, textureX, TEXTURE_Y + TEXTURE_HEIGHT - BORDER_BOTTOM,
BORDER_LEFT, BORDER_BOTTOM);
}
for (int x = BORDER_LEFT; x < width - BORDER_RIGHT; x += BODY_WIDTH) {
int segmentWidth = Math.min(BODY_WIDTH, width - BORDER_RIGHT - x);
int textureX = TEXTURE_X + BORDER_LEFT;
// Content
for (int y = BORDER_TOP; y < height - BORDER_BOTTOM; y += BODY_HEIGHT) {
int segmentHeight = Math.min(BODY_HEIGHT, height - BORDER_BOTTOM - y);
renderer.drawTexturedRect(x, y, textureX, TEXTURE_Y + BORDER_TOP, segmentWidth, segmentHeight);
}
// Top border
renderer.drawTexturedRect(x, 0, textureX, TEXTURE_Y, segmentWidth, BORDER_TOP);
// Bottom border
renderer.drawTexturedRect(x, height - BORDER_BOTTOM, textureX, TEXTURE_Y + TEXTURE_HEIGHT - BORDER_BOTTOM,
segmentWidth, BORDER_BOTTOM);
}
drawTimelineCursor(renderer, size);
}
/**
* Draws the timeline cursor.
* This is separate from the main draw method so subclasses can repaint the cursor
* in case it got drawn over by other elements.
* @param renderer Gui renderer used to draw the cursor
* @param size Size of the drawable area
*/
protected void drawTimelineCursor(GuiRenderer renderer, ReadableDimension size) {
int height = size.getHeight();
renderer.bindTexture(TEXTURE);
int visibleLength = (int) (length * zoom);
int cursor = MathHelper.clamp_int(cursorPosition, offset, offset + visibleLength);
double positionInVisible = cursor - offset;
double fractionOfVisible = positionInVisible / visibleLength;
int cursorX = (int) (BORDER_LEFT + fractionOfVisible * (size.getWidth() - BORDER_LEFT - BORDER_RIGHT));
// Pin
renderer.drawTexturedRect(cursorX - 2, BORDER_TOP - 1, 64, 0, 5, 4);
// Needle
for (int y = BORDER_TOP - 1; y < height - BORDER_BOTTOM; y += 11) {
int segmentHeight = Math.min(11, height - BORDER_BOTTOM - y);
renderer.drawTexturedRect(cursorX - 2, y, 64, 4, 5, segmentHeight);
}
}
/**
* Returns the time which the mouse is at.
* @param mouseX X coordinate of the mouse
* @param mouseY Y coordinate of the mouse
* @return The time or -1 if the mouse isn't on the timeline
*/
protected int getTimeAt(int mouseX, int mouseY) {
if (size == null) {
return -1;
}
Point mouse = new Point(mouseX, mouseY);
getContainer().convertFor(this, mouse);
mouseX = mouse.getX();
mouseY = mouse.getY();
if (mouseX < 0 || mouseY < 0
|| mouseX > size.getWidth() || mouseY > size.getHeight()) {
return -1;
}
int width = size.getWidth();
int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT;
double segmentLength = length * zoom;
double segmentTime = segmentLength * (mouseX - BORDER_LEFT) / bodyWidth;
return Math.min(Math.max((int) Math.round(offset + segmentTime), 0), length);
}
public void onClick(int time) {
if (onClick != null) {
onClick.run(time);
}
}
@Override
public ReadableDimension calcMinSize() {
return new Dimension(0, 0);
}
@Override
public T setLength(int length) {
this.length = length;
return getThis();
}
@Override
public int getLength() {
return length;
}
@Override
public T setCursorPosition(int position) {
this.cursorPosition = position;
return getThis();
}
@Override
public int getCursorPosition() {
return cursorPosition;
}
@Override
public T setZoom(double zoom) {
this.zoom = zoom;
return getThis();
}
@Override
public double getZoom() {
return zoom;
}
@Override
public T setOffset(int offset) {
this.offset = offset;
return getThis();
}
@Override
public int getOffset() {
return offset;
}
@Override
public T onClick(OnClick onClick) {
this.onClick = onClick;
return getThis();
}
@Override
public boolean mouseClick(ReadablePoint position, int button) {
int time = getTimeAt(position.getX(), position.getY());
if (time != -1) {
onClick(time);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2015 johni0702
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.johni0702.minecraft.gui.element.advanced;
import de.johni0702.minecraft.gui.container.GuiContainer;
public class GuiTimeline extends AbstractGuiTimeline<GuiTimeline> {
public GuiTimeline() {
}
public GuiTimeline(GuiContainer container) {
super(container);
}
@Override
protected GuiTimeline getThis() {
return this;
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2015 johni0702
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.johni0702.minecraft.gui.element.advanced;
import de.johni0702.minecraft.gui.element.GuiElement;
public interface IGuiTimeline<T extends IGuiTimeline<T>> extends GuiElement<T> {
/**
* Set the total length of the timeline.
* @param length length in milliseconds, must be > 0
* @return {@code this}, for chaining
*/
T setLength(int length);
/**
* Returns the total length of the timeline.
* @return The total length in millisconds
*/
int getLength();
/**
* Set the current position of the cursor. Should be between 0 and {@link #getLength()}.
* @param position Position of the cursor in milliseconds
* @return {@code this}, for chaining
*/
T setCursorPosition(int position);
/**
* Returns the current position of the cursor. Should be between 0 and {@link #getLength()}.
* @return cursor position in milliseconds
*/
int getCursorPosition();
/**
* Set the zoom of this timeline. 1/10 allows the user to see 1/10 of the total length.
* @param zoom The zoom factor. Must be between 1 (inclusive) and 0 (exclusive)
* @return {@code this}, for chaining
*/
T setZoom(double zoom);
/**
* Returns the zoom of this timeline. 1/10 allows the user to see 1/10 of the total length.
* @return The zoom factor. Must be between 1 (inclusive) and 0 (exclusive)
*/
double getZoom();
/**
* Set the position of the timeline which should be shown.
* The left side of the timeline will start at this offset.
* @param offset The offset in milliseconds
* @return {@code this}, for chaining
*/
T setOffset(int offset);
/**
* Returns the position of the timeline which should be shown.
* The left side of the timeline will start at this offset.
* @return The offset in milliseconds
*/
int getOffset();
T onClick(OnClick onClick);
interface OnClick {
void run(int time);
}
}

View File

@@ -35,15 +35,32 @@ import java.util.Collection;
import java.util.Map;
public abstract class CustomLayout<T extends GuiContainer<T>> implements Layout {
private final Layout parent;
private Map<GuiElement, Pair<Point, Dimension>> result = Maps.newHashMap();
public CustomLayout() {
this(null);
}
public CustomLayout(Layout parent) {
this.parent = parent;
}
@Override
@SuppressWarnings("unchecked")
public Map<GuiElement, Pair<ReadablePoint, ReadableDimension>> layOut(GuiContainer container, ReadableDimension size) {
result.clear();
Collection<GuiElement> elements = container.getChildren();
for (GuiElement element : elements) {
result.put(element, Pair.of(new Point(0, 0), new Dimension(element.getMinSize())));
if (parent == null) {
Collection<GuiElement> elements = container.getChildren();
for (GuiElement element : elements) {
result.put(element, Pair.of(new Point(0, 0), new Dimension(element.getMinSize())));
}
} else {
Map<GuiElement, Pair<ReadablePoint, ReadableDimension>> elements = parent.layOut(container, size);
for (Map.Entry<GuiElement, Pair<ReadablePoint, ReadableDimension>> entry : elements.entrySet()) {
Pair<ReadablePoint, ReadableDimension> pair = entry.getValue();
result.put(entry.getKey(), Pair.of(new Point(pair.getLeft()), new Dimension(pair.getRight())));
}
}
layout((T) container, size.getWidth(), size.getHeight());

View File

@@ -27,7 +27,6 @@ import de.johni0702.minecraft.gui.container.GuiContainer;
import de.johni0702.minecraft.gui.element.GuiElement;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.apache.commons.lang3.tuple.Pair;
@@ -40,11 +39,13 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
@RequiredArgsConstructor
public class GridLayout implements Layout {
private static final Data DEFAULT_DATA = new Data();
private final int columns;
@Accessors(chain = true)
@Getter
@Setter
private int columns;
@Accessors(chain = true)
@Getter

View File

@@ -67,7 +67,9 @@ public class HorizontalLayout implements Layout {
GuiElement element = entry.getKey();
Data data = entry.getValue() instanceof Data ? (Data) entry.getValue() : DEFAULT_DATA;
Dimension elementSize = new Dimension(element.getMinSize());
elementSize.setHeight(Math.min(size.getHeight(), element.getMaxSize().getHeight()));
ReadableDimension elementMaxSize = element.getMaxSize();
elementSize.setWidth(Math.min(size.getWidth() - x, Math.min(elementSize.getWidth(), elementMaxSize.getWidth())));
elementSize.setHeight(Math.min(size.getHeight(), elementMaxSize.getHeight()));
int remainingHeight = size.getHeight() - elementSize.getHeight();
int y = (int) (data.alignment * remainingHeight);
map.put(element, Pair.<ReadablePoint, ReadableDimension>of(new Point(x, y), elementSize));

View File

@@ -67,6 +67,8 @@ public class VerticalLayout implements Layout {
GuiElement element = entry.getKey();
Data data = entry.getValue() instanceof Data ? (Data) entry.getValue() : DEFAULT_DATA;
Dimension elementSize = new Dimension(element.getMinSize());
ReadableDimension elementMaxSize = element.getMaxSize();
elementSize.setHeight(Math.min(size.getHeight() - y, Math.min(elementSize.getHeight(), elementMaxSize.getHeight())));
elementSize.setWidth(Math.min(size.getWidth(), element.getMaxSize().getWidth()));
int remainingWidth = size.getWidth() - elementSize.getWidth();
int x = (int) (data.alignment * remainingWidth);