diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/base/BaseWidget.java b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/base/BaseWidget.java index b9da5d80..d8db1105 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/base/BaseWidget.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/base/BaseWidget.java @@ -53,17 +53,17 @@ public abstract class BaseWidget implements Widget { } @Override - public void setWidth(float width) { + public void setWidth(Float width) { this.width = width; } @Override - public void setHeight(float height) { + public void setHeight(Float height) { this.height = height; } @Override - public void setSize(float width, float height) { + public void setSize(Float width, Float height) { this.width = width; this.height = height; } @@ -115,23 +115,23 @@ public abstract class BaseWidget implements Widget { } @Override - public void setX(float x) { + public void setX(Float x) { this.x = x; } @Override - public void setY(float y) { + public void setY(Float y) { this.y = y; } @Override - public void setPosition(float x, float y) { + public void setPosition(Float x, Float y) { this.x = x; this.y = y; } @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.marginRight = right; this.marginBottom = bottom; @@ -139,7 +139,7 @@ public abstract class BaseWidget implements Widget { } @Override - public void setMargin(float top, float rightLeft, float bottom) { + public void setMargin(Float top, Float rightLeft, Float bottom) { this.marginTop = top; this.marginRight = rightLeft; this.marginBottom = bottom; @@ -147,7 +147,7 @@ public abstract class BaseWidget implements Widget { } @Override - public void setMargin(float topBottom, float rightLeft) { + public void setMargin(Float topBottom, Float rightLeft) { this.marginTop = topBottom; this.marginRight = rightLeft; this.marginBottom = topBottom; @@ -155,7 +155,7 @@ public abstract class BaseWidget implements Widget { } @Override - public void setMargin(float all) { + public void setMargin(Float all) { this.marginTop = all; this.marginRight = all; this.marginBottom = all; @@ -163,22 +163,22 @@ public abstract class BaseWidget implements Widget { } @Override - public void setMarginTop(float margin) { + public void setMarginTop(Float margin) { this.marginTop = margin; } @Override - public void setMarginRight(float margin) { + public void setMarginRight(Float margin) { this.marginRight = margin; } @Override - public void setMarginBottom(float margin) { + public void setMarginBottom(Float margin) { this.marginBottom = margin; } @Override - public void setMarginLeft(float margin) { + public void setMarginLeft(Float margin) { this.marginLeft = margin; } @@ -203,7 +203,7 @@ public abstract class BaseWidget implements Widget { } @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.paddingRight = right; this.paddingBottom = bottom; @@ -211,7 +211,7 @@ public abstract class BaseWidget implements Widget { } @Override - public void setPadding(float top, float rightLeft, float bottom) { + public void setPadding(Float top, Float rightLeft, Float bottom) { this.paddingTop = top; this.paddingRight = rightLeft; this.paddingBottom = bottom; @@ -219,7 +219,7 @@ public abstract class BaseWidget implements Widget { } @Override - public void setPadding(float topBottom, float rightLeft) { + public void setPadding(Float topBottom, Float rightLeft) { this.paddingTop = topBottom; this.paddingRight = rightLeft; this.paddingBottom = topBottom; @@ -227,7 +227,7 @@ public abstract class BaseWidget implements Widget { } @Override - public void setPadding(float all) { + public void setPadding(Float all) { this.paddingTop = all; this.paddingRight = all; this.paddingBottom = all; @@ -235,22 +235,22 @@ public abstract class BaseWidget implements Widget { } @Override - public void setPaddingTop(float padding) { + public void setPaddingTop(Float padding) { this.paddingTop = padding; } @Override - public void setPaddingRight(float padding) { + public void setPaddingRight(Float padding) { this.paddingRight = padding; } @Override - public void setPaddingBottom(float padding) { + public void setPaddingBottom(Float padding) { this.paddingBottom = padding; } @Override - public void setPaddingLeft(float padding) { + public void setPaddingLeft(Float padding) { this.paddingLeft = padding; } diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/base/Widget.java b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/base/Widget.java index 034d22cb..d239a64d 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/base/Widget.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/base/Widget.java @@ -12,11 +12,11 @@ public interface Widget extends KeyEventHandler { 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(); @@ -26,11 +26,11 @@ public interface Widget extends KeyEventHandler { 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(); @@ -42,21 +42,21 @@ public interface Widget extends KeyEventHandler { 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(); @@ -66,21 +66,21 @@ public interface Widget extends KeyEventHandler { 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(); diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/BaseComponent.java b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/BaseComponent.java index d21d19d7..bd2518b4 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/BaseComponent.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/BaseComponent.java @@ -2,9 +2,26 @@ package com.bartlomiejpluta.base.api.game.gui.component; import com.bartlomiejpluta.base.api.game.gui.base.BaseWidget; +import static java.util.Collections.emptyList; + public abstract class BaseComponent extends BaseWidget implements Component { protected boolean focused; + @Override + public Iterable getChildren() { + return emptyList(); + } + + @Override + public void add(Component component) { + throw new UnsupportedOperationException(); + } + + @Override + public void remove(Component component) { + throw new UnsupportedOperationException(); + } + @Override public boolean isFocused() { return focused; diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/BaseContainer.java b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/BaseContainer.java index 35f8b200..dddfd063 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/BaseContainer.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/BaseContainer.java @@ -5,8 +5,16 @@ import com.bartlomiejpluta.base.api.game.input.KeyEvent; import java.util.LinkedList; import java.util.List; +import static java.util.Collections.unmodifiableList; + public abstract class BaseContainer extends BaseComponent implements Container { protected final List children = new LinkedList<>(); + private final List readOnlyChildren = unmodifiableList(children); + + @Override + public Iterable getChildren() { + return readOnlyChildren; + } @Override public void add(Component component) { diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/Component.java b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/Component.java index 8578bc95..7c126007 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/Component.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/Component.java @@ -3,6 +3,12 @@ package com.bartlomiejpluta.base.api.game.gui.component; import com.bartlomiejpluta.base.api.game.gui.base.Widget; public interface Component extends Widget { + Iterable getChildren(); + + void add(Component component); + + void remove(Component component); + boolean isFocused(); void focus(); diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/Container.java b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/Container.java index 2c86d1c4..b03c1fe2 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/Container.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/Container.java @@ -1,7 +1,4 @@ package com.bartlomiejpluta.base.api.game.gui.component; public interface Container extends Component { - void add(Component component); - - void remove(Component component); } diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/Label.java b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/Label.java index 6c549772..e2dcadbe 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/Label.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/component/Label.java @@ -7,23 +7,27 @@ import com.bartlomiejpluta.base.api.game.screen.Screen; import static java.util.Objects.requireNonNull; public class Label extends BaseComponent { - private final GUI gui; +// private final GUI gui; private String text = ""; private String font; private float fontSize; private int alignment = GUI.ALIGN_LEFT; - private final Color color; + private Color color; private final float[] bounds = new float[4]; - public Label(GUI gui, String font) { - this.gui = requireNonNull(gui); - this.font = requireNonNull(font); + public Label() { - 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() { return text; } @@ -44,7 +48,7 @@ public class Label extends BaseComponent { return fontSize; } - public void setFontSize(float fontSize) { + public void setFontSize(Float fontSize) { this.fontSize = fontSize; } @@ -52,7 +56,7 @@ public class Label extends BaseComponent { return alignment; } - public void setAlignment(int alignment) { + public void setAlignment(Integer alignment) { this.alignment = alignment; } @@ -60,7 +64,7 @@ public class Label extends BaseComponent { return color.getRed(); } - public void setRed(float value) { + public void setRed(Float value) { color.setRed(value); } @@ -68,7 +72,7 @@ public class Label extends BaseComponent { return color.getGreen(); } - public void setGreen(float value) { + public void setGreen(Float value) { color.setGreen(value); } @@ -76,7 +80,7 @@ public class Label extends BaseComponent { return color.getBlue(); } - public void setBlue(float value) { + public void setBlue(Float value) { color.setBlue(value); } @@ -84,15 +88,15 @@ public class Label extends BaseComponent { return color.getAlpha(); } - public void setAlpha(float value) { + public void setAlpha(Float 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); } - public void setColor(float red, float green, float blue) { + public void setColor(Float red, Float green, Float blue) { color.setRGB(red, green, blue); } @@ -116,4 +120,9 @@ public class Label extends BaseComponent { gui.fill(); gui.putTextBox(x + paddingLeft, y + paddingTop, getWidth() - paddingLeft - paddingRight, text, bounds); } + + @Override + public String toString() { + return "Label[" + text + "]"; + } } diff --git a/engine/build.gradle b/engine/build.gradle index 0efd24ad..5f1e7171 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -86,6 +86,9 @@ dependencies { compileOnly '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. implementation "org.joml:joml:${jomlVersion}" } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/widget/ScreenWidget.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/widget/ScreenWidget.java index 98f4f804..ee8d3057 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/widget/ScreenWidget.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/widget/ScreenWidget.java @@ -58,32 +58,32 @@ public class ScreenWidget implements Widget { } @Override - public void setX(float x) { + public void setX(Float x) { throw new UnsupportedOperationException(); } @Override - public void setY(float y) { + public void setY(Float y) { throw new UnsupportedOperationException(); } @Override - public void setPosition(float x, float y) { + public void setPosition(Float x, Float y) { throw new UnsupportedOperationException(); } @Override - public void setWidth(float width) { + public void setWidth(Float width) { throw new UnsupportedOperationException(); } @Override - public void setHeight(float height) { + public void setHeight(Float height) { throw new UnsupportedOperationException(); } @Override - public void setSize(float width, float height) { + public void setSize(Float width, Float height) { throw new UnsupportedOperationException(); } @@ -113,42 +113,42 @@ public class ScreenWidget implements Widget { } @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(); } @Override - public void setMargin(float top, float rightLeft, float bottom) { + public void setMargin(Float top, Float rightLeft, Float bottom) { throw new UnsupportedOperationException(); } @Override - public void setMargin(float topBottom, float rightLeft) { + public void setMargin(Float topBottom, Float rightLeft) { throw new UnsupportedOperationException(); } @Override - public void setMargin(float all) { + public void setMargin(Float all) { throw new UnsupportedOperationException(); } @Override - public void setMarginTop(float margin) { + public void setMarginTop(Float margin) { throw new UnsupportedOperationException(); } @Override - public void setMarginRight(float margin) { + public void setMarginRight(Float margin) { throw new UnsupportedOperationException(); } @Override - public void setMarginBottom(float margin) { + public void setMarginBottom(Float margin) { throw new UnsupportedOperationException(); } @Override - public void setMarginLeft(float margin) { + public void setMarginLeft(Float margin) { throw new UnsupportedOperationException(); } @@ -173,42 +173,42 @@ public class ScreenWidget implements Widget { } @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(); } @Override - public void setPadding(float top, float rightLeft, float bottom) { + public void setPadding(Float top, Float rightLeft, Float bottom) { throw new UnsupportedOperationException(); } @Override - public void setPadding(float topBottom, float rightLeft) { + public void setPadding(Float topBottom, Float rightLeft) { throw new UnsupportedOperationException(); } @Override - public void setPadding(float all) { + public void setPadding(Float all) { throw new UnsupportedOperationException(); } @Override - public void setPaddingTop(float padding) { + public void setPaddingTop(Float padding) { throw new UnsupportedOperationException(); } @Override - public void setPaddingRight(float padding) { + public void setPaddingRight(Float padding) { throw new UnsupportedOperationException(); } @Override - public void setPaddingBottom(float padding) { + public void setPaddingBottom(Float padding) { throw new UnsupportedOperationException(); } @Override - public void setPaddingLeft(float padding) { + public void setPaddingLeft(Float padding) { throw new UnsupportedOperationException(); } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/xml/inflater/ComponentInflater.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/xml/inflater/ComponentInflater.java new file mode 100644 index 00000000..55c53f72 --- /dev/null +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/xml/inflater/ComponentInflater.java @@ -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. ) + 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. ) + 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(); + } +}