package io.github.lonamiwebs.klooni;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.scenes.scene2d.ui.ImageButton;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.JsonReader;
import com.badlogic.gdx.utils.JsonValue;
// Represents a Theme for the current game.
// These are loaded from external files, so more
// can be easily added
public class Theme {
//region Members
private String displayName;
private String name;
private int price;
public Color background;
public Color foreground;
private Color emptyCell;
public Color currentScore;
public Color highScore;
public Color bonus;
public Color bandColor;
public Color textColor;
private Color[] cells;
public static Skin skin;
public Texture cellTexture;
// Save the button styles so the changes here get reflected
private ImageButton.ImageButtonStyle[] buttonStyles;
//endregion
//region Constructor
private Theme() {
buttonStyles = new ImageButton.ImageButtonStyle[4];
}
//endregion
//region Static methods
static boolean exists(final String name) {
return Gdx.files.internal("themes/"+name+".theme").exists();
}
// Gets all the available themes on the available on the internal game storage
public static Array<Theme> getThemes() {
String[] themes = Gdx.files.internal("themes/theme.list").readString().split("\n");
Array<Theme> result = new Array<Theme>(themes.length);
for (int i = 0; i < themes.length; ++i) {
FileHandle file = Gdx.files.internal("themes/" + themes[i] + ".theme");
if (file.exists())
result.add(Theme.fromFile(file));
else {
Gdx.app.log(
"Theme/Info", "Non-existing theme '" + themes[i] +
"' found on theme.list (line " + (i + 1) + ")");
}
}
return result;
}
static Theme getTheme(final String name) {
return new Theme().update(name);
}
private static Theme fromFile(FileHandle handle) {
return new Theme().update(handle);
}
// Used to determine the best foreground color (black or white) given a background color
// Formula took from http://alienryderflex.com/hsp.html
// Not used yet, but may be useful
private final static double BRIGHTNESS_CUTOFF = 0.5;
public static boolean shouldUseWhite(Color color) {
double brightness = Math.sqrt(
color.r * color.r * .299 +
color.g * color.g * .587 +
color.b * color.b * .114);
return brightness < BRIGHTNESS_CUTOFF;
}
//endregion
//region Theme updating
// Updates the theme with all the values from the specified file or name
public Theme update(final String name) {
return update(Gdx.files.internal("themes/"+name+".theme"));
}
private Theme update(final FileHandle handle) {
if (skin == null) {
throw new NullPointerException("A Theme.skin must be set before updating any Theme instance");
}
final JsonValue json = new JsonReader().parse(handle.readString());
name = handle.nameWithoutExtension();
displayName = json.getString("name");
price = json.getInt("price");
JsonValue colors = json.get("colors");
// Java won't allow unsigned integers, we need to use Long
background = new Color((int)Long.parseLong(colors.getString("background"), 16));
foreground = new Color((int)Long.parseLong(colors.getString("foreground"), 16));
JsonValue buttonColors = colors.get("buttons");
Color[] buttons = new Color[buttonColors.size];
for (int i = 0; i < buttons.length; ++i) {
buttons[i] = new Color((int)Long.parseLong(buttonColors.getString(i), 16));
if (buttonStyles[i] == null) {
buttonStyles[i] = new ImageButton.ImageButtonStyle();
}
// Update the style. Since every button uses an instance from this
// array, the changes will appear on screen automatically.
buttonStyles[i].up = skin.newDrawable("button_up", buttons[i]);
buttonStyles[i].down = skin.newDrawable("button_down", buttons[i]);
}
currentScore = new Color((int)Long.parseLong(colors.getString("current_score"), 16));
highScore = new Color((int)Long.parseLong(colors.getString("high_score"), 16));
bonus = new Color((int)Long.parseLong(colors.getString("bonus"), 16));
bandColor = new Color((int)Long.parseLong(colors.getString("band"), 16));
textColor = new Color((int)Long.parseLong(colors.getString("text"), 16));
emptyCell = new Color((int)Long.parseLong(colors.getString("empty_cell"), 16));
JsonValue cellColors = colors.get("cells");
cells = new Color[cellColors.size];
for (int i = 0; i < cells.length; ++i) {
cells[i] = new Color((int)Long.parseLong(cellColors.getString(i), 16));
}
String cellTextureFile = json.getString("cell_texture");
cellTexture = SkinLoader.loadPng("cells/"+cellTextureFile);
return this;
}
//endregion
//region Applying the theme
public String getName() {
return name;
}
public String getDisplay() {
return displayName;
}
public int getPrice() {
return price;
}
public ImageButton.ImageButtonStyle getStyle(int button) {
return buttonStyles[button];
}
public Color getCellColor(int colorIndex) {
return colorIndex < 0 ? emptyCell : cells[colorIndex];
}
public void glClearBackground() {
Gdx.gl.glClearColor(background.r, background.g, background.b, background.a);
}
public void updateStyle(ImageButton.ImageButtonStyle style, int styleIndex) {
style.imageUp = buttonStyles[styleIndex].imageUp;
style.imageDown = buttonStyles[styleIndex].imageDown;
}
//endregion
//region Styling utilities
// A 1x1 blank pixel map to be tinted and used in multiple places
public static Texture getBlankTexture() {
final Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
pixmap.setColor(Color.WHITE);
pixmap.fill();
final Texture result = new Texture(pixmap);
pixmap.dispose();
return result;
}
//endregion
//region Disposal
void dispose() {
}
//endregion
}