Create working scaffolding of Component Inflater

This commit is contained in:
2021-03-15 14:37:30 +01:00
parent 449278b3cf
commit c92c4f31a7
10 changed files with 249 additions and 83 deletions

View File

@@ -53,17 +53,17 @@ public abstract class BaseWidget implements Widget {
} }
@Override @Override
public void setWidth(float width) { public void setWidth(Float width) {
this.width = width; this.width = width;
} }
@Override @Override
public void setHeight(float height) { public void setHeight(Float height) {
this.height = height; this.height = height;
} }
@Override @Override
public void setSize(float width, float height) { public void setSize(Float width, Float height) {
this.width = width; this.width = width;
this.height = height; this.height = height;
} }
@@ -115,23 +115,23 @@ public abstract class BaseWidget implements Widget {
} }
@Override @Override
public void setX(float x) { public void setX(Float x) {
this.x = x; this.x = x;
} }
@Override @Override
public void setY(float y) { public void setY(Float y) {
this.y = y; this.y = y;
} }
@Override @Override
public void setPosition(float x, float y) { public void setPosition(Float x, Float y) {
this.x = x; this.x = x;
this.y = y; this.y = y;
} }
@Override @Override
public void setMargin(float top, float right, float bottom, float left) { public void setMargin(Float top, Float right, Float bottom, Float left) {
this.marginTop = top; this.marginTop = top;
this.marginRight = right; this.marginRight = right;
this.marginBottom = bottom; this.marginBottom = bottom;
@@ -139,7 +139,7 @@ public abstract class BaseWidget implements Widget {
} }
@Override @Override
public void setMargin(float top, float rightLeft, float bottom) { public void setMargin(Float top, Float rightLeft, Float bottom) {
this.marginTop = top; this.marginTop = top;
this.marginRight = rightLeft; this.marginRight = rightLeft;
this.marginBottom = bottom; this.marginBottom = bottom;
@@ -147,7 +147,7 @@ public abstract class BaseWidget implements Widget {
} }
@Override @Override
public void setMargin(float topBottom, float rightLeft) { public void setMargin(Float topBottom, Float rightLeft) {
this.marginTop = topBottom; this.marginTop = topBottom;
this.marginRight = rightLeft; this.marginRight = rightLeft;
this.marginBottom = topBottom; this.marginBottom = topBottom;
@@ -155,7 +155,7 @@ public abstract class BaseWidget implements Widget {
} }
@Override @Override
public void setMargin(float all) { public void setMargin(Float all) {
this.marginTop = all; this.marginTop = all;
this.marginRight = all; this.marginRight = all;
this.marginBottom = all; this.marginBottom = all;
@@ -163,22 +163,22 @@ public abstract class BaseWidget implements Widget {
} }
@Override @Override
public void setMarginTop(float margin) { public void setMarginTop(Float margin) {
this.marginTop = margin; this.marginTop = margin;
} }
@Override @Override
public void setMarginRight(float margin) { public void setMarginRight(Float margin) {
this.marginRight = margin; this.marginRight = margin;
} }
@Override @Override
public void setMarginBottom(float margin) { public void setMarginBottom(Float margin) {
this.marginBottom = margin; this.marginBottom = margin;
} }
@Override @Override
public void setMarginLeft(float margin) { public void setMarginLeft(Float margin) {
this.marginLeft = margin; this.marginLeft = margin;
} }
@@ -203,7 +203,7 @@ public abstract class BaseWidget implements Widget {
} }
@Override @Override
public void setPadding(float top, float right, float bottom, float left) { public void setPadding(Float top, Float right, Float bottom, Float left) {
this.paddingTop = top; this.paddingTop = top;
this.paddingRight = right; this.paddingRight = right;
this.paddingBottom = bottom; this.paddingBottom = bottom;
@@ -211,7 +211,7 @@ public abstract class BaseWidget implements Widget {
} }
@Override @Override
public void setPadding(float top, float rightLeft, float bottom) { public void setPadding(Float top, Float rightLeft, Float bottom) {
this.paddingTop = top; this.paddingTop = top;
this.paddingRight = rightLeft; this.paddingRight = rightLeft;
this.paddingBottom = bottom; this.paddingBottom = bottom;
@@ -219,7 +219,7 @@ public abstract class BaseWidget implements Widget {
} }
@Override @Override
public void setPadding(float topBottom, float rightLeft) { public void setPadding(Float topBottom, Float rightLeft) {
this.paddingTop = topBottom; this.paddingTop = topBottom;
this.paddingRight = rightLeft; this.paddingRight = rightLeft;
this.paddingBottom = topBottom; this.paddingBottom = topBottom;
@@ -227,7 +227,7 @@ public abstract class BaseWidget implements Widget {
} }
@Override @Override
public void setPadding(float all) { public void setPadding(Float all) {
this.paddingTop = all; this.paddingTop = all;
this.paddingRight = all; this.paddingRight = all;
this.paddingBottom = all; this.paddingBottom = all;
@@ -235,22 +235,22 @@ public abstract class BaseWidget implements Widget {
} }
@Override @Override
public void setPaddingTop(float padding) { public void setPaddingTop(Float padding) {
this.paddingTop = padding; this.paddingTop = padding;
} }
@Override @Override
public void setPaddingRight(float padding) { public void setPaddingRight(Float padding) {
this.paddingRight = padding; this.paddingRight = padding;
} }
@Override @Override
public void setPaddingBottom(float padding) { public void setPaddingBottom(Float padding) {
this.paddingBottom = padding; this.paddingBottom = padding;
} }
@Override @Override
public void setPaddingLeft(float padding) { public void setPaddingLeft(Float padding) {
this.paddingLeft = padding; this.paddingLeft = padding;
} }

View File

@@ -12,11 +12,11 @@ public interface Widget extends KeyEventHandler {
float getY(); float getY();
void setX(float x); void setX(Float x);
void setY(float y); void setY(Float y);
void setPosition(float x, float y); void setPosition(Float x, Float y);
float getWidth(); float getWidth();
@@ -26,11 +26,11 @@ public interface Widget extends KeyEventHandler {
float getActualHeight(); float getActualHeight();
void setWidth(float width); void setWidth(Float width);
void setHeight(float height); void setHeight(Float height);
void setSize(float width, float height); void setSize(Float width, Float height);
SizeMode getWidthMode(); SizeMode getWidthMode();
@@ -42,21 +42,21 @@ public interface Widget extends KeyEventHandler {
void setSizeMode(SizeMode widthMode, SizeMode heightMode); void setSizeMode(SizeMode widthMode, SizeMode heightMode);
void setMargin(float top, float right, float bottom, float left); void setMargin(Float top, Float right, Float bottom, Float left);
void setMargin(float top, float rightLeft, float bottom); void setMargin(Float top, Float rightLeft, Float bottom);
void setMargin(float topBottom, float rightLeft); void setMargin(Float topBottom, Float rightLeft);
void setMargin(float all); void setMargin(Float all);
void setMarginTop(float margin); void setMarginTop(Float margin);
void setMarginRight(float margin); void setMarginRight(Float margin);
void setMarginBottom(float margin); void setMarginBottom(Float margin);
void setMarginLeft(float margin); void setMarginLeft(Float margin);
float getMarginTop(); float getMarginTop();
@@ -66,21 +66,21 @@ public interface Widget extends KeyEventHandler {
float getMarginLeft(); float getMarginLeft();
void setPadding(float top, float right, float bottom, float left); void setPadding(Float top, Float right, Float bottom, Float left);
void setPadding(float top, float rightLeft, float bottom); void setPadding(Float top, Float rightLeft, Float bottom);
void setPadding(float topBottom, float rightLeft); void setPadding(Float topBottom, Float rightLeft);
void setPadding(float all); void setPadding(Float all);
void setPaddingTop(float padding); void setPaddingTop(Float padding);
void setPaddingRight(float padding); void setPaddingRight(Float padding);
void setPaddingBottom(float padding); void setPaddingBottom(Float padding);
void setPaddingLeft(float padding); void setPaddingLeft(Float padding);
float getPaddingTop(); float getPaddingTop();

View File

@@ -2,9 +2,26 @@ package com.bartlomiejpluta.base.api.game.gui.component;
import com.bartlomiejpluta.base.api.game.gui.base.BaseWidget; import com.bartlomiejpluta.base.api.game.gui.base.BaseWidget;
import static java.util.Collections.emptyList;
public abstract class BaseComponent extends BaseWidget implements Component { public abstract class BaseComponent extends BaseWidget implements Component {
protected boolean focused; protected boolean focused;
@Override
public Iterable<Component> getChildren() {
return emptyList();
}
@Override
public void add(Component component) {
throw new UnsupportedOperationException();
}
@Override
public void remove(Component component) {
throw new UnsupportedOperationException();
}
@Override @Override
public boolean isFocused() { public boolean isFocused() {
return focused; return focused;

View File

@@ -5,8 +5,16 @@ import com.bartlomiejpluta.base.api.game.input.KeyEvent;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import static java.util.Collections.unmodifiableList;
public abstract class BaseContainer extends BaseComponent implements Container { public abstract class BaseContainer extends BaseComponent implements Container {
protected final List<Component> children = new LinkedList<>(); protected final List<Component> children = new LinkedList<>();
private final List<Component> readOnlyChildren = unmodifiableList(children);
@Override
public Iterable<Component> getChildren() {
return readOnlyChildren;
}
@Override @Override
public void add(Component component) { public void add(Component component) {

View File

@@ -3,6 +3,12 @@ package com.bartlomiejpluta.base.api.game.gui.component;
import com.bartlomiejpluta.base.api.game.gui.base.Widget; import com.bartlomiejpluta.base.api.game.gui.base.Widget;
public interface Component extends Widget { public interface Component extends Widget {
Iterable<Component> getChildren();
void add(Component component);
void remove(Component component);
boolean isFocused(); boolean isFocused();
void focus(); void focus();

View File

@@ -1,7 +1,4 @@
package com.bartlomiejpluta.base.api.game.gui.component; package com.bartlomiejpluta.base.api.game.gui.component;
public interface Container extends Component { public interface Container extends Component {
void add(Component component);
void remove(Component component);
} }

View File

@@ -7,23 +7,27 @@ import com.bartlomiejpluta.base.api.game.screen.Screen;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
public class Label extends BaseComponent { public class Label extends BaseComponent {
private final GUI gui; // private final GUI gui;
private String text = ""; private String text = "";
private String font; private String font;
private float fontSize; private float fontSize;
private int alignment = GUI.ALIGN_LEFT; private int alignment = GUI.ALIGN_LEFT;
private final Color color; private Color color;
private final float[] bounds = new float[4]; private final float[] bounds = new float[4];
public Label(GUI gui, String font) { public Label() {
this.gui = requireNonNull(gui);
this.font = requireNonNull(font);
this.color = this.gui.createColor();
} }
// public Label(GUI gui, String font) {
// this.gui = requireNonNull(gui);
// this.font = requireNonNull(font);
//
// this.color = this.gui.createColor();
// }
public String getText() { public String getText() {
return text; return text;
} }
@@ -44,7 +48,7 @@ public class Label extends BaseComponent {
return fontSize; return fontSize;
} }
public void setFontSize(float fontSize) { public void setFontSize(Float fontSize) {
this.fontSize = fontSize; this.fontSize = fontSize;
} }
@@ -52,7 +56,7 @@ public class Label extends BaseComponent {
return alignment; return alignment;
} }
public void setAlignment(int alignment) { public void setAlignment(Integer alignment) {
this.alignment = alignment; this.alignment = alignment;
} }
@@ -60,7 +64,7 @@ public class Label extends BaseComponent {
return color.getRed(); return color.getRed();
} }
public void setRed(float value) { public void setRed(Float value) {
color.setRed(value); color.setRed(value);
} }
@@ -68,7 +72,7 @@ public class Label extends BaseComponent {
return color.getGreen(); return color.getGreen();
} }
public void setGreen(float value) { public void setGreen(Float value) {
color.setGreen(value); color.setGreen(value);
} }
@@ -76,7 +80,7 @@ public class Label extends BaseComponent {
return color.getBlue(); return color.getBlue();
} }
public void setBlue(float value) { public void setBlue(Float value) {
color.setBlue(value); color.setBlue(value);
} }
@@ -84,15 +88,15 @@ public class Label extends BaseComponent {
return color.getAlpha(); return color.getAlpha();
} }
public void setAlpha(float value) { public void setAlpha(Float value) {
color.setAlpha(value); color.setAlpha(value);
} }
public void setColor(float red, float green, float blue, float alpha) { public void setColor(Float red, Float green, Float blue, Float alpha) {
color.setRGBA(red, green, blue, alpha); color.setRGBA(red, green, blue, alpha);
} }
public void setColor(float red, float green, float blue) { public void setColor(Float red, Float green, Float blue) {
color.setRGB(red, green, blue); color.setRGB(red, green, blue);
} }
@@ -116,4 +120,9 @@ public class Label extends BaseComponent {
gui.fill(); gui.fill();
gui.putTextBox(x + paddingLeft, y + paddingTop, getWidth() - paddingLeft - paddingRight, text, bounds); gui.putTextBox(x + paddingLeft, y + paddingTop, getWidth() - paddingLeft - paddingRight, text, bounds);
} }
@Override
public String toString() {
return "Label[" + text + "]";
}
} }

View File

@@ -86,6 +86,9 @@ dependencies {
compileOnly 'org.projectlombok:lombok' compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok'
implementation "org.codehaus.janino:janino:${janinoVersion}"
implementation "org.codehaus.janino:commons-compiler:${janinoVersion}"
// This dependency is used by the application. // This dependency is used by the application.
implementation "org.joml:joml:${jomlVersion}" implementation "org.joml:joml:${jomlVersion}"
} }

View File

@@ -58,32 +58,32 @@ public class ScreenWidget implements Widget {
} }
@Override @Override
public void setX(float x) { public void setX(Float x) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setY(float y) { public void setY(Float y) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setPosition(float x, float y) { public void setPosition(Float x, Float y) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setWidth(float width) { public void setWidth(Float width) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setHeight(float height) { public void setHeight(Float height) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setSize(float width, float height) { public void setSize(Float width, Float height) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@@ -113,42 +113,42 @@ public class ScreenWidget implements Widget {
} }
@Override @Override
public void setMargin(float top, float right, float bottom, float left) { public void setMargin(Float top, Float right, Float bottom, Float left) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setMargin(float top, float rightLeft, float bottom) { public void setMargin(Float top, Float rightLeft, Float bottom) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setMargin(float topBottom, float rightLeft) { public void setMargin(Float topBottom, Float rightLeft) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setMargin(float all) { public void setMargin(Float all) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setMarginTop(float margin) { public void setMarginTop(Float margin) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setMarginRight(float margin) { public void setMarginRight(Float margin) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setMarginBottom(float margin) { public void setMarginBottom(Float margin) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setMarginLeft(float margin) { public void setMarginLeft(Float margin) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@@ -173,42 +173,42 @@ public class ScreenWidget implements Widget {
} }
@Override @Override
public void setPadding(float top, float right, float bottom, float left) { public void setPadding(Float top, Float right, Float bottom, Float left) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setPadding(float top, float rightLeft, float bottom) { public void setPadding(Float top, Float rightLeft, Float bottom) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setPadding(float topBottom, float rightLeft) { public void setPadding(Float topBottom, Float rightLeft) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setPadding(float all) { public void setPadding(Float all) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setPaddingTop(float padding) { public void setPaddingTop(Float padding) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setPaddingRight(float padding) { public void setPaddingRight(Float padding) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setPaddingBottom(float padding) { public void setPaddingBottom(Float padding) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setPaddingLeft(float padding) { public void setPaddingLeft(Float padding) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@@ -0,0 +1,126 @@
package com.bartlomiejpluta.base.engine.gui.xml.inflater;
import com.bartlomiejpluta.base.api.game.gui.base.GUI;
import com.bartlomiejpluta.base.api.game.gui.base.SizeMode;
import com.bartlomiejpluta.base.api.game.gui.component.Component;
import com.bartlomiejpluta.base.engine.util.reflection.ClassLoader;
import lombok.SneakyThrows;
import org.codehaus.janino.ExpressionEvaluator;
import org.springframework.beans.factory.annotation.Autowired;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.io.InputStream;
import java.util.stream.Stream;
@org.springframework.stereotype.Component
public class ComponentInflater {
private static final String[] IMPORTS = Stream.of(GUI.class, SizeMode.class).map(Class::getCanonicalName).toArray(String[]::new);
private final DocumentBuilder builder;
private final ClassLoader loader;
@Autowired
@SneakyThrows
public ComponentInflater(ClassLoader loader) {
this.loader = loader;
var factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
this.builder = factory.newDocumentBuilder();
}
@SneakyThrows
public Component inflate(String xml) {
var document = builder.parse(xml);
return parseNode(document.getDocumentElement());
}
@SneakyThrows
public Component inflate(File file) {
var document = builder.parse(file);
return parseNode(document.getDocumentElement());
}
@SneakyThrows
public Component inflate(InputStream is) {
var document = builder.parse(is);
return parseNode(document.getDocumentElement());
}
@SneakyThrows
private Component parseNode(Node node) {
var uri = node.getNamespaceURI();
var name = node.getLocalName();
if (uri != null) {
name = uri + "." + name;
}
var canonicalName = name.replaceAll("\\*", "").replaceAll("\\.+", ".");
var componentClass = loader.loadClass(canonicalName);
var component = createComponent(componentClass, node.getAttributes());
var children = node.getChildNodes();
// The component is text-like node (e.g. <Label>Some text</Label>)
if (children.getLength() == 1) {
var child = children.item(0);
if (child.getNodeType() == Node.TEXT_NODE) {
var textSetter = componentClass.getMethod("setText", String.class);
textSetter.invoke(component, child.getNodeValue());
return component;
}
}
// The component has non-text children (e.g. <HLayout><Label>Some text</Label></HLayout>)
for (int i = 0; i < children.getLength(); ++i) {
var childNode = children.item(i);
if (childNode.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
component.add(parseNode(childNode));
}
return component;
}
@SneakyThrows
private Component createComponent(Class<?> componentClass, NamedNodeMap attributes) {
var component = (Component) componentClass.getConstructor().newInstance();
// Set attributes via setter methods
for (int i = 0; i < attributes.getLength(); ++i) {
var attribute = attributes.item(i);
// Ignore namespaces definitions
if ("xmlns".equals(attribute.getPrefix())) {
continue;
}
var setterName = createSetterMethodName(attribute.getLocalName());
var value = parseValue(attribute.getNodeValue());
var setter = componentClass.getMethod(setterName, value.getClass());
setter.invoke(component, value);
}
return component;
}
private static String createSetterMethodName(String name) {
return "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
}
@SneakyThrows
private Object parseValue(String value) {
var evaluator = new ExpressionEvaluator();
evaluator.setDefaultImports(IMPORTS);
evaluator.cook(value);
return evaluator.evaluate();
}
}