package squidpony.squidgrid.gui.gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.utils.Pools;
/**
* @author smelC
*/
public class UIUtil {
/**
* Writes {@code text} at {@code (x, y)} by cutting off using "…" if it gets
* wider than {@code width}.
*
* @param batch
* @param font
* The font to use
* @param text
* The text to draw
* @param color
* The text's color
* @param align
* The alignment (see {@link com.badlogic.gdx.utils.Align}).
* @param width
* The desired width of the text
* @param x
* Where to draw
* @param y
* Where to draw
*/
public static void drawLimitedWidthText(Batch batch, BitmapFont font, String text, Color color,
int align, float width, float x, float y) {
final GlyphLayout glyph = Pools.obtain(GlyphLayout.class);
glyph.setText(font, text, 0, text.length(), color, width, align,
/* do not wrap */ false, /* the ellipsis */ "…");
font.draw(batch, glyph, x, y);
Pools.free(glyph);
}
/**
* Draws margins around an actor.
*
* @param renderer_
* The renderer to use. If {@code null} a new one will be
* allocated.
* @param a
* the actor to draw around
* @param margin
* The size of the margin to draw.
* @param color
* The margins' colors.
*/
public static void drawMarginsAround(ShapeRenderer renderer_, Actor a, float margin, Color color,
CornerStyle cornerStyle) {
drawMarginsAround(renderer_, a.getX(), a.getY(), a.getWidth(), a.getHeight(), margin, color,
cornerStyle, 1f, 1f);
}
/**
* Draws margins around a rectangle
*
* @param botLeftX
* The rectangle's bottom left.
* @param botLeftY
* The rectangle's bottom left.
* @param width
* The rectangle's width.
* @param height
* The rectangle's height.
* @param xmargin
* The size of the left margin and the size of the right margin.
* @param ymargin
* The size of the bottom margin and the size of the top margin.
* @param c
* The margins' colors.
*/
public static void drawMarginsAround(float botLeftX, float botLeftY, int width, int height, int xmargin,
int ymargin, Color c) {
if (xmargin == 0 && ymargin == 0)
return;
final ShapeRenderer renderer = new ShapeRenderer();
renderer.begin(ShapeType.Filled);
renderer.setColor(c);
if (0 < xmargin) {
/* The left rectangle */
renderer.rect(botLeftX - xmargin, botLeftY - ymargin, xmargin, height + (ymargin * 2));
/* The right rectangle */
renderer.rect(botLeftX + width, botLeftY - ymargin, xmargin, height + (ymargin * 2));
}
if (0 < ymargin) {
/* The bottom rectangle */
renderer.rect(botLeftX, botLeftY - ymargin, width, ymargin);
/* The top rectangle */
renderer.rect(botLeftX, botLeftY + height, width, ymargin);
}
renderer.end();
renderer.dispose();
}
/**
* @param renderer_
* The renderer to use. If {@code null} a new one will be
* allocated.
* @param botLeftX
* The bottom left x cell of the rectangle to draw around.
* @param botLeftY
* The bottom left y cell of the rectangle to draw around.
* @param width
* The width of the button considered.
* @param height
* The width of the button considered.
* @param margin
* The size of the margin to draw.
* @param color
* The color to draw
* @param cornerStyle
* The style with which to draw the margins
*/
public static void drawMarginsAround(ShapeRenderer renderer_, float botLeftX, float botLeftY, float width,
float height, float margin, Color color, CornerStyle cornerStyle) {
drawMarginsAround(renderer_, botLeftX, botLeftY, width, height, margin, color, cornerStyle, 1f, 1f);
}
/**
* @param renderer_
* The renderer to use. If {@code null} a new one will be
* allocated.
* @param botLeftX
* The bottom left x cell of the rectangle to draw around.
* @param botLeftY
* The bottom left y cell of the rectangle to draw around.
* @param width
* The width of the button considered.
* @param height
* The width of the button considered.
* @param margin
* The size of the margin to draw.
* @param color
* The color to draw
* @param cornerStyle
* The style with which to draw the margins
* @param zoomX
* A multiplier for the world x-size of non-ShapeRenderer
* objects, that needs to be reversed for this
* @param zoomY
* A multiplier for the world y-size of non-ShapeRenderer
* objects, that needs to be reversed for this
*/
public static void drawMarginsAround(ShapeRenderer renderer_, float botLeftX, float botLeftY, float width,
float height, float margin, Color color, CornerStyle cornerStyle, float zoomX, float zoomY) {
if (margin == 0 || color == null)
/* Nothing to do */
return;
botLeftY += 1;
final boolean reset;
final ShapeRenderer renderer = renderer_ == null ? new ShapeRenderer() : renderer_;
/*
* No matter the state of the given ShapeRenderer, we'll be fine, thanks
* to this:
*/
if (!renderer.isDrawing()) {
reset = true;
renderer.begin(ShapeType.Filled);
} else
reset = false;
renderer.scale(1f / zoomX, 1f / zoomY, 1f);
renderer.setColor(color);
if (cornerStyle == CornerStyle.ROUNDED || cornerStyle == CornerStyle.MISSING) {
/* Left margin */
renderer.rect(botLeftX - margin, botLeftY, margin, height);
/* Right margin */
renderer.rect(botLeftX + width, botLeftY, margin, height);
} else {
/* Left margin */
renderer.rect(botLeftX - margin, botLeftY - margin, margin, height + (margin * 2));
/* Right margin */
renderer.rect(botLeftX + width, botLeftY - margin, margin, height + (margin * 2));
}
/* Bottom margin */
renderer.rect(botLeftX, botLeftY - margin, width, margin);
/* Top margin */
renderer.rect(botLeftX, botLeftY + height, width, margin);
if (cornerStyle == CornerStyle.ROUNDED) {
/* Bottom left */
renderer.arc(botLeftX, botLeftY, margin, 180, 90);
/* Top left */
renderer.arc(botLeftX, botLeftY + height, margin, 90, 90);
/* Top right */
renderer.arc(botLeftX + width, botLeftY + height, margin, 0, 90);
/* Bottom Right */
renderer.arc(botLeftX + width, botLeftY, margin, 270, 90);
}
if (reset)
renderer.end();
if (renderer_ == null)
/* I allocated it, I must dispose it */
renderer.dispose();
}
/**
* Draws a rectangle using a {@link ShapeRenderer}.
*
* @param sRender_
* The renderer to use. If {@code null} a new one will be
* allocated.
* @param botLeftX
* The bottom left x of the rectangle.
* @param botLeftY
* The bottom left y of the rectangle.
* @param width
* The rectangle's width
* @param height
* The rectangle's height
* @param st
* The style to use
* @param color
* The rectangle's color
*/
public static void drawRectangle(/* @Nullable */ShapeRenderer sRender_, float botLeftX, float botLeftY,
float width, float height, ShapeType st, Color color) {
final ShapeRenderer sRender = sRender_ == null ? new ShapeRenderer() : sRender_;
final boolean reset;
/*
* No matter the state of the given ShapeRenderer, we'll be fine, thanks
* to this:
*/
if (!sRender.isDrawing()) {
reset = true;
sRender.begin(st);
} else
reset = false;
sRender.setColor(color);
sRender.rect(botLeftX, botLeftY, width, height);
if (reset)
sRender.end();
if (sRender != sRender_)
/* I allocated it */
sRender.dispose();
}
/**
* Draws a rectangle using a {@link ShapeRenderer}, allocating a new one for
* the occasion.
*
* @param botLeftX
* The bottom left x of the rectangle.
* @param botLeftY
* The bottom left y of the rectangle.
* @param width
* The rectangle's width
* @param height
* The rectangle's height
* @param st
* The style to use
* @param color
* The rectangle's color
*/
public static void drawRectangle(float botLeftX, float botLeftY, float width, float height, ShapeType st,
Color color) {
drawRectangle(null, botLeftX, botLeftY, width, height, st, color);
}
/**
* @author smelC
*/
public static enum CornerStyle {
SQUARE,
/**
* Here's an example of this style:
*
* <br>
*
* <img src="http://i.imgur.com/AQgWeic.png"/>.
*/
ROUNDED,
/**
* A NES-like style (to my taste..). Try it, I can't explain it with
* sentences. Here's an example:
*
* <br>
*
* <img src="http://i.imgur.com/PQSvT0t.png"/>
*/
MISSING,
}
/**
* A vertical move triggered by keyboard keys.
*
* @author smelC
*/
public static enum YMoveKind {
/** The kind corresponding to arrow up */
UP,
/** The kind corresponding to arrow down */
DOWN,
/** The kind corresponding to page down */
PAGE_DOWN,
/** The kind corresponding to page up */
PAGE_UP;
/**
* @return {@code true} if {@code this} is downward.
*/
public boolean isDown() {
switch (this) {
case DOWN:
case PAGE_DOWN:
return true;
case PAGE_UP:
case UP:
return false;
}
throw new IllegalStateException("Unmatched " + getClass().getSimpleName() + ": " + this);
}
/**
* @param keycode
* @param vim
* Whether to recognize vim shortcuts (j/k).
* @return The move kind corresponding to {@code keycode}, or
* {@code null} if none.
*/
public static YMoveKind of(int keycode, boolean vim) {
if (keycode == Keys.UP || keycode == Keys.DPAD_UP || keycode == Keys.NUMPAD_8)
return UP;
else if (keycode == Keys.DOWN || keycode == Keys.DPAD_DOWN || keycode == Keys.NUMPAD_2)
return DOWN;
else if (keycode == Keys.PAGE_UP)
return PAGE_UP;
else if (keycode == Keys.PAGE_DOWN)
return PAGE_DOWN;
else if (vim) {
if (keycode == Keys.J)
return DOWN;
else if (keycode == Keys.K)
return UP;
else
return null;
} else
return null;
}
}
}