001package squidpony.squidgrid.gui.gdx; 002 003import com.badlogic.gdx.Gdx; 004import com.badlogic.gdx.assets.AssetDescriptor; 005import com.badlogic.gdx.assets.AssetManager; 006import com.badlogic.gdx.graphics.Color; 007import com.badlogic.gdx.graphics.Pixmap; 008import com.badlogic.gdx.graphics.Texture; 009import com.badlogic.gdx.graphics.g2d.Batch; 010import com.badlogic.gdx.graphics.g2d.BitmapFont; 011import com.badlogic.gdx.graphics.g2d.SpriteBatch; 012import com.badlogic.gdx.graphics.g2d.TextureRegion; 013import com.badlogic.gdx.graphics.glutils.ShaderProgram; 014import com.badlogic.gdx.scenes.scene2d.Actor; 015import com.badlogic.gdx.scenes.scene2d.ui.Image; 016import com.badlogic.gdx.scenes.scene2d.ui.Label; 017import com.badlogic.gdx.utils.Align; 018import com.badlogic.gdx.utils.Disposable; 019import squidpony.IColorCenter; 020 021import java.util.*; 022 023/** 024 * Class for creating text blocks. 025 * 026 * This class defaults to having no padding and having no font set. You can use a 027 * default square or narrow font by calling the appropriate method, or set the font 028 * to any AngelCode bitmap font on the classpath (typically in libGDX, this would be 029 * in the assets folder; these fonts can be created by Hiero in the libGDX tools, 030 * see https://github.com/libgdx/libgdx/wiki/Hiero for more) 031 * 032 * After all settings are set, one of the initialization methods must be called 033 * before the factory can be used. 034 * 035 * In order to easily support Unicode, strings are treated as a series of code 036 * points. 037 * 038 * All images have transparent backgrounds. 039 * 040 * @author Eben Howard - http://squidpony.com - howard@squidpony.com 041 * @author Tommy Ettinger 042 */ 043public class TextCellFactory implements Disposable { 044 045 /** 046 * The commonly used symbols in roguelike games. 047 */ 048 public static final String DEFAULT_FITTING = "@!#$%^&*()_+1234567890-=~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz;:,'\"{}?/\\ ", 049 LINE_FITTING = "┼├┤┴┬┌┐└┘│─", SQUID_FITTING = DEFAULT_FITTING + LINE_FITTING; 050 051 /** 052 * The {@link AssetManager} from where to load the font. Use it to share 053 * loading of a font's file across multiple factories. 054 */ 055 protected /* Nullable */AssetManager assetManager; 056 public BitmapFont bmpFont = null; 057 protected Texture block = null; 058 protected String fitting = SQUID_FITTING; 059 protected IColorCenter<Color> scc; 060 protected int leftPadding = 0, rightPadding = 0, topPadding = 0, bottomPadding = 0; 061 protected int width = 1, height = 1; 062 protected float actualCellWidth = 1, actualCellHeight = 1; 063 protected float distanceFieldScaleX = 36f, distanceFieldScaleY = 36f; 064 private boolean initialized = false, initializedByFont = false, initializedBySize = false; 065 protected boolean distanceField = false; 066 protected ShaderProgram shader; 067 protected float smoothingMultiplier = 1f; 068 protected float descent, lineHeight; 069 private Label.LabelStyle style; 070 protected java.util.LinkedHashMap<String, String> swap = new LinkedHashMap<>(32); 071 072 073 /** 074 * Creates a default valued factory. One of the initialization methods must 075 * be called before this factory can be used! 076 */ 077 public TextCellFactory() { 078 this(null); 079 } 080 081 /** 082 * A default valued factory that uses the given {@link AssetManager} to load 083 * the font file. Use this constructor if you are likely to load the same 084 * font over and over (recall that, without an {@link AssetManager}, each 085 * instance of {@link TextCellFactory} will load its font from disk). This 086 * primarily matters if you are using fonts not bundled with SquidLib, since 087 * accessing a BitmapFont with a method (not a String) from DefaultResources 088 * caches the BitmapFont already. 089 * 090 * @param assetManager an ordinary libGDX AssetManager 091 */ 092 public TextCellFactory(/* Nullable */ AssetManager assetManager) { 093 this.assetManager = assetManager; 094 scc = DefaultResources.getSCC(); 095 } 096 097 public TextCellFactory copy() 098 { 099 TextCellFactory next = new TextCellFactory(assetManager); 100 //next.bmpFont = bmpFont; 101 next.bmpFont = new BitmapFont(new BitmapFont.BitmapFontData(bmpFont.getData().getFontFile(), false), 102 bmpFont.getRegions(), bmpFont.usesIntegerPositions()); 103 next.block = block; 104 next.swap = new LinkedHashMap<>(swap); 105 next.distanceField = distanceField; 106 next.distanceFieldScaleX = distanceFieldScaleX; 107 next.distanceFieldScaleY = distanceFieldScaleY; 108 next.shader = null; 109 next.fitting = fitting; 110 next.height = height; 111 next.width = width; 112 next.actualCellWidth = actualCellWidth; 113 next.actualCellHeight = actualCellHeight; 114 next.descent = descent; 115 next.lineHeight = lineHeight; 116 //next.modifiedHeight = modifiedHeight; 117 next.smoothingMultiplier = smoothingMultiplier; 118 next.scc = scc; 119 if(initializedBySize) 120 next.initBySize(); 121 else if(initializedByFont) 122 next.initByFont(); 123 return next; 124 } 125 /** 126 * Initializes the factory to then be able to create text cells on demand. 127 * 128 * Will match the width and height to 12 and 12, scaling the font to fit. 129 * 130 * Calling this after the factory has already been initialized will 131 * re-initialize it. 132 * 133 * @return this for method chaining 134 */ 135 public TextCellFactory initByFont() { 136 bmpFont.setFixedWidthGlyphs(fitting); 137 width = (int)bmpFont.getSpaceWidth(); 138 lineHeight = bmpFont.getLineHeight(); 139 height = (int)(lineHeight); 140 descent = bmpFont.getDescent(); 141 142 actualCellWidth = width; 143 actualCellHeight = height; 144 //modifiedHeight = height; 145 Pixmap temp = new Pixmap(1, 1, Pixmap.Format.RGBA8888); 146 temp.setColor(Color.WHITE); 147 temp.fill(); 148 block = new Texture(1, 1, Pixmap.Format.RGBA8888); 149 block.draw(temp, 0, 0); 150 temp.dispose(); 151 style = new Label.LabelStyle(bmpFont, null); 152 initialized = true; 153 initializedByFont = true; 154 return this; 155 } 156 157 /** 158 * Initializes the factory to then be able to create text cells on demand. 159 * 160 * Will strictly use the provided width and height values to size the cells. 161 * 162 * Calling this after the factory has already been initialized will 163 * re-initialize it. 164 * 165 * @return this for method chaining 166 */ 167 public TextCellFactory initBySize() { 168 //bmpFont.setFixedWidthGlyphs(fitting); 169 Pixmap temp = new Pixmap(1, 1, Pixmap.Format.RGBA8888); 170 temp.setColor(Color.WHITE); 171 temp.fill(); 172 block = new Texture(1, 1, Pixmap.Format.RGBA8888); 173 block.draw(temp, 0, 0); 174 temp.dispose(); 175 if(distanceField) 176 { 177 bmpFont.getData().setScale(width / distanceFieldScaleX, height / distanceFieldScaleY); 178 179 shader = new ShaderProgram(DefaultResources.vertexShader, DefaultResources.fragmentShader); 180 if (!shader.isCompiled()) { 181 Gdx.app.error("shader", "Distance Field font shader compilation failed:\n" + shader.getLog()); 182 } 183 lineHeight = bmpFont.getLineHeight(); 184 //lineTweak = lineHeight / 20f; 185 //distanceFieldScaleX *= (((float)width) / height) / (distanceFieldScaleX / distanceFieldScaleY); 186 } 187 else { 188 shader = SpriteBatch.createDefaultShader(); 189 lineHeight = bmpFont.getLineHeight(); 190 //lineTweak = lineHeight * 0.0625f; 191 } 192 descent = bmpFont.getDescent(); 193 style = new Label.LabelStyle(bmpFont, null); 194 initialized = true; 195 initializedBySize = true; 196 return this; 197 } 198 199 /** 200 * Initializes the factory to then be able to create text cells on demand. 201 * 202 * (This is identical to initBySize() when using libGDX.) 203 * 204 * @return this for method chaining 205 */ 206 public TextCellFactory initVerbatim() { 207 return initBySize(); 208 } 209 210 /** 211 * Returns the font used by this factory. 212 * 213 * @return the font 214 */ 215 public BitmapFont font() { 216 return bmpFont; 217 } 218 219 /** 220 * Sets this factory to use the provided font. 221 * 222 * This is a way to complete a needed step; the font must be set before initializing, which can be done by a few 223 * methods in this class. 224 * 225 * This should be called with an argument such as "Rogue-Zodiac-6x12.fnt", that is, it should have the .fnt 226 * extension as opposed to the .png that accompanies such a bitmap font. The bitmap font should be either in the 227 * internal folder that libGDX knows about, which means it is in the assets folder of your project usually, or it 228 * can be on the classpath, which mostly applies to these resources bundled with SquidLib: 229 * <ul> 230 * <li>DefaultResources.squareName = "Zodiac-Square-12x12.fnt"</li> 231 * <li>DefaultResources.narrowName = "Rogue-Zodiac-6x12.fnt"</li> 232 * <li>DefaultResources.unicodeName = "Mandrill-6x16.fnt"</li> 233 * <li>DefaultResources.smoothName = "Inconsolata-LGC-8x18.fnt"</li> 234 * <li>DefaultResources.squareNameLarge = "Zodiac-Square-24x24.fnt"</li> 235 * <li>DefaultResources.narrowNameLarge = "Rogue-Zodiac-12x24.fnt"</li> 236 * <li>DefaultResources.unicodeNameLarge = "Mandrill-12x32.fnt"</li> 237 * <li>DefaultResources.smoothNameLarge = "Inconsolata-LGC-12x24.fnt"</li> 238 * <li>DefaultResources.narrowNameExtraLarge = "Rogue-Zodiac-18x36.fnt"</li> 239 * <li>There is also a sequence of resized versions of Inconsolata LGC, altered to fit in a square area. These 240 * don't have names in DefaultResources; you should use the overload of font() that takes a BitmapFont if you 241 * want to use the multiple, increasingly-resized versions.</li> 242 * </ul> 243 * "Rogue-Zodiac-12x24.fnt", which is easily accessed by the field DefaultResources.narrowNameLarge , can also 244 * be set using TextCellFactory.defaultNarrowFont() instead of font(). "Zodiac-Square-12x12.fnt", also accessible 245 * as DefaultResources.squareName , can be set using TextCellFactory.defaultSquareFont() instead of font(). 246 * "Inconsolata-LGC-12x24.fnt", also accessible as DefaultResources.smoothNameLarge , can be set using 247 * TextCellFactory.defaultFont() instead of font(). All three of these alternatives will cache the BitmapFont if 248 * the same one is requested later, but this font() method will not. 249 * <br> 250 * See https://github.com/libgdx/libgdx/wiki/Hiero for some ways to create a bitmap font this can use. Several fonts 251 * in this list were created using Hiero (not Hiero4), and several were created with AngelCode's BMFont tool. 252 * 253 * @param fontpath the path to the font to use 254 * @return this factory for method chaining 255 */ 256 public TextCellFactory font(String fontpath) { 257 if (assetManager == null) { 258 if (Gdx.files.internal(fontpath).exists()) 259 bmpFont = new BitmapFont(Gdx.files.internal(fontpath)); 260 else if (Gdx.files.classpath(fontpath).exists()) 261 bmpFont = new BitmapFont(Gdx.files.classpath(fontpath)); 262 else 263 bmpFont = DefaultResources.getDefaultFont(); 264 } 265 else { 266 assetManager.load(new AssetDescriptor<>(fontpath, BitmapFont.class)); 267 /* 268 * We're using the AssetManager not be asynchronous, but to avoid 269 * loading a file twice (because that takes some time (tens of 270 * milliseconds)). Hence this KISS code to avoid having to handle a 271 * not-yet-loaded font: 272 */ 273 assetManager.finishLoading(); 274 bmpFont = assetManager.get(fontpath, BitmapFont.class); 275 } 276 return this; 277 } 278 /** 279 * Sets this factory to use the provided BitmapFont as its font without re-constructing anything. 280 * 281 * This is a way to complete a needed step; the font must be set before initializing, which can be done by a few 282 * methods in this class. 283 * 284 * This should be called with an argument such as {@code DefaultResources.getDefaultFont()} or any other variable 285 * with BitmapFont as its type. The bitmap font will not be loaded from file with this method, which it would be if 286 * you called the overload of font() that takes a String more than once. These BitmapFont resources are already 287 * bundled with SquidLib: 288 * <ul> 289 * <li>DefaultResources.getDefaultFont() = "Zodiac-Square-12x12.fnt"</li> 290 * <li>DefaultResources.getDefaultNarrowFont() = "Rogue-Zodiac-6x12.fnt"</li> 291 * <li>DefaultResources.getDefaultUnicodeFont() = "Mandrill-6x16.fnt"</li> 292 * <li>DefaultResources.getSmoothFont() = "Inconsolata-LGC-8x18.fnt"</li> 293 * <li>DefaultResources.getLargeFont() = "Zodiac-Square-24x24.fnt"</li> 294 * <li>DefaultResources.getLargeNarrowFont() = "Rogue-Zodiac-12x24.fnt"</li> 295 * <li>DefaultResources.getLargeUnicodeFont() = "Mandrill-12x32.fnt"</li> 296 * <li>DefaultResources.getLargeSmoothFont() = "Inconsolata-LGC-12x24.fnt"</li> 297 * <li>DefaultResources.getExtraLargeNarrowFont() = "Rogue-Zodiac-18x36.fnt"</li> 298 * <li>There is also a sequence of resized versions of Inconsolata LGC, altered to fit in a square area. These 299 * can be accessed with DefaultResources.getZoomedFont(), passing an int between 0 and 11 inclusive.</li> 300 * </ul> 301 * "Rogue-Zodiac-12x24.fnt", which is easily accessed by the method DefaultResources.getLargeNarrowFont() , can also 302 * be set using TextCellFactory.defaultNarrowFont() instead of font(). "Zodiac-Square-12x12.fnt", also accessible 303 * with DefaultResources.getDefaultFont() , can be set using TextCellFactory.defaultSquareFont() instead of font(). 304 * "Inconsolata-LGC-12x24.fnt", also accessible with DefaultResources.getLargeSmoothFont() , can be set using 305 * TextCellFactory.defaultFont() instead of font(). All three of these alternatives will cache the BitmapFont if 306 * the same one is requested later, but this font() method will not. 307 * <br> 308 * See https://github.com/libgdx/libgdx/wiki/Hiero for some ways to create a bitmap font this can use. Several fonts 309 * in this list were created using Hiero (not Hiero4), and several were created with AngelCode's BMFont tool. 310 * 311 * @param bitmapFont the BitmapFont this should use 312 * @return this factory for method chaining 313 */ 314 public TextCellFactory font(BitmapFont bitmapFont) { 315 if (bitmapFont == null) { 316 bmpFont = DefaultResources.getDefaultFont(); 317 } 318 else { 319 bmpFont = bitmapFont; 320 } 321 return this; 322 } 323 324 /** 325 * Sets the font to a distance field font with the given String path to a .fnt file and String path to a texture. 326 * Distance field fonts should scale cleanly to multiple resolutions without artifacts. Does not use AssetManager 327 * since you shouldn't need to reload the font if it scales with one image. You need to configure the shader to use 328 * distance field fonts unless a class already does this for you (SquidLayers handles shader configuration 329 * internally, for example). TextCellFactory has a method, configureShader(Batch), that does this and should be 330 * called while that Batch has begun rendering, typically in an override of some containing Scene2D Group's 331 * draw(Batch, float) method. 332 * <br> 333 * At least two distance field fonts are included in SquidLib; one is square, one is narrow, and they can both be 334 * accessed using either the predefined TextCellFactory objects in DefaultResources, accessible with 335 * getStretchableFont() for narrow or getStretchableSquareFont() for square, or the setter methods in this class, 336 * defaultDistanceFieldFont() for square and defaultNarrowDistanceFieldFont() for narrow. 337 * <br> 338 * To create distance field fonts that work well with monospace layout is... time-consuming and error-prone, though 339 * not especially difficult for most fonts. The process is documented as well as we can, given how differently all 340 * fonts are made, in a file not included in the distribution JAR but present on GitHub: 341 * https://github.com/SquidPony/SquidLib/blob/master/squidlib/etc/making-distance-field-fonts.txt 342 * @param fontPath the path to a .fnt bitmap font file with distance field effects applied, which requires a complex 343 * process to create. 344 * @param texturePath the path to the texture used by the bitmap font 345 * @return this factory for method chaining 346 */ 347 public TextCellFactory fontDistanceField(String fontPath, String texturePath) { 348 Texture tex; 349 if (Gdx.files.internal(texturePath).exists()) { 350 Gdx.app.debug("font", "Using internal font texture at " + texturePath); 351 tex = new Texture(Gdx.files.internal(texturePath), true); 352 tex.setFilter(Texture.TextureFilter.MipMapLinearNearest, Texture.TextureFilter.Linear); 353 } else if (Gdx.files.classpath(texturePath).exists()) { 354 Gdx.app.debug("font", "Using classpath font texture at " + texturePath); 355 tex = new Texture(Gdx.files.classpath(texturePath), true); 356 tex.setFilter(Texture.TextureFilter.MipMapLinearNearest, Texture.TextureFilter.Linear); 357 } else { 358 bmpFont = DefaultResources.getDefaultFont(); 359 Gdx.app.error("TextCellFactory", "Could not find font file: " + texturePath + ", using defaults"); 360 return this; 361 } 362 if (Gdx.files.internal(fontPath).exists()) { 363 Gdx.app.debug("font", "Using internal font at " + fontPath); 364 bmpFont = new BitmapFont(Gdx.files.internal(fontPath), new TextureRegion(tex), false); 365 distanceField = true; 366 } else if (Gdx.files.classpath(fontPath).exists()) { 367 Gdx.app.debug("font", "Using classpath font at " + fontPath); 368 bmpFont = new BitmapFont(Gdx.files.classpath(fontPath), new TextureRegion(tex), false); 369 distanceField = true; 370 } else { 371 bmpFont = DefaultResources.getDefaultFont(); 372 Gdx.app.error("TextCellFactory", "Could not find font file: " + fontPath + ", using defaults"); 373 } 374 //bmpFont.getData().padBottom = bmpFont.getDescent(); 375 distanceFieldScaleX = bmpFont.getData().getGlyph(' ').xadvance - 1f; 376 distanceFieldScaleY = bmpFont.getLineHeight() - 1f; 377 return this; 378 } 379 /** 380 * Sets this factory to use a default 12x24 font that supports Latin, Greek, Cyrillic, and many more, including 381 * box-drawing characters, zodiac signs, playing-card suits, and chess piece symbols. This is enough to support the 382 * output of anything that DungeonUtility can make for a dungeon or FakeLanguageGen can make for text with its 383 * defaults, which is difficult for any font to do. The box-drawing characters in this don't quite line up, and in 384 * some colors there may appear to be gaps (white text on black backgrounds will show it, but not much else). 385 * 386 * This is a way to complete a needed step; the font must be set before initializing, which can be done by a few 387 * methods in this class. 388 * 389 * @return this factory for method chaining 390 */ 391 public TextCellFactory defaultFont() 392 { 393 bmpFont = DefaultResources.getLargeSmoothFont(); 394 return this; 395 } 396 /** 397 * Sets this factory to use a default 12x24 font that renders very accurately, with no gaps between box-drawing 398 * characters and very geometric lines. 399 * 400 * This is a way to complete a needed step; the font must be set before initializing, which can be done by a few 401 * methods in this class. 402 * 403 * @return this factory for method chaining 404 */ 405 public TextCellFactory defaultNarrowFont() 406 { 407 bmpFont = DefaultResources.getLargeNarrowFont(); 408 return this; 409 } 410 411 /** 412 * Sets this factory to use a default 12x12 font, which... is square, and doesn't look as bad as many square fonts 413 * do, plus it supports box-drawing characters with no gaps. 414 * 415 * This is a way to complete a needed step; the font must be set before initializing, which can be done by a few 416 * methods in this class. 417 * 418 * @return this factory for method chaining 419 */ 420 public TextCellFactory defaultSquareFont() 421 { 422 bmpFont = DefaultResources.getDefaultFont(); 423 return this; 424 } 425 426 /** 427 * Sets the TextCellFactory to use a square distance field font that will resize to whatever size you request. 428 * You must configure the shader if you use a distance field font, unless a class does it for you, like SquidLayers. 429 * The configureShader(Batch) method of this class can be used to set up the shader if you don't use SquidLayers; 430 * see its docs for more information. 431 * @return this TextCellFactory set to use a square distance field font 432 */ 433 public TextCellFactory defaultDistanceFieldFont() 434 { 435 fontDistanceField(DefaultResources.distanceFieldSquare, DefaultResources.distanceFieldSquareTexture); 436 return this; 437 } 438 /** 439 * Sets the TextCellFactory to use a half-square distance field font that will resize to whatever size you request. 440 * You must configure the shader if you use a distance field font, unless a class does it for you, like SquidLayers. 441 * The configureShader(Batch) method of this class can be used to set up the shader if you don't use SquidLayers; 442 * see its docs for more information. 443 * @return this TextCellFactory set to use a half-square distance field font 444 */ 445 public TextCellFactory defaultNarrowDistanceFieldFont() 446 { 447 fontDistanceField(DefaultResources.distanceFieldNarrow, DefaultResources.distanceFieldNarrowTexture); 448 return this; 449 } 450 451 /** 452 * Returns the width of a single cell. 453 * 454 * @return the width 455 */ 456 public int width() { 457 return width; 458 } 459 460 /** 461 * Sets the factory's cell width to the provided value. Clamps at 1 on the 462 * lower bound to ensure valid calculations. 463 * 464 * @param width the desired width 465 * @return this factory for method chaining 466 */ 467 public TextCellFactory width(int width) { 468 this.width = Math.max(1, width); 469 actualCellWidth = this.width; 470 return this; 471 } 472 473 /** 474 * Returns the height of a single cell. 475 * 476 * @return 477 */ 478 public int height() { 479 return height; 480 } 481 482 /** 483 * Sets the factory's cell height to the provided value. Clamps at 1 on the 484 * lower bound to ensure valid calculations. 485 * 486 * @param height the desired width 487 * @return this factory for method chaining 488 */ 489 public TextCellFactory height(int height) { 490 this.height = Math.max(1, height); 491 //modifiedHeight = this.height; 492 actualCellHeight = this.height; 493 return this; 494 } 495 /** 496 * Sets the factory's height used for text to the provided value, but does not change the size of a cell. Clamps at 497 * 1 on the lower bound to ensure valid calculations. 498 * 499 * @param width the desired width 500 * @return this factory for method chaining 501 */ 502 public TextCellFactory tweakWidth(int width) { 503 this.width = Math.max(1, width); 504 return this; 505 } 506 507 /** 508 * Sets the factory's height used for text to the provided value, but does not change the size of a cell. Clamps at 509 * 1 on the lower bound to ensure valid calculations. 510 * 511 * @param height the desired height 512 * @return this factory for method chaining 513 */ 514 public TextCellFactory tweakHeight(int height) { 515 this.height = Math.max(1, height); 516 //modifiedHeight = this.height; 517 return this; 518 } 519 520 /** 521 * Returns the current String of code points that are used for sizing the 522 * cells. 523 * 524 * Note that this is actually a set of codepoints and treating them as an 525 * array of chars might give undesired results. 526 * 527 * @return the String used for sizing calculations 528 */ 529 public String fit() { 530 return fitting; 531 } 532 533 /** 534 * Sets the characters that will be guaranteed to fit to the provided ones. 535 * This will override any previously set string. 536 * 537 * @param fit the String of code points to size to 538 * @return this factory for method chaining 539 */ 540 public TextCellFactory fit(String fit) { 541 fitting = fit; 542 bmpFont.setFixedWidthGlyphs(fitting); 543 width = (int)bmpFont.getSpaceWidth(); 544 return this; 545 } 546 547 /** 548 * Adds the code points in the string to the list of characters that will be 549 * guaranteed to fit. 550 * 551 * @param fit the String of code points to size to 552 * @return this factory for method chaining 553 */ 554 public TextCellFactory addFit(String fit) { 555 fitting += fit; 556 bmpFont.setFixedWidthGlyphs(fitting); 557 width = (int)bmpFont.getSpaceWidth(); 558 return this; 559 } 560 561 /** 562 * Returns whether this factory is currently set to do antialiasing on the 563 * characters rendered, which is always true. 564 * 565 * @return true if antialiasing is set 566 */ 567 public boolean antialias() { 568 return true; 569 } 570 571 /** 572 * All fonts will be rendered with antialiasing, this doesn't do anything. 573 * 574 * @param antialias ignored, will always use antialiasing 575 * @return this factory for method chaining 576 * @deprecated AA is the wave of the future! 577 */ 578 public TextCellFactory antialias(boolean antialias) { 579 return this; 580 } 581 582 /** 583 * Sets the amount of padding on all sides to the provided value. 584 * 585 * @param padding how much padding in pixels 586 * @return this for method chaining 587 */ 588 public TextCellFactory padding(int padding) { 589 leftPadding = padding; 590 rightPadding = padding; 591 topPadding = padding; 592 bottomPadding = padding; 593 return this; 594 } 595 596 /** 597 * Returns the padding on the left side. 598 * 599 * @return amount of padding in pixels 600 */ 601 public int leftPadding() { 602 return leftPadding; 603 } 604 605 /** 606 * Sets the amount of padding on the left side to the provided value. 607 * 608 * @param padding how much padding in pixels 609 * @return this for method chaining 610 */ 611 public TextCellFactory leftPadding(int padding) { 612 leftPadding = padding; 613 return this; 614 } 615 616 /** 617 * Returns the padding on the right side. 618 * 619 * @return amount of padding in pixels 620 */ 621 public int rightPadding() { 622 return rightPadding; 623 } 624 625 /** 626 * Sets the amount of padding on the right side to the provided value. 627 * 628 * @param padding how much padding in pixels 629 * @return this for method chaining 630 */ 631 public TextCellFactory rightPadding(int padding) { 632 rightPadding = padding; 633 return this; 634 } 635 636 /** 637 * Returns the padding on the top side. 638 * 639 * @return amount of padding in pixels 640 */ 641 public int topPadding() { 642 return topPadding; 643 } 644 645 /** 646 * Sets the amount of padding on the top side to the provided value. 647 * 648 * @param padding how much padding in pixels 649 * @return this for method chaining 650 */ 651 public TextCellFactory topPadding(int padding) { 652 topPadding = padding; 653 return this; 654 } 655 656 /** 657 * Returns the padding on the bottom side. 658 * 659 * @return amount of padding in pixels 660 */ 661 public int bottomPadding() { 662 return bottomPadding; 663 } 664 665 /** 666 * Sets the amount of padding on the bottom side to the provided value. 667 * 668 * @param padding how much padding in pixels 669 * @return this for method chaining 670 */ 671 public TextCellFactory bottomPadding(int padding) { 672 bottomPadding = padding; 673 return this; 674 } 675 676 /** 677 * @param icc 678 * The color center to use. Should not be {@code null}. 679 * @return {@code this} 680 * @throws NullPointerException 681 * If {@code icc} is {@code null}. 682 */ 683 public TextCellFactory setColorCenter(IColorCenter<Color> icc) { 684 if (icc == null) 685 /* Better fail now than later */ 686 throw new NullPointerException( 687 "The color center should not be null in " + getClass().getSimpleName()); 688 scc = icc; 689 return this; 690 } 691 692 /** 693 * Returns true if this factory is fully initialized and ready to build text cells. 694 * 695 * @return true if initialized 696 */ 697 public boolean initialized() { 698 return initialized; 699 } 700 701 /** 702 * Returns true if the given character will fit inside the current cell 703 * dimensions with the current font. 704 * 705 * ISO Control characters, non-printing characters and invalid unicode 706 * characters are all considered by definition to fit. 707 * 708 * @param codepoint 709 * @return 710 */ 711 public boolean willFit(int codepoint) { 712 if (!initialized) { 713 throw new IllegalStateException("This factory has not yet been initialized!"); 714 } 715 716 if (!Character.isValidCodePoint(codepoint) || 717 (codepoint <= 0x001F) || (codepoint >= 0x007F && codepoint <= 0x009F)) // same as isIsoControl 718 { 719 return true; 720 } 721 722 return fitting.contains(String.valueOf(Character.toChars(codepoint))); 723 } 724 725 /** 726 * Use the specified Batch to draw a String (often just one char long) with the default color (white), with x and y 727 * determining the world-space coordinates for the upper-left corner. 728 * 729 * @param batch the LibGDX Batch to do the drawing 730 * @param s the string to draw, often but not necessarily one char. Can be null to draw a solid block instead. 731 * @param x x of the upper-left corner of the region of text in world coordinates. 732 * @param y y of the upper-left corner of the region of text in world coordinates. 733 */ 734 public void draw(Batch batch, String s, float x, float y) { 735 if (!initialized) { 736 throw new IllegalStateException("This factory has not yet been initialized!"); 737 } 738 739 // + descent * 3 / 2f 740 // - distanceFieldScaleY / 12f 741 742 //height - lineTweak * 2f 743 if (s == null) { 744 batch.setColor(1f,1f,1f,1f); 745 batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); // + descent * 1 / 3f 746 } else if(s.length() > 0 && s.charAt(0) == '\0') { 747 batch.setColor(1f,1f,1f,1f); 748 batch.draw(block, x, y - actualCellHeight, actualCellWidth * s.length(), actualCellHeight); // descent * 1 / 3f 749 } else { 750 bmpFont.setColor(1f,1f,1f,1f); 751 if(swap.containsKey(s)) 752 bmpFont.draw(batch, swap.get(s), x, y - descent + 1/* * 1.5f*//* - lineHeight * 0.2f */ /* + descent*/, width * s.length(), Align.center, false); 753 else 754 bmpFont.draw(batch, s, x, y - descent + 1/* * 1.5f*//* - lineHeight * 0.2f */ /* + descent*/, width * s.length(), Align.center, false); 755 } 756 } 757 /** 758 * Use the specified Batch to draw a String (often just one char long) in the specified rgba color, with x and y 759 * determining the world-space coordinates for the upper-left corner. 760 * 761 * @param batch the LibGDX Batch to do the drawing 762 * @param s the string to draw, often but not necessarily one char. Can be null to draw a solid block instead. 763 * @param r 0.0 to 0.1 red value 764 * @param g 0.0 to 0.1 green value 765 * @param b 0.0 to 0.1 blue value 766 * @param a 0.0 to 0.1 alpha value 767 * @param x x of the upper-left corner of the region of text in world coordinates. 768 * @param y y of the upper-left corner of the region of text in world coordinates. 769 */ 770 public void draw(Batch batch, String s, float r, float g, float b, float a, float x, float y) { 771 if (!initialized) { 772 throw new IllegalStateException("This factory has not yet been initialized!"); 773 } 774 775 if (s == null) { 776 Color orig = scc.filter(batch.getColor()); 777 batch.setColor(r, g, b, a); 778 batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); // descent * 1 / 3f 779 batch.setColor(orig); 780 } else if(s.length() > 0 && s.charAt(0) == '\0') { 781 Color orig = scc.filter(batch.getColor()); 782 batch.setColor(r, g, b, a); 783 batch.draw(block, x, y - actualCellHeight, actualCellWidth * s.length(), actualCellHeight); // descent * 1 / 3f 784 batch.setColor(orig); 785 } else { 786 bmpFont.setColor(r, g, b, a); 787 if(swap.containsKey(s)) 788 bmpFont.draw(batch, swap.get(s), x, y - descent + 1/* * 1.5f*//* - lineHeight * 0.2f */ /* + descent*/, width * s.length(), Align.center, false); 789 else 790 bmpFont.draw(batch, s, x, y - descent + 1/* * 1.5f*//* - lineHeight * 0.2f */ /* + descent*/, width * s.length(), Align.center, false); 791 } 792 } 793 794 /** 795 * Use the specified Batch to draw a String (often just one char long) in the specified LibGDX Color, with x and y 796 * determining the world-space coordinates for the upper-left corner. 797 * 798 * @param batch the LibGDX Batch to do the drawing 799 * @param s the string to draw, often but not necessarily one char. Can be null to draw a solid block instead. 800 * @param color the LibGDX Color to draw the char(s) with, all the same color 801 * @param x x of the upper-left corner of the region of text in world coordinates. 802 * @param y y of the upper-left corner of the region of text in world coordinates. 803 */ 804 public void draw(Batch batch, String s, Color color, float x, float y) { 805 if (!initialized) { 806 throw new IllegalStateException("This factory has not yet been initialized!"); 807 } 808 809 if (s == null) { 810 Color orig = batch.getColor(); 811 batch.setColor(scc.filter(color)); 812 batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); // descent * 1 / 3f 813 batch.setColor(orig); 814 } else if(s.length() > 0 && s.charAt(0) == '\0') { 815 Color orig = batch.getColor(); 816 batch.setColor(scc.filter(color)); 817 batch.draw(block, x, y - actualCellHeight, actualCellWidth * s.length(), actualCellHeight); // descent * 1 / 3f 818 batch.setColor(orig); 819 } else { 820 bmpFont.setColor(scc.filter(color)); 821 if(swap.containsKey(s)) 822 bmpFont.draw(batch, swap.get(s), x, y - descent + 1/* * 1.5f*//* - lineHeight * 0.2f */ /* + descent*/, width * s.length(), Align.center, false); 823 else 824 bmpFont.draw(batch, s, x, y - descent + 1/* * 1.5f*//* - lineHeight * 0.2f */ /* + descent*/, width * s.length(), Align.center, false); 825 } 826 } 827 828 /** 829 * Use the specified Batch to draw a TextureRegion with the default tint color (white, so un-tinted), with x and y 830 * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched 831 * if its size does not match what this TextCellFactory uses for width and height. 832 * 833 * @param batch the LibGDX Batch to do the drawing 834 * @param tr the TextureRegion to draw. Can be null to draw a solid block instead. 835 * @param x x of the upper-left corner of the region of text in world coordinates. 836 * @param y y of the upper-left corner of the region of text in world coordinates. 837 */ 838 public void draw(Batch batch, TextureRegion tr, float x, float y) { 839 if (!initialized) { 840 throw new IllegalStateException("This factory has not yet been initialized!"); 841 } 842 843 if (tr == null) { 844 batch.draw(block, x, y - height, actualCellWidth, actualCellHeight); 845 } else { 846 batch.draw(tr, x, y - height, width, height); 847 } 848 } 849 /** 850 * Use the specified Batch to draw a TextureRegion tinted with the specified rgba color, with x and y 851 * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched 852 * if its size does not match what this TextCellFactory uses for width and height. 853 * 854 * @param batch the LibGDX Batch to do the drawing 855 * @param tr the TextureRegion to draw. Can be null to draw a solid block instead. 856 * @param r 0.0 to 0.1 red value 857 * @param g 0.0 to 0.1 green value 858 * @param b 0.0 to 0.1 blue value 859 * @param a 0.0 to 0.1 alpha value 860 * @param x x of the upper-left corner of the region of text in world coordinates. 861 * @param y y of the upper-left corner of the region of text in world coordinates. 862 */ 863 public void draw(Batch batch, TextureRegion tr, float r, float g, float b, float a, float x, float y) { 864 if (!initialized) { 865 throw new IllegalStateException("This factory has not yet been initialized!"); 866 } 867 868 if (tr == null) { 869 Color orig = batch.getColor(); 870 batch.setColor(r, g, b, a); 871 batch.draw(block, x, y - height, actualCellWidth, actualCellHeight); 872 batch.setColor(orig); 873 } else { 874 Color orig = batch.getColor(); 875 batch.setColor(r, g, b, a); 876 batch.draw(tr, x, y - height, width, height); 877 batch.setColor(orig); 878 } 879 } 880 881 /** 882 * Use the specified Batch to draw a TextureRegion tinted with the specified LibGDX Color, with x and y 883 * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched 884 * if its size does not match what this TextCellFactory uses for width and height. 885 * 886 * @param batch the LibGDX Batch to do the drawing 887 * @param tr the TextureRegion to draw. Can be null to draw a solid block instead. 888 * @param color the LibGDX Color to draw the char(s) with, all the same color 889 * @param x x of the upper-left corner of the region of text in world coordinates. 890 * @param y y of the upper-left corner of the region of text in world coordinates. 891 */ 892 public void draw(Batch batch, TextureRegion tr, Color color, float x, float y) { 893 if (!initialized) { 894 throw new IllegalStateException("This factory has not yet been initialized!"); 895 } 896 897 if (tr == null) { 898 Color orig = batch.getColor(); 899 batch.setColor(scc.filter(color)); 900 batch.draw(block, x, y - height, actualCellWidth, actualCellHeight); 901 batch.setColor(orig); 902 } else { 903 Color orig = batch.getColor(); 904 batch.setColor(scc.filter(color)); 905 batch.draw(tr, x, y - height, width, height); 906 batch.setColor(orig); 907 } 908 } 909 910 /** 911 * Use the specified Batch to draw a TextureRegion with the default tint color (white, so un-tinted), with x and y 912 * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched 913 * only if the supplied width and height do not match what its own dimensions are. 914 * 915 * @param batch the LibGDX Batch to do the drawing 916 * @param tr the TextureRegion to draw. Can be null to draw a solid block instead. 917 * @param x x of the upper-left corner of the region of text in world coordinates. 918 * @param y y of the upper-left corner of the region of text in world coordinates. 919 * @param width the width of the TextureRegion or solid block in pixels. 920 * @param height the height of the TextureRegion or solid block in pixels. 921 */ 922 public void draw(Batch batch, TextureRegion tr, float x, float y, float width, float height) { 923 if (!initialized) { 924 throw new IllegalStateException("This factory has not yet been initialized!"); 925 } 926 927 if (tr == null) { 928 batch.draw(block, x, y - height, width, height); 929 } else { 930 batch.draw(tr, x, y - height, width, height); 931 } 932 } 933 /** 934 * Use the specified Batch to draw a TextureRegion tinted with the specified rgba color, with x and y 935 * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched 936 * only if the supplied width and height do not match what its own dimensions are. 937 * 938 * @param batch the LibGDX Batch to do the drawing 939 * @param tr the TextureRegion to draw. Can be null to draw a solid block instead. 940 * @param r 0.0 to 0.1 red value 941 * @param g 0.0 to 0.1 green value 942 * @param b 0.0 to 0.1 blue value 943 * @param a 0.0 to 0.1 alpha value 944 * @param x x of the upper-left corner of the region of text in world coordinates. 945 * @param y y of the upper-left corner of the region of text in world coordinates. 946 * @param width the width of the TextureRegion or solid block in pixels. 947 * @param height the height of the TextureRegion or solid block in pixels. 948 */ 949 public void draw(Batch batch, TextureRegion tr, float r, float g, float b, float a, float x, float y, float width, float height) { 950 if (!initialized) { 951 throw new IllegalStateException("This factory has not yet been initialized!"); 952 } 953 954 if (tr == null) { 955 Color orig = batch.getColor(); 956 batch.setColor(r, g, b, a); 957 batch.draw(block, x, y - height, width, height); 958 batch.setColor(orig); 959 } else { 960 Color orig = batch.getColor(); 961 batch.setColor(r, g, b, a); 962 batch.draw(tr, x, y - height, width, height); 963 batch.setColor(orig); 964 } 965 } 966 967 /** 968 * Use the specified Batch to draw a TextureRegion tinted with the specified LibGDX Color, with x and y 969 * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched 970 * only if the supplied width and height do not match what its own dimensions are. 971 * 972 * @param batch the LibGDX Batch to do the drawing 973 * @param tr the TextureRegion to draw. Can be null to draw a solid block instead. 974 * @param color the LibGDX Color to draw the char(s) with, all the same color 975 * @param x x of the upper-left corner of the region of text in world coordinates. 976 * @param y y of the upper-left corner of the region of text in world coordinates. 977 * @param width the width of the TextureRegion or solid block in pixels. 978 * @param height the height of the TextureRegion or solid block in pixels. 979 */ 980 public void draw(Batch batch, TextureRegion tr, Color color, float x, float y, float width, float height) { 981 if (!initialized) { 982 throw new IllegalStateException("This factory has not yet been initialized!"); 983 } 984 985 if (tr == null) { 986 Color orig = batch.getColor(); 987 batch.setColor(scc.filter(color)); 988 batch.draw(block, x, y - height, width, height); 989 batch.setColor(orig); 990 } else { 991 Color orig = batch.getColor(); 992 batch.setColor(scc.filter(color)); 993 batch.draw(tr, x, y - height, width, height); 994 batch.setColor(orig); 995 } 996 } 997 998 /** 999 * Converts a String into a Label, or if the argument s is null, creates an Image of a solid block. Can be used 1000 * for preparing glyphs for animation effects. 1001 * @param s a String to make into an Actor, which can be null for a solid block. 1002 * @return the Actor, with no position set. 1003 */ 1004 public Label makeWrappingString(String s) { 1005 if (!initialized) { 1006 throw new IllegalStateException("This factory has not yet been initialized!"); 1007 } 1008 if (s == null) { 1009 s = ""; 1010 } 1011 Label lb = new Label(s, style); 1012 lb.setWrap(true); 1013 // lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1014 return lb; 1015 1016 } 1017 1018 /** 1019 * Converts a String into a Label, or if the argument s is null, creates an Image of a solid block. Can be used 1020 * for preparing glyphs for animation effects, and is used internally for this purpose. 1021 * @param s a String to make into an Actor, which can be null for a solid block. 1022 * @param color a Color to tint s with. 1023 * @return the Actor, with no position set. 1024 */ 1025 public Actor makeActor(String s, Color color) { 1026 if (!initialized) { 1027 throw new IllegalStateException("This factory has not yet been initialized!"); 1028 } 1029 if (s == null) { 1030 Image im = new Image(block); 1031 im.setColor(scc.filter(color)); 1032 //im.setSize(width, height - MathUtils.ceil(bmpFont.getDescent() / 2f)); 1033 im.setSize(actualCellWidth, actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1034 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1035 return im; 1036 } else if(s.length() > 0 && s.charAt(0) == '\0') { 1037 Image im = new Image(block); 1038 im.setColor(scc.filter(color)); 1039 //im.setSize(width * s.length(), height - MathUtils.ceil(bmpFont.getDescent() / 2f)); 1040 im.setSize(actualCellWidth * s.length(), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1041 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1042 return im; 1043 } else { 1044 Label lb; 1045 if(swap.containsKey(s)) 1046 lb = new Label(swap.get(s), style); 1047 else 1048 lb = new Label(s, style); 1049 lb.setSize(width * s.length(), height - descent); //+ lineTweak * 1f 1050 lb.setColor(scc.filter(color)); 1051 // lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1052 return lb; 1053 } 1054 } 1055 1056 /** 1057 * Converts a String into a ColorChangeLabel, or if the argument s is null, creates a ColorChangeImage of a solid 1058 * block. Can be used for preparing glyphs for animation effects, and is used internally for this purpose. The 1059 * ColorChange classes will rotate between all colors given in the List each second, and are not affected by setColor, 1060 * though they are affected by their setColors methods. Their color change is not considered an animation for the 1061 * purposes of things like SquidPanel.hasActiveAnimations() . 1062 * @param s a String to make into an Actor, which can be null for a solid block. 1063 * @param colors a List of Color to tint s with, looping through all elements in the list each second 1064 * @return the Actor, with no position set. 1065 */ 1066 public Actor makeActor(String s, Collection<Color> colors) { 1067 if (!initialized) { 1068 throw new IllegalStateException("This factory has not yet been initialized!"); 1069 } 1070 ArrayList<Color> colors2; 1071 if(colors == null || colors.isEmpty()) 1072 colors2 = null; 1073 else { 1074 colors2 = new ArrayList<>(colors.size()); 1075 for (Color c : colors) { 1076 colors2.add(scc.filter(c)); 1077 } 1078 } 1079 if (s == null) { 1080 ColorChangeImage im = new ColorChangeImage(block, colors2); 1081 //im.setSize(width, height - MathUtils.ceil(bmpFont.getDescent() / 2f)); 1082 im.setSize(actualCellWidth, actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1083 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1084 return im; 1085 } else if(s.length() > 0 && s.charAt(0) == '\0') { 1086 ColorChangeImage im = new ColorChangeImage(block, colors2); 1087 //im.setSize(width * s.length(), height - MathUtils.ceil(bmpFont.getDescent() / 2f)); 1088 im.setSize(actualCellWidth * s.length(), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1089 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1090 return im; 1091 } else { 1092 ColorChangeLabel lb; 1093 if(swap.containsKey(s)) 1094 lb = new ColorChangeLabel(swap.get(s), style, colors2); 1095 else 1096 lb = new ColorChangeLabel(s, style, colors2); 1097 lb.setSize(width * s.length(), height - descent); //+ lineTweak * 1f 1098 // lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1099 return lb; 1100 } 1101 } 1102 /** 1103 * Converts a String into a ColorChangeLabel, or if the argument s is null, creates a ColorChangeImage of a solid 1104 * block. Can be used for preparing glyphs for animation effects, and is used internally for this purpose. The 1105 * ColorChange classes will rotate between all colors given in the List each second, and are not affected by setColor, 1106 * though they are affected by their setColors methods. Their color change is not considered an animation for the 1107 * purposes of things like SquidPanel.hasActiveAnimations() . 1108 * @param s a String to make into an Actor, which can be null for a solid block. 1109 * @param colors a List of Color to tint s with, looping through all elements in the list each second 1110 * @param loopTime the amount of time, in seconds, to spend looping through all colors in the list 1111 * @return the Actor, with no position set. 1112 */ 1113 public Actor makeActor(String s, Collection<Color> colors, float loopTime) { 1114 if (!initialized) { 1115 throw new IllegalStateException("This factory has not yet been initialized!"); 1116 } 1117 ArrayList<Color> colors2; 1118 if(colors == null || colors.isEmpty()) 1119 colors2 = null; 1120 else { 1121 colors2 = new ArrayList<>(colors.size()); 1122 for (Color c : colors) { 1123 colors2.add(scc.filter(c)); 1124 } 1125 } 1126 if (s == null) { 1127 ColorChangeImage im = new ColorChangeImage(block, loopTime, colors2); 1128 //im.setSize(width, height - MathUtils.ceil(bmpFont.getDescent() / 2f)); 1129 im.setSize(actualCellWidth, actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1130 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1131 return im; 1132 } else if(s.length() > 0 && s.charAt(0) == '\0') { 1133 ColorChangeImage im = new ColorChangeImage(block, loopTime, colors2); 1134 //im.setSize(width * s.length(), height - MathUtils.ceil(bmpFont.getDescent() / 2f)); 1135 im.setSize(actualCellWidth * s.length(), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1136 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1137 return im; 1138 } else { 1139 ColorChangeLabel lb; 1140 if(swap.containsKey(s)) 1141 lb = new ColorChangeLabel(swap.get(s), style, loopTime, colors2); 1142 else 1143 lb = new ColorChangeLabel(s, style, loopTime, colors2); 1144 lb.setSize(width * s.length(), height - descent); //+ lineTweak * 1f 1145 // lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1146 return lb; 1147 } 1148 } 1149 1150 /** 1151 * Converts a TextureRegion into an Image, or if the argument s is null, creates an Image of a solid block. Can be 1152 * used for preparing images for animation effects. Stretches the TextureRegion to match a single cell's dimensions. 1153 * @param tr a TextureRegion to make into an Actor, which can be null for a solid block. 1154 * @param color a Color to tint tr with. 1155 * @return the Actor, with no position set. 1156 */ 1157 public Actor makeActor(TextureRegion tr, Color color) { 1158 if (!initialized) { 1159 throw new IllegalStateException("This factory has not yet been initialized!"); 1160 } 1161 if (tr == null) { 1162 Image im = new Image(block); 1163 im.setColor(scc.filter(color)); 1164 im.setSize(width, height); 1165 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1166 return im; 1167 } else { 1168 Image im = new Image(tr); 1169 im.setColor(scc.filter(color)); 1170 im.setSize(width, height); 1171 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1172 return im; 1173 } 1174 } 1175 1176 /** 1177 * Converts a TextureRegion into an Image, or if the argument s is null, creates an Image of a solid block. Can be 1178 * used for preparing images for animation effects. Ensures the returned Image has the given width and height. 1179 * @param tr a TextureRegion to make into an Actor, which can be null for a solid block. 1180 * @param color a Color to tint tr with. 1181 * @return the Actor, with no position set. 1182 */ 1183 public Actor makeActor(TextureRegion tr, Color color, float width, float height) { 1184 if (!initialized) { 1185 throw new IllegalStateException("This factory has not yet been initialized!"); 1186 } 1187 if (tr == null) { 1188 Image im = new Image(block); 1189 im.setColor(scc.filter(color)); 1190 im.setSize(width, height); 1191 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1192 return im; 1193 } else { 1194 Image im = new Image(tr); 1195 im.setColor(scc.filter(color)); 1196 im.setSize(width, height); 1197 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1198 return im; 1199 } 1200 } 1201 1202 /** 1203 * Returns a solid block of white, 1x1 pixel in size; can be drawn at other sizes by Batch. 1204 * 1205 * @return a white 1x1 pixel Texture. 1206 */ 1207 public Texture getSolid() { 1208 if (!initialized) { 1209 throw new IllegalStateException("This factory has not yet been initialized!"); 1210 } 1211 return block; 1212 } 1213 1214 public boolean isDistanceField() { 1215 return distanceField; 1216 } 1217 1218 public float getDistanceFieldScaleX() { 1219 return distanceFieldScaleX; 1220 } 1221 public float getDistanceFieldScaleY() { 1222 return distanceFieldScaleY; 1223 } 1224 1225 /** 1226 * If this uses a distance field font, the smoothing multiplier affects how crisp or blurry lines are, with higher 1227 * numbers generally resulting in more crisp fonts, but numbers that are too high cause jagged aliasing. 1228 * @return the current smoothing multiplier as a float, which starts at 1f. 1229 */ 1230 public float getSmoothingMultiplier() { 1231 return smoothingMultiplier; 1232 } 1233 1234 /** 1235 * If this uses a distance field font, the smoothing multiplier affects how crisp or blurry lines are, with higher 1236 * numbers generally resulting in more crisp fonts, but numbers that are too high cause jagged aliasing. 1237 * @param smoothingMultiplier the new value for the smoothing multiplier as a float; should be fairly close to 1f. 1238 * @return this for chaining 1239 */ 1240 public TextCellFactory setSmoothingMultiplier(float smoothingMultiplier) { 1241 this.smoothingMultiplier = smoothingMultiplier; 1242 return this; 1243 } 1244 1245 /** 1246 * If using a distance field font, you MUST call this at some point while the batch has begun, or use code that 1247 * calls it for you (which is now much of SquidLib). A typical point to call it is in the 1248 * "void draw(Batch batch, float parentAlpha)" method or an overriding method for a Scene2D class. You should call 1249 * configureShader rarely, typically only a few times per frame if there are no images to render, and this means the 1250 * logical place to call it is in the outermost Group that contains any SquidPanel objects or other widgets. If you 1251 * have multipleTextCellFactory objects, each one needs to have configureShader called before it is used to draw. 1252 * <br> 1253 * SquidLayers and SquidPanel already call this method in their draw overrides, so you don't need to call this 1254 * manually if you use SquidLayers or SquidPanel. 1255 * <br> 1256 * If you don't use a distance field font, you don't need to call this, but calling it won't cause problems. 1257 * 1258 * @param batch the Batch, such as a SpriteBatch, to configure to render distance field fonts if necessary. 1259 */ 1260 public void configureShader(Batch batch) { 1261 if (initialized && distanceField) { 1262 batch.setShader(shader); 1263 shader.setUniformf("u_smoothing", 3.5f * smoothingMultiplier * bmpFont.getData().scaleX); 1264 1265 } 1266 } 1267 /** 1268 * Releases all resources of this object. 1269 */ 1270 @Override 1271 public void dispose() { 1272 if(bmpFont != null) bmpFont.dispose(); 1273 if(block != null) block.dispose(); 1274 } 1275 1276 /** 1277 * Gets the descent of this TextCellFactory's BitmapFont, which may be useful for layout outside this class. 1278 * @return the descent of the BitmapFont this object uses 1279 */ 1280 public float getDescent() { 1281 return descent; 1282 } 1283 1284 /** 1285 * Adds a pair of Strings (typically both with length 1) as a replacement pair, so when the find String is requested 1286 * to be drawn, the replace String is used instead. These are used when drawing text in each cell in SquidPanel and 1287 * related classes, so Strings longer than 1 char are rare, if they occur at all. 1288 * <br> 1289 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 1290 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 1291 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap("^", ",")} and also 1292 * {@code addSwap(",", ":")}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 1293 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 1294 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 1295 * @param find the requested String that will be changed 1296 * @param replace the replacement String that will be used in place of find 1297 * @return this for chaining 1298 */ 1299 public TextCellFactory addSwap(String find, String replace) 1300 { 1301 if(find.startsWith("\0")) 1302 return this; 1303 swap.put(find, replace); 1304 return this; 1305 } 1306 1307 /** 1308 * Adds a pair of chars as a replacement pair, so when the find char is requested to be drawn, the replace char is 1309 * used instead. 1310 * <br> 1311 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 1312 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 1313 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also 1314 * {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 1315 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 1316 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 1317 * @param find the requested char that will be changed (converted to a length-1 String) 1318 * @param replace the replacement char that will be used in place of find (converted to a length-1 String) 1319 * @return this for chaining 1320 */ 1321 public TextCellFactory addSwap(char find, char replace) 1322 { 1323 if(find == '\0') 1324 return this; 1325 swap.put(String.valueOf(find), String.valueOf(replace)); 1326 return this; 1327 } 1328 1329 /** 1330 * Removes the replacement pair, if present, that searches for the given key, find. 1331 * <br> 1332 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 1333 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 1334 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap("^", ",")} and also 1335 * {@code addSwap(",", ":")}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 1336 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 1337 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 1338 * @param find the String that would be changed in the replacement pair 1339 * @return this for chaining 1340 */ 1341 public TextCellFactory removeSwap(String find) 1342 { 1343 swap.remove(find); 1344 return this; 1345 } 1346 1347 /** 1348 * Removes the replacement pair, if present, that searches for the given key, find. 1349 * <br> 1350 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 1351 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 1352 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also 1353 * {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 1354 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 1355 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 1356 * @return this for chaining 1357 */ 1358 public TextCellFactory removeSwap(char find) 1359 { 1360 swap.remove(String.valueOf(find)); 1361 return this; 1362 } 1363 1364 /** 1365 * Gets the current mapping of "swaps", or replacement pairs, to replace keys requested for drawing with their 1366 * values in the LinkedHashMap. 1367 * <br> 1368 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 1369 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 1370 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap("^", ",")} and also 1371 * {@code addSwap(",", ":")}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 1372 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 1373 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 1374 * @return the mapping of replacement pairs 1375 */ 1376 public LinkedHashMap<String, String> getAllSwaps() { 1377 return swap; 1378 } 1379 1380 /** 1381 * Sets the mapping of replacement pairs to a different one as a Map of String keys to String values. 1382 * <br> 1383 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 1384 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 1385 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap("^", ",")} and also 1386 * {@code addSwap(",", ":")}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 1387 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 1388 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 1389 * @param swaps the Map of replacement pairs; keys requested for drawing will be replaced with their values 1390 * @return this for chaining 1391 */ 1392 public TextCellFactory setAllSwaps(Map<String, String> swaps) { 1393 this.swap = new LinkedHashMap<>(swaps.size()); 1394 for(Map.Entry<String, String> kv : swaps.entrySet()) 1395 { 1396 if(!kv.getKey().startsWith("\0")) 1397 this.swap.put(kv.getKey(), kv.getValue()); 1398 } 1399 return this; 1400 } 1401 1402 /** 1403 * Appends to the mapping of replacement pairs, adding or replacing any entries in the current mapping with the 1404 * entries in a Map of String keys to String values. 1405 * <br> 1406 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 1407 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 1408 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap("^", ",")} and also 1409 * {@code addSwap(",", ":")}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 1410 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 1411 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 1412 * @param swaps the Map of replacement pairs to add; keys requested for drawing will be replaced with their values 1413 * @return this for chaining 1414 */ 1415 public TextCellFactory addSwaps(Map<String, String> swaps) { 1416 1417 for(Map.Entry<String, String> kv : swaps.entrySet()) 1418 { 1419 if(!kv.getKey().startsWith("\0")) 1420 swap.put(kv.getKey(), kv.getValue()); 1421 } 1422 return this; 1423 } 1424 1425 /** 1426 * Clears all replacement pairs this has been told to swap. 1427 * <br> 1428 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 1429 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 1430 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap("^", ",")} and also 1431 * {@code addSwap(",", ":")}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 1432 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 1433 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 1434 * @return this for chaining 1435 */ 1436 public TextCellFactory clearSwaps() 1437 { 1438 swap.clear(); 1439 return this; 1440 } 1441}