001package squidpony.squidgrid.gui.gdx; 002 003import com.badlogic.gdx.Input.Keys; 004import com.badlogic.gdx.graphics.Color; 005import com.badlogic.gdx.graphics.glutils.ShapeRenderer; 006import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; 007import com.badlogic.gdx.scenes.scene2d.Actor; 008 009/** 010 * @author smelC 011 */ 012public class UIUtil { 013 014 /** 015 * Draws margins around an actor. 016 * 017 * @param renderer_ 018 * The renderer to use. If {@code null} a new one will be 019 * allocated. 020 * @param a 021 * @param margin 022 * The size of the margin to draw. 023 * @param c 024 * The margins' colors. 025 */ 026 public static void drawMarginsAround(ShapeRenderer renderer_, Actor a, float margin, Color color, 027 CornerStyle cornerStyle) { 028 drawMarginsAround(renderer_, a.getX(), a.getY(), a.getWidth(), a.getHeight(), margin, color, 029 cornerStyle, 1f, 1f); 030 } 031 032 /** 033 * Draws margins around a rectangle 034 * 035 * @param botLeftX 036 * The rectangle's bottom left. 037 * @param botLeftY 038 * The rectangle's bottom left. 039 * @param width 040 * The rectangle's width. 041 * @param height 042 * The rectangle's height. 043 * @param xmargin 044 * The size of the left margin and the size of the right margin. 045 * @param ymargin 046 * The size of the bottom margin and the size of the top margin. 047 * @param c 048 * The margins' colors. 049 */ 050 public static void drawMarginsAround(float botLeftX, float botLeftY, int width, int height, int xmargin, 051 int ymargin, Color c) { 052 if (xmargin == 0 && ymargin == 0) 053 return; 054 055 final ShapeRenderer renderer = new ShapeRenderer(); 056 renderer.begin(ShapeType.Filled); 057 renderer.setColor(c); 058 059 if (0 < xmargin) { 060 /* The left rectangle */ 061 renderer.rect(botLeftX - xmargin, botLeftY - ymargin, xmargin, height + (ymargin * 2)); 062 /* The right rectangle */ 063 renderer.rect(botLeftX + width, botLeftY - ymargin, xmargin, height + (ymargin * 2)); 064 } 065 if (0 < ymargin) { 066 /* The bottom rectangle */ 067 renderer.rect(botLeftX, botLeftY - ymargin, width, ymargin); 068 /* The top rectangle */ 069 renderer.rect(botLeftX, botLeftY + height, width, ymargin); 070 } 071 072 renderer.end(); 073 renderer.dispose(); 074 } 075 076 /** 077 * @param renderer_ 078 * The renderer to use. If {@code null} a new one will be 079 * allocated. 080 * @param botLeftX 081 * The bottom left x cell of the rectangle to draw around. 082 * @param botLeftY 083 * The bottom left y cell of the rectangle to draw around. 084 * @param width 085 * The width of the button considered. 086 * @param height 087 * The width of the button considered. 088 * @param margin 089 * The size of the margin to draw. 090 * @param color 091 * The color to draw 092 * @param cornerStyle 093 * The style with which to draw the margins 094 */ 095 public static void drawMarginsAround(ShapeRenderer renderer_, float botLeftX, float botLeftY, float width, 096 float height, float margin, Color color, CornerStyle cornerStyle) { 097 drawMarginsAround(renderer_, botLeftX, botLeftY, width, height, margin, color, cornerStyle, 1f, 1f); 098 } 099 100 /** 101 * @param renderer_ 102 * The renderer to use. If {@code null} a new one will be 103 * allocated. 104 * @param botLeftX 105 * The bottom left x cell of the rectangle to draw around. 106 * @param botLeftY 107 * The bottom left y cell of the rectangle to draw around. 108 * @param width 109 * The width of the button considered. 110 * @param height 111 * The width of the button considered. 112 * @param margin 113 * The size of the margin to draw. 114 * @param color 115 * The color to draw 116 * @param cornerStyle 117 * The style with which to draw the margins 118 * @param zoomX 119 * A multiplier for the world x-size of non-ShapeRenderer 120 * objects, that needs to be reversed for this 121 * @param zoomY 122 * A multiplier for the world y-size of non-ShapeRenderer 123 * objects, that needs to be reversed for this 124 */ 125 public static void drawMarginsAround(ShapeRenderer renderer_, float botLeftX, float botLeftY, float width, 126 float height, float margin, Color color, CornerStyle cornerStyle, float zoomX, float zoomY) { 127 if (margin == 0 || color == null) 128 /* Nothing to do */ 129 return; 130 131 botLeftY += 1; 132 133 final boolean reset; 134 final ShapeRenderer renderer = renderer_ == null ? new ShapeRenderer() : renderer_; 135 /* 136 * No matter the state of the given ShapeRenderer, we'll be fine, thanks 137 * to this: 138 */ 139 if (!renderer.isDrawing()) { 140 reset = true; 141 renderer.begin(ShapeType.Filled); 142 } else 143 reset = false; 144 renderer.scale(1f / zoomX, 1f / zoomY, 1f); 145 renderer.setColor(color); 146 147 if (cornerStyle == CornerStyle.ROUNDED || cornerStyle == CornerStyle.MISSING) { 148 /* Left margin */ 149 renderer.rect(botLeftX - margin, botLeftY, margin, height); 150 /* Right margin */ 151 renderer.rect(botLeftX + width, botLeftY, margin, height); 152 } else { 153 /* Left margin */ 154 renderer.rect(botLeftX - margin, botLeftY - margin, margin, height + (margin * 2)); 155 /* Right margin */ 156 renderer.rect(botLeftX + width, botLeftY - margin, margin, height + (margin * 2)); 157 } 158 /* Bottom margin */ 159 renderer.rect(botLeftX, botLeftY - margin, width, margin); 160 /* Top margin */ 161 renderer.rect(botLeftX, botLeftY + height, width, margin); 162 163 if (cornerStyle == CornerStyle.ROUNDED) { 164 /* Bottom left */ 165 renderer.arc(botLeftX, botLeftY, margin, 180, 90); 166 /* Top left */ 167 renderer.arc(botLeftX, botLeftY + height, margin, 90, 90); 168 /* Top right */ 169 renderer.arc(botLeftX + width, botLeftY + height, margin, 0, 90); 170 /* Bottom Right */ 171 renderer.arc(botLeftX + width, botLeftY, margin, 270, 90); 172 } 173 174 if (reset) 175 renderer.end(); 176 177 if (renderer_ == null) 178 /* I allocated it, I must dispose it */ 179 renderer.dispose(); 180 } 181 182 /** 183 * Draws a rectangle using a {@link ShapeRenderer}. 184 * 185 * @parem sRender_ The renderer to use. If {@code null} a new one will be 186 * allocated. 187 * @param botLeftX 188 * The bottom left x of the rectangle. 189 * @param botLeftY 190 * The bottom left y of the rectangle. 191 * @param width 192 * The rectangle's width 193 * @param height 194 * The rectangle's height 195 * @param st 196 * The style to use 197 * @param color 198 * The rectangle's color 199 */ 200 public static void drawRectangle(/* @Nullable */ShapeRenderer sRender_, float botLeftX, float botLeftY, 201 float width, float height, ShapeType st, Color color) { 202 final ShapeRenderer sRender = sRender_ == null ? new ShapeRenderer() : sRender_; 203 final boolean reset; 204 /* 205 * No matter the state of the given ShapeRenderer, we'll be fine, thanks 206 * to this: 207 */ 208 if (!sRender.isDrawing()) { 209 reset = true; 210 sRender.begin(st); 211 } else 212 reset = false; 213 sRender.setColor(color); 214 sRender.rect(botLeftX, botLeftY, width, height); 215 if (reset) 216 sRender.end(); 217 if (sRender != sRender_) 218 /* I allocated it */ 219 sRender.dispose(); 220 } 221 222 /** 223 * Draws a rectangle using a {@link ShapeRenderer}, allocating a new one for 224 * the occasion. 225 * 226 * @param botLeftX 227 * The bottom left x of the rectangle. 228 * @param botLeftY 229 * The bottom left y of the rectangle. 230 * @param width 231 * The rectangle's width 232 * @param height 233 * The rectangle's height 234 * @param st 235 * The style to use 236 * @param color 237 * The rectangle's color 238 */ 239 public static void drawRectangle(float botLeftX, float botLeftY, float width, float height, ShapeType st, 240 Color color) { 241 drawRectangle(null, botLeftX, botLeftY, width, height, st, color); 242 } 243 244 /** 245 * @author smelC 246 */ 247 public static enum CornerStyle { 248 SQUARE, 249 /** 250 * Here's an example of this style: 251 * 252 * <br> 253 * 254 * <img src="http://i.imgur.com/AQgWeic.png"/>. 255 */ 256 ROUNDED, 257 /** 258 * A NES-like style (to my taste..). Try it, I can't explain it with 259 * sentences. Here's an example: 260 * 261 * <br> 262 * 263 * <img src="http://i.imgur.com/PQSvT0t.png"/> 264 */ 265 MISSING, 266 } 267 268 /** 269 * A vertical move triggered by keyboard keys. 270 * 271 * @author smelC 272 */ 273 public static enum YMoveKind { 274 /** The kind corresponding to arrow up */ 275 UP, 276 /** The kind corresponding to arrow down */ 277 DOWN, 278 /** The kind corresponding to page down */ 279 PAGE_DOWN, 280 /** The kind corresponding to page up */ 281 PAGE_UP; 282 283 /** 284 * @return {@code true} if {@code this} is downward. 285 */ 286 public boolean isDown() { 287 switch (this) { 288 case DOWN: 289 case PAGE_DOWN: 290 return true; 291 case PAGE_UP: 292 case UP: 293 return false; 294 } 295 throw new IllegalStateException("Unmatched " + getClass().getSimpleName() + ": " + this); 296 } 297 298 /** 299 * @param keycode 300 * @param vim 301 * Whether to recognize vim shortcuts (j/k). 302 * @return The move kind corresponding to {@code keycode}, or 303 * {@code null} if none. 304 */ 305 public static YMoveKind of(int keycode, boolean vim) { 306 if (keycode == Keys.UP || keycode == Keys.DPAD_UP || keycode == Keys.NUMPAD_8) 307 return UP; 308 else if (keycode == Keys.DOWN || keycode == Keys.DPAD_DOWN || keycode == Keys.NUMPAD_2) 309 return DOWN; 310 else if (keycode == Keys.PAGE_UP) 311 return PAGE_UP; 312 else if (keycode == Keys.PAGE_DOWN) 313 return PAGE_DOWN; 314 else if (vim) { 315 if (keycode == Keys.J) 316 return DOWN; 317 else if (keycode == Keys.K) 318 return UP; 319 else 320 return null; 321 } else 322 return null; 323 } 324 } 325 326}