summaryrefslogtreecommitdiffstats
path: root/core/src/ch/asynk/gdx/boardgame/ui
diff options
context:
space:
mode:
authorJérémy Zurcher <jeremy@asynk.ch>2018-10-03 16:29:04 +0200
committerJérémy Zurcher <jeremy@asynk.ch>2018-10-03 16:29:04 +0200
commit2f1bec6890815033211fde71e645c5a57e502a20 (patch)
treea83756b4df61e729fdbdf495c19423dc7799e269 /core/src/ch/asynk/gdx/boardgame/ui
parent977ce8e5a8f967f2ad9acc634111231e3af9ef7a (diff)
downloadgdx-boardgame-2f1bec6890815033211fde71e645c5a57e502a20.zip
gdx-boardgame-2f1bec6890815033211fde71e645c5a57e502a20.tar.gz
tabletop -> boardgame
Diffstat (limited to 'core/src/ch/asynk/gdx/boardgame/ui')
-rw-r--r--core/src/ch/asynk/gdx/boardgame/ui/Alignment.java168
-rw-r--r--core/src/ch/asynk/gdx/boardgame/ui/Assembly.java63
-rw-r--r--core/src/ch/asynk/gdx/boardgame/ui/Button.java67
-rw-r--r--core/src/ch/asynk/gdx/boardgame/ui/Element.java116
-rw-r--r--core/src/ch/asynk/gdx/boardgame/ui/Label.java61
-rw-r--r--core/src/ch/asynk/gdx/boardgame/ui/Menu.java126
-rw-r--r--core/src/ch/asynk/gdx/boardgame/ui/Patch.java23
-rw-r--r--core/src/ch/asynk/gdx/boardgame/ui/Root.java28
8 files changed, 652 insertions, 0 deletions
diff --git a/core/src/ch/asynk/gdx/boardgame/ui/Alignment.java b/core/src/ch/asynk/gdx/boardgame/ui/Alignment.java
new file mode 100644
index 0000000..67da089
--- /dev/null
+++ b/core/src/ch/asynk/gdx/boardgame/ui/Alignment.java
@@ -0,0 +1,168 @@
+package ch.asynk.gdx.boardgame.ui;
+
+public enum Alignment
+{
+ ABSOLUTE, // Root
+ RELATIVE, // Default
+ TOP_LEFT,
+ TOP_RIGHT,
+ TOP_CENTER,
+ MIDDLE_LEFT,
+ MIDDLE_RIGHT,
+ MIDDLE_CENTER,
+ BOTTOM_LEFT,
+ BOTTOM_RIGHT,
+ BOTTOM_CENTER;
+
+ public Alignment verticalMirror()
+ {
+ switch(this) {
+ case TOP_LEFT:
+ return TOP_RIGHT;
+ case MIDDLE_LEFT:
+ return MIDDLE_RIGHT;
+ case BOTTOM_LEFT:
+ return BOTTOM_RIGHT;
+ case TOP_RIGHT:
+ return TOP_LEFT;
+ case MIDDLE_RIGHT:
+ return MIDDLE_LEFT;
+ case BOTTOM_RIGHT:
+ return BOTTOM_LEFT;
+ }
+ return this;
+ }
+
+ public Alignment horizontalMirror()
+ {
+ switch(this) {
+ case TOP_LEFT:
+ return BOTTOM_LEFT;
+ case TOP_CENTER:
+ return BOTTOM_CENTER;
+ case TOP_RIGHT:
+ return BOTTOM_RIGHT;
+ case BOTTOM_LEFT:
+ return TOP_LEFT;
+ case BOTTOM_CENTER:
+ return TOP_CENTER;
+ case BOTTOM_RIGHT:
+ return TOP_RIGHT;
+ }
+ return this;
+ }
+
+ public boolean isTop()
+ {
+ switch(this) {
+ case TOP_LEFT:
+ case TOP_CENTER:
+ case TOP_RIGHT:
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isMiddle()
+ {
+ boolean r = false;
+ switch(this) {
+ case MIDDLE_LEFT:
+ case MIDDLE_CENTER:
+ case MIDDLE_RIGHT:
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isBottom()
+ {
+ boolean r = false;
+ switch(this) {
+ case BOTTOM_LEFT:
+ case BOTTOM_CENTER:
+ case BOTTOM_RIGHT:
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isLeft()
+ {
+ boolean r = false;
+ switch(this) {
+ case TOP_LEFT:
+ case MIDDLE_LEFT:
+ case BOTTOM_LEFT:
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isRight()
+ {
+ boolean r = false;
+ switch(this) {
+ case TOP_RIGHT:
+ case MIDDLE_RIGHT:
+ case BOTTOM_RIGHT:
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isCenter()
+ {
+ switch(this) {
+ case TOP_CENTER:
+ case MIDDLE_CENTER:
+ case BOTTOM_CENTER:
+ return true;
+ }
+ return false;
+ }
+
+ public float getX(Element element, float width)
+ {
+ float x = element.getInnerX();
+ switch(this) {
+ case TOP_LEFT:
+ case MIDDLE_LEFT:
+ case BOTTOM_LEFT:
+ break;
+ case TOP_CENTER:
+ case MIDDLE_CENTER:
+ case BOTTOM_CENTER:
+ x += ((element.getInnerWidth() - width) / 2);
+ break;
+ case TOP_RIGHT:
+ case MIDDLE_RIGHT:
+ case BOTTOM_RIGHT:
+ x += (element.getInnerWidth() - width);
+ break;
+ }
+ return x;
+ }
+
+ public float getY(Element element, float height)
+ {
+ float y = element.getInnerY();
+ switch(this) {
+ case TOP_LEFT:
+ case TOP_CENTER:
+ case TOP_RIGHT:
+ y += (element.getInnerHeight() - height);
+ break;
+ case MIDDLE_LEFT:
+ case MIDDLE_CENTER:
+ case MIDDLE_RIGHT:
+ y += ((element.getInnerHeight() - height) / 2);
+ break;
+ case BOTTOM_LEFT:
+ case BOTTOM_CENTER:
+ case BOTTOM_RIGHT:
+ break;
+ }
+ return y;
+ }
+}
diff --git a/core/src/ch/asynk/gdx/boardgame/ui/Assembly.java b/core/src/ch/asynk/gdx/boardgame/ui/Assembly.java
new file mode 100644
index 0000000..c603383
--- /dev/null
+++ b/core/src/ch/asynk/gdx/boardgame/ui/Assembly.java
@@ -0,0 +1,63 @@
+package ch.asynk.gdx.boardgame.ui;
+
+import com.badlogic.gdx.graphics.g2d.Batch;
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
+
+import ch.asynk.gdx.boardgame.util.IterableSet;
+
+public abstract class Assembly extends Element
+{
+ private IterableSet<Element> children;
+ private Element touched;
+
+ public Assembly(int c)
+ {
+ this.children = new IterableSet<Element>(c);
+ }
+
+ public void add(Element e)
+ {
+ if (children.add(e)) {
+ e.setParent(this);
+ }
+ }
+
+ public void remove(Element e)
+ {
+ if (children.remove(e)) {
+ e.setParent(null);
+ }
+ }
+
+ public Element touched()
+ {
+ return touched;
+ }
+
+ @Override public boolean touch(float x, float y)
+ {
+ for (Element e : children)
+ if (e.touch(x, y)) {
+ touched = e;
+ return true;
+ }
+ touched = null;
+ return false;
+ }
+
+ @Override public void taint()
+ {
+ children.forEach( c -> c.taint() );
+ }
+
+ @Override public void draw(Batch batch)
+ {
+ if (tainted) computeGeometry();
+ children.forEach( c -> c.draw(batch) );
+ }
+
+ @Override public void drawDebug(ShapeRenderer debugShapes)
+ {
+ children.forEach( c -> c.drawDebug(debugShapes) );
+ }
+}
diff --git a/core/src/ch/asynk/gdx/boardgame/ui/Button.java b/core/src/ch/asynk/gdx/boardgame/ui/Button.java
new file mode 100644
index 0000000..9bc1149
--- /dev/null
+++ b/core/src/ch/asynk/gdx/boardgame/ui/Button.java
@@ -0,0 +1,67 @@
+package ch.asynk.gdx.boardgame.ui;
+
+import com.badlogic.gdx.graphics.g2d.Batch;
+import com.badlogic.gdx.graphics.g2d.BitmapFont;
+import com.badlogic.gdx.graphics.g2d.NinePatch;
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
+
+public class Button extends Patch
+{
+ private Label label;
+ private float spacing; // for label alignment;
+
+ public Button(BitmapFont font, NinePatch patch)
+ {
+ this(font, patch, 0);
+ }
+
+ public Button(BitmapFont font, NinePatch patch, float padding)
+ {
+ this(font, patch, padding, 0);
+ }
+
+ public Button(BitmapFont font, NinePatch patch, float padding, float spacing)
+ {
+ super(patch);
+ this.padding = padding;
+ this.spacing = spacing;
+ label = new Label(font);
+ label.setParent(this);
+ label.setAlignment(Alignment.MIDDLE_CENTER);
+ }
+
+ public void write(String text)
+ {
+ label.write(text);
+ this.tainted = true; // might impact Button's geometry
+ }
+
+ public void setLabelAlignment(Alignment alignment)
+ {
+ label.setAlignment(alignment);
+ }
+
+ @Override public void computeGeometry()
+ {
+ float dd = 2 * (padding + spacing);
+ label.computeGeometry(); // update dimensions
+ rect.width = label.getWidth() + dd;
+ rect.height = label.getHeight() + dd;
+ super.computeGeometry();
+ label.computeGeometry(); // update position
+ }
+
+ @Override public void draw(Batch batch)
+ {
+ if (!visible) return;
+ if (tainted) computeGeometry();
+ super.draw(batch);
+ label.draw(batch);
+ }
+
+ @Override public void drawDebug(ShapeRenderer debugShapes)
+ {
+ super.drawDebug(debugShapes);
+ label.drawDebug(debugShapes);
+ }
+}
diff --git a/core/src/ch/asynk/gdx/boardgame/ui/Element.java b/core/src/ch/asynk/gdx/boardgame/ui/Element.java
new file mode 100644
index 0000000..25f38eb
--- /dev/null
+++ b/core/src/ch/asynk/gdx/boardgame/ui/Element.java
@@ -0,0 +1,116 @@
+package ch.asynk.gdx.boardgame.ui;
+
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
+import com.badlogic.gdx.math.Rectangle;
+
+import ch.asynk.gdx.boardgame.Drawable;
+import ch.asynk.gdx.boardgame.Touchable;
+
+public abstract class Element implements Drawable, Touchable
+{
+ public boolean blocked;
+ public boolean visible;
+ protected float padding;
+ protected Element parent;
+ protected Alignment alignment;
+ protected Rectangle rect; // outer drawing coordinates
+ protected float x, y; // given position
+ protected boolean tainted; // geometry must be computed
+
+ protected Element()
+ {
+ this.blocked = false;
+ this.visible = true;
+ this.padding = 0;
+ this.parent = null;
+ this.alignment = alignment.RELATIVE;
+ this.rect = new Rectangle(0, 0, 0, 0);
+ this.x = this.y = 0;
+ this.tainted = true;
+ }
+
+ @Override public final float getX() { return rect.x; }
+ @Override public final float getY() { return rect.y; }
+ @Override public final float getWidth() { return rect.width; }
+ @Override public final float getHeight() { return rect.height; }
+
+ @Override public final float getInnerX() { return rect.x + padding; }
+ @Override public final float getInnerY() { return rect.y + padding; }
+ @Override public final float getInnerWidth() { return rect.width - 2 * padding; }
+ @Override public final float getInnerHeight() { return rect.height - 2 * padding; }
+
+ @Override public void drawDebug(ShapeRenderer debugShapes)
+ {
+ debugShapes.rect(getX(), getY(), getWidth(), getHeight());
+ }
+
+ @Override public boolean touch(float x, float y)
+ {
+ if (blocked || !visible) return false;
+ return rect.contains(x, y);
+ }
+
+ public void taint()
+ {
+ this.tainted = true;
+ }
+
+ @Override public void setPosition(float x, float y, float w, float h)
+ {
+ this.x = x;
+ this.y = y;
+ this.rect.width = w;
+ this.rect.height = h;
+ this.tainted = true;
+ // rect.(x,y) will be set in computeGeometry
+ }
+
+ public void setParent(Element parent)
+ {
+ this.parent = parent;
+ this.tainted = true;
+ }
+
+ public void setPadding(float padding)
+ {
+ this.padding = padding;
+ this.tainted = true;
+ }
+
+ public void setAlignment(Alignment alignment)
+ {
+ this.alignment = alignment;
+ this.tainted = true;
+ }
+
+ public final void translate(float dx, float dy)
+ {
+ setPosition(x + dx, y + dy);
+ }
+
+ public final void setPosition(Rectangle r)
+ {
+ setPosition(r.x, r.x, r.width, r.height);
+ }
+
+ public final void setPosition(float x, float y)
+ {
+ setPosition(x, y, rect.width, rect.height);
+ }
+
+ protected void computeGeometry()
+ {
+ if (alignment == Alignment.ABSOLUTE || parent == null) {
+ rect.x = x;
+ rect.y = y;
+ } else if (alignment == Alignment.RELATIVE) {
+ rect.x = x + parent.getInnerX();
+ rect.y = y + parent.getInnerX();
+ } else {
+ rect.x = x + alignment.getX(parent, rect.width);
+ rect.y = y + alignment.getY(parent, rect.height);
+ }
+ this.tainted = false;
+ // System.err.println(String.format("%s : %s", this, rect));
+ }
+}
diff --git a/core/src/ch/asynk/gdx/boardgame/ui/Label.java b/core/src/ch/asynk/gdx/boardgame/ui/Label.java
new file mode 100644
index 0000000..32ae814
--- /dev/null
+++ b/core/src/ch/asynk/gdx/boardgame/ui/Label.java
@@ -0,0 +1,61 @@
+package ch.asynk.gdx.boardgame.ui;
+
+import com.badlogic.gdx.graphics.g2d.Batch;
+import com.badlogic.gdx.graphics.g2d.BitmapFont;
+import com.badlogic.gdx.graphics.g2d.GlyphLayout;
+
+public class Label extends Element
+{
+ private BitmapFont font;
+ private GlyphLayout layout;
+ private float fx;
+ private float fy;
+ private String text;
+
+ public Label(BitmapFont font)
+ {
+ this(font, 0);
+ }
+
+ public Label(BitmapFont font, float padding)
+ {
+ this(font, padding, Alignment.RELATIVE);
+ }
+
+ public Label(BitmapFont font, float padding, Alignment alignment)
+ {
+ super();
+ this.font = font;
+ this.padding = padding;
+ this.alignment = alignment;
+ this.layout = new GlyphLayout();
+ }
+
+ public void write(String text)
+ {
+ write(text, getX(), getY());
+ }
+
+ public void write(String text, float x, float y)
+ {
+ this.text = text;
+ this.layout.setText(font, (text == null) ? "" : text);
+ this.tainted = true;
+ }
+
+ @Override protected void computeGeometry()
+ {
+ this.rect.width = (layout.width + (2 * padding));
+ this.rect.height = (layout.height + (2 * padding));
+ super.computeGeometry();
+ fx = getInnerX();
+ fy = getInnerY() + layout.height;
+ }
+
+ @Override public void draw(Batch batch)
+ {
+ if (!visible) return;
+ if (tainted) computeGeometry();
+ font.draw(batch, layout, fx, fy);
+ }
+}
diff --git a/core/src/ch/asynk/gdx/boardgame/ui/Menu.java b/core/src/ch/asynk/gdx/boardgame/ui/Menu.java
new file mode 100644
index 0000000..aa62483
--- /dev/null
+++ b/core/src/ch/asynk/gdx/boardgame/ui/Menu.java
@@ -0,0 +1,126 @@
+package ch.asynk.gdx.boardgame.ui;
+
+import com.badlogic.gdx.graphics.g2d.Batch;
+import com.badlogic.gdx.graphics.g2d.NinePatch;
+import com.badlogic.gdx.graphics.g2d.BitmapFont;
+
+public class Menu extends Patch
+{
+ private Label title;
+ private Label[] entries;
+ private Integer touchedItem;
+
+ private int entriesOffset; // horizontal offset
+ private int titleSpacing; // between title and entries
+ private int entriesSpacing; // between entries
+
+ public Menu(BitmapFont font, NinePatch patch, String title, String[] entries)
+ {
+ super(patch);
+ this.touchedItem = null;
+ setTitle(font, title);
+ setEntries(font, entries);
+ }
+
+ public void setTitle(BitmapFont font, String title)
+ {
+ this.title = new Label(font);
+ this.title.write(title);
+ this.tainted = true;
+ }
+
+ public void setEntries(BitmapFont font, String[] entries)
+ {
+ this.entries = new Label[entries.length];
+ for (int i = 0; i < entries.length; i++) {
+ Label l = new Label(font);
+ l.write(entries[i]);
+ this.entries[i] = l;
+ }
+ this.tainted = true;
+ }
+
+ public void setLabelsOffset(int entriesOffset)
+ {
+ this.entriesOffset = entriesOffset;
+ this.tainted = true;
+ }
+
+ public void setPaddings(int titlePadding, int labelPadding)
+ {
+ this.title.setPadding(titlePadding);
+ for (Label label : entries) {
+ label.setPadding(labelPadding);
+ }
+ this.tainted = true;
+ }
+
+ public void setSpacings(int titleSpacing, int entriesSpacing)
+ {
+ this.titleSpacing = titleSpacing;
+ this.entriesSpacing = entriesSpacing;
+ this.tainted = true;
+ }
+
+ @Override public void computeGeometry()
+ {
+ title.computeGeometry();
+ float h = title.getHeight();
+ float w = title.getWidth();
+ for (Label label : entries) {
+ label.computeGeometry();
+ h += label.getHeight();
+ float t = label.getWidth() + entriesOffset;
+ if (t > w)
+ w = t;
+ }
+ h += (titleSpacing + (entriesSpacing * (entries.length - 1)) + (2 * padding));
+ w += (2 * padding);
+
+ rect.width = w;
+ rect.height = h;
+ super.computeGeometry();
+
+ float x = getInnerX();
+ float y = getInnerY();
+
+ // setPosition() will trigger computeGeometry() from within draw()
+ for (int i = entries.length - 1; i >= 0; i--) {
+ entries[i].setPosition(x + entriesOffset, y);
+ y += entries[i].getHeight() + entriesSpacing;
+ }
+ y -= entriesSpacing;
+ y += titleSpacing;
+ title.setPosition(x, y);
+ }
+
+ public Integer touched()
+ {
+ return touchedItem;
+ }
+
+ @Override public boolean touch(float x, float y)
+ {
+ touchedItem = null;
+ if (super.touch(x, y)) {
+ for (int i = 0; i < entries.length; i++) {
+ if (entries[i].touch(x, y)) {
+ touchedItem = i;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override public void draw(Batch batch)
+ {
+ if (!visible) return;
+ if (tainted) computeGeometry();
+ super.draw(batch);
+ title.draw(batch);
+ for (Label label : entries) {
+ label.draw(batch);
+ }
+ }
+}
diff --git a/core/src/ch/asynk/gdx/boardgame/ui/Patch.java b/core/src/ch/asynk/gdx/boardgame/ui/Patch.java
new file mode 100644
index 0000000..df2cc06
--- /dev/null
+++ b/core/src/ch/asynk/gdx/boardgame/ui/Patch.java
@@ -0,0 +1,23 @@
+package ch.asynk.gdx.boardgame.ui;
+
+import com.badlogic.gdx.graphics.g2d.Batch;
+import com.badlogic.gdx.graphics.g2d.NinePatch;
+
+public class Patch extends Element
+{
+ private NinePatch patch;
+
+ public Patch(NinePatch patch)
+ {
+ super();
+ this.patch = patch;
+ setPosition(0, 0, patch.getTotalWidth(), patch.getTotalHeight());
+ }
+
+ @Override public void draw(Batch batch)
+ {
+ if (!visible) return;
+ if (tainted) computeGeometry();
+ patch.draw(batch, getX(), getY(), getWidth(), getHeight());
+ }
+}
diff --git a/core/src/ch/asynk/gdx/boardgame/ui/Root.java b/core/src/ch/asynk/gdx/boardgame/ui/Root.java
new file mode 100644
index 0000000..2353c41
--- /dev/null
+++ b/core/src/ch/asynk/gdx/boardgame/ui/Root.java
@@ -0,0 +1,28 @@
+package ch.asynk.gdx.boardgame.ui;
+
+import com.badlogic.gdx.math.Rectangle;
+
+public class Root extends Assembly
+{
+ public Root(int c)
+ {
+ super(c);
+ this.alignment = Alignment.ABSOLUTE;
+ }
+
+ public void resize(Rectangle r)
+ {
+ resize(r.x, r.y, r.width, r.height);
+ }
+
+ public void resize(float width, float height)
+ {
+ resize(getX(), getY(), width, height);
+ }
+
+ public void resize(float x, float y, float width, float height)
+ {
+ setPosition(x, y, width, height);
+ taint();
+ }
+}