package squidpony.squidgrid.gui.gdx; import com.badlogic.gdx.assets.AssetManager; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture.TextureFilter; import com.badlogic.gdx.graphics.g2d.TextureRegion; import squidpony.IColorCenter; /** * An almost-concrete implementation of {@link IPanelBuilder}. This class makes * the assumption that font files are only available for square and even sizes. * The only method to implement is {@link #fontfile(int)} that must return the * name of the file where a font of a given size lives. * * <p> * I think this class should be generalized so that it supports cell width and * cell height that are proportional (for example: a height that is the double * of the width), but not to arbitrary combinations. In that case * {@link #adjustCellSize(int)} would become impossible to implement. * </p> * * @author smelC */ public abstract class SquidPanelBuilder extends IPanelBuilder.Skeleton { protected final /* @Nullable */ IColorCenter<Color> icc; public final /* @Nullable */ AssetManager assetManager; protected final int smallestFont; protected final int largestFont; protected final int fontOffset; /** * The color passed to {@link SquidPanel#setDefaultForeground(Color)} when * building a new panel, if non-{@code null}. */ protected /* @Nullable */ Color defaultForegroundColor; /** * @param smallestFont * The smallest font size available. * @param largestFont * The largest font size available. * @param fontOffset * This offset is added to the cell size when computing the font * size for a given cell size. * @param icc * The color center to give to * {@link SquidPanel#setColorCenter(IColorCenter)}, or * {@code null} not to call this method. * @param assetManager */ public SquidPanelBuilder(int smallestFont, int largestFont, int fontOffset, /* @Nullable */IColorCenter<Color> icc, /* @Nullable */ AssetManager assetManager) { this.icc = icc; this.assetManager = assetManager; this.smallestFont = smallestFont; this.largestFont = largestFont; this.fontOffset = fontOffset; } @Override public SquidPanel buildScreenWide(int screenWidth, int screenHeight, int desiredCellSize, /* @Nullable */ TextCellFactory tcf) { final int sz = adjustCellSize(desiredCellSize); final int hcells = screenWidth / sz; final int vcells = screenHeight / sz; final SquidPanel result = buildByCells(hcells, vcells, sz, sz, tcf); final int vmargin = screenHeight - (vcells * sz); final int hmargin = screenWidth - (hcells * sz); result.setPosition(hmargin / 2, vmargin / 2); /* TODO smelC Draw margins ? */ return result; } @Override public SquidPanel buildByCells(int hCells, int vCells, int cellWidth, int cellHeight, /*@Nullable*/ TextCellFactory tcf_) { final TextCellFactory tcf; final boolean freshTCF; if (tcf_ != null && tcf_.width() == cellWidth && tcf_.height() == cellHeight) { /* Can reuse */ tcf = tcf_; freshTCF = false; } else { tcf = new TextCellFactory(assetManager); freshTCF = true; } if (cellWidth == cellHeight) { final int fontSize = fontSizeForCellSize(cellWidth); if (!hasFontOfSize(fontSize)) throw new IllegalStateException("No font of size " + fontSize); final String fontFile = fontfile(fontSize); if (freshTCF) { /* Initialize it */ tcf.font(fontFile); for (TextureRegion region : tcf.font().getRegions()) region.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); tcf.initByFont(); tcf.width(cellWidth).height(cellHeight); } final SquidPanel result = new SquidPanel(hCells, vCells, tcf); if (icc != null) result.setColorCenter(icc); if (defaultForegroundColor != null) result.setDefaultForeground(defaultForegroundColor); return result; } else throw new IllegalStateException("Non square cells aren't supported"); } /** * @param sz * @return A valid cell size, as close as possible to {@code sz}. */ @Override public int adjustCellSize(int sz) { int result = sz % 2 == 0 ? sz : sz - 1; if (hasFontForCellOfSize(result)) return result; if (cellSizeTooBig(sz)) { final int offset = -2; while (0 < result) { result += offset; if (hasFontForCellOfSize(result)) return result; } throw new IllegalStateException("There's a bug in the computation of the cell size"); } else if (cellSizeTooSmall(result)) { final int offset; offset = 2; while (/* It's better to stop one day */ result < 512) { result += offset; if (hasFontForCellOfSize(result)) return result; } throw new IllegalStateException("There's a bug in the computation of the cell size"); } else throw new IllegalStateException("There's a bug in the computation of the cell size"); } @Override public boolean cellSizeTooBig(int cellSize) { return largestFont < fontSizeForCellSize(cellSize); } @Override public boolean cellSizeTooSmall(int cellSize) { return fontSizeForCellSize(cellSize) < smallestFont; } @Override public boolean hasFontForCellOfSize(int cellSize) { return hasFontOfSize(fontSizeForCellSize(cellSize)); } @Override public int fontSizeForCellSize(int cellSize) { return cellSize + fontOffset; } @Override public boolean hasFontOfSize(int sz) { return sz % 2 == 0 && smallestFont <= sz && sz <= largestFont; } /** * @param c * The default foreground color that freshly created panels will * have. Can be {@code null} to use {@link SquidPanel}'s default. */ public void setDefaultForegroundColor(/* @Nullable */Color c) { this.defaultForegroundColor = c; } /** * @param sz * @return The name of the file where the font of size {@code sz} lives. */ protected abstract String fontfile(int sz); }