001package squidpony.squidgrid.gui.gdx;
002
003import com.badlogic.gdx.Gdx;
004import com.badlogic.gdx.graphics.Color;
005import com.badlogic.gdx.graphics.Pixmap;
006import com.badlogic.gdx.graphics.Texture;
007import com.badlogic.gdx.graphics.g2d.Batch;
008import com.badlogic.gdx.graphics.g2d.BitmapFont;
009import com.badlogic.gdx.graphics.g2d.TextureRegion;
010import com.badlogic.gdx.scenes.scene2d.Actor;
011import com.badlogic.gdx.scenes.scene2d.ui.Image;
012import com.badlogic.gdx.scenes.scene2d.ui.Label;
013import com.badlogic.gdx.utils.Align;
014
015/**
016 * Class for creating text blocks.
017 *
018 * This class defaults to having no padding and having no font set. You can use a
019 * default square or narrow font by calling the appropriate method, or set the font
020 * to any AngelCode bitmap font on the classpath (typically in libGDX, this would be
021 * in the assets folder; these fonts can be created by Hiero in the libGDX tools,
022 * see https://github.com/libgdx/libgdx/wiki/Hiero for more)
023 *
024 * After all settings are set, one of the initialization methods must be called
025 * before the factory can be used.
026 *
027 * In order to easily support Unicode, strings are treated as a series of code
028 * points.
029 *
030 * All images have transparent backgrounds.
031 *
032 * @author Eben Howard - http://squidpony.com - howard@squidpony.com
033 */
034public class TextCellFactory {
035
036    /**
037     * The commonly used symbols in roguelike games.
038     */
039    public static final String DEFAULT_FITTING = "@!#$%^&*()_+1234567890-=~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz;:,'\"{}?/\\ ",
040    LINE_FITTING = "┼├┤┴┬┌┐└┘│─", SQUID_FITTING = DEFAULT_FITTING + LINE_FITTING;
041
042    protected BitmapFont bmpFont = null;
043    protected Texture block = null;
044    protected String fitting = SQUID_FITTING;
045    protected int leftPadding = 0, rightPadding = 0, topPadding = 0, bottomPadding = 0;
046    protected int width = 1, height = 1;
047    private boolean initialized = false;
048
049    /**
050     * Creates a default valued factory. One of the initialization methods must
051     * be called before this factory can be used!
052     */
053    public TextCellFactory() {
054    }
055
056    /**
057     * Initializes the factory to then be able to create text cells on demand.
058     *
059     * Will match the width and height to 12 and 12, scaling the font to fit.
060     *
061     * Calling this after the factory has already been initialized will
062     * re-initialize it.
063     *
064     * @return this for method chaining
065     */
066    public TextCellFactory initByFont() {
067        bmpFont.setFixedWidthGlyphs(fitting);
068        this.width = (int)bmpFont.getSpaceWidth();
069        this.height = (int)(bmpFont.getLineHeight());
070        Pixmap temp = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
071        temp.setColor(Color.WHITE);
072        temp.fill();
073        block = new Texture(1, 1, Pixmap.Format.RGBA8888);
074        block.draw(temp, 0, 0);
075        temp.dispose();
076        initialized = true;
077        return this;
078    }
079
080    /**
081     * Initializes the factory to then be able to create text cells on demand.
082     *
083     * Will strictly use the provided width and height values to size the cells.
084     *
085     * Calling this after the factory has already been initialized will
086     * re-initialize it.
087     *
088     * @return this for method chaining
089     */
090    public TextCellFactory initBySize() {
091        bmpFont.setFixedWidthGlyphs(fitting);
092        Pixmap temp = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
093        temp.setColor(Color.WHITE);
094        temp.fill();
095        block = new Texture(1, 1, Pixmap.Format.RGBA8888);
096        block.draw(temp, 0, 0);
097        temp.dispose();
098        initialized = true;
099        return this;
100    }
101
102    /**
103     * Initializes the factory to then be able to create text cells on demand.
104     *
105     * (This is identical to initBySize() when using libGDX.)
106     *
107     * @return this for method chaining
108     */
109    public TextCellFactory initVerbatim() {
110        return initBySize();
111    }
112
113    /**
114     * Returns the font used by this factory.
115     *
116     * @return the font
117     */
118    public BitmapFont font() {
119        return bmpFont;
120    }
121
122    /**
123     * Sets this factory to use the provided font.
124     *
125     * This is a way to complete a needed step; the font must be set before initializing, which can be done by a few
126     * methods in this class.
127     *
128     * This should be called with an argument such as "Rogue-Zodiac-6x12.fnt", that is, it should have the .fnt
129     * extension as opposed to the .png that accompanies such a bitmap font. The bitmap font should be on the classpath,
130     * which usually means it is in the libGDX assets folder, but can also be a resource bundled with SquidLib:
131     * <ul>
132     *     <li>"Rogue-Zodiac-6x12.fnt"</li>
133     *     <li>"Rogue-Zodiac-12x24.fnt" (available with the defaultNarrowFont() method as well)</li>
134     *     <li>"Zodiac-Square-12x12.fnt" (available with the defaultSquareFont() method as well)</li>
135     *     <li>"Zodiac-Square-24x24.fnt"</li>
136     *     <li>"Mandrill-6x16.fnt"</li>
137     *     <li>"Mandrill-12x32.fnt"</li>
138     * </ul>
139     *
140     * See https://github.com/libgdx/libgdx/wiki/Hiero for some ways to create a bitmap font this can use.
141     *
142     * @param fontpath the path to the font to use
143     * @return this factory for method chaining
144     */
145    public TextCellFactory font(String fontpath) {
146        this.bmpFont = new BitmapFont(Gdx.files.internal(fontpath));
147        return this;
148    }
149
150    /**
151     * Sets this factory to use a default 12x24 font.
152     *
153     * This is a way to complete a needed step; the font must be set before initializing, which can be done by a few
154     * methods in this class.
155     *
156     * @return this factory for method chaining
157     */
158    public TextCellFactory defaultNarrowFont()
159    {
160        bmpFont = DefaultResources.getLargeNarrowFont();
161        return this;
162    }
163
164    /**
165     * Sets this factory to use a default 12x12 font.
166     *
167     * This is a way to complete a needed step; the font must be set before initializing, which can be done by a few
168     * methods in this class.
169     *
170     * @return this factory for method chaining
171     */
172    public TextCellFactory defaultSquareFont()
173    {
174        bmpFont = DefaultResources.getDefaultFont();
175        return this;
176    }
177
178    /**
179     * Returns the width of a single cell.
180     *
181     * @return the width
182     */
183    public int width() {
184        return width;
185    }
186
187    /**
188     * Sets the factory's cell width to the provided value. Clamps at 1 on the
189     * lower bound to ensure valid calculations.
190     *
191     * @param width the desired width
192     * @return this factory for method chaining
193     */
194    public TextCellFactory width(int width) {
195        this.width = Math.max(1, width);
196        return this;
197    }
198
199    /**
200     * Returns the height of a single cell.
201     *
202     * @return
203     */
204    public int height() {
205        return height;
206    }
207
208    /**
209     * Sets the factory's cell height to the provided value. Clamps at 1 on the
210     * lower bound to ensure valid calculations.
211     *
212     * @param height the desired width
213     * @return this factory for method chaining
214     */
215    public TextCellFactory height(int height) {
216        this.height = Math.max(1, height);
217        return this;
218    }
219
220    /**
221     * Returns the current String of code points that are used for sizing the
222     * cells.
223     *
224     * Note that this is actually a set of codepoints and treating them as an
225     * array of chars might give undesired results.
226     *
227     * @return the String used for sizing calculations
228     */
229    public String fit() {
230        return fitting;
231    }
232
233    /**
234     * Sets the characters that will be guaranteed to fit to the provided ones.
235     * This will override any previously set string.
236     *
237     * @param fit the String of code points to size to
238     * @return this factory for method chaining
239     */
240    public TextCellFactory fit(String fit) {
241        fitting = fit;
242        bmpFont.setFixedWidthGlyphs(fitting);
243        this.width = (int)bmpFont.getSpaceWidth();
244        return this;
245    }
246
247    /**
248     * Adds the code points in the string to the list of characters that will be
249     * guaranteed to fit.
250     *
251     * @param fit the String of code points to size to
252     * @return this factory for method chaining
253     */
254    public TextCellFactory addFit(String fit) {
255        fitting += fit;
256        bmpFont.setFixedWidthGlyphs(fitting);
257        this.width = (int)bmpFont.getSpaceWidth();
258        return this;
259    }
260
261    /**
262     * Returns whether this factory is currently set to do antialiasing on the
263     * characters rendered, which is always true.
264     *
265     * @return true if antialiasing is set
266     */
267    public boolean antialias() {
268        return true;
269    }
270
271    /**
272     * All fonts will be rendered with antialiasing, this doesn't do anything.
273     *
274     * @param antialias ignored, will always use antialiasing
275     * @return this factory for method chaining
276     * @deprecated AA is the wave of the future!
277     */
278    public TextCellFactory antialias(boolean antialias) {
279        return this;
280    }
281
282    /**
283     * Sets the amount of padding on all sides to the provided value.
284     *
285     * @param padding how much padding in pixels
286     * @return this for method chaining
287     */
288    public TextCellFactory padding(int padding) {
289        leftPadding = padding;
290        rightPadding = padding;
291        topPadding = padding;
292        bottomPadding = padding;
293        return this;
294    }
295    
296    /**
297     * Returns the padding on the left side.
298     * 
299     * @return amount of padding in pixels
300     */
301    public int leftPadding() {
302        return leftPadding;
303    }
304
305    /**
306     * Sets the amount of padding on the left side to the provided value.
307     *
308     * @param padding how much padding in pixels
309     * @return this for method chaining
310     */
311    public TextCellFactory leftPadding(int padding) {
312        leftPadding = padding;
313        return this;
314    }
315
316    /**
317     * Returns the padding on the right side.
318     * 
319     * @return amount of padding in pixels
320     */
321    public int rightPadding() {
322        return rightPadding;
323    }
324    
325    /**
326     * Sets the amount of padding on the right side to the provided value.
327     *
328     * @param padding how much padding in pixels
329     * @return this for method chaining
330     */
331    public TextCellFactory rightPadding(int padding) {
332        rightPadding = padding;
333        return this;
334    }
335
336    /**
337     * Returns the padding on the top side.
338     * 
339     * @return amount of padding in pixels
340     */
341    public int topPadding() {
342        return topPadding;
343    }
344    
345    /**
346     * Sets the amount of padding on the top side to the provided value.
347     *
348     * @param padding how much padding in pixels
349     * @return this for method chaining
350     */
351    public TextCellFactory topPadding(int padding) {
352        topPadding = padding;
353        return this;
354    }
355
356    /**
357     * Returns the padding on the bottom side.
358     * 
359     * @return amount of padding in pixels
360     */
361    public int bottomPadding() {
362        return bottomPadding;
363    }
364
365    /**
366     * Sets the amount of padding on the bottom side to the provided value.
367     *
368     * @param padding how much padding in pixels
369     * @return this for method chaining
370     */
371    public TextCellFactory bottomPadding(int padding) {
372        bottomPadding = padding;
373        return this;
374    }
375    /**
376     * Returns true if this factory is fully initialized and ready to build text cells.
377     * 
378     * @return true if initialized
379     */
380    public boolean initialized() {
381        return initialized;
382    }
383
384
385    /**
386     * Returns true if the given character will fit inside the current cell
387     * dimensions with the current font.
388     *
389     * ISO Control characters, non-printing characters and invalid unicode
390     * characters are all considered by definition to fit.
391     *
392     * @param codepoint
393     * @return
394     */
395    public boolean willFit(int codepoint) {
396        if (!initialized) {
397            throw new IllegalStateException("This factory has not yet been initialized!");
398        }
399        
400        if (!Character.isValidCodePoint(codepoint) || Character.isISOControl(codepoint)) {
401            return true;
402        }
403
404        return fitting.contains(String.valueOf(Character.toChars(codepoint)));
405    }
406
407    /**
408     * Use the specified Batch to draw a String (often just one char long) with the default color (white), with x and y
409     * determining the world-space coordinates for the upper-left corner.
410     *
411     * @param batch the LibGDX Batch to do the drawing
412     * @param s the string to draw, often but not necessarily one char. Can be null to draw a solid block instead.
413     * @param x x of the upper-left corner of the region of text in world coordinates.
414     * @param y y of the upper-left corner of the region of text in world coordinates.
415     */
416    public void draw(Batch batch, String s, float x, float y) {
417        if (!initialized) {
418            throw new IllegalStateException("This factory has not yet been initialized!");
419        }
420        if (s == null) {
421            batch.draw(block, x, y - height, width, height);
422        } else if(s.length() > 0 && s.charAt(0) == '\0') {
423            batch.draw(block, x, y - height, width * s.length(), height);
424        } else {
425            bmpFont.draw(batch, s, x, y - bmpFont.getDescent(), width * s.length(), Align.center, false);
426        }
427    }
428    /**
429     * Use the specified Batch to draw a String (often just one char long) in the specified rgba color, with x and y
430     * determining the world-space coordinates for the upper-left corner.
431     *
432     * @param batch the LibGDX Batch to do the drawing
433     * @param s the string to draw, often but not necessarily one char. Can be null to draw a solid block instead.
434     * @param r 0.0 to 0.1 red value
435     * @param g 0.0 to 0.1 green value
436     * @param b 0.0 to 0.1 blue value
437     * @param a 0.0 to 0.1 alpha value
438     * @param x x of the upper-left corner of the region of text in world coordinates.
439     * @param y y of the upper-left corner of the region of text in world coordinates.
440     */
441    public void draw(Batch batch, String s, float r, float g, float b, float a, float x, float y) {
442        if (!initialized) {
443            throw new IllegalStateException("This factory has not yet been initialized!");
444        }
445        if (s == null) {
446            Color orig = batch.getColor();
447            batch.setColor(r, g, b, a);
448            batch.draw(block, x, y - height, width, height);
449            batch.setColor(orig);
450        } else if(s.length() > 0 && s.charAt(0) == '\0') {
451            Color orig = batch.getColor();
452            batch.setColor(r, g, b, a);
453            batch.draw(block, x, y - height, width * s.length(), height);
454            batch.setColor(orig);
455        } else {
456            bmpFont.setColor(r, g, b, a);
457            bmpFont.draw(batch, s, x, y - bmpFont.getDescent(), width * s.length(), Align.center, false);
458        }
459    }
460
461    /**
462     * Use the specified Batch to draw a String (often just one char long) in the specified LibGDX Color, with x and y
463     * determining the world-space coordinates for the upper-left corner.
464     *
465     * @param batch the LibGDX Batch to do the drawing
466     * @param s the string to draw, often but not necessarily one char. Can be null to draw a solid block instead.
467     * @param color the LibGDX Color to draw the char(s) with, all the same color
468     * @param x x of the upper-left corner of the region of text in world coordinates.
469     * @param y y of the upper-left corner of the region of text in world coordinates.
470     */
471    public void draw(Batch batch, String s, Color color, float x, float y) {
472        if (!initialized) {
473            throw new IllegalStateException("This factory has not yet been initialized!");
474        }
475        bmpFont.setColor(color);
476
477        if (s == null) {
478            Color orig = batch.getColor();
479            batch.setColor(color);
480            batch.draw(block, x, y - height, width, height);
481            batch.setColor(orig);
482        } else if(s.length() > 0 && s.charAt(0) == '\0') {
483            Color orig = batch.getColor();
484            batch.setColor(color);
485            batch.draw(block, x, y - height, width * s.length(), height);
486            batch.setColor(orig);
487        } else {
488            bmpFont.setColor(color);
489            bmpFont.draw(batch, s, x, y - bmpFont.getDescent(), width * s.length(), Align.center, false);
490        }
491    }
492
493    /**
494     * Use the specified Batch to draw a TextureRegion with the default tint color (white, so un-tinted), with x and y
495     * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched
496     * if its size does not match what this TextCellFactory uses for width and height.
497     *
498     * @param batch the LibGDX Batch to do the drawing
499     * @param tr the TextureRegion to draw. Can be null to draw a solid block instead.
500     * @param x x of the upper-left corner of the region of text in world coordinates.
501     * @param y y of the upper-left corner of the region of text in world coordinates.
502     */
503    public void draw(Batch batch, TextureRegion tr, float x, float y) {
504        if (!initialized) {
505            throw new IllegalStateException("This factory has not yet been initialized!");
506        }
507        if (tr == null) {
508            batch.draw(block, x, y - height, width, height);
509        } else {
510            batch.draw(tr, x, y - height, width, height);
511        }
512    }
513    /**
514     * Use the specified Batch to draw a TextureRegion tinted with the specified rgba color, with x and y
515     * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched
516     * if its size does not match what this TextCellFactory uses for width and height.
517     *
518     * @param batch the LibGDX Batch to do the drawing
519     * @param tr the TextureRegion to draw. Can be null to draw a solid block instead.
520     * @param r 0.0 to 0.1 red value
521     * @param g 0.0 to 0.1 green value
522     * @param b 0.0 to 0.1 blue value
523     * @param a 0.0 to 0.1 alpha value
524     * @param x x of the upper-left corner of the region of text in world coordinates.
525     * @param y y of the upper-left corner of the region of text in world coordinates.
526     */
527    public void draw(Batch batch, TextureRegion tr, float r, float g, float b, float a, float x, float y) {
528        if (!initialized) {
529            throw new IllegalStateException("This factory has not yet been initialized!");
530        }
531        if (tr == null) {
532            Color orig = batch.getColor();
533            batch.setColor(r, g, b, a);
534            batch.draw(block, x, y - height, width, height);
535            batch.setColor(orig);
536        } else {
537            Color orig = batch.getColor();
538            batch.setColor(r, g, b, a);
539            batch.draw(tr, x, y - height, width, height);
540            batch.setColor(orig);
541        }
542    }
543
544    /**
545     * Use the specified Batch to draw a TextureRegion tinted with the specified LibGDX Color, with x and y
546     * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched
547     * if its size does not match what this TextCellFactory uses for width and height.
548     *
549     * @param batch the LibGDX Batch to do the drawing
550     * @param tr the TextureRegion to draw. Can be null to draw a solid block instead.
551     * @param color the LibGDX Color to draw the char(s) with, all the same color
552     * @param x x of the upper-left corner of the region of text in world coordinates.
553     * @param y y of the upper-left corner of the region of text in world coordinates.
554     */
555    public void draw(Batch batch, TextureRegion tr, Color color, float x, float y) {
556        if (!initialized) {
557            throw new IllegalStateException("This factory has not yet been initialized!");
558        }
559        bmpFont.setColor(color);
560
561        if (tr == null) {
562            Color orig = batch.getColor();
563            batch.setColor(color);
564            batch.draw(block, x, y - height, width, height);
565            batch.setColor(orig);
566        } else {
567            Color orig = batch.getColor();
568            batch.setColor(color);
569            batch.draw(tr, x, y - height, width, height);
570            batch.setColor(orig);
571        }
572    }
573
574    /**
575     * Use the specified Batch to draw a TextureRegion with the default tint color (white, so un-tinted), with x and y
576     * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched
577     * only if the supplied width and height do not match what its own dimensions are.
578     *
579     * @param batch the LibGDX Batch to do the drawing
580     * @param tr the TextureRegion to draw. Can be null to draw a solid block instead.
581     * @param x x of the upper-left corner of the region of text in world coordinates.
582     * @param y y of the upper-left corner of the region of text in world coordinates.
583     * @param width the width of the TextureRegion or solid block in pixels.
584     * @param height the height of the TextureRegion or solid block in pixels.
585     */
586    public void draw(Batch batch, TextureRegion tr, float x, float y, float width, float height) {
587        if (!initialized) {
588            throw new IllegalStateException("This factory has not yet been initialized!");
589        }
590        if (tr == null) {
591            batch.draw(block, x, y - height, width, height);
592        } else {
593            batch.draw(tr, x, y - height, width, height);
594        }
595    }
596    /**
597     * Use the specified Batch to draw a TextureRegion tinted with the specified rgba color, with x and y
598     * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched
599     * only if the supplied width and height do not match what its own dimensions are.
600     *
601     * @param batch the LibGDX Batch to do the drawing
602     * @param tr the TextureRegion to draw. Can be null to draw a solid block instead.
603     * @param r 0.0 to 0.1 red value
604     * @param g 0.0 to 0.1 green value
605     * @param b 0.0 to 0.1 blue value
606     * @param a 0.0 to 0.1 alpha value
607     * @param x x of the upper-left corner of the region of text in world coordinates.
608     * @param y y of the upper-left corner of the region of text in world coordinates.
609     * @param width the width of the TextureRegion or solid block in pixels.
610     * @param height the height of the TextureRegion or solid block in pixels.
611     */
612    public void draw(Batch batch, TextureRegion tr, float r, float g, float b, float a, float x, float y, float width, float height) {
613        if (!initialized) {
614            throw new IllegalStateException("This factory has not yet been initialized!");
615        }
616        if (tr == null) {
617            Color orig = batch.getColor();
618            batch.setColor(r, g, b, a);
619            batch.draw(block, x, y - height, width, height);
620            batch.setColor(orig);
621        } else {
622            Color orig = batch.getColor();
623            batch.setColor(r, g, b, a);
624            batch.draw(tr, x, y - height, width, height);
625            batch.setColor(orig);
626        }
627    }
628
629    /**
630     * Use the specified Batch to draw a TextureRegion tinted with the specified LibGDX Color, with x and y
631     * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched
632     * only if the supplied width and height do not match what its own dimensions are.
633     *
634     * @param batch the LibGDX Batch to do the drawing
635     * @param tr the TextureRegion to draw. Can be null to draw a solid block instead.
636     * @param color the LibGDX Color to draw the char(s) with, all the same color
637     * @param x x of the upper-left corner of the region of text in world coordinates.
638     * @param y y of the upper-left corner of the region of text in world coordinates.
639     * @param width the width of the TextureRegion or solid block in pixels.
640     * @param height the height of the TextureRegion or solid block in pixels.
641     */
642    public void draw(Batch batch, TextureRegion tr, Color color, float x, float y, float width, float height) {
643        if (!initialized) {
644            throw new IllegalStateException("This factory has not yet been initialized!");
645        }
646
647        if (tr == null) {
648            Color orig = batch.getColor();
649            batch.setColor(color);
650            batch.draw(block, x, y - height, width, height);
651            batch.setColor(orig);
652        } else {
653            Color orig = batch.getColor();
654            batch.setColor(color);
655            batch.draw(tr, x, y - height, width, height);
656            batch.setColor(orig);
657        }
658    }
659
660    /**
661     * Converts a String into a Label, or if the argument s is null, creates an Image of a solid block. Can be used
662     * for preparing glyphs for animation effects, and is used internally for this purpose.
663     * @param s a String to make into an Actor, which can be null for a solid block.
664     * @param color a Color to tint s with.
665     * @return the Actor, with no position set.
666     */
667    public Actor makeActor(String s, Color color) {
668        if (!initialized) {
669            throw new IllegalStateException("This factory has not yet been initialized!");
670        }
671        if (s == null) {
672            Image im = new Image(block);
673            im.setColor(color);
674            im.setSize(width, height);
675            // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
676            return im;
677        } else if(s.length() > 0 && s.charAt(0) == '\0') {
678            Image im = new Image(block);
679            im.setColor(color);
680            im.setSize(width * s.length(), height);
681            // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
682            return im;
683        } else {
684            Label lb = new Label(s, new Label.LabelStyle(bmpFont, null));
685            lb.setColor(color);
686            // lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
687            return lb;
688        }
689    }
690
691    /**
692     * Converts a TextureRegion into an Image, or if the argument s is null, creates an Image of a solid block. Can be
693     * used for preparing images for animation effects. Stretches the TextureRegion to match a single cell's dimensions.
694     * @param tr a TextureRegion to make into an Actor, which can be null for a solid block.
695     * @param color a Color to tint tr with.
696     * @return the Actor, with no position set.
697     */
698    public Actor makeActor(TextureRegion tr, Color color) {
699        if (!initialized) {
700            throw new IllegalStateException("This factory has not yet been initialized!");
701        }
702        if (tr == null) {
703            Image im = new Image(block);
704            im.setColor(color);
705            im.setSize(width, height);
706            // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
707            return im;
708        } else {
709            Image im = new Image(tr);
710            im.setColor(color);
711            im.setSize(width, height);
712            // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
713            return im;
714        }
715    }
716
717    /**
718     * Converts a TextureRegion into an Image, or if the argument s is null, creates an Image of a solid block. Can be
719     * used for preparing images for animation effects. Ensures the returned Image has the given width and height.
720     * @param tr a TextureRegion to make into an Actor, which can be null for a solid block.
721     * @param color a Color to tint tr with.
722     * @return the Actor, with no position set.
723     */
724    public Actor makeActor(TextureRegion tr, Color color, float width, float height) {
725        if (!initialized) {
726            throw new IllegalStateException("This factory has not yet been initialized!");
727        }
728        if (tr == null) {
729            Image im = new Image(block);
730            im.setColor(color);
731            im.setSize(width, height);
732            // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
733            return im;
734        } else {
735            Image im = new Image(tr);
736            im.setColor(color);
737            im.setSize(width, height);
738            // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
739            return im;
740        }
741    }
742
743    /**
744     * Returns a solid block of white, 1x1 pixel in size; can be drawn at other sizes by Batch.
745     *
746     * @return a white 1x1 pixel Texture.
747     */
748    public Texture getSolid() {
749        if (!initialized) {
750            throw new IllegalStateException("This factory has not yet been initialized!");
751        }
752        return block;
753    }
754
755}