mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 19:58:00 +00:00
- Removed copy of libgdx gui
- added shaders to adventure module - changed build order to build adventure module before desktop to pack it in the same zip but not add it as dependency - adjusted mobile gui module to support adventure module.
This commit is contained in:
@@ -18,6 +18,15 @@
|
||||
</repositories>
|
||||
<build>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${project.basedir}</directory>
|
||||
<includes>
|
||||
<include>**/*.vert</include>
|
||||
<include>**/*.frag</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
@@ -164,6 +173,11 @@
|
||||
<artifactId>forge-gui</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>forge</groupId>
|
||||
<artifactId>forge-gui-mobile</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.raeleus.TenPatch</groupId>
|
||||
<artifactId>tenpatch</artifactId>
|
||||
@@ -176,6 +190,12 @@
|
||||
<version>22.0.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>forge</groupId>
|
||||
<artifactId>forge-gui-mobile</artifactId>
|
||||
<version>1.6.46-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
|
||||
15
forge-adventure/shaders/grayscale.frag
Normal file
15
forge-adventure/shaders/grayscale.frag
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_texCoords;
|
||||
uniform sampler2D u_texture;
|
||||
uniform float u_grayness;
|
||||
|
||||
void main() {
|
||||
vec4 c = v_color * texture2D(u_texture, v_texCoords);
|
||||
float grey = dot( c.rgb, vec3(0.22, 0.707, 0.071) );
|
||||
vec3 blendedColor = mix(c.rgb, vec3(grey), u_grayness);
|
||||
gl_FragColor = vec4(blendedColor.rgb, c.a);
|
||||
}
|
||||
14
forge-adventure/shaders/grayscale.vert
Normal file
14
forge-adventure/shaders/grayscale.vert
Normal file
@@ -0,0 +1,14 @@
|
||||
attribute vec4 a_position;
|
||||
attribute vec4 a_color;
|
||||
attribute vec2 a_texCoord0;
|
||||
|
||||
uniform mat4 u_projTrans;
|
||||
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_texCoords;
|
||||
|
||||
void main() {
|
||||
v_color = a_color;
|
||||
v_texCoords = a_texCoord0;
|
||||
gl_Position = u_projTrans * a_position;
|
||||
}
|
||||
40
forge-adventure/shaders/outline.frag
Normal file
40
forge-adventure/shaders/outline.frag
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
precision mediump int;
|
||||
#endif
|
||||
|
||||
uniform sampler2D u_texture;
|
||||
uniform vec2 u_viewportInverse;
|
||||
uniform vec3 u_color;
|
||||
uniform float u_offset;
|
||||
uniform float u_step;
|
||||
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_texCoord;
|
||||
|
||||
#define ALPHA_VALUE_BORDER 0.5
|
||||
|
||||
void main() {
|
||||
vec2 T = v_texCoord.xy;
|
||||
|
||||
float alpha = 0.0;
|
||||
bool allin = true;
|
||||
for( float ix = -u_offset; ix < u_offset; ix += u_step )
|
||||
{
|
||||
for( float iy = -u_offset; iy < u_offset; iy += u_step )
|
||||
{
|
||||
float newAlpha = texture2D(u_texture, T + vec2(ix, iy) * u_viewportInverse).a;
|
||||
allin = allin && newAlpha > ALPHA_VALUE_BORDER;
|
||||
if (newAlpha > ALPHA_VALUE_BORDER && newAlpha >= alpha)
|
||||
{
|
||||
alpha = newAlpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (allin)
|
||||
{
|
||||
alpha = 0.0;
|
||||
}
|
||||
|
||||
gl_FragColor = vec4(u_color,alpha);
|
||||
}
|
||||
16
forge-adventure/shaders/outline.vert
Normal file
16
forge-adventure/shaders/outline.vert
Normal file
@@ -0,0 +1,16 @@
|
||||
uniform mat4 u_projTrans;
|
||||
|
||||
attribute vec4 a_position;
|
||||
attribute vec2 a_texCoord0;
|
||||
attribute vec4 a_color;
|
||||
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_texCoord;
|
||||
|
||||
uniform vec2 u_viewportInverse;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projTrans * a_position;
|
||||
v_texCoord = a_texCoord0;
|
||||
v_color = a_color;
|
||||
}
|
||||
23
forge-adventure/shaders/underwater.frag
Normal file
23
forge-adventure/shaders/underwater.frag
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifdef GL_ES
|
||||
#define PRECISION mediump
|
||||
precision PRECISION float;
|
||||
precision PRECISION int;
|
||||
#else
|
||||
#define PRECISION
|
||||
#endif
|
||||
|
||||
varying vec2 v_texCoords;
|
||||
uniform sampler2D u_texture;
|
||||
uniform float u_amount;
|
||||
uniform float u_speed;
|
||||
uniform float u_time;
|
||||
|
||||
void main () {
|
||||
vec2 uv = v_texCoords;
|
||||
|
||||
uv.y += (cos((uv.y + (u_time * 0.04 * u_speed)) * 45.0) * 0.0019 * u_amount) + (cos((uv.y + (u_time * 0.1 * u_speed)) * 10.0) * 0.002 * u_amount);
|
||||
|
||||
uv.x += (sin((uv.y + (u_time * 0.07 * u_speed)) * 15.0) * 0.0029 * u_amount) + (sin((uv.y + (u_time * 0.1 * u_speed)) * 15.0) * 0.002 * u_amount);
|
||||
|
||||
gl_FragColor = texture2D(u_texture, uv);
|
||||
}
|
||||
57
forge-adventure/shaders/warp.frag
Normal file
57
forge-adventure/shaders/warp.frag
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
varying vec2 v_texCoords;
|
||||
uniform sampler2D u_texture;
|
||||
|
||||
uniform float u_time;
|
||||
uniform float u_speed;
|
||||
uniform float u_amount;
|
||||
uniform vec2 u_viewport;
|
||||
uniform vec2 u_position;
|
||||
|
||||
float random2d(vec2 n) {
|
||||
return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
|
||||
}
|
||||
|
||||
float randomRange (in vec2 seed, in float min, in float max) {
|
||||
return min + random2d(seed) * (max - min);
|
||||
}
|
||||
|
||||
float insideRange(float v, float bottom, float top) {
|
||||
return step(bottom, v) - step(top, v);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
float time = floor(u_time * u_speed * 60.0);
|
||||
|
||||
vec3 outCol = texture2D(u_texture, v_texCoords).rgb;
|
||||
|
||||
float maxOffset = u_amount/2.0;
|
||||
for (float i = 0.0; i < 2.0; i += 1.0) {
|
||||
float sliceY = random2d(vec2(time, 2345.0 + float(i)));
|
||||
float sliceH = random2d(vec2(time, 9035.0 + float(i))) * 0.25;
|
||||
float hOffset = randomRange(vec2(time, 9625.0 + float(i)), -maxOffset, maxOffset);
|
||||
vec2 uvOff = v_texCoords;
|
||||
uvOff.x += hOffset;
|
||||
if (insideRange(v_texCoords.y, sliceY, fract(sliceY+sliceH)) == 1.0){
|
||||
outCol = texture2D(u_texture, uvOff).rgb;
|
||||
}
|
||||
}
|
||||
|
||||
float maxColOffset = u_amount / 6.0;
|
||||
float rnd = random2d(vec2(time , 9545.0));
|
||||
vec2 colOffset = vec2(randomRange(vec2(time , 9545.0), -maxColOffset, maxColOffset),
|
||||
randomRange(vec2(time , 7205.0), -maxColOffset, maxColOffset));
|
||||
if (rnd < 0.33) {
|
||||
outCol.r = texture2D(u_texture, v_texCoords + colOffset).r;
|
||||
} else if (rnd < 0.66) {
|
||||
outCol.g = texture2D(u_texture, v_texCoords + colOffset).g;
|
||||
} else {
|
||||
outCol.b = texture2D(u_texture, v_texCoords + colOffset).b;
|
||||
}
|
||||
|
||||
gl_FragColor = vec4(outCol, 1.0);
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.ScreenUtils;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.Graphics;
|
||||
import forge.adventure.scene.ForgeScene;
|
||||
import forge.adventure.scene.Scene;
|
||||
import forge.adventure.scene.SceneType;
|
||||
|
||||
@@ -7,17 +7,15 @@ import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Clipboard;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.utils.Clipboard;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.FrameRate;
|
||||
import forge.adventure.libgdxgui.GuiMobile;
|
||||
import forge.adventure.libgdxgui.assets.AssetsDownloader;
|
||||
import forge.adventure.libgdxgui.assets.FSkin;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.assets.ImageCache;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.screens.SplashScreen;
|
||||
import forge.Forge;
|
||||
import forge.FrameRate;
|
||||
import forge.GuiMobile;
|
||||
import forge.adventure.scene.SettingsScene;
|
||||
import forge.adventure.util.Config;
|
||||
import forge.assets.AssetsDownloader;
|
||||
import forge.assets.FSkin;
|
||||
import forge.assets.FSkinFont;
|
||||
import forge.assets.ImageCache;
|
||||
import forge.error.ExceptionHandler;
|
||||
import forge.gui.FThreads;
|
||||
import forge.gui.GuiBase;
|
||||
@@ -25,6 +23,8 @@ import forge.interfaces.IDeviceAdapter;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.model.FModel;
|
||||
import forge.screens.FScreen;
|
||||
import forge.screens.SplashScreen;
|
||||
import forge.sound.MusicPlaylist;
|
||||
import forge.sound.SoundSystem;
|
||||
import forge.util.BuildInfo;
|
||||
@@ -155,7 +155,7 @@ class StartAdventure extends AdventureApplicationAdapter {
|
||||
} else {
|
||||
skinName = "default"; //use default skin if preferences file doesn't exist yet
|
||||
}
|
||||
FSkin.loadLight(skinName, splashScreen);
|
||||
FSkin.loadLight(skinName, splashScreen,Config.instance().getFile("skin"));
|
||||
|
||||
textureFiltering = prefs.getPrefBoolean(ForgePreferences.FPref.UI_LIBGDX_TEXTURE_FILTERING);
|
||||
showFPS = prefs.getPrefBoolean(ForgePreferences.FPref.UI_SHOW_FPS);
|
||||
@@ -293,6 +293,7 @@ public class Main {
|
||||
}
|
||||
|
||||
config.setWindowIcon(Config.instance().getFilePath("forge-adventure.png"));
|
||||
|
||||
new Lwjgl3Application(start, config);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
package forge.adventure.libgdxgui;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import forge.adventure.libgdxgui.screens.match.MatchController;
|
||||
import forge.adventure.libgdxgui.assets.ImageCache;
|
||||
import forge.game.card.CardView;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.util.ImageFetcher;
|
||||
|
||||
public abstract class CachedCardImage implements ImageFetcher.Callback {
|
||||
protected final String key;
|
||||
static final ImageFetcher fetcher = GuiBase.getInterface().getImageFetcher();
|
||||
|
||||
public CachedCardImage(final CardView card) {
|
||||
key = card.getCurrentState().getImageKey(MatchController.instance.getLocalPlayers());
|
||||
fetch();
|
||||
}
|
||||
|
||||
public CachedCardImage(final InventoryItem ii) {
|
||||
key = ii.getImageKey(false);
|
||||
fetch();
|
||||
}
|
||||
|
||||
public CachedCardImage(String key) {
|
||||
this.key = key;
|
||||
fetch();
|
||||
}
|
||||
|
||||
public void fetch() {
|
||||
if (!ImageCache.imageKeyFileExists(key)) {
|
||||
fetcher.fetchImage(key, this);
|
||||
}
|
||||
}
|
||||
|
||||
public Texture getImage() {
|
||||
return ImageCache.getImage(key, true);
|
||||
}
|
||||
|
||||
public Texture getImage(String mykey) {
|
||||
return ImageCache.getImage(mykey, true);
|
||||
}
|
||||
|
||||
public abstract void onImageFetched();
|
||||
}
|
||||
@@ -1,920 +0,0 @@
|
||||
package forge.adventure.libgdxgui;
|
||||
|
||||
import com.badlogic.gdx.Application;
|
||||
import com.badlogic.gdx.ApplicationListener;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input.Keys;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.utils.Clipboard;
|
||||
import forge.adventure.libgdxgui.animation.ForgeAnimation;
|
||||
import forge.adventure.libgdxgui.assets.AssetsDownloader;
|
||||
import forge.adventure.libgdxgui.assets.FSkin;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.assets.ImageCache;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.screens.SplashScreen;
|
||||
import forge.adventure.libgdxgui.screens.match.MatchController;
|
||||
import forge.adventure.libgdxgui.toolbox.*;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
import forge.error.ExceptionHandler;
|
||||
import forge.gui.FThreads;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.gui.error.BugReporter;
|
||||
import forge.interfaces.IDeviceAdapter;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.localinstance.properties.ForgePreferences.FPref;
|
||||
import forge.model.FModel;
|
||||
import forge.sound.MusicPlaylist;
|
||||
import forge.sound.SoundSystem;
|
||||
import forge.util.Callback;
|
||||
import forge.util.CardTranslation;
|
||||
import forge.util.FileUtil;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
|
||||
public class Forge implements ApplicationListener {
|
||||
public static final String CURRENT_VERSION = "1.6.42.001";
|
||||
|
||||
public static final Forge app = new Forge();
|
||||
private static final Deque<FScreen> Dscreens = new ArrayDeque<>();
|
||||
public static String extrawide = "default";
|
||||
public static float heigtModifier = 0.0f;
|
||||
public static boolean showFPS = false;
|
||||
public static boolean altPlayerLayout = false;
|
||||
public static boolean altZoneTabs = false;
|
||||
public static String enableUIMask = "Full";
|
||||
public static boolean enablePreloadExtendedArt = false;
|
||||
public static boolean isTabletDevice = false;
|
||||
public static String locale = "en-US";
|
||||
public static boolean hdbuttons = false;
|
||||
public static boolean hdstart = false;
|
||||
public static boolean isPortraitMode = false;
|
||||
public static boolean gameInProgress = false;
|
||||
public static boolean disposeTextures = false;
|
||||
public static int cacheSize = 400;
|
||||
public static int totalDeviceRAM = 0;
|
||||
public static int androidVersion = 0;
|
||||
public static boolean autoCache = false;
|
||||
public static int lastButtonIndex = 0;
|
||||
public static String CJK_Font = "";
|
||||
private static Clipboard clipboard;
|
||||
private static IDeviceAdapter deviceAdapter;
|
||||
private static int screenWidth;
|
||||
private static int screenHeight;
|
||||
private static forge.adventure.libgdxgui.Graphics graphics;
|
||||
private static forge.adventure.libgdxgui.FrameRate frameRate;
|
||||
private static FScreen currentScreen;
|
||||
private static SplashScreen splashScreen;
|
||||
private static KeyInputAdapter keyInputAdapter;
|
||||
private static boolean exited;
|
||||
private static int continuousRenderingCount = 1; //initialize to 1 since continuous rendering is the default
|
||||
private static boolean textureFiltering = false;
|
||||
private static boolean destroyThis = false;
|
||||
private static boolean isloadingaMatch = false;
|
||||
private MainInputProcessor input;
|
||||
|
||||
private Forge() {
|
||||
}
|
||||
|
||||
public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0, boolean value, boolean androidOrientation, int totalRAM, boolean isTablet, int AndroidAPI, String AndroidRelease, String deviceName) {
|
||||
if (GuiBase.getInterface() == null) {
|
||||
clipboard = clipboard0;
|
||||
deviceAdapter = deviceAdapter0;
|
||||
GuiBase.setUsingAppDirectory(assetDir0.contains("forge.app")); //obb directory on android uses the package name as entrypoint
|
||||
GuiBase.setInterface(new forge.adventure.libgdxgui.GuiMobile(assetDir0));
|
||||
GuiBase.enablePropertyConfig(value);
|
||||
isPortraitMode = androidOrientation;
|
||||
totalDeviceRAM = totalRAM;
|
||||
isTabletDevice = isTablet;
|
||||
androidVersion = AndroidAPI;
|
||||
}
|
||||
GuiBase.setDeviceInfo(deviceName, AndroidRelease, AndroidAPI, totalRAM);
|
||||
return app;
|
||||
}
|
||||
|
||||
public static void openHomeScreen(int index) {
|
||||
}
|
||||
|
||||
public static Clipboard getClipboard() {
|
||||
return clipboard;
|
||||
}
|
||||
|
||||
public static IDeviceAdapter getDeviceAdapter() {
|
||||
return deviceAdapter;
|
||||
}
|
||||
|
||||
public static void startContinuousRendering() {
|
||||
if (++continuousRenderingCount == 1) {
|
||||
//only set continuous rendering to true if needed
|
||||
Gdx.graphics.setContinuousRendering(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void stopContinuousRendering() {
|
||||
if (continuousRenderingCount > 0 && --continuousRenderingCount == 0) {
|
||||
//only set continuous rendering to false if all continuous rendering requests have been ended
|
||||
Gdx.graphics.setContinuousRendering(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getHeightModifier() {
|
||||
return heigtModifier;
|
||||
}
|
||||
|
||||
public static void setHeightModifier(float height) {
|
||||
heigtModifier = height;
|
||||
}
|
||||
|
||||
public static void adjustHeightModifier(float DisplayW, float DisplayH) {
|
||||
if (isLandscapeMode()) {//TODO: Fullscreen support for Display without screen controls
|
||||
float aspectratio = DisplayW / DisplayH;
|
||||
if (aspectratio > 1.82f) {/* extra wide */
|
||||
setHeightModifier(200.0f);
|
||||
extrawide = "extrawide";
|
||||
} else if (aspectratio > 1.7f) {/* wide */
|
||||
setHeightModifier(100.0f);
|
||||
extrawide = "wide";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void showMenu() {
|
||||
if (currentScreen == null) {
|
||||
return;
|
||||
}
|
||||
endKeyInput(); //end key input before menu shown
|
||||
if (FOverlay.getTopOverlay() == null) { //don't show menu if overlay open
|
||||
currentScreen.showMenu();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean onHomeScreen() {
|
||||
return Dscreens.size() == 1;
|
||||
}
|
||||
|
||||
public static void back() {
|
||||
|
||||
}
|
||||
|
||||
//set screen that will be gone to on pressing Back before going to current Back screen
|
||||
public static void setBackScreen(final FScreen screen0, boolean replace) {
|
||||
Dscreens.remove(screen0); //remove screen from previous position in navigation history
|
||||
int index = Dscreens.size() - 1;
|
||||
if (index > 0) {
|
||||
Dscreens.addLast(screen0);
|
||||
if (replace) { //remove previous back screen if replacing back screen
|
||||
Dscreens.removeFirst();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void restart(boolean silent) {
|
||||
if (exited) {
|
||||
return;
|
||||
} //don't allow exiting multiple times
|
||||
|
||||
Callback<Boolean> callback = new Callback<Boolean>() {
|
||||
@Override
|
||||
public void run(Boolean result) {
|
||||
if (result) {
|
||||
exited = true;
|
||||
deviceAdapter.restart();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final Localizer localizer = Localizer.getInstance();
|
||||
|
||||
if (silent) {
|
||||
callback.run(true);
|
||||
} else {
|
||||
FOptionPane.showConfirmDialog(
|
||||
localizer.getMessage("lblAreYouSureYouWishRestartForge"), localizer.getMessage("lblRestartForge"),
|
||||
localizer.getMessage("lblRestart"), localizer.getMessage("lblCancel"), callback);
|
||||
}
|
||||
}
|
||||
|
||||
public static void exit(boolean silent) {
|
||||
if (exited) {
|
||||
return;
|
||||
} //don't allow exiting multiple times
|
||||
|
||||
Callback<Boolean> callback = new Callback<Boolean>() {
|
||||
@Override
|
||||
public void run(Boolean result) {
|
||||
if (result) {
|
||||
exited = true;
|
||||
deviceAdapter.exit();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final Localizer localizer = Localizer.getInstance();
|
||||
|
||||
if (silent) {
|
||||
callback.run(true);
|
||||
} else {
|
||||
FOptionPane.showConfirmDialog(
|
||||
localizer.getMessage("lblAreYouSureYouWishExitForge"), localizer.getMessage("lblExitForge"),
|
||||
localizer.getMessage("lblExit"), localizer.getMessage("lblCancel"), callback);
|
||||
}
|
||||
}
|
||||
|
||||
public static void openScreen(final FScreen screen0) {
|
||||
openScreen(screen0, false);
|
||||
}
|
||||
|
||||
public static void openScreen(final FScreen screen0, final boolean replaceBackScreen) {
|
||||
if (currentScreen == screen0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentScreen == null) {
|
||||
Dscreens.addFirst(screen0);
|
||||
setCurrentScreen(screen0);
|
||||
return;
|
||||
}
|
||||
|
||||
currentScreen.onSwitchAway(new Callback<Boolean>() {
|
||||
@Override
|
||||
public void run(Boolean result) {
|
||||
if (result) {
|
||||
if (replaceBackScreen && !Dscreens.isEmpty()) {
|
||||
Dscreens.removeFirst();
|
||||
}
|
||||
if (Dscreens.peekFirst() != screen0) { //prevent screen being its own back screen
|
||||
Dscreens.addFirst(screen0);
|
||||
}
|
||||
setCurrentScreen(screen0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean isTextureFilteringEnabled() {
|
||||
return textureFiltering;
|
||||
}
|
||||
|
||||
public static boolean isLandscapeMode() {
|
||||
if (GuiBase.isAndroid())
|
||||
return !isPortraitMode;
|
||||
return screenWidth > screenHeight;
|
||||
}
|
||||
|
||||
public static boolean isLoadingaMatch() {
|
||||
return isloadingaMatch;
|
||||
}
|
||||
|
||||
public static void setLoadingaMatch(boolean value) {
|
||||
isloadingaMatch = value;
|
||||
}
|
||||
|
||||
public static int getScreenWidth() {
|
||||
return screenWidth;
|
||||
}
|
||||
|
||||
public static int getScreenHeight() {
|
||||
return screenHeight;
|
||||
}
|
||||
|
||||
public static FScreen getCurrentScreen() {
|
||||
return currentScreen;
|
||||
}
|
||||
|
||||
private static void setCurrentScreen(FScreen screen0) {
|
||||
String toNewScreen = screen0 != null ? screen0.toString() : "";
|
||||
String previousScreen = currentScreen != null ? currentScreen.toString() : "";
|
||||
|
||||
gameInProgress = toNewScreen.toLowerCase().contains("match") || previousScreen.toLowerCase().contains("match");
|
||||
boolean dispose = toNewScreen.toLowerCase().contains("homescreen") && disposeTextures;
|
||||
try {
|
||||
endKeyInput(); //end key input before switching screens
|
||||
ForgeAnimation.endAll(); //end all active animations before switching screens
|
||||
|
||||
currentScreen = screen0;
|
||||
currentScreen.setSize(screenWidth, screenHeight);
|
||||
currentScreen.onActivate();
|
||||
/*keep Dscreens growing
|
||||
if (Dscreens.size() > 3) {
|
||||
for(int x = Dscreens.size(); x > 3; x--) {
|
||||
Dscreens.removeLast();
|
||||
}
|
||||
}*/
|
||||
/* for checking only
|
||||
if (!Dscreens.isEmpty()) {
|
||||
int x = 0;
|
||||
for(FScreen fScreen : Dscreens) {
|
||||
System.out.println("Screen ["+x+"]: "+fScreen.toString());
|
||||
x++;
|
||||
}
|
||||
System.out.println("---------------");
|
||||
}*/
|
||||
} catch (Exception ex) {
|
||||
graphics.end();
|
||||
//check if sentry is enabled, if not it will call the gui interface but here we end the graphics so we only send it via sentry..
|
||||
if (BugReporter.isSentryEnabled())
|
||||
BugReporter.reportException(ex);
|
||||
} finally {
|
||||
if (dispose)
|
||||
ImageCache.disposeTexture();
|
||||
}
|
||||
}
|
||||
|
||||
//log message to Forge.log file
|
||||
public static void log(Object message) {
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
public static void startKeyInput(KeyInputAdapter adapter) {
|
||||
if (keyInputAdapter == adapter) {
|
||||
return;
|
||||
}
|
||||
if (keyInputAdapter != null) {
|
||||
keyInputAdapter.onInputEnd(); //make sure previous adapter is ended
|
||||
}
|
||||
keyInputAdapter = adapter;
|
||||
Gdx.input.setOnscreenKeyboardVisible(true);
|
||||
}
|
||||
|
||||
public static boolean endKeyInput() {
|
||||
if (keyInputAdapter == null) {
|
||||
return false;
|
||||
}
|
||||
keyInputAdapter.onInputEnd();
|
||||
keyInputAdapter = null;
|
||||
MainInputProcessor.keyTyped = false;
|
||||
MainInputProcessor.lastKeyTyped = '\0';
|
||||
Gdx.input.setOnscreenKeyboardVisible(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
//install our error handler
|
||||
ExceptionHandler.registerErrorHandling();
|
||||
|
||||
GuiBase.setIsAndroid(Gdx.app.getType() == Application.ApplicationType.Android);
|
||||
|
||||
graphics = new Graphics();
|
||||
splashScreen = new SplashScreen();
|
||||
frameRate = new FrameRate();
|
||||
input=new MainInputProcessor();
|
||||
Gdx.input.setInputProcessor(input);
|
||||
/*
|
||||
Set CatchBackKey here and exit the app when you hit the
|
||||
back button while the textures,fonts,etc are still loading,
|
||||
to prevent rendering issue when you try to restart
|
||||
the app again (seems it doesnt dispose correctly...?!?)
|
||||
*/
|
||||
Gdx.input.setCatchKey(Keys.BACK, true);
|
||||
destroyThis = true; //Prevent back()
|
||||
ForgePreferences prefs = new ForgePreferences();
|
||||
|
||||
String skinName;
|
||||
if (FileUtil.doesFileExist(ForgeConstants.MAIN_PREFS_FILE)) {
|
||||
skinName = prefs.getPref(FPref.UI_SKIN);
|
||||
} else {
|
||||
skinName = "default"; //use default skin if preferences file doesn't exist yet
|
||||
}
|
||||
FSkin.loadLight(skinName, splashScreen);
|
||||
|
||||
textureFiltering = prefs.getPrefBoolean(FPref.UI_LIBGDX_TEXTURE_FILTERING);
|
||||
showFPS = prefs.getPrefBoolean(FPref.UI_SHOW_FPS);
|
||||
altPlayerLayout = prefs.getPrefBoolean(FPref.UI_ALT_PLAYERINFOLAYOUT);
|
||||
altZoneTabs = prefs.getPrefBoolean(FPref.UI_ALT_PLAYERZONETABS);
|
||||
enableUIMask = prefs.getPref(FPref.UI_ENABLE_BORDER_MASKING);
|
||||
if (prefs.getPref(FPref.UI_ENABLE_BORDER_MASKING).equals("true")) //override old settings if not updated
|
||||
enableUIMask = "Full";
|
||||
else if (prefs.getPref(FPref.UI_ENABLE_BORDER_MASKING).equals("false"))
|
||||
enableUIMask = "Off";
|
||||
enableUIMask = "Full";
|
||||
enablePreloadExtendedArt = prefs.getPrefBoolean(FPref.UI_ENABLE_PRELOAD_EXTENDED_ART);
|
||||
locale = prefs.getPref(FPref.UI_LANGUAGE);
|
||||
autoCache = prefs.getPrefBoolean(FPref.UI_AUTO_CACHE_SIZE);
|
||||
disposeTextures = prefs.getPrefBoolean(FPref.UI_ENABLE_DISPOSE_TEXTURES);
|
||||
CJK_Font = prefs.getPref(FPref.UI_CJK_FONT);
|
||||
|
||||
if (autoCache) {
|
||||
//increase cacheSize for devices with RAM more than 5GB, default is 400. Some phones have more than 10GB RAM (Mi 10, OnePlus 8, S20, etc..)
|
||||
if (totalDeviceRAM > 5000) //devices with more than 10GB RAM will have 800 Cache size, 600 Cache size for morethan 5GB RAM
|
||||
cacheSize = totalDeviceRAM > 10000 ? 800 : 600;
|
||||
}
|
||||
//init cache
|
||||
ImageCache.initCache(cacheSize);
|
||||
final Localizer localizer = Localizer.getInstance();
|
||||
|
||||
//load model on background thread (using progress bar to report progress)
|
||||
FThreads.invokeInBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//see if app or assets need updating
|
||||
AssetsDownloader.checkForUpdates(splashScreen);
|
||||
if (exited) {
|
||||
return;
|
||||
} //don't continue if user chose to exit or couldn't download required assets
|
||||
|
||||
FModel.initialize(splashScreen.getProgressBar(), null);
|
||||
|
||||
splashScreen.getProgressBar().setDescription(localizer.getMessage("lblLoadingFonts"));
|
||||
FSkinFont.preloadAll(locale);
|
||||
|
||||
splashScreen.getProgressBar().setDescription(localizer.getMessage("lblLoadingCardTranslations"));
|
||||
CardTranslation.preloadTranslation(locale, ForgeConstants.LANG_DIR);
|
||||
|
||||
splashScreen.getProgressBar().setDescription(localizer.getMessage("lblFinishingStartup"));
|
||||
|
||||
//add reminder to preload
|
||||
if (enablePreloadExtendedArt) {
|
||||
if (autoCache)
|
||||
splashScreen.getProgressBar().setDescription(localizer.getMessage("lblPreloadExtendedArt") + "\nDetected RAM: " + totalDeviceRAM + "MB. Cache size: " + cacheSize);
|
||||
else
|
||||
splashScreen.getProgressBar().setDescription(localizer.getMessage("lblPreloadExtendedArt"));
|
||||
} else {
|
||||
if (autoCache)
|
||||
splashScreen.getProgressBar().setDescription(localizer.getMessage("lblFinishingStartup") + "\nDetected RAM: " + totalDeviceRAM + "MB. Cache size: " + cacheSize);
|
||||
else
|
||||
splashScreen.getProgressBar().setDescription(localizer.getMessage("lblFinishingStartup"));
|
||||
}
|
||||
|
||||
Gdx.app.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
afterDbLoaded();
|
||||
/* call preloadExtendedArt here, if we put it above we will *
|
||||
* get error: No OpenGL context found in the current thread. */
|
||||
preloadExtendedArt();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void preloadExtendedArt() {
|
||||
if (!enablePreloadExtendedArt)
|
||||
return;
|
||||
List<String> borderlessCardlistkeys = FileUtil.readFile(ForgeConstants.BORDERLESS_CARD_LIST_FILE);
|
||||
if (borderlessCardlistkeys.isEmpty())
|
||||
return;
|
||||
List<String> filteredkeys = new ArrayList<>();
|
||||
for (String cardname : borderlessCardlistkeys) {
|
||||
File image = new File(ForgeConstants.CACHE_CARD_PICS_DIR + ForgeConstants.PATH_SEPARATOR + cardname + ".jpg");
|
||||
if (image.exists())
|
||||
filteredkeys.add(cardname);
|
||||
}
|
||||
if (!filteredkeys.isEmpty())
|
||||
ImageCache.preloadCache(filteredkeys);
|
||||
}
|
||||
|
||||
private void afterDbLoaded() {
|
||||
stopContinuousRendering(); //save power consumption by disabling continuous rendering once assets loaded
|
||||
|
||||
FSkin.loadFull(splashScreen);
|
||||
|
||||
SoundSystem.instance.setBackgroundMusic(MusicPlaylist.MENUS); //start background music
|
||||
destroyThis = false; //Allow back()
|
||||
Gdx.input.setCatchKey(Keys.MENU, true);
|
||||
openHomeScreen(-1); //default for startup
|
||||
splashScreen = null;
|
||||
|
||||
boolean isLandscapeMode = isLandscapeMode();
|
||||
|
||||
|
||||
//adjust height modifier
|
||||
adjustHeightModifier(getScreenWidth(), getScreenHeight());
|
||||
|
||||
//update landscape mode preference if it doesn't match what the app loaded as
|
||||
if (FModel.getPreferences().getPrefBoolean(FPref.UI_LANDSCAPE_MODE) != isLandscapeMode) {
|
||||
FModel.getPreferences().setPref(FPref.UI_LANDSCAPE_MODE, isLandscapeMode);
|
||||
FModel.getPreferences().save();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
if (showFPS)
|
||||
frameRate.update();
|
||||
|
||||
try {
|
||||
ImageCache.allowSingleLoad();
|
||||
ForgeAnimation.advanceAll();
|
||||
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // Clear the screen.
|
||||
|
||||
FContainer screen = currentScreen;
|
||||
if (screen == null) {
|
||||
screen = splashScreen;
|
||||
if (screen == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
graphics.begin(screenWidth, screenHeight);
|
||||
screen.screenPos.setSize(screenWidth, screenHeight);
|
||||
if (screen.getRotate180()) {
|
||||
graphics.startRotateTransform(screenWidth / 2, screenHeight / 2, 180);
|
||||
}
|
||||
screen.draw(graphics);
|
||||
if (screen.getRotate180()) {
|
||||
graphics.endTransform();
|
||||
}
|
||||
for (FOverlay overlay : FOverlay.getOverlays()) {
|
||||
if (overlay.isVisibleOnScreen(currentScreen)) {
|
||||
overlay.screenPos.setSize(screenWidth, screenHeight);
|
||||
overlay.setSize(screenWidth, screenHeight); //update overlay sizes as they're rendered
|
||||
if (overlay.getRotate180()) {
|
||||
graphics.startRotateTransform(screenWidth / 2, screenHeight / 2, 180);
|
||||
}
|
||||
overlay.draw(graphics);
|
||||
if (overlay.getRotate180()) {
|
||||
graphics.endTransform();
|
||||
}
|
||||
}
|
||||
}
|
||||
graphics.end();
|
||||
} catch (Exception ex) {
|
||||
graphics.end();
|
||||
//check if sentry is enabled, if not it will call the gui interface but here we end the graphics so we only send it via sentry..
|
||||
if (BugReporter.isSentryEnabled())
|
||||
BugReporter.reportException(ex);
|
||||
}
|
||||
if (showFPS)
|
||||
frameRate.render();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height) {
|
||||
try {
|
||||
screenWidth = width;
|
||||
screenHeight = height;
|
||||
if (currentScreen != null) {
|
||||
currentScreen.setSize(width, height);
|
||||
} else if (splashScreen != null) {
|
||||
splashScreen.setSize(width, height);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
graphics.end();
|
||||
//check if sentry is enabled, if not it will call the gui interface but here we end the graphics so we only send it via sentry..
|
||||
if (BugReporter.isSentryEnabled())
|
||||
BugReporter.reportException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
if (MatchController.getHostedMatch() != null) {
|
||||
MatchController.getHostedMatch().pause();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume() {
|
||||
if (MatchController.getHostedMatch() != null) {
|
||||
MatchController.getHostedMatch().resume();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (currentScreen != null) {
|
||||
FOverlay.hideAll();
|
||||
currentScreen.onClose(null);
|
||||
currentScreen = null;
|
||||
}
|
||||
Dscreens.clear();
|
||||
graphics.dispose();
|
||||
SoundSystem.instance.dispose();
|
||||
try {
|
||||
ExceptionHandler.unregisterErrorHandling();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class KeyInputAdapter {
|
||||
public static boolean isCtrlKeyDown() {
|
||||
return Gdx.input.isKeyPressed(Keys.CONTROL_LEFT) || Gdx.input.isKeyPressed(Keys.CONTROL_RIGHT);
|
||||
}
|
||||
|
||||
public static boolean isShiftKeyDown() {
|
||||
return Gdx.input.isKeyPressed(Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Keys.SHIFT_RIGHT);
|
||||
}
|
||||
|
||||
public static boolean isAltKeyDown() {
|
||||
return Gdx.input.isKeyPressed(Keys.ALT_LEFT) || Gdx.input.isKeyPressed(Keys.ALT_RIGHT);
|
||||
}
|
||||
|
||||
public static boolean isModifierKey(int keyCode) {
|
||||
switch (keyCode) {
|
||||
case Keys.CONTROL_LEFT:
|
||||
case Keys.CONTROL_RIGHT:
|
||||
case Keys.SHIFT_LEFT:
|
||||
case Keys.SHIFT_RIGHT:
|
||||
case Keys.ALT_LEFT:
|
||||
case Keys.ALT_RIGHT:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract FDisplayObject getOwner();
|
||||
|
||||
public abstract boolean allowTouchInput();
|
||||
|
||||
public abstract boolean keyTyped(char ch);
|
||||
|
||||
public abstract boolean keyDown(int keyCode);
|
||||
|
||||
public abstract void onInputEnd();
|
||||
|
||||
//also allow handling of keyUp but don't require it
|
||||
public boolean keyUp(int keyCode) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MainInputProcessor extends FGestureAdapter {
|
||||
private static final List<FDisplayObject> potentialListeners = new ArrayList<>();
|
||||
private static char lastKeyTyped;
|
||||
private static boolean keyTyped, shiftKeyDown;
|
||||
//mouseMoved and scrolled events for desktop version
|
||||
private int mouseMovedX, mouseMovedY;
|
||||
|
||||
@Override
|
||||
public boolean keyDown(int keyCode) {
|
||||
if (keyCode == Keys.MENU) {
|
||||
showMenu();
|
||||
return true;
|
||||
}
|
||||
if (keyCode == Keys.SHIFT_LEFT || keyCode == Keys.SHIFT_RIGHT) {
|
||||
shiftKeyDown = true;
|
||||
}
|
||||
|
||||
// Cursor keys emulate swipe gestures
|
||||
// First we touch the screen and later swipe (fling) in the direction of the key pressed
|
||||
if (keyCode == Keys.LEFT) {
|
||||
touchDown(0, 0, 0, 0);
|
||||
return fling(1000, 0);
|
||||
}
|
||||
if (keyCode == Keys.RIGHT) {
|
||||
touchDown(0, 0, 0, 0);
|
||||
return fling(-1000, 0);
|
||||
}
|
||||
if (keyCode == Keys.UP) {
|
||||
touchDown(0, 0, 0, 0);
|
||||
return fling(0, -1000);
|
||||
}
|
||||
if (keyCode == Keys.DOWN) {
|
||||
touchDown(0, 0, 0, 0);
|
||||
return fling(0, 1000);
|
||||
}
|
||||
if (keyCode == Keys.BACK) {
|
||||
if (destroyThis)
|
||||
deviceAdapter.exit();
|
||||
else if (onHomeScreen() && isLandscapeMode())
|
||||
back();
|
||||
}
|
||||
if (keyInputAdapter == null) {
|
||||
if (KeyInputAdapter.isModifierKey(keyCode)) {
|
||||
return false; //don't process modifiers keys for unknown adapter
|
||||
}
|
||||
//if no active key input adapter, give current screen or overlay a chance to handle key
|
||||
FContainer container = FOverlay.getTopOverlay();
|
||||
if (container == null) {
|
||||
container = currentScreen;
|
||||
if (container == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return container.keyDown(keyCode);
|
||||
}
|
||||
return keyInputAdapter.keyDown(keyCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyUp(int keyCode) {
|
||||
keyTyped = false; //reset on keyUp
|
||||
if (keyCode == Keys.SHIFT_LEFT || keyCode == Keys.SHIFT_RIGHT) {
|
||||
shiftKeyDown = false;
|
||||
}
|
||||
if (keyInputAdapter != null) {
|
||||
return keyInputAdapter.keyUp(keyCode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyTyped(char ch) {
|
||||
if (keyInputAdapter != null) {
|
||||
if (ch >= ' ' && ch <= '~') { //only process this event if character is printable
|
||||
//prevent firing this event more than once for the same character on the same key down, otherwise it fires too often
|
||||
if (lastKeyTyped != ch || !keyTyped) {
|
||||
keyTyped = true;
|
||||
lastKeyTyped = ch;
|
||||
return keyInputAdapter.keyTyped(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void updatePotentialListeners(int x, int y) {
|
||||
potentialListeners.clear();
|
||||
|
||||
//base potential listeners on object containing touch down point
|
||||
for (FOverlay overlay : FOverlay.getOverlaysTopDown()) {
|
||||
if (overlay.isVisibleOnScreen(currentScreen)) {
|
||||
overlay.buildTouchListeners(x, y, potentialListeners);
|
||||
if (overlay.preventInputBehindOverlay()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentScreen != null) {
|
||||
currentScreen.buildTouchListeners(x, y, potentialListeners);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean touchDown(int x, int y, int pointer, int button) {
|
||||
if (pointer == 0) { //don't change listeners when second finger goes down for zoom
|
||||
updatePotentialListeners(x, y);
|
||||
if (keyInputAdapter != null) {
|
||||
if (!keyInputAdapter.allowTouchInput() || !potentialListeners.contains(keyInputAdapter.getOwner())) {
|
||||
endKeyInput(); //end key input if needed
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.touchDown(x, y, pointer, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean press(float x, float y) {
|
||||
try {
|
||||
for (FDisplayObject listener : potentialListeners) {
|
||||
if (listener.press(listener.screenToLocalX(x), listener.screenToLocalY(y))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
BugReporter.reportException(ex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release(float x, float y) {
|
||||
try {
|
||||
for (FDisplayObject listener : potentialListeners) {
|
||||
if (listener.release(listener.screenToLocalX(x), listener.screenToLocalY(y))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
BugReporter.reportException(ex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean longPress(float x, float y) {
|
||||
try {
|
||||
for (FDisplayObject listener : potentialListeners) {
|
||||
if (listener.longPress(listener.screenToLocalX(x), listener.screenToLocalY(y))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
BugReporter.reportException(ex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
if (shiftKeyDown && flick(x, y)) {
|
||||
return true; //give flick logic a chance to handle Shift+click
|
||||
}
|
||||
try {
|
||||
for (FDisplayObject listener : potentialListeners) {
|
||||
if (listener.tap(listener.screenToLocalX(x), listener.screenToLocalY(y), count)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
BugReporter.reportException(ex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean flick(float x, float y) {
|
||||
try {
|
||||
for (FDisplayObject listener : potentialListeners) {
|
||||
if (listener.flick(listener.screenToLocalX(x), listener.screenToLocalY(y))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
BugReporter.reportException(ex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fling(float velocityX, float velocityY) {
|
||||
try {
|
||||
for (FDisplayObject listener : potentialListeners) {
|
||||
if (listener.fling(velocityX, velocityY)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
BugReporter.reportException(ex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pan(float x, float y, float deltaX, float deltaY, boolean moreVertical) {
|
||||
try {
|
||||
for (FDisplayObject listener : potentialListeners) {
|
||||
if (listener.pan(listener.screenToLocalX(x), listener.screenToLocalY(y), deltaX, deltaY, moreVertical)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
BugReporter.reportException(ex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean panStop(float x, float y) {
|
||||
try {
|
||||
for (FDisplayObject listener : potentialListeners) {
|
||||
if (listener.panStop(listener.screenToLocalX(x), listener.screenToLocalY(y))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
BugReporter.reportException(ex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean zoom(float x, float y, float amount) {
|
||||
try {
|
||||
for (FDisplayObject listener : potentialListeners) {
|
||||
if (listener.zoom(listener.screenToLocalX(x), listener.screenToLocalY(y), amount)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
BugReporter.reportException(ex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseMoved(int x, int y) {
|
||||
mouseMovedX = x;
|
||||
mouseMovedY = y;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean scrolled(float amountX, float amountY) {
|
||||
updatePotentialListeners(mouseMovedX, mouseMovedY);
|
||||
|
||||
if (KeyInputAdapter.isCtrlKeyDown()) { //zoom in or out based on amount
|
||||
return zoom(mouseMovedX, mouseMovedY, -Utils.AVG_FINGER_WIDTH * amountY);
|
||||
}
|
||||
|
||||
boolean handled;
|
||||
if (KeyInputAdapter.isShiftKeyDown()) {
|
||||
handled = pan(mouseMovedX, mouseMovedY, -Utils.AVG_FINGER_WIDTH * amountX, 0, false);
|
||||
} else {
|
||||
handled = pan(mouseMovedX, mouseMovedY, 0, -Utils.AVG_FINGER_HEIGHT * amountY, true);
|
||||
}
|
||||
if (panStop(mouseMovedX, mouseMovedY)) {
|
||||
handled = true;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package forge.adventure.libgdxgui;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
import com.badlogic.gdx.utils.TimeUtils;
|
||||
|
||||
/**
|
||||
* A nicer class for showing framerate that doesn't spam the console
|
||||
* like Logger.log()
|
||||
*
|
||||
* @author William Hartman
|
||||
*/
|
||||
|
||||
public class FrameRate implements Disposable{
|
||||
long lastTimeCounted;
|
||||
private float sinceChange;
|
||||
private float frameRate;
|
||||
private final BitmapFont font;
|
||||
private final SpriteBatch batch;
|
||||
private OrthographicCamera cam;
|
||||
|
||||
public FrameRate() {
|
||||
lastTimeCounted = TimeUtils.millis();
|
||||
sinceChange = 0;
|
||||
frameRate = Gdx.graphics.getFramesPerSecond();
|
||||
font = new BitmapFont();
|
||||
batch = new SpriteBatch();
|
||||
cam = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
||||
}
|
||||
|
||||
public void resize(int screenWidth, int screenHeight) {
|
||||
cam = new OrthographicCamera(screenWidth, screenHeight);
|
||||
cam.translate(screenWidth / 2, screenHeight / 2);
|
||||
cam.update();
|
||||
batch.setProjectionMatrix(cam.combined);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
long delta = TimeUtils.timeSinceMillis(lastTimeCounted);
|
||||
lastTimeCounted = TimeUtils.millis();
|
||||
sinceChange += delta;
|
||||
if(sinceChange >= 1000) {
|
||||
sinceChange = 0;
|
||||
frameRate = Gdx.graphics.getFramesPerSecond();
|
||||
}
|
||||
}
|
||||
|
||||
public void render() {
|
||||
batch.begin();
|
||||
font.draw(batch, (int)frameRate + " fps", 3, Gdx.graphics.getHeight() - 3);
|
||||
batch.end();
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
font.dispose();
|
||||
batch.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,887 +0,0 @@
|
||||
package forge.adventure.libgdxgui;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
|
||||
import com.badlogic.gdx.math.Matrix4;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
|
||||
import forge.adventure.libgdxgui.assets.FImage;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.util.TextBounds;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
public class Graphics {
|
||||
private static final int GL_BLEND = GL20.GL_BLEND;
|
||||
private static final int GL_LINE_SMOOTH = 2848; //create constant here since not in GL20
|
||||
|
||||
private final Batch batch;
|
||||
private final ShapeRenderer shapeRenderer = new ShapeRenderer();
|
||||
private final Deque<Matrix4> Dtransforms = new ArrayDeque<>();
|
||||
private final Vector3 tmp = new Vector3();
|
||||
private float regionHeight;
|
||||
private Rectangle bounds;
|
||||
private Rectangle visibleBounds;
|
||||
private int failedClipCount;
|
||||
private float alphaComposite = 1;
|
||||
private int transformCount = 0;
|
||||
private final String sVertex = "uniform mat4 u_projTrans;\n" +
|
||||
"\n" +
|
||||
"attribute vec4 a_position;\n" +
|
||||
"attribute vec2 a_texCoord0;\n" +
|
||||
"attribute vec4 a_color;\n" +
|
||||
"\n" +
|
||||
"varying vec4 v_color;\n" +
|
||||
"varying vec2 v_texCoord;\n" +
|
||||
"\n" +
|
||||
"uniform vec2 u_viewportInverse;\n" +
|
||||
"\n" +
|
||||
"void main() {\n" +
|
||||
" gl_Position = u_projTrans * a_position;\n" +
|
||||
" v_texCoord = a_texCoord0;\n" +
|
||||
" v_color = a_color;\n" +
|
||||
"}";
|
||||
private final String sFragment = "#ifdef GL_ES\n" +
|
||||
"precision mediump float;\n" +
|
||||
"precision mediump int;\n" +
|
||||
"#endif\n" +
|
||||
"\n" +
|
||||
"uniform sampler2D u_texture;\n" +
|
||||
"\n" +
|
||||
"// The inverse of the viewport dimensions along X and Y\n" +
|
||||
"uniform vec2 u_viewportInverse;\n" +
|
||||
"\n" +
|
||||
"// Color of the outline\n" +
|
||||
"uniform vec3 u_color;\n" +
|
||||
"\n" +
|
||||
"// Thickness of the outline\n" +
|
||||
"uniform float u_offset;\n" +
|
||||
"\n" +
|
||||
"// Step to check for neighbors\n" +
|
||||
"uniform float u_step;\n" +
|
||||
"\n" +
|
||||
"varying vec4 v_color;\n" +
|
||||
"varying vec2 v_texCoord;\n" +
|
||||
"\n" +
|
||||
"#define ALPHA_VALUE_BORDER 0.5\n" +
|
||||
"\n" +
|
||||
"void main() {\n" +
|
||||
" vec2 T = v_texCoord.xy;\n" +
|
||||
"\n" +
|
||||
" float alpha = 0.0;\n" +
|
||||
" bool allin = true;\n" +
|
||||
" for( float ix = -u_offset; ix < u_offset; ix += u_step )\n" +
|
||||
" {\n" +
|
||||
" for( float iy = -u_offset; iy < u_offset; iy += u_step )\n" +
|
||||
" {\n" +
|
||||
" float newAlpha = texture2D(u_texture, T + vec2(ix, iy) * u_viewportInverse).a;\n" +
|
||||
" allin = allin && newAlpha > ALPHA_VALUE_BORDER;\n" +
|
||||
" if (newAlpha > ALPHA_VALUE_BORDER && newAlpha >= alpha)\n" +
|
||||
" {\n" +
|
||||
" alpha = newAlpha;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" if (allin)\n" +
|
||||
" {\n" +
|
||||
" alpha = 0.0;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" gl_FragColor = vec4(u_color,alpha);\n" +
|
||||
"}";
|
||||
|
||||
private final ShaderProgram shaderOutline = new ShaderProgram(sVertex, sFragment);
|
||||
|
||||
public Graphics() {
|
||||
batch = new SpriteBatch();
|
||||
ShaderProgram.pedantic = false;
|
||||
}
|
||||
public Graphics(Batch batch,float regionWidth0, float regionHeight0) {
|
||||
this.batch=batch;bound(regionWidth0, regionHeight0);
|
||||
}
|
||||
public void bound(float regionWidth0, float regionHeight0) {
|
||||
bounds = new Rectangle(0, 0, regionWidth0, regionHeight0);
|
||||
regionHeight = regionHeight0;
|
||||
visibleBounds = new Rectangle(bounds);
|
||||
}
|
||||
|
||||
public void begin(float regionWidth0, float regionHeight0) {
|
||||
batch.begin();
|
||||
bounds = new Rectangle(0, 0, regionWidth0, regionHeight0);
|
||||
regionHeight = regionHeight0;
|
||||
visibleBounds = new Rectangle(bounds);
|
||||
}
|
||||
|
||||
public void end() {
|
||||
if (batch.isDrawing()) {
|
||||
batch.end();
|
||||
}
|
||||
if (shapeRenderer.getCurrentType() != null) {
|
||||
shapeRenderer.end();
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
batch.dispose();
|
||||
shapeRenderer.dispose();
|
||||
shaderOutline.dispose();
|
||||
}
|
||||
|
||||
public SpriteBatch getBatch() {
|
||||
return (SpriteBatch)batch;
|
||||
}
|
||||
|
||||
public boolean startClip() {
|
||||
return startClip(0, 0, bounds.width, bounds.height);
|
||||
}
|
||||
public boolean startClip(float x, float y, float w, float h) {
|
||||
batch.flush(); //must flush batch to prevent other things not rendering
|
||||
|
||||
Rectangle clip = new Rectangle(adjustX(x), adjustY(y, h), w, h);
|
||||
if (!Dtransforms.isEmpty()) { //transform position if needed
|
||||
tmp.set(clip.x, clip.y, 0);
|
||||
tmp.mul(batch.getTransformMatrix());
|
||||
float minX = tmp.x;
|
||||
float maxX = minX;
|
||||
float minY = tmp.y;
|
||||
float maxY = minY;
|
||||
tmp.set(clip.x + clip.width, clip.y, 0);
|
||||
tmp.mul(batch.getTransformMatrix());
|
||||
if (tmp.x < minX) { minX = tmp.x; }
|
||||
else if (tmp.x > maxX) { maxX = tmp.x; }
|
||||
if (tmp.y < minY) { minY = tmp.y; }
|
||||
else if (tmp.y > maxY) { maxY = tmp.y; }
|
||||
tmp.set(clip.x + clip.width, clip.y + clip.height, 0);
|
||||
tmp.mul(batch.getTransformMatrix());
|
||||
if (tmp.x < minX) { minX = tmp.x; }
|
||||
else if (tmp.x > maxX) { maxX = tmp.x; }
|
||||
if (tmp.y < minY) { minY = tmp.y; }
|
||||
else if (tmp.y > maxY) { maxY = tmp.y; }
|
||||
tmp.set(clip.x, clip.y + clip.height, 0);
|
||||
tmp.mul(batch.getTransformMatrix());
|
||||
if (tmp.x < minX) { minX = tmp.x; }
|
||||
else if (tmp.x > maxX) { maxX = tmp.x; }
|
||||
if (tmp.y < minY) { minY = tmp.y; }
|
||||
else if (tmp.y > maxY) { maxY = tmp.y; }
|
||||
|
||||
clip.set(minX, minY, maxX - minX, maxY - minY);
|
||||
}
|
||||
if (!ScissorStack.pushScissors(clip)) {
|
||||
failedClipCount++; //tracked failed clips to prevent calling popScissors on endClip
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public void endClip() {
|
||||
if (failedClipCount == 0) {
|
||||
batch.flush(); //must flush batch to ensure stuffed rendered during clip respects that clip
|
||||
ScissorStack.popScissors();
|
||||
}
|
||||
else {
|
||||
failedClipCount--;
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(FDisplayObject displayObj) {
|
||||
if (displayObj.getWidth() <= 0 || displayObj.getHeight() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Rectangle parentBounds = bounds;
|
||||
bounds = new Rectangle(parentBounds.x + displayObj.getLeft(), parentBounds.y + displayObj.getTop(), displayObj.getWidth(), displayObj.getHeight());
|
||||
if (!Dtransforms.isEmpty()) { //transform screen position if needed by applying transform matrix to rectangle
|
||||
updateScreenPosForRotation(displayObj);
|
||||
}
|
||||
else {
|
||||
displayObj.screenPos.set(bounds);
|
||||
}
|
||||
|
||||
Rectangle intersection = Utils.getIntersection(bounds, visibleBounds);
|
||||
if (intersection != null) { //avoid drawing object if it's not within visible region
|
||||
final Rectangle backup = visibleBounds;
|
||||
visibleBounds = intersection;
|
||||
|
||||
if (displayObj.getRotate90()) { //use top-right corner of bounds as pivot point
|
||||
startRotateTransform(displayObj.getWidth(), 0, -90);
|
||||
updateScreenPosForRotation(displayObj);
|
||||
}
|
||||
else if (displayObj.getRotate180()) { //use center of bounds as pivot point
|
||||
startRotateTransform(displayObj.getWidth() / 2, displayObj.getHeight() / 2, 180);
|
||||
//screen position won't change for this object from a 180 degree rotation
|
||||
}
|
||||
|
||||
displayObj.draw(this);
|
||||
|
||||
if (displayObj.getRotate90() || displayObj.getRotate180()) {
|
||||
endTransform();
|
||||
}
|
||||
|
||||
visibleBounds = backup;
|
||||
}
|
||||
|
||||
bounds = parentBounds;
|
||||
}
|
||||
|
||||
private void updateScreenPosForRotation(FDisplayObject displayObj) {
|
||||
tmp.set(bounds.x, regionHeight - bounds.y, 0);
|
||||
tmp.mul(batch.getTransformMatrix());
|
||||
tmp.y = regionHeight - tmp.y;
|
||||
float minX = tmp.x;
|
||||
float maxX = minX;
|
||||
float minY = tmp.y;
|
||||
float maxY = minY;
|
||||
tmp.set(bounds.x + bounds.width, regionHeight - bounds.y, 0);
|
||||
tmp.mul(batch.getTransformMatrix());
|
||||
tmp.y = regionHeight - tmp.y;
|
||||
if (tmp.x < minX) { minX = tmp.x; }
|
||||
else if (tmp.x > maxX) { maxX = tmp.x; }
|
||||
if (tmp.y < minY) { minY = tmp.y; }
|
||||
else if (tmp.y > maxY) { maxY = tmp.y; }
|
||||
tmp.set(bounds.x + bounds.width, regionHeight - bounds.y - bounds.height, 0);
|
||||
tmp.mul(batch.getTransformMatrix());
|
||||
tmp.y = regionHeight - tmp.y;
|
||||
if (tmp.x < minX) { minX = tmp.x; }
|
||||
else if (tmp.x > maxX) { maxX = tmp.x; }
|
||||
if (tmp.y < minY) { minY = tmp.y; }
|
||||
else if (tmp.y > maxY) { maxY = tmp.y; }
|
||||
tmp.set(bounds.x, regionHeight - bounds.y - bounds.height, 0);
|
||||
tmp.mul(batch.getTransformMatrix());
|
||||
tmp.y = regionHeight - tmp.y;
|
||||
if (tmp.x < minX) { minX = tmp.x; }
|
||||
else if (tmp.x > maxX) { maxX = tmp.x; }
|
||||
if (tmp.y < minY) { minY = tmp.y; }
|
||||
else if (tmp.y > maxY) { maxY = tmp.y; }
|
||||
|
||||
displayObj.screenPos.set(minX, minY, maxX - minX, maxY - minY);
|
||||
}
|
||||
|
||||
public void drawLine(float thickness, FSkinColor skinColor, float x1, float y1, float x2, float y2) {
|
||||
drawLine(thickness, skinColor.getColor(), x1, y1, x2, y2);
|
||||
}
|
||||
public void drawLine(float thickness, Color color, float x1, float y1, float x2, float y2) {
|
||||
batch.end(); //must pause batch while rendering shapes
|
||||
|
||||
if (thickness > 1) {
|
||||
Gdx.gl.glLineWidth(thickness);
|
||||
}
|
||||
if (alphaComposite < 1) {
|
||||
color = FSkinColor.alphaColor(color, color.a * alphaComposite);
|
||||
}
|
||||
boolean needSmoothing = (x1 != x2 && y1 != y2);
|
||||
if (color.a < 1 || needSmoothing) { //enable blending so alpha colored shapes work properly
|
||||
Gdx.gl.glEnable(GL_BLEND);
|
||||
}
|
||||
if (needSmoothing) {
|
||||
Gdx.gl.glEnable(GL_LINE_SMOOTH);
|
||||
}
|
||||
|
||||
startShape(ShapeType.Line);
|
||||
shapeRenderer.setColor(color);
|
||||
shapeRenderer.line(adjustX(x1), adjustY(y1, 0), adjustX(x2), adjustY(y2, 0));
|
||||
endShape();
|
||||
|
||||
if (needSmoothing) {
|
||||
Gdx.gl.glDisable(GL_LINE_SMOOTH);
|
||||
}
|
||||
if (color.a < 1 || needSmoothing) {
|
||||
Gdx.gl.glDisable(GL_BLEND);
|
||||
}
|
||||
if (thickness > 1) {
|
||||
Gdx.gl.glLineWidth(1);
|
||||
}
|
||||
|
||||
batch.begin();
|
||||
}
|
||||
|
||||
public void drawArrow(float borderThickness, float arrowThickness, float arrowSize, FSkinColor skinColor, float x1, float y1, float x2, float y2) {
|
||||
drawArrow(borderThickness, arrowThickness, arrowSize, skinColor.getColor(), x1, y1, x2, y2);
|
||||
}
|
||||
public void drawArrow(float borderThickness, float arrowThickness, float arrowSize, Color color, float x1, float y1, float x2, float y2) {
|
||||
batch.end(); //must pause batch while rendering shapes
|
||||
|
||||
if (alphaComposite < 1) {
|
||||
color = FSkinColor.alphaColor(color, color.a * alphaComposite);
|
||||
}
|
||||
Gdx.gl.glEnable(GL_BLEND);
|
||||
Gdx.gl.glEnable(GL_LINE_SMOOTH);
|
||||
|
||||
float angle = new Vector2(x2 - x1, y2 - y1).angleRad();
|
||||
float perpRotation = (float)(Math.PI * 0.5f);
|
||||
float arrowHeadRotation = (float)(Math.PI * 0.8f);
|
||||
float arrowTipAngle = (float)(Math.PI - arrowHeadRotation);
|
||||
float halfThickness = arrowThickness / 2;
|
||||
|
||||
int index = 0;
|
||||
float[] vertices = new float[14];
|
||||
Vector2 arrowCorner1 = new Vector2(x2 + arrowSize * (float)Math.cos(angle + arrowHeadRotation), y2 + arrowSize * (float)Math.sin(angle + arrowHeadRotation));
|
||||
Vector2 arrowCorner2 = new Vector2(x2 + arrowSize * (float)Math.cos(angle - arrowHeadRotation), y2 + arrowSize * (float)Math.sin(angle - arrowHeadRotation));
|
||||
float arrowCornerLen = (arrowCorner1.dst(arrowCorner2) - arrowThickness) / 2;
|
||||
float arrowHeadLen = arrowSize * (float)Math.cos(arrowTipAngle);
|
||||
index = addVertex(arrowCorner1.x, arrowCorner1.y, vertices, index);
|
||||
index = addVertex(x2, y2, vertices, index);
|
||||
index = addVertex(arrowCorner2.x, arrowCorner2.y, vertices, index);
|
||||
index = addVertex(arrowCorner2.x + arrowCornerLen * (float)Math.cos(angle + perpRotation), arrowCorner2.y + arrowCornerLen * (float)Math.sin(angle + perpRotation), vertices, index);
|
||||
index = addVertex(x1 + halfThickness * (float)Math.cos(angle - perpRotation), y1 + halfThickness * (float)Math.sin(angle - perpRotation), vertices, index);
|
||||
index = addVertex(x1 + halfThickness * (float)Math.cos(angle + perpRotation), y1 + halfThickness * (float)Math.sin(angle + perpRotation), vertices, index);
|
||||
index = addVertex(arrowCorner1.x + arrowCornerLen * (float)Math.cos(angle - perpRotation), arrowCorner1.y + arrowCornerLen * (float)Math.sin(angle - perpRotation), vertices, index);
|
||||
|
||||
//draw arrow tail
|
||||
startShape(ShapeType.Filled);
|
||||
shapeRenderer.setColor(color);
|
||||
shapeRenderer.rectLine(adjustX(x1), adjustY(y1, 0),
|
||||
adjustX(x2 - arrowHeadLen * (float)Math.cos(angle)), //shorten tail to make room for arrow head
|
||||
adjustY(y2 - arrowHeadLen * (float)Math.sin(angle), 0), arrowThickness);
|
||||
|
||||
//draw arrow head
|
||||
shapeRenderer.triangle(vertices[0], vertices[1], vertices[2], vertices[3], vertices[4], vertices[5]);
|
||||
endShape();
|
||||
|
||||
//draw border around arrow
|
||||
if (borderThickness > 1) {
|
||||
Gdx.gl.glLineWidth(borderThickness);
|
||||
}
|
||||
startShape(ShapeType.Line);
|
||||
shapeRenderer.setColor(Color.BLACK);
|
||||
shapeRenderer.polygon(vertices);
|
||||
endShape();
|
||||
if (borderThickness > 1) {
|
||||
Gdx.gl.glLineWidth(1);
|
||||
}
|
||||
|
||||
Gdx.gl.glDisable(GL_LINE_SMOOTH);
|
||||
Gdx.gl.glDisable(GL_BLEND);
|
||||
|
||||
batch.begin();
|
||||
}
|
||||
|
||||
private int addVertex(float x, float y, float[] vertices, int index) {
|
||||
vertices[index] = adjustX(x);
|
||||
vertices[index + 1] = adjustY(y, 0);
|
||||
return index + 2;
|
||||
}
|
||||
|
||||
public void drawfillBorder(float thickness, Color color, float x, float y, float w, float h, float cornerRadius) {
|
||||
drawRoundRect(thickness, color, x, y, w, h, cornerRadius);
|
||||
fillRoundRect(color, x, y, w, h, cornerRadius);
|
||||
}
|
||||
|
||||
public void drawRoundRect(float thickness, FSkinColor skinColor, float x, float y, float w, float h, float cornerRadius) {
|
||||
drawRoundRect(thickness, skinColor.getColor(), x, y, w, h, cornerRadius);
|
||||
}
|
||||
public void drawRoundRect(float thickness, Color color, float x, float y, float w, float h, float cornerRadius) {
|
||||
batch.end(); //must pause batch while rendering shapes
|
||||
|
||||
if (thickness > 1) {
|
||||
Gdx.gl.glLineWidth(thickness);
|
||||
}
|
||||
if (alphaComposite < 1) {
|
||||
color = FSkinColor.alphaColor(color, color.a * alphaComposite);
|
||||
}
|
||||
if (color.a < 1 || cornerRadius > 0) { //enable blending so alpha colored shapes work properly
|
||||
Gdx.gl.glEnable(GL_BLEND);
|
||||
}
|
||||
if (cornerRadius > 0) {
|
||||
Gdx.gl.glEnable(GL_LINE_SMOOTH);
|
||||
}
|
||||
|
||||
//adjust width/height so rectangle covers equivalent filled area
|
||||
w = Math.round(w + 1);
|
||||
h = Math.round(h + 1);
|
||||
|
||||
startShape(ShapeType.Line);
|
||||
shapeRenderer.setColor(color);
|
||||
|
||||
shapeRenderer.arc(adjustX(x) + cornerRadius, adjustY(y + cornerRadius, 0), cornerRadius, 90f, 90f);
|
||||
shapeRenderer.arc(adjustX(x) + w - cornerRadius, adjustY(y + cornerRadius, 0), cornerRadius, 0f, 90f);
|
||||
shapeRenderer.arc(adjustX(x) + w - cornerRadius, adjustY(y + h - cornerRadius, 0), cornerRadius, 270, 90f);
|
||||
shapeRenderer.arc(adjustX(x) + cornerRadius, adjustY(y + h - cornerRadius, 0), cornerRadius, 180, 90f);
|
||||
shapeRenderer.rect(adjustX(x), adjustY(y+cornerRadius, h-cornerRadius*2), w, h-cornerRadius*2);
|
||||
shapeRenderer.rect(adjustX(x+cornerRadius), adjustY(y, h), w-cornerRadius*2, h);
|
||||
|
||||
endShape();
|
||||
|
||||
if (cornerRadius > 0) {
|
||||
Gdx.gl.glDisable(GL_LINE_SMOOTH);
|
||||
}
|
||||
if (color.a < 1 || cornerRadius > 0) {
|
||||
Gdx.gl.glDisable(GL_BLEND);
|
||||
}
|
||||
if (thickness > 1) {
|
||||
Gdx.gl.glLineWidth(1);
|
||||
}
|
||||
|
||||
batch.begin();
|
||||
}
|
||||
|
||||
public void fillRoundRect(FSkinColor skinColor, float x, float y, float w, float h, float cornerRadius) {
|
||||
fillRoundRect(skinColor.getColor(), x, y, w, h, cornerRadius);
|
||||
}
|
||||
public void fillRoundRect(Color color, float x, float y, float w, float h, float cornerRadius) {
|
||||
batch.end(); //must pause batch while rendering shapes
|
||||
if (alphaComposite < 1) {
|
||||
color = FSkinColor.alphaColor(color, color.a * alphaComposite);
|
||||
}
|
||||
if (color.a < 1) { //enable blending so alpha colored shapes work properly
|
||||
Gdx.gl.glEnable(GL_BLEND);
|
||||
}
|
||||
startShape(ShapeType.Filled);
|
||||
shapeRenderer.setColor(color);
|
||||
shapeRenderer.arc(adjustX(x) + cornerRadius, adjustY(y + cornerRadius, 0), cornerRadius, 90f, 90f);
|
||||
shapeRenderer.arc(adjustX(x) + w - cornerRadius, adjustY(y + cornerRadius, 0), cornerRadius, 0f, 90f);
|
||||
shapeRenderer.arc(adjustX(x) + w - cornerRadius, adjustY(y + h - cornerRadius, 0), cornerRadius, 270, 90f);
|
||||
shapeRenderer.arc(adjustX(x) + cornerRadius, adjustY(y + h - cornerRadius, 0), cornerRadius, 180, 90f);
|
||||
shapeRenderer.rect(adjustX(x), adjustY(y+cornerRadius, h-cornerRadius*2), w, h-cornerRadius*2);
|
||||
shapeRenderer.rect(adjustX(x+cornerRadius), adjustY(y, h), w-cornerRadius*2, h);
|
||||
endShape();
|
||||
if (color.a < 1) {
|
||||
Gdx.gl.glDisable(GL_BLEND);
|
||||
}
|
||||
batch.begin();
|
||||
}
|
||||
|
||||
public void drawRect(float thickness, FSkinColor skinColor, float x, float y, float w, float h) {
|
||||
drawRect(thickness, skinColor.getColor(), x, y, w, h);
|
||||
}
|
||||
public void drawRect(float thickness, Color color, float x, float y, float w, float h) {
|
||||
batch.end(); //must pause batch while rendering shapes
|
||||
|
||||
if (thickness > 1) {
|
||||
Gdx.gl.glLineWidth(thickness);
|
||||
}
|
||||
if (alphaComposite < 1) {
|
||||
color = FSkinColor.alphaColor(color, color.a * alphaComposite);
|
||||
}
|
||||
Gdx.gl.glEnable(GL_BLEND);
|
||||
Gdx.gl.glEnable(GL_LINE_SMOOTH); //must be smooth to ensure edges aren't missed
|
||||
|
||||
startShape(ShapeType.Line);
|
||||
shapeRenderer.setColor(color);
|
||||
shapeRenderer.rect(adjustX(x), adjustY(y, h), w, h);
|
||||
endShape();
|
||||
|
||||
Gdx.gl.glDisable(GL_LINE_SMOOTH);
|
||||
Gdx.gl.glDisable(GL_BLEND);
|
||||
if (thickness > 1) {
|
||||
Gdx.gl.glLineWidth(1);
|
||||
}
|
||||
|
||||
batch.begin();
|
||||
}
|
||||
|
||||
public void fillRect(FSkinColor skinColor, float x, float y, float w, float h) {
|
||||
fillRect(skinColor.getColor(), x, y, w, h);
|
||||
}
|
||||
public void fillRect(Color color, float x, float y, float w, float h) {
|
||||
batch.end(); //must pause batch while rendering shapes
|
||||
|
||||
if (alphaComposite < 1) {
|
||||
color = FSkinColor.alphaColor(color, color.a * alphaComposite);
|
||||
}
|
||||
if (color.a < 1) { //enable blending so alpha colored shapes work properly
|
||||
Gdx.gl.glEnable(GL_BLEND);
|
||||
}
|
||||
|
||||
startShape(ShapeType.Filled);
|
||||
shapeRenderer.setColor(color);
|
||||
shapeRenderer.rect(adjustX(x), adjustY(y, h), w, h);
|
||||
endShape();
|
||||
|
||||
if (color.a < 1) {
|
||||
Gdx.gl.glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
batch.begin();
|
||||
}
|
||||
|
||||
public void drawCircle(float thickness, FSkinColor skinColor, float x, float y, float radius) {
|
||||
drawCircle(thickness, skinColor.getColor(), x, y, radius);
|
||||
}
|
||||
public void drawCircle(float thickness, Color color, float x, float y, float radius) {
|
||||
batch.end(); //must pause batch while rendering shapes
|
||||
|
||||
if (thickness > 1) {
|
||||
Gdx.gl.glLineWidth(thickness);
|
||||
}
|
||||
if (alphaComposite < 1) {
|
||||
color = FSkinColor.alphaColor(color, color.a * alphaComposite);
|
||||
}
|
||||
Gdx.gl.glEnable(GL_BLEND);
|
||||
Gdx.gl.glEnable(GL_LINE_SMOOTH);
|
||||
|
||||
startShape(ShapeType.Line);
|
||||
shapeRenderer.setColor(color);
|
||||
shapeRenderer.circle(adjustX(x), adjustY(y, 0), radius);
|
||||
endShape();
|
||||
|
||||
Gdx.gl.glDisable(GL_LINE_SMOOTH);
|
||||
Gdx.gl.glDisable(GL_BLEND);
|
||||
if (thickness > 1) {
|
||||
Gdx.gl.glLineWidth(1);
|
||||
}
|
||||
|
||||
batch.begin();
|
||||
}
|
||||
|
||||
public void fillCircle(FSkinColor skinColor, float x, float y, float radius) {
|
||||
fillCircle(skinColor.getColor(), x, y, radius);
|
||||
}
|
||||
public void fillCircle(Color color, float x, float y, float radius) {
|
||||
batch.end(); //must pause batch while rendering shapes
|
||||
|
||||
if (alphaComposite < 1) {
|
||||
color = FSkinColor.alphaColor(color, color.a * alphaComposite);
|
||||
}
|
||||
if (color.a < 1) { //enable blending so alpha colored shapes work properly
|
||||
Gdx.gl.glEnable(GL_BLEND);
|
||||
}
|
||||
|
||||
startShape(ShapeType.Filled);
|
||||
shapeRenderer.setColor(color);
|
||||
shapeRenderer.circle(adjustX(x), adjustY(y, 0), radius); //TODO: Make smoother
|
||||
endShape();
|
||||
|
||||
if (color.a < 1) {
|
||||
Gdx.gl.glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
batch.begin();
|
||||
}
|
||||
|
||||
public void fillTriangle(FSkinColor skinColor, float x1, float y1, float x2, float y2, float x3, float y3) {
|
||||
fillTriangle(skinColor.getColor(), x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
public void fillTriangle(Color color, float x1, float y1, float x2, float y2, float x3, float y3) {
|
||||
batch.end(); //must pause batch while rendering shapes
|
||||
|
||||
if (alphaComposite < 1) {
|
||||
color = FSkinColor.alphaColor(color, color.a * alphaComposite);
|
||||
}
|
||||
if (color.a < 1) { //enable blending so alpha colored shapes work properly
|
||||
Gdx.gl.glEnable(GL_BLEND);
|
||||
}
|
||||
|
||||
startShape(ShapeType.Filled);
|
||||
shapeRenderer.setColor(color);
|
||||
shapeRenderer.triangle(adjustX(x1), adjustY(y1, 0), adjustX(x2), adjustY(y2, 0), adjustX(x3), adjustY(y3, 0));
|
||||
endShape();
|
||||
|
||||
if (color.a < 1) {
|
||||
Gdx.gl.glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
batch.begin();
|
||||
}
|
||||
|
||||
public void fillGradientRect(FSkinColor skinColor1, FSkinColor skinColor2, boolean vertical, float x, float y, float w, float h) {
|
||||
fillGradientRect(skinColor1.getColor(), skinColor2.getColor(), vertical, x, y, w, h);
|
||||
}
|
||||
public void fillGradientRect(FSkinColor skinColor1, Color color2, boolean vertical, float x, float y, float w, float h) {
|
||||
fillGradientRect(skinColor1.getColor(), color2, vertical, x, y, w, h);
|
||||
}
|
||||
public void fillGradientRect(Color color1, FSkinColor skinColor2, boolean vertical, float x, float y, float w, float h) {
|
||||
fillGradientRect(color1, skinColor2.getColor(), vertical, x, y, w, h);
|
||||
}
|
||||
public void fillGradientRect(Color color1, Color color2, boolean vertical, float x, float y, float w, float h) {
|
||||
batch.end(); //must pause batch while rendering shapes
|
||||
|
||||
if (alphaComposite < 1) {
|
||||
color1 = FSkinColor.alphaColor(color1, color1.a * alphaComposite);
|
||||
color2 = FSkinColor.alphaColor(color2, color2.a * alphaComposite);
|
||||
}
|
||||
boolean needBlending = (color1.a < 1 || color2.a < 1);
|
||||
if (needBlending) { //enable blending so alpha colored shapes work properly
|
||||
Gdx.gl.glEnable(GL_BLEND);
|
||||
}
|
||||
|
||||
Color topLeftColor = color1;
|
||||
Color topRightColor = vertical ? color1 : color2;
|
||||
Color bottomLeftColor = vertical ? color2 : color1;
|
||||
Color bottomRightColor = color2;
|
||||
|
||||
startShape(ShapeType.Filled);
|
||||
shapeRenderer.rect(adjustX(x), adjustY(y, h), w, h, bottomLeftColor, bottomRightColor, topRightColor, topLeftColor);
|
||||
endShape();
|
||||
|
||||
if (needBlending) {
|
||||
Gdx.gl.glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
batch.begin();
|
||||
}
|
||||
|
||||
private void startShape(ShapeType shapeType) {
|
||||
if (!Dtransforms.isEmpty()) {
|
||||
//must copy matrix before starting shape if transformed
|
||||
shapeRenderer.setTransformMatrix(batch.getTransformMatrix());
|
||||
}
|
||||
shapeRenderer.begin(shapeType);
|
||||
}
|
||||
|
||||
private void endShape() {
|
||||
shapeRenderer.end();
|
||||
}
|
||||
|
||||
public void setAlphaComposite(float alphaComposite0) {
|
||||
alphaComposite = alphaComposite0;
|
||||
batch.setColor(new Color(1, 1, 1, alphaComposite));
|
||||
}
|
||||
public void resetAlphaComposite() {
|
||||
alphaComposite = 1;
|
||||
batch.setColor(Color.WHITE);
|
||||
}
|
||||
public float getfloatAlphaComposite() { return alphaComposite; }
|
||||
|
||||
public void drawBorderImage(FImage image, Color borderColor, Color tintColor, float x, float y, float w, float h, boolean tint) {
|
||||
float oldalpha = alphaComposite;
|
||||
if(tint && !tintColor.equals(borderColor)){
|
||||
drawRoundRect(2f, borderLining(borderColor.toString()), x, y, w, h, (h-w)/12);
|
||||
fillRoundRect(tintColor, x, y, w, h, (h-w)/12);
|
||||
} else {
|
||||
image.draw(this, x, y, w, h);
|
||||
fillRoundRect(borderColor, x, y, w, h, (h-w)/10);//show corners edges
|
||||
}
|
||||
setAlphaComposite(oldalpha);
|
||||
}
|
||||
public void drawborderImage(Color borderColor, float x, float y, float w, float h) {
|
||||
float oldalpha = alphaComposite;
|
||||
fillRoundRect(borderColor, x, y, w, h, (h-w)/12);
|
||||
setAlphaComposite(oldalpha);
|
||||
}
|
||||
public void drawImage(FImage image, Color borderColor, float x, float y, float w, float h) {
|
||||
image.draw(this, x, y, w, h);
|
||||
fillRoundRect(borderColor, x+1, y+1, w-1.5f, h-1.5f, (h-w)/10);//used by zoom let some edges show...
|
||||
}
|
||||
public void drawImage(FImage image, float x, float y, float w, float h) {
|
||||
drawImage(image, x, y, w, h, false);
|
||||
}
|
||||
public void drawImage(FImage image, float x, float y, float w, float h, boolean withDarkOverlay) {
|
||||
image.draw(this, x, y, w, h);
|
||||
if(withDarkOverlay){
|
||||
float oldalpha = alphaComposite;
|
||||
setAlphaComposite(0.4f);
|
||||
fillRect(Color.BLACK, x, y, w, h);
|
||||
setAlphaComposite(oldalpha);
|
||||
}
|
||||
}
|
||||
public void drawImage(Texture image, float x, float y, float w, float h) {
|
||||
batch.draw(image, adjustX(x), adjustY(y, h), w, h);
|
||||
}
|
||||
public void drawImage(TextureRegion image, float x, float y, float w, float h) {
|
||||
if (image != null)
|
||||
batch.draw(image, adjustX(x), adjustY(y, h), w, h);
|
||||
}
|
||||
public void drawImage(TextureRegion image, TextureRegion glowImageReference, float x, float y, float w, float h, Color glowColor, boolean selected) {
|
||||
if (image == null || glowImageReference == null)
|
||||
return;
|
||||
//1st image is the image on top of the shader, 2nd image is for the outline reference for the shader glow...
|
||||
// if the 1st image don't have transparency in the middle (only on the sides, top and bottom, use the 1st image as outline reference...
|
||||
if (!selected) {
|
||||
batch.draw(image, adjustX(x), adjustY(y, h), w, h);
|
||||
} else {
|
||||
batch.end();
|
||||
shaderOutline.bind();
|
||||
shaderOutline.setUniformf("u_viewportInverse", new Vector2(1f / w, 1f / h));
|
||||
shaderOutline.setUniformf("u_offset", 3f);
|
||||
shaderOutline.setUniformf("u_step", Math.min(1f, w / 70f));
|
||||
shaderOutline.setUniformf("u_color", new Vector3(glowColor.r, glowColor.g, glowColor.b));
|
||||
batch.setShader(shaderOutline);
|
||||
batch.begin();
|
||||
//glow
|
||||
batch.draw(glowImageReference, adjustX(x), adjustY(y, h), w, h);
|
||||
batch.end();
|
||||
batch.setShader(null);
|
||||
batch.begin();
|
||||
//img
|
||||
batch.draw(image, adjustX(x), adjustY(y, h), w, h);
|
||||
}
|
||||
}
|
||||
public void drawDeckBox(FImage cardArt, float scale, TextureRegion image, TextureRegion glowImageReference, float x, float y, float w, float h, Color glowColor, boolean selected) {
|
||||
if (image == null || glowImageReference == null)
|
||||
return;
|
||||
float yBox = y-(h*0.25f);
|
||||
if (!selected) {
|
||||
cardArt.draw(this,x+((w-w*scale)/2), y+((h-h*scale)/3f), w*scale, h*scale/1.85f);
|
||||
batch.draw(image, adjustX(x), adjustY(yBox, h), w, h);
|
||||
} else {
|
||||
batch.end();
|
||||
shaderOutline.bind();
|
||||
shaderOutline.setUniformf("u_viewportInverse", new Vector2(1f / w, 1f / h));
|
||||
shaderOutline.setUniformf("u_offset", 3f);
|
||||
shaderOutline.setUniformf("u_step", Math.min(1f, w / 70f));
|
||||
shaderOutline.setUniformf("u_color", new Vector3(glowColor.r, glowColor.g, glowColor.b));
|
||||
batch.setShader(shaderOutline);
|
||||
batch.begin();
|
||||
//glow
|
||||
batch.draw(glowImageReference, adjustX(x), adjustY(yBox, h), w, h);
|
||||
batch.end();
|
||||
batch.setShader(null);
|
||||
batch.begin();
|
||||
//cardart
|
||||
cardArt.draw(this,x+((w-w*scale)/2), y+((h-h*scale)/3f), w*scale, h*scale/1.85f);
|
||||
//deckbox
|
||||
batch.draw(image, adjustX(x), adjustY(yBox, h), w, h);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawRepeatingImage(Texture image, float x, float y, float w, float h) {
|
||||
if (startClip(x, y, w, h)) { //only render if clip successful, otherwise it will escape bounds
|
||||
int tilesW = (int)(w / image.getWidth()) + 1;
|
||||
int tilesH = (int)(h / image.getHeight()) + 1;
|
||||
batch.draw(image, adjustX(x), adjustY(y, h),
|
||||
image.getWidth() * tilesW,
|
||||
image.getHeight() * tilesH,
|
||||
0, tilesH, tilesW, 0);
|
||||
}
|
||||
endClip();
|
||||
}
|
||||
|
||||
//draw vertically flipped image
|
||||
public void drawFlippedImage(Texture image, float x, float y, float w, float h) {
|
||||
batch.draw(image, adjustX(x), adjustY(y, h), w, h, 0, 0, image.getWidth(), image.getHeight(), false, true);
|
||||
}
|
||||
|
||||
public void drawImageWithTransforms(TextureRegion image, float x, float y, float w, float h, float rotation, boolean flipX, boolean flipY) {
|
||||
float originX = x + w / 2;
|
||||
float originY = y + h / 2;
|
||||
batch.draw(image.getTexture(), adjustX(x), adjustY(y, h), originX - x, h - (originY - y), w, h, 1, 1, rotation, image.getRegionX(), image.getRegionY(), image.getRegionWidth(), image.getRegionHeight(), flipX, flipY);
|
||||
}
|
||||
|
||||
public void setProjectionMatrix(Matrix4 matrix) {
|
||||
batch.setProjectionMatrix(matrix);
|
||||
shapeRenderer.setProjectionMatrix(matrix);
|
||||
}
|
||||
|
||||
public void startRotateTransform(float originX, float originY, float rotation) {
|
||||
batch.end();
|
||||
Dtransforms.addFirst(new Matrix4(batch.getTransformMatrix().idt())); //startshape is using this above as reference
|
||||
transformCount++;
|
||||
batch.getTransformMatrix().idt().translate(adjustX(originX), adjustY(originY, 0), 0).rotate(Vector3.Z, rotation).translate(-adjustX(originX), -adjustY(originY, 0), 0);
|
||||
batch.begin();
|
||||
}
|
||||
|
||||
public void endTransform() {
|
||||
batch.end();
|
||||
shapeRenderer.setTransformMatrix(batch.getTransformMatrix().idt());
|
||||
Dtransforms.removeFirst();
|
||||
transformCount--;
|
||||
if(transformCount != Dtransforms.size()) {
|
||||
System.err.println(String.format("Stack count: %d, transformCount: %d", Dtransforms.size(), transformCount));
|
||||
transformCount = 0;
|
||||
Dtransforms.clear();
|
||||
}
|
||||
batch.getTransformMatrix().idt(); //reset
|
||||
shapeRenderer.getTransformMatrix().idt(); //reset
|
||||
batch.begin();
|
||||
}
|
||||
|
||||
public void drawRotatedImage(Texture image, float x, float y, float w, float h, float originX, float originY, float rotation) {
|
||||
drawRotatedImage(image, x, y, w, h, originX, originY, 0, 0, image.getWidth(), image.getHeight(), rotation);
|
||||
}
|
||||
public void drawRotatedImage(TextureRegion image, float x, float y, float w, float h, float originX, float originY, float rotation) {
|
||||
drawRotatedImage(image.getTexture(), x, y, w, h, originX, originY, image.getRegionX(), image.getRegionY(), image.getRegionWidth(), image.getRegionHeight(), rotation);
|
||||
}
|
||||
public void drawRotatedImage(Texture image, float x, float y, float w, float h, float originX, float originY, int srcX, int srcY, int srcWidth, int srcHeight, float rotation) {
|
||||
batch.draw(image, adjustX(x), adjustY(y, h), originX - x, h - (originY - y), w, h, 1, 1, rotation, srcX, srcY, srcWidth, srcHeight, false, false);
|
||||
}
|
||||
|
||||
public void drawText(String text, FSkinFont font, FSkinColor skinColor, float x, float y, float w, float h, boolean wrap, int horzAlignment, boolean centerVertically) {
|
||||
drawText(text, font, skinColor.getColor(), x, y, w, h, wrap, horzAlignment, centerVertically);
|
||||
}
|
||||
public void drawText(String text, FSkinFont font, Color color, float x, float y, float w, float h, boolean wrap, int horzAlignment, boolean centerVertically) {
|
||||
if (text == null)
|
||||
return;
|
||||
if (alphaComposite < 1) {
|
||||
color = FSkinColor.alphaColor(color, color.a * alphaComposite);
|
||||
}
|
||||
if (color.a < 1) { //enable blending so alpha colored shapes work properly
|
||||
Gdx.gl.glEnable(GL_BLEND);
|
||||
}
|
||||
|
||||
TextBounds textBounds;
|
||||
if (wrap) {
|
||||
textBounds = font.getWrappedBounds(text, w);
|
||||
}
|
||||
else {
|
||||
textBounds = font.getMultiLineBounds(text);
|
||||
}
|
||||
|
||||
boolean needClip = false;
|
||||
|
||||
while (textBounds.width > w || textBounds.height > h) {
|
||||
if (font.canShrink()) { //shrink font to fit if possible
|
||||
font = font.shrink();
|
||||
if (wrap) {
|
||||
textBounds = font.getWrappedBounds(text, w);
|
||||
}
|
||||
else {
|
||||
textBounds = font.getMultiLineBounds(text);
|
||||
}
|
||||
}
|
||||
else {
|
||||
needClip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (needClip) { //prevent text flowing outside region if couldn't shrink it to fit
|
||||
startClip(x, y, w, h);
|
||||
}
|
||||
|
||||
float textHeight = textBounds.height;
|
||||
if (h > textHeight && centerVertically) {
|
||||
y += (h - textHeight) / 2;
|
||||
}
|
||||
|
||||
font.draw(batch, text, color, adjustX(x), adjustY(y, 0), w, wrap, horzAlignment);
|
||||
|
||||
if (needClip) {
|
||||
endClip();
|
||||
}
|
||||
|
||||
if (color.a < 1) {
|
||||
Gdx.gl.glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
//use nifty trick with multiple text renders to draw outlined text
|
||||
public void drawOutlinedText(String text, FSkinFont skinFont, Color textColor, Color outlineColor, float x, float y, float w, float h, boolean wrap, int horzAlignment, boolean centerVertically) {
|
||||
drawText(text, skinFont, outlineColor, x - 1, y, w, h, wrap, horzAlignment, centerVertically);
|
||||
drawText(text, skinFont, outlineColor, x, y - 1, w, h, wrap, horzAlignment, centerVertically);
|
||||
drawText(text, skinFont, outlineColor, x - 1, y - 1, w, h, wrap, horzAlignment, centerVertically);
|
||||
drawText(text, skinFont, outlineColor, x + 1, y, w, h, wrap, horzAlignment, centerVertically);
|
||||
drawText(text, skinFont, outlineColor, x, y + 1, w, h, wrap, horzAlignment, centerVertically);
|
||||
drawText(text, skinFont, outlineColor, x + 1, y + 1, w, h, wrap, horzAlignment, centerVertically);
|
||||
drawText(text, skinFont, textColor, x, y, w, h, wrap, horzAlignment, centerVertically);
|
||||
}
|
||||
|
||||
public float adjustX(float x) {
|
||||
return x + bounds.x;
|
||||
}
|
||||
|
||||
public float adjustY(float y, float height) {
|
||||
return regionHeight - y - bounds.y - height; //flip y-axis
|
||||
}
|
||||
public Color borderLining(String c){
|
||||
if (c == null || c == "")
|
||||
return Color.valueOf("#fffffd");
|
||||
int c_r = Integer.parseInt(c.substring(0,2),16);
|
||||
int c_g = Integer.parseInt(c.substring(2,4),16);
|
||||
int c_b = Integer.parseInt(c.substring(4,6),16);
|
||||
int brightness = ((c_r * 299) + (c_g * 587) + (c_b * 114)) / 1000;
|
||||
return brightness > 155 ? Color.valueOf("#171717") : Color.valueOf("#fffffd");
|
||||
}
|
||||
}
|
||||
@@ -1,329 +0,0 @@
|
||||
package forge.adventure.libgdxgui;
|
||||
|
||||
import com.badlogic.gdx.Application.ApplicationType;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.google.common.base.Function;
|
||||
import forge.adventure.libgdxgui.assets.*;
|
||||
import forge.adventure.libgdxgui.card.CardRenderer;
|
||||
import forge.adventure.libgdxgui.deck.FDeckViewer;
|
||||
import forge.adventure.libgdxgui.error.BugReportDialog;
|
||||
import forge.adventure.libgdxgui.screens.LoadingOverlay;
|
||||
import forge.adventure.libgdxgui.screens.match.MatchController;
|
||||
import forge.adventure.libgdxgui.screens.settings.GuiDownloader;
|
||||
import forge.adventure.libgdxgui.sound.AudioClip;
|
||||
import forge.adventure.libgdxgui.sound.AudioMusic;
|
||||
import forge.adventure.libgdxgui.toolbox.FOptionPane;
|
||||
import forge.adventure.libgdxgui.toolbox.GuiChoose;
|
||||
import forge.adventure.libgdxgui.util.LibGDXImageFetcher;
|
||||
import forge.deck.Deck;
|
||||
import forge.gamemodes.match.HostedMatch;
|
||||
import forge.gui.download.GuiDownloadService;
|
||||
import forge.gui.interfaces.IGuiBase;
|
||||
import forge.gui.interfaces.IGuiGame;
|
||||
import forge.item.PaperCard;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.skin.FSkinProp;
|
||||
import forge.localinstance.skin.ISkinImage;
|
||||
import forge.sound.IAudioClip;
|
||||
import forge.sound.IAudioMusic;
|
||||
import forge.util.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class GuiMobile implements IGuiBase {
|
||||
private final String assetsDir;
|
||||
private final ImageFetcher imageFetcher = new LibGDXImageFetcher();
|
||||
|
||||
public GuiMobile(final String assetsDir0) {
|
||||
assetsDir = assetsDir0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunningOnDesktop() {
|
||||
if(Gdx.app==null)
|
||||
return true;
|
||||
return Gdx.app.getType() == ApplicationType.Desktop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLibgdxPort() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentVersion() {
|
||||
return Forge.CURRENT_VERSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAssetsDir() {
|
||||
return assetsDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFetcher getImageFetcher() {
|
||||
return imageFetcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invokeInEdtNow(final Runnable proc) {
|
||||
proc.run();
|
||||
Gdx.graphics.requestRendering(); //must request rendering in case this procedure wasn't triggered by a local event
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invokeInEdtLater(final Runnable proc) {
|
||||
Gdx.app.postRunnable(proc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invokeInEdtAndWait(final Runnable proc) {
|
||||
if (isGuiThread()) {
|
||||
proc.run();
|
||||
}
|
||||
else {
|
||||
new WaitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
proc.run();
|
||||
}
|
||||
}.invokeAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGuiThread() {
|
||||
return !ThreadUtil.isGameThread();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISkinImage getSkinIcon(final FSkinProp skinProp) {
|
||||
if (skinProp == null) { return null; }
|
||||
return FSkin.getImages().get(skinProp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISkinImage getUnskinnedIcon(final String path) {
|
||||
if (isGuiThread()) {
|
||||
return new FTextureImage(new Texture(Gdx.files.absolute(path)));
|
||||
}
|
||||
|
||||
//use a delay load image to avoid an error if called from background thread
|
||||
return new FDelayLoadImage(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISkinImage getCardArt(final PaperCard card) {
|
||||
return CardRenderer.getCardArt(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISkinImage getCardArt(final PaperCard card, final boolean backFace) {
|
||||
return CardRenderer.getCardArt(card, backFace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISkinImage createLayeredImage(final FSkinProp background, final String overlayFilename, final float opacity) {
|
||||
return new FBufferedImage(background.getWidth(), background.getHeight(), opacity) {
|
||||
@Override
|
||||
protected void draw(final Graphics g, final float w, final float h) {
|
||||
g.drawImage(FSkin.getImages().get(background), 0, 0, background.getWidth(), background.getHeight());
|
||||
|
||||
if (FileUtil.doesFileExist(overlayFilename)) {
|
||||
try {
|
||||
final Texture overlay = new Texture(Gdx.files.absolute(overlayFilename));
|
||||
g.drawImage(overlay, (background.getWidth() - overlay.getWidth()) / 2, (background.getHeight() - overlay.getHeight()) / 2, overlay.getWidth(), overlay.getHeight());
|
||||
} catch (final Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
Gdx.graphics.requestRendering(); //ensure image appears right away
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showImageDialog(final ISkinImage image, final String message, final String title) {
|
||||
new WaitCallback<Integer>() {
|
||||
@Override
|
||||
public void run() {
|
||||
FOptionPane.showMessageDialog(message, title, (FImage)image, this);
|
||||
}
|
||||
}.invokeAndWait();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int showOptionDialog(final String message, final String title, final FSkinProp icon, final List<String> options, final int defaultOption) {
|
||||
return new WaitCallback<Integer>() {
|
||||
@Override
|
||||
public void run() {
|
||||
FOptionPane.showOptionDialog(message, title, icon == null ? null : FSkin.getImages().get(icon), options, defaultOption, this);
|
||||
}
|
||||
}.invokeAndWait();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String showInputDialog(final String message, final String title, final FSkinProp icon, final String initialInput, final List<String> inputOptions) {
|
||||
return new WaitCallback<String>() {
|
||||
@Override
|
||||
public void run() {
|
||||
FOptionPane.showInputDialog(message, title, initialInput, inputOptions, this);
|
||||
}
|
||||
}.invokeAndWait();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display) {
|
||||
return new WaitCallback<List<T>>() {
|
||||
@Override
|
||||
public void run() {
|
||||
GuiChoose.getChoices(message, min, max, choices, selected, display, this);
|
||||
}
|
||||
}.invokeAndWait();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> order(final String title, final String top, final int remainingObjectsMin, final int remainingObjectsMax,
|
||||
final List<T> sourceChoices, final List<T> destChoices) {
|
||||
return new WaitCallback<List<T>>() {
|
||||
@Override
|
||||
public void run() {
|
||||
GuiChoose.order(title, top, remainingObjectsMin, remainingObjectsMax, sourceChoices, destChoices, null, this);
|
||||
}
|
||||
}.invokeAndWait();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBugReportDialog(final String title, final String text, final boolean showExitAppBtn) {
|
||||
BugReportDialog.show(title, text, showExitAppBtn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showCardList(final String title, final String message, final List<PaperCard> list) {
|
||||
final Deck deck = new Deck(title + " - " + message);
|
||||
deck.getMain().addAllFlat(list);
|
||||
FDeckViewer.show(deck, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showBoxedProduct(final String title, final String message, final List<PaperCard> list) {
|
||||
final Deck deck = new Deck(title + " - " + message); //TODO: Make this nicer
|
||||
deck.getMain().addAllFlat(list);
|
||||
FDeckViewer.show(deck);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperCard chooseCard(final String title, final String message, final List<PaperCard> list) {
|
||||
return new WaitCallback<PaperCard>() {
|
||||
@Override
|
||||
public void run() {
|
||||
GuiChoose.one(title + " - " + message, list, this);
|
||||
}
|
||||
}.invokeAndWait();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvatarCount() {
|
||||
if (FSkin.isLoaded()) {
|
||||
return FSkin.getAvatars().size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSleevesCount() {
|
||||
if (FSkin.isLoaded()) {
|
||||
return FSkin.getSleeves().size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String showFileDialog(final String title, final String defaultDir) {
|
||||
return ForgeConstants.USER_GAMES_DIR + "Test.fgs"; //TODO: Show dialog
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getSaveFile(final File defaultFile) {
|
||||
return defaultFile; //TODO: Show dialog
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(final GuiDownloadService service, final Callback<Boolean> callback) {
|
||||
new GuiDownloader(service, callback).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshSkin() {
|
||||
//todo refresh skin selector
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyToClipboard(final String text) {
|
||||
Forge.getClipboard().setContents(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void browseToUrl(final String url) {
|
||||
Gdx.net.openURI(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAudioClip createAudioClip(final String filename) {
|
||||
return AudioClip.createClip(ForgeConstants.SOUND_DIR + filename);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAudioMusic createAudioMusic(final String filename) {
|
||||
return new AudioMusic(filename);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startAltSoundSystem(final String filename, final boolean isSynchronized) {
|
||||
//TODO: Support alt sound system
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearImageCache() {
|
||||
ImageCache.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showSpellShop() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBazaar() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGuiGame getNewGuiGame() {
|
||||
return MatchController.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HostedMatch hostMatch() {
|
||||
return MatchController.hostMatch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runBackgroundTask(String message, Runnable task) {
|
||||
LoadingOverlay.runBackgroundTask(message, task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodeSymbols(String str, boolean formatReminderText) {
|
||||
return str; //not needed for mobile
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preventSystemSleep(boolean preventSleep) {
|
||||
Forge.getDeviceAdapter().preventSystemSleep(preventSleep);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package forge.adventure.libgdxgui.animation;
|
||||
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.sound.AudioClip;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.model.FModel;
|
||||
|
||||
public enum AbilityEffect {
|
||||
LIGHTNING("lightning.gif", "lightning.wav");
|
||||
|
||||
private final String gif, wav;
|
||||
private forge.adventure.libgdxgui.animation.GifAnimation animation;
|
||||
private AudioClip soundClip;
|
||||
|
||||
AbilityEffect(String gif0, String wav0) {
|
||||
gif = gif0;
|
||||
wav = wav0;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (animation == null) {
|
||||
animation = new GifAnimation(ForgeConstants.EFFECTS_DIR + gif);
|
||||
}
|
||||
if (soundClip == null) {
|
||||
soundClip = AudioClip.createClip(ForgeConstants.EFFECTS_DIR + wav);
|
||||
}
|
||||
soundClip.play(FModel.getPreferences().getPrefInt(ForgePreferences.FPref.UI_VOL_SOUNDS)/100f);
|
||||
animation.start();
|
||||
}
|
||||
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
if (animation != null) {
|
||||
animation.draw(g, x, y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package forge.adventure.libgdxgui.animation;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ForgeAnimation {
|
||||
private static final List<ForgeAnimation> activeAnimations = new ArrayList<>();
|
||||
// A guard against inspecting activeAnimations while it's in the process of being edited
|
||||
private static boolean changingActiveAnimations = false;
|
||||
|
||||
public void start() {
|
||||
if (activeAnimations.contains(this)) { return; } //prevent starting the same animation multiple times
|
||||
|
||||
activeAnimations.add(this);
|
||||
if (activeAnimations.size() == 1 && !changingActiveAnimations) { //if first animation being started, ensure continuous rendering turned on
|
||||
Forge.startContinuousRendering();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (!activeAnimations.contains(this)) { return; } //prevent stopping the same animation multiple times
|
||||
|
||||
activeAnimations.remove(this);
|
||||
onEnd(false);
|
||||
if (activeAnimations.isEmpty()) { //when all animations have stopped, turn continuous rendering back off
|
||||
Forge.stopContinuousRendering();
|
||||
}
|
||||
}
|
||||
|
||||
public static void advanceAll() {
|
||||
if (activeAnimations.isEmpty()) { return; }
|
||||
|
||||
float dt = Gdx.graphics.getDeltaTime();
|
||||
for (int i = 0; i < activeAnimations.size(); i++) {
|
||||
if (!activeAnimations.get(i).advance(dt)) {
|
||||
// Without this guard, there is leaky behavior when a new animation is started
|
||||
// via the onEnd callback of a finishing animation; this is because the length
|
||||
// of the list is in the process of changing from 1 to 0 to 1 again, so
|
||||
// stopContinuousRendering() won't be called in this function (so it's
|
||||
// important to not allow startContinuousRendering() to be called either).
|
||||
changingActiveAnimations = true;
|
||||
activeAnimations.remove(i).onEnd(false);
|
||||
changingActiveAnimations = false;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (activeAnimations.isEmpty()) { //when all animations have ended, turn continuous rendering back off
|
||||
Forge.stopContinuousRendering();
|
||||
}
|
||||
}
|
||||
|
||||
public static void endAll() {
|
||||
if (activeAnimations.isEmpty()) { return; }
|
||||
|
||||
for (ForgeAnimation animation : activeAnimations) {
|
||||
animation.onEnd(true);
|
||||
}
|
||||
activeAnimations.clear();
|
||||
Forge.stopContinuousRendering();
|
||||
}
|
||||
|
||||
//return true if animation should continue, false to stop the animation
|
||||
protected abstract boolean advance(float dt);
|
||||
protected abstract void onEnd(boolean endingAll);
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
package forge.adventure.libgdxgui.animation;
|
||||
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.toolbox.FOverlay;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
|
||||
public class ForgeTransition extends ForgeAnimation {
|
||||
private static final FOverlay overlay = new FOverlay(null) {
|
||||
@Override protected void doLayout(final float width, final float height) {
|
||||
}
|
||||
};
|
||||
private static final Map<FDisplayObject, TransitionObject> transitionLookup = new LinkedHashMap<>();
|
||||
|
||||
public static void queue(final FDisplayObject obj, final Rectangle destBounds, final float duration, final Runnable onFinished) {
|
||||
queue(obj, destBounds, duration, 0, false, onFinished);
|
||||
}
|
||||
public static void queue(final FDisplayObject obj, final Rectangle destBounds, final float duration, final float arcAmount, final boolean arcOriginBelow, final Runnable onFinished) {
|
||||
TransitionObject transitionObj = transitionLookup.get(obj);
|
||||
if (transitionObj == null) {
|
||||
transitionObj = new TransitionObject(obj);
|
||||
transitionLookup.put(obj, transitionObj);
|
||||
overlay.add(transitionObj);
|
||||
obj.setVisible(false); //hide original object while transition in progress
|
||||
}
|
||||
final ForgeTransition transition = new ForgeTransition(transitionObj, destBounds, duration, arcAmount, arcOriginBelow, onFinished);
|
||||
transitionObj.transitions.add(transition);
|
||||
if (transitionObj.transitions.size() == 1) {
|
||||
transition.start(); //start transition right away if first transition added
|
||||
overlay.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
private final TransitionObject obj;
|
||||
/*private final Rectangle destBounds;
|
||||
private final float duration;
|
||||
private final float arcAmount;
|
||||
private final boolean arcOriginBelow;*/
|
||||
private final Runnable onFinished;
|
||||
|
||||
private ForgeTransition(final TransitionObject obj0, final Rectangle destBounds0, final float duration0, final float arcAmount0, final boolean arcOriginBelow0, final Runnable onFinished0) {
|
||||
obj = obj0;
|
||||
/*destBounds = destBounds0;
|
||||
duration = duration0;
|
||||
arcAmount = arcAmount0;
|
||||
arcOriginBelow = arcOriginBelow0;*/
|
||||
onFinished = onFinished0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean advance(final float dt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnd(final boolean endingAll) {
|
||||
if (onFinished != null) {
|
||||
onFinished.run();
|
||||
}
|
||||
|
||||
if (endingAll) {
|
||||
transitionLookup.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
final int index = obj.transitions.indexOf(this);
|
||||
obj.transitions.remove(index);
|
||||
if (index == 0) {
|
||||
if (obj.transitions.isEmpty()) {
|
||||
transitionLookup.remove(obj.originalObj);
|
||||
overlay.remove(obj);
|
||||
obj.originalObj.setVisible(true);
|
||||
if (transitionLookup.isEmpty()) {
|
||||
overlay.setVisible(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
obj.transitions.getFirst().start(); //start next transition if needed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class TransitionObject extends FDisplayObject {
|
||||
private final FDisplayObject originalObj;
|
||||
private final LinkedList<ForgeTransition> transitions = new LinkedList<>();
|
||||
|
||||
private TransitionObject(final FDisplayObject originalObj0) {
|
||||
originalObj = originalObj0;
|
||||
setBounds(originalObj.screenPos.x, originalObj.screenPos.y, originalObj.getWidth(), originalObj.getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(final Graphics g) {
|
||||
originalObj.draw(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package forge.adventure.libgdxgui.animation;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.g2d.Animation;
|
||||
import com.badlogic.gdx.graphics.g2d.Animation.PlayMode;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
|
||||
public class GifAnimation extends ForgeAnimation {
|
||||
private final Animation<TextureRegion> animation;
|
||||
private TextureRegion currentFrame;
|
||||
private float stateTime;
|
||||
|
||||
public GifAnimation(String filename) {
|
||||
animation = GifDecoder.loadGIFAnimation(PlayMode.NORMAL, Gdx.files.absolute(filename).read());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
currentFrame = animation.getKeyFrame(0);
|
||||
super.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean advance(float dt) {
|
||||
stateTime += dt;
|
||||
currentFrame = animation.getKeyFrame(stateTime);
|
||||
return currentFrame != null;
|
||||
}
|
||||
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
if (currentFrame != null) {
|
||||
g.drawImage(currentFrame, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnd(boolean endingAll) {
|
||||
}
|
||||
}
|
||||
@@ -1,737 +0,0 @@
|
||||
package forge.adventure.libgdxgui.animation;
|
||||
|
||||
/* Copyright by Johannes Borchardt */
|
||||
/* LibGdx conversion 2014 by Anton Persson */
|
||||
/* Released under Apache 2.0 */
|
||||
/* https://code.google.com/p/animated-gifs-in-android/ */
|
||||
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.Animation;
|
||||
import com.badlogic.gdx.graphics.g2d.Animation.PlayMode;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Vector;
|
||||
|
||||
public class GifDecoder {
|
||||
/**
|
||||
* File read status: No errors.
|
||||
*/
|
||||
public static final int STATUS_OK = 0;
|
||||
/**
|
||||
* File read status: Error decoding file (may be partially decoded)
|
||||
*/
|
||||
public static final int STATUS_FORMAT_ERROR = 1;
|
||||
/**
|
||||
* File read status: Unable to open source.
|
||||
*/
|
||||
public static final int STATUS_OPEN_ERROR = 2;
|
||||
/** max decoder pixel stack size */
|
||||
protected static final int MAX_STACK_SIZE = 4096;
|
||||
protected InputStream in;
|
||||
protected int status;
|
||||
protected int width; // full image width
|
||||
protected int height; // full image height
|
||||
protected boolean gctFlag; // global color table used
|
||||
protected int gctSize; // size of global color table
|
||||
protected int loopCount = 1; // iterations; 0 = repeat forever
|
||||
protected int[] gct; // global color table
|
||||
protected int[] lct; // local color table
|
||||
protected int[] act; // active color table
|
||||
protected int bgIndex; // background color index
|
||||
protected int bgColor; // background color
|
||||
protected int lastBgColor; // previous bg color
|
||||
protected int pixelAspect; // pixel aspect ratio
|
||||
protected boolean lctFlag; // local color table flag
|
||||
protected boolean interlace; // interlace flag
|
||||
protected int lctSize; // local color table size
|
||||
protected int ix, iy, iw, ih; // current image rectangle
|
||||
protected int lrx, lry, lrw, lrh;
|
||||
protected DixieMap image; // current frame
|
||||
protected DixieMap lastPixmap; // previous frame
|
||||
protected byte[] block = new byte[256]; // current data block
|
||||
protected int blockSize = 0; // block size last graphic control extension info
|
||||
protected int dispose = 0; // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev
|
||||
protected int lastDispose = 0;
|
||||
protected boolean transparency = false; // use transparent color
|
||||
protected int delay = 0; // delay in milliseconds
|
||||
protected int transIndex; // transparent color index
|
||||
// LZW decoder working arrays
|
||||
protected short[] prefix;
|
||||
protected byte[] suffix;
|
||||
protected byte[] pixelStack;
|
||||
protected byte[] pixels;
|
||||
protected Vector<GifFrame> frames; // frames read from current file
|
||||
protected int frameCount;
|
||||
|
||||
private static class DixieMap extends Pixmap {
|
||||
DixieMap(int w, int h, Format f) {
|
||||
super(w, h, f);
|
||||
}
|
||||
|
||||
DixieMap(int[] data, int w, int h, Format f) {
|
||||
super(w, h, f);
|
||||
|
||||
int x, y;
|
||||
|
||||
for(y = 0; y < h; y++) {
|
||||
for(x = 0; x < w; x++) {
|
||||
int pxl_ARGB8888 = data[x + y * w];
|
||||
int pxl_RGBA8888 =
|
||||
((pxl_ARGB8888 >> 24) & 0x000000ff) | ((pxl_ARGB8888 << 8) & 0xffffff00);
|
||||
// convert ARGB8888 > RGBA8888
|
||||
drawPixel(x, y, pxl_RGBA8888);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height) {
|
||||
java.nio.ByteBuffer bb = getPixels();
|
||||
|
||||
int k, l;
|
||||
|
||||
for(k = y; k < y + height; k++) {
|
||||
int _offset = offset;
|
||||
for(l = x; l < x + width; l++) {
|
||||
int pxl = bb.getInt(4 * (l + k * width));
|
||||
|
||||
// convert RGBA8888 > ARGB8888
|
||||
pixels[_offset++] = ((pxl >> 8) & 0x00ffffff) | ((pxl << 24) & 0xff000000);
|
||||
}
|
||||
offset += stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class GifFrame {
|
||||
public GifFrame(DixieMap im, int del) {
|
||||
image = im;
|
||||
delay = del;
|
||||
}
|
||||
|
||||
public DixieMap image;
|
||||
public int delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets display duration for specified frame.
|
||||
*
|
||||
* @param n
|
||||
* int index of frame
|
||||
* @return delay in milliseconds
|
||||
*/
|
||||
public int getDelay(int n) {
|
||||
delay = -1;
|
||||
if ((n >= 0) && (n < frameCount)) {
|
||||
delay = frames.elementAt(n).delay;
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of frames read from file.
|
||||
*
|
||||
* @return frame count
|
||||
*/
|
||||
public int getFrameCount() {
|
||||
return frameCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first (or only) image read.
|
||||
*
|
||||
* @return BufferedPixmap containing first frame, or null if none.
|
||||
*/
|
||||
public Pixmap getPixmap() {
|
||||
return getFrame(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "Netscape" iteration count, if any. A count of 0 means repeat indefinitely.
|
||||
*
|
||||
* @return iteration count if one was specified, else 1.
|
||||
*/
|
||||
public int getLoopCount() {
|
||||
return loopCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new frame image from current data (and previous frames as specified by their disposition codes).
|
||||
*/
|
||||
protected void setPixels() {
|
||||
// expose destination image's pixels as int array
|
||||
int[] dest = new int[width * height];
|
||||
// fill in starting image contents based on last image's dispose code
|
||||
if (lastDispose > 0) {
|
||||
if (lastDispose == 3) {
|
||||
// use image before last
|
||||
int n = frameCount - 2;
|
||||
if (n > 0) {
|
||||
lastPixmap = getFrame(n - 1);
|
||||
} else {
|
||||
lastPixmap = null;
|
||||
}
|
||||
}
|
||||
if (lastPixmap != null) {
|
||||
lastPixmap.getPixels(dest, 0, width, 0, 0, width, height);
|
||||
// copy pixels
|
||||
if (lastDispose == 2) {
|
||||
// fill last image rect area with background color
|
||||
int c = 0;
|
||||
if (!transparency) {
|
||||
c = lastBgColor;
|
||||
}
|
||||
for (int i = 0; i < lrh; i++) {
|
||||
int n1 = (lry + i) * width + lrx;
|
||||
int n2 = n1 + lrw;
|
||||
for (int k = n1; k < n2; k++) {
|
||||
dest[k] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// copy each source line to the appropriate place in the destination
|
||||
int pass = 1;
|
||||
int inc = 8;
|
||||
int iline = 0;
|
||||
for (int i = 0; i < ih; i++) {
|
||||
int line = i;
|
||||
if (interlace) {
|
||||
if (iline >= ih) {
|
||||
pass++;
|
||||
switch (pass) {
|
||||
case 2:
|
||||
iline = 4;
|
||||
break;
|
||||
case 3:
|
||||
iline = 2;
|
||||
inc = 4;
|
||||
break;
|
||||
case 4:
|
||||
iline = 1;
|
||||
inc = 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
line = iline;
|
||||
iline += inc;
|
||||
}
|
||||
line += iy;
|
||||
if (line < height) {
|
||||
int k = line * width;
|
||||
int dx = k + ix; // start of line in dest
|
||||
int dlim = dx + iw; // end of dest line
|
||||
if ((k + width) < dlim) {
|
||||
dlim = k + width; // past dest edge
|
||||
}
|
||||
int sx = i * iw; // start of line in source
|
||||
while (dx < dlim) {
|
||||
// map color and insert in destination
|
||||
int index = ((int) pixels[sx++]) & 0xff;
|
||||
int c = act[index];
|
||||
if (c != 0) {
|
||||
dest[dx] = c;
|
||||
}
|
||||
dx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
image = new DixieMap(dest, width, height, Pixmap.Format.RGBA8888);
|
||||
//Pixmap.createPixmap(dest, width, height, Config.ARGB_4444);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the image contents of frame n.
|
||||
*
|
||||
* @return BufferedPixmap representation of frame, or null if n is invalid.
|
||||
*/
|
||||
public DixieMap getFrame(int n) {
|
||||
if (frameCount <= 0)
|
||||
return null;
|
||||
n = n % frameCount;
|
||||
return frames.elementAt(n).image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads GIF image from stream
|
||||
*
|
||||
* @param is
|
||||
* containing GIF file.
|
||||
* @return read status code (0 = no errors)
|
||||
*/
|
||||
public int read(InputStream is) {
|
||||
init();
|
||||
if (is != null) {
|
||||
in = is;
|
||||
readHeader();
|
||||
if (!err()) {
|
||||
readContents();
|
||||
if (frameCount < 0) {
|
||||
status = STATUS_FORMAT_ERROR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status = STATUS_OPEN_ERROR;
|
||||
}
|
||||
try {
|
||||
is.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes LZW image data into pixel array. Adapted from John Cristy's BitmapMagick.
|
||||
*/
|
||||
protected void decodeBitmapData() {
|
||||
int nullCode = -1;
|
||||
int npix = iw * ih;
|
||||
int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi;
|
||||
if ((pixels == null) || (pixels.length < npix)) {
|
||||
pixels = new byte[npix]; // allocate new pixel array
|
||||
}
|
||||
if (prefix == null) {
|
||||
prefix = new short[MAX_STACK_SIZE];
|
||||
}
|
||||
if (suffix == null) {
|
||||
suffix = new byte[MAX_STACK_SIZE];
|
||||
}
|
||||
if (pixelStack == null) {
|
||||
pixelStack = new byte[MAX_STACK_SIZE + 1];
|
||||
}
|
||||
// Initialize GIF data stream decoder.
|
||||
data_size = read();
|
||||
clear = 1 << data_size;
|
||||
end_of_information = clear + 1;
|
||||
available = clear + 2;
|
||||
old_code = nullCode;
|
||||
code_size = data_size + 1;
|
||||
code_mask = (1 << code_size) - 1;
|
||||
for (code = 0; code < clear; code++) {
|
||||
prefix[code] = 0; // XXX ArrayIndexOutOfBoundsException
|
||||
suffix[code] = (byte) code;
|
||||
}
|
||||
// Decode GIF pixel stream.
|
||||
datum = bits = count = first = top = pi = bi = 0;
|
||||
for (i = 0; i < npix;) {
|
||||
if (top == 0) {
|
||||
if (bits < code_size) {
|
||||
// Load bytes until there are enough bits for a code.
|
||||
if (count == 0) {
|
||||
// Read a new data block.
|
||||
count = readBlock();
|
||||
if (count <= 0) {
|
||||
break;
|
||||
}
|
||||
bi = 0;
|
||||
}
|
||||
datum += (((int) block[bi]) & 0xff) << bits;
|
||||
bits += 8;
|
||||
bi++;
|
||||
count--;
|
||||
continue;
|
||||
}
|
||||
// Get the next code.
|
||||
code = datum & code_mask;
|
||||
datum >>= code_size;
|
||||
bits -= code_size;
|
||||
// Interpret the code
|
||||
if ((code > available) || (code == end_of_information)) {
|
||||
break;
|
||||
}
|
||||
if (code == clear) {
|
||||
// Reset decoder.
|
||||
code_size = data_size + 1;
|
||||
code_mask = (1 << code_size) - 1;
|
||||
available = clear + 2;
|
||||
old_code = nullCode;
|
||||
continue;
|
||||
}
|
||||
if (old_code == nullCode) {
|
||||
pixelStack[top++] = suffix[code];
|
||||
old_code = code;
|
||||
first = code;
|
||||
continue;
|
||||
}
|
||||
in_code = code;
|
||||
if (code == available) {
|
||||
pixelStack[top++] = (byte) first;
|
||||
code = old_code;
|
||||
}
|
||||
while (code > clear) {
|
||||
pixelStack[top++] = suffix[code];
|
||||
code = prefix[code];
|
||||
}
|
||||
first = ((int) suffix[code]) & 0xff;
|
||||
// Add a new string to the string table,
|
||||
if (available >= MAX_STACK_SIZE) {
|
||||
break;
|
||||
}
|
||||
pixelStack[top++] = (byte) first;
|
||||
prefix[available] = (short) old_code;
|
||||
suffix[available] = (byte) first;
|
||||
available++;
|
||||
if (((available & code_mask) == 0) && (available < MAX_STACK_SIZE)) {
|
||||
code_size++;
|
||||
code_mask += available;
|
||||
}
|
||||
old_code = in_code;
|
||||
}
|
||||
// Pop a pixel off the pixel stack.
|
||||
top--;
|
||||
pixels[pi++] = pixelStack[top];
|
||||
i++;
|
||||
}
|
||||
for (i = pi; i < npix; i++) {
|
||||
pixels[i] = 0; // clear missing pixels
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an error was encountered during reading/decoding
|
||||
*/
|
||||
protected boolean err() {
|
||||
return status != STATUS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes or re-initializes reader
|
||||
*/
|
||||
protected void init() {
|
||||
status = STATUS_OK;
|
||||
frameCount = 0;
|
||||
frames = new Vector<>();
|
||||
gct = null;
|
||||
lct = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a single byte from the input stream.
|
||||
*/
|
||||
protected int read() {
|
||||
int curByte = 0;
|
||||
try {
|
||||
curByte = in.read();
|
||||
} catch (Exception e) {
|
||||
status = STATUS_FORMAT_ERROR;
|
||||
}
|
||||
return curByte;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads next variable length block from input.
|
||||
*
|
||||
* @return number of bytes stored in "buffer"
|
||||
*/
|
||||
protected int readBlock() {
|
||||
blockSize = read();
|
||||
int n = 0;
|
||||
if (blockSize > 0) {
|
||||
try {
|
||||
int count = 0;
|
||||
while (n < blockSize) {
|
||||
count = in.read(block, n, blockSize - n);
|
||||
if (count == -1) {
|
||||
break;
|
||||
}
|
||||
n += count;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (n < blockSize) {
|
||||
status = STATUS_FORMAT_ERROR;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads color table as 256 RGB integer values
|
||||
*
|
||||
* @param ncolors
|
||||
* int number of colors to read
|
||||
* @return int array containing 256 colors (packed ARGB with full alpha)
|
||||
*/
|
||||
protected int[] readColorTable(int ncolors) {
|
||||
int nbytes = 3 * ncolors;
|
||||
int[] tab = null;
|
||||
byte[] c = new byte[nbytes];
|
||||
int n = 0;
|
||||
try {
|
||||
n = in.read(c);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (n < nbytes) {
|
||||
status = STATUS_FORMAT_ERROR;
|
||||
} else {
|
||||
tab = new int[256]; // max size to avoid bounds checks
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
while (i < ncolors) {
|
||||
int r = ((int) c[j++]) & 0xff;
|
||||
int g = ((int) c[j++]) & 0xff;
|
||||
int b = ((int) c[j++]) & 0xff;
|
||||
tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
}
|
||||
return tab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main file parser. Reads GIF content blocks.
|
||||
*/
|
||||
protected void readContents() {
|
||||
// read GIF file content blocks
|
||||
boolean done = false;
|
||||
while (!(done || err())) {
|
||||
int code = read();
|
||||
switch (code) {
|
||||
case 0x2C: // image separator
|
||||
readBitmap();
|
||||
break;
|
||||
case 0x21: // extension
|
||||
code = read();
|
||||
switch (code) {
|
||||
case 0xf9: // graphics control extension
|
||||
readGraphicControlExt();
|
||||
break;
|
||||
case 0xff: // application extension
|
||||
readBlock();
|
||||
StringBuilder app = new StringBuilder();
|
||||
for (int i = 0; i < 11; i++) {
|
||||
app.append((char) block[i]);
|
||||
}
|
||||
if (app.toString().equals("NETSCAPE2.0")) {
|
||||
readNetscapeExt();
|
||||
} else {
|
||||
skip(); // don't care
|
||||
}
|
||||
break;
|
||||
case 0xfe:// comment extension
|
||||
skip();
|
||||
break;
|
||||
case 0x01:// plain text extension
|
||||
skip();
|
||||
break;
|
||||
default: // uninteresting extension
|
||||
skip();
|
||||
}
|
||||
break;
|
||||
case 0x3b: // terminator
|
||||
done = true;
|
||||
break;
|
||||
case 0x00: // bad byte, but keep going and see what happens break;
|
||||
default:
|
||||
status = STATUS_FORMAT_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads Graphics Control Extension values
|
||||
*/
|
||||
protected void readGraphicControlExt() {
|
||||
read(); // block size
|
||||
int packed = read(); // packed fields
|
||||
dispose = (packed & 0x1c) >> 2; // disposal method
|
||||
if (dispose == 0) {
|
||||
dispose = 1; // elect to keep old image if discretionary
|
||||
}
|
||||
transparency = (packed & 1) != 0;
|
||||
delay = readShort() * 10; // delay in milliseconds
|
||||
transIndex = read(); // transparent color index
|
||||
read(); // block terminator
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads GIF file header information.
|
||||
*/
|
||||
protected void readHeader() {
|
||||
StringBuilder id = new StringBuilder();
|
||||
for (int i = 0; i < 6; i++) {
|
||||
id.append((char) read());
|
||||
}
|
||||
if (!id.toString().startsWith("GIF")) {
|
||||
status = STATUS_FORMAT_ERROR;
|
||||
return;
|
||||
}
|
||||
readLSD();
|
||||
if (gctFlag && !err()) {
|
||||
gct = readColorTable(gctSize);
|
||||
bgColor = gct[bgIndex];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads next frame image
|
||||
*/
|
||||
protected void readBitmap() {
|
||||
ix = readShort(); // (sub)image position & size
|
||||
iy = readShort();
|
||||
iw = readShort();
|
||||
ih = readShort();
|
||||
int packed = read();
|
||||
lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace
|
||||
lctSize = (int) Math.pow(2, (packed & 0x07) + 1);
|
||||
// 3 - sort flag
|
||||
// 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color
|
||||
// table size
|
||||
interlace = (packed & 0x40) != 0;
|
||||
if (lctFlag) {
|
||||
lct = readColorTable(lctSize); // read table
|
||||
act = lct; // make local table active
|
||||
} else {
|
||||
act = gct; // make global table active
|
||||
if (bgIndex == transIndex) {
|
||||
bgColor = 0;
|
||||
}
|
||||
}
|
||||
int save = 0;
|
||||
if (transparency) {
|
||||
save = act[transIndex];
|
||||
act[transIndex] = 0; // set transparent color if specified
|
||||
}
|
||||
if (act == null) {
|
||||
status = STATUS_FORMAT_ERROR; // no color table defined
|
||||
}
|
||||
if (err()) {
|
||||
return;
|
||||
}
|
||||
decodeBitmapData(); // decode pixel data
|
||||
skip();
|
||||
if (err()) {
|
||||
return;
|
||||
}
|
||||
frameCount++;
|
||||
// create new image to receive frame data
|
||||
image = new DixieMap(width, height, Pixmap.Format.RGBA8888);
|
||||
setPixels(); // transfer pixel data to image
|
||||
frames.addElement(new GifFrame(image, delay)); // add image to frame
|
||||
// list
|
||||
if (transparency) {
|
||||
act[transIndex] = save;
|
||||
}
|
||||
resetFrame();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads Logical Screen Descriptor
|
||||
*/
|
||||
protected void readLSD() {
|
||||
// logical screen size
|
||||
width = readShort();
|
||||
height = readShort();
|
||||
// packed fields
|
||||
int packed = read();
|
||||
gctFlag = (packed & 0x80) != 0; // 1 : global color table flag
|
||||
// 2-4 : color resolution
|
||||
// 5 : gct sort flag
|
||||
gctSize = 2 << (packed & 7); // 6-8 : gct size
|
||||
bgIndex = read(); // background color index
|
||||
pixelAspect = read(); // pixel aspect ratio
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads Netscape extenstion to obtain iteration count
|
||||
*/
|
||||
protected void readNetscapeExt() {
|
||||
do {
|
||||
readBlock();
|
||||
if (block[0] == 1) {
|
||||
// loop count sub-block
|
||||
int b1 = ((int) block[1]) & 0xff;
|
||||
int b2 = ((int) block[2]) & 0xff;
|
||||
loopCount = (b2 << 8) | b1;
|
||||
}
|
||||
} while ((blockSize > 0) && !err());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads next 16-bit value, LSB first
|
||||
*/
|
||||
protected int readShort() {
|
||||
// read 16-bit value, LSB first
|
||||
return read() | (read() << 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets frame state for reading next image.
|
||||
*/
|
||||
protected void resetFrame() {
|
||||
lastDispose = dispose;
|
||||
lrx = ix;
|
||||
lry = iy;
|
||||
lrw = iw;
|
||||
lrh = ih;
|
||||
lastPixmap = image;
|
||||
lastBgColor = bgColor;
|
||||
dispose = 0;
|
||||
transparency = false;
|
||||
delay = 0;
|
||||
lct = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips variable length blocks up to and including next zero length block.
|
||||
*/
|
||||
protected void skip() {
|
||||
do {
|
||||
readBlock();
|
||||
} while ((blockSize > 0) && !err());
|
||||
}
|
||||
|
||||
private Animation<TextureRegion> getAnimation(PlayMode playType) {
|
||||
int nrFrames = getFrameCount();
|
||||
Pixmap frame = getFrame(0);
|
||||
int width = frame.getWidth();
|
||||
int height = frame.getHeight();
|
||||
int vzones = (int)Math.sqrt(nrFrames);
|
||||
int hzones = vzones;
|
||||
|
||||
while(vzones * hzones < nrFrames) vzones++;
|
||||
|
||||
int v, h;
|
||||
|
||||
Pixmap target = new Pixmap(width * hzones, height * vzones, Pixmap.Format.RGBA8888);
|
||||
|
||||
for(h = 0; h < hzones; h++) {
|
||||
for(v = 0; v < vzones; v++) {
|
||||
int frameID = v + h * vzones;
|
||||
if(frameID < nrFrames) {
|
||||
frame = getFrame(frameID);
|
||||
target.drawPixmap(frame, h * width, v * height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Texture texture = new Texture(target);
|
||||
Array<TextureRegion> texReg = new Array<>();
|
||||
|
||||
for(h = 0; h < hzones; h++) {
|
||||
for(v = 0; v < vzones; v++) {
|
||||
int frameID = v + h * vzones;
|
||||
if(frameID < nrFrames) {
|
||||
TextureRegion tr = new TextureRegion(texture, h * width, v * height, width, height);
|
||||
texReg.add(tr);
|
||||
}
|
||||
}
|
||||
}
|
||||
float frameDuration = (float)getDelay(0);
|
||||
frameDuration /= 1000; // convert milliseconds into seconds
|
||||
|
||||
return new Animation<>(frameDuration, texReg, playType);
|
||||
}
|
||||
|
||||
public static Animation<TextureRegion> loadGIFAnimation(PlayMode playType, InputStream is) {
|
||||
GifDecoder gdec = new GifDecoder();
|
||||
gdec.read(is);
|
||||
return gdec.getAnimation(playType);
|
||||
}
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import com.badlogic.gdx.Application.ApplicationType;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.gui.FThreads;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.gui.download.GuiDownloadZipService;
|
||||
import forge.gui.util.SOptionPane;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.adventure.libgdxgui.screens.SplashScreen;
|
||||
import forge.util.FileUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
public class AssetsDownloader {
|
||||
public static final boolean SHARE_DESKTOP_ASSETS = true; //change to false to test downloading separate assets for desktop version
|
||||
|
||||
private final static ImmutableList<String> downloadIgnoreExit = ImmutableList.of("Download", "Ignore", "Exit");
|
||||
private final static ImmutableList<String> downloadExit = ImmutableList.of("Download", "Exit");
|
||||
|
||||
//if not sharing desktop assets, check whether assets are up to date
|
||||
public static void checkForUpdates(final SplashScreen splashScreen) {
|
||||
if (Gdx.app.getType() == ApplicationType.Desktop && SHARE_DESKTOP_ASSETS) { return; }
|
||||
|
||||
final boolean isSnapshots = Forge.CURRENT_VERSION.contains("SNAPSHOT");
|
||||
final String snapsURL = "https://downloads.cardforge.org/dailysnapshots/";
|
||||
final String releaseURL = "https://releases.cardforge.org/forge/forge-gui-android/";
|
||||
final String versionText = isSnapshots ? snapsURL + "version.txt" : releaseURL + "version.txt";
|
||||
|
||||
splashScreen.getProgressBar().setDescription("Checking for updates...");
|
||||
|
||||
String message;
|
||||
boolean connectedToInternet = Forge.getDeviceAdapter().isConnectedToInternet();
|
||||
if (connectedToInternet) {
|
||||
try {
|
||||
URL versionUrl = new URL(versionText);
|
||||
String version = FileUtil.readFileToString(versionUrl);
|
||||
String filename = "forge-android-" + version + "-signed-aligned.apk";
|
||||
String apkURL = isSnapshots ? snapsURL + filename : releaseURL + version + "/" + filename;
|
||||
if (!StringUtils.isEmpty(version) && !Forge.CURRENT_VERSION.equals(version)) {
|
||||
splashScreen.prepareForDialogs();
|
||||
|
||||
message = "A new version of Forge is available (" + version + ").\n" +
|
||||
"You are currently on an older version (" + Forge.CURRENT_VERSION + ").\n\n" +
|
||||
"Would you like to update to the new version now?";
|
||||
if (!Forge.getDeviceAdapter().isConnectedToWifi()) {
|
||||
message += " If so, you may want to connect to wifi first. The download is around 6.5MB.";
|
||||
}
|
||||
if (SOptionPane.showConfirmDialog(message, "New Version Available", "Update Now", "Update Later", true, true)) {
|
||||
String apkFile = new GuiDownloadZipService("", "update", apkURL,
|
||||
Forge.getDeviceAdapter().getDownloadsDir(), null, splashScreen.getProgressBar()).download(filename);
|
||||
if (apkFile != null) {
|
||||
/* FileUriExposedException was added on API 24, Forge now targets API 26 so Android 10 and above runs,
|
||||
most user thinks Forge crashes but in reality, the method below just can't open the apk when Forge
|
||||
exits silently to run the downloaded apk. Some devices allow the apk to run but most users are annoyed when
|
||||
Forge didn't open the apk so I downgrade the check so it will run only on target devices without FileUriExposedException */
|
||||
if (Forge.androidVersion < 24) {
|
||||
Forge.getDeviceAdapter().openFile(apkFile);
|
||||
Forge.exit(true);
|
||||
return;
|
||||
}
|
||||
// API 24 and above needs manual apk installation unless we provide a FileProvider for FileUriExposedException
|
||||
switch (SOptionPane.showOptionDialog("Download Successful. Go to your downloads folder and install " + filename +" to update Forge. Forge will now exit.", "", null, ImmutableList.of("Ok"))) {
|
||||
default:
|
||||
Forge.exit(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
SOptionPane.showMessageDialog("Could not download update. " +
|
||||
"Press OK to proceed without update.", "Update Failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
//see if assets need updating
|
||||
File versionFile = new File(ForgeConstants.ASSETS_DIR + "version.txt");
|
||||
if (!versionFile.exists()) {
|
||||
try {
|
||||
versionFile.createNewFile();
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Forge.exit(true); //can't continue if this fails
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (Forge.CURRENT_VERSION.equals(FileUtil.readFileToString(versionFile)) && FSkin.getSkinDir() != null) {
|
||||
return; //if version matches what had been previously saved and FSkin isn't requesting assets download, no need to download assets
|
||||
}
|
||||
|
||||
splashScreen.prepareForDialogs(); //ensure colors set up for showing message dialogs
|
||||
|
||||
boolean canIgnoreDownload = FSkin.getAllSkins() != null; //don't allow ignoring download if resource files haven't been previously loaded
|
||||
|
||||
if (!connectedToInternet) {
|
||||
message = "Updated resource files cannot be downloaded due to lack of internet connection.\n\n";
|
||||
if (canIgnoreDownload) {
|
||||
message += "You can continue without this download, but you may miss out on card fixes or experience other problems.";
|
||||
}
|
||||
else {
|
||||
message += "You cannot start the app since you haven't previously downloaded these files.";
|
||||
}
|
||||
SOptionPane.showMessageDialog(message, "No Internet Connection");
|
||||
if (!canIgnoreDownload) {
|
||||
Forge.exit(true); //exit if can't ignore download
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//prompt user whether they wish to download the updated resource files
|
||||
message = "There are updated resource files to download. " +
|
||||
"This download is around 50MB, ";
|
||||
if (Forge.getDeviceAdapter().isConnectedToWifi()) {
|
||||
message += "which shouldn't take long if your wifi connection is good.";
|
||||
}
|
||||
else {
|
||||
message += "so it's highly recommended that you connect to wifi first.";
|
||||
}
|
||||
final List<String> options;
|
||||
message += "\n\n";
|
||||
if (canIgnoreDownload) {
|
||||
message += "If you choose to ignore this download, you may miss out on card fixes or experience other problems.";
|
||||
options = downloadIgnoreExit;
|
||||
} else {
|
||||
message += "This download is mandatory to start the app since you haven't previously downloaded these files.";
|
||||
options = downloadExit;
|
||||
}
|
||||
|
||||
switch (SOptionPane.showOptionDialog(message, "", null, options)) {
|
||||
case 1:
|
||||
if (!canIgnoreDownload) {
|
||||
Forge.exit(true); //exit if can't ignore download
|
||||
}
|
||||
return;
|
||||
case 2:
|
||||
Forge.exit(true);
|
||||
return;
|
||||
}
|
||||
|
||||
//allow deletion on Android 10 or if using app-specific directory
|
||||
boolean allowDeletion = Forge.androidVersion < 30 || GuiBase.isUsingAppDirectory();
|
||||
String assetURL = isSnapshots ? snapsURL + "assets.zip" : releaseURL + Forge.CURRENT_VERSION + "/" + "assets.zip";
|
||||
new GuiDownloadZipService("", "resource files", assetURL,
|
||||
ForgeConstants.ASSETS_DIR, ForgeConstants.RES_DIR, splashScreen.getProgressBar(), allowDeletion).downloadAndUnzip();
|
||||
|
||||
if (allowDeletion)
|
||||
FSkinFont.deleteCachedFiles(); //delete cached font files in case any skin's .ttf file changed
|
||||
|
||||
//reload light version of skin after assets updated
|
||||
FThreads.invokeInEdtAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
FSkinFont.updateAll(); //update all fonts used by splash screen
|
||||
FSkin.loadLight(FSkin.getName(), splashScreen);
|
||||
}
|
||||
});
|
||||
|
||||
//save version string to file once assets finish downloading
|
||||
//so they don't need to be re-downloaded until you upgrade again
|
||||
FileUtil.writeFile(versionFile, Forge.CURRENT_VERSION);
|
||||
|
||||
//add restart after assets update
|
||||
String msg = allowDeletion ? "Resource update finished..." : "Forge misses some files for deletion.\nIf you encounter issues, try deleting the Forge/res folder and/or deleting Forge/cache/fonts folder and try to download and update the assets.";
|
||||
switch (SOptionPane.showOptionDialog(msg, "", null, ImmutableList.of("Restart"))) {
|
||||
default:
|
||||
Forge.restart(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,391 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright 2011 See AUTHORS file.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.PixmapIO;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont.BitmapFontData;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont.Glyph;
|
||||
import com.badlogic.gdx.graphics.g2d.PixmapPacker.Page;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
/**
|
||||
* This file is 'borrowed' from gdx-tools in the libgdx source
|
||||
*/
|
||||
|
||||
/** A utility to output BitmapFontData to a FNT file. This can be useful for caching the result from TrueTypeFont, for faster load
|
||||
* times.
|
||||
* <p>
|
||||
* The font file format is from the AngelCodeFont BMFont tool.
|
||||
* <p>
|
||||
* Output is nearly identical to the FreeType settting in the Hiero tool {@Link com.badlogic.gdx.tools.hiero.Hiero}. BitmapFontWriter gives more flexibility, eg
|
||||
* borders and shadows can be used. Hiero is able to avoid outputting the same glyph image more than once if multiple character
|
||||
* codes have the exact same glyph.
|
||||
* @author mattdesl AKA davedes */
|
||||
public class BitmapFontWriter {
|
||||
|
||||
/** The output format. */
|
||||
public enum OutputFormat {
|
||||
|
||||
/** AngelCodeFont text format */
|
||||
Text,
|
||||
/** AngelCodeFont XML format */
|
||||
XML
|
||||
}
|
||||
|
||||
/** The output format */
|
||||
private static OutputFormat format = OutputFormat.Text;
|
||||
|
||||
/** Sets the AngelCodeFont output format for subsequent writes; can be text (for LibGDX) or XML (for other engines, like
|
||||
* Pixi.js).
|
||||
*
|
||||
* @param fmt the output format to use */
|
||||
public static void setOutputFormat (OutputFormat fmt) {
|
||||
if (fmt == null) throw new NullPointerException("format cannot be null");
|
||||
format = fmt;
|
||||
}
|
||||
|
||||
/** Returns the currently used output format.
|
||||
* @return the output format */
|
||||
public static OutputFormat getOutputFormat () {
|
||||
return format;
|
||||
}
|
||||
|
||||
/** The Padding parameter for FontInfo. */
|
||||
public static class Padding {
|
||||
public int up, down, left, right;
|
||||
|
||||
public Padding () {
|
||||
}
|
||||
|
||||
public Padding (int up, int down, int left, int right) {
|
||||
this.up = up;
|
||||
this.down = down;
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
}
|
||||
|
||||
/** The spacing parameter for FontInfo. */
|
||||
public static class Spacing {
|
||||
public int horizontal, vertical;
|
||||
}
|
||||
|
||||
/** The font "info" line; everything except padding and override metrics are ignored by LibGDX's BitmapFont reader, it is otherwise just useful for
|
||||
* clean and organized output. */
|
||||
public static class FontInfo {
|
||||
/** Face name */
|
||||
public String face;
|
||||
/** Font size (pt) */
|
||||
public int size = 12;
|
||||
/** Whether the font is bold */
|
||||
public boolean bold;
|
||||
/** Whether the font is italic */
|
||||
public boolean italic;
|
||||
/** The charset; or null/empty for default */
|
||||
public String charset;
|
||||
/** Whether the font uses unicode glyphs */
|
||||
public boolean unicode = true;
|
||||
/** Stretch for height; default to 100% */
|
||||
public int stretchH = 100;
|
||||
/** Whether smoothing is applied */
|
||||
public boolean smooth = true;
|
||||
/** Amount of anti-aliasing that was applied to the font */
|
||||
public int aa = 2;
|
||||
/** Padding that was applied to the font */
|
||||
public Padding padding = new Padding();
|
||||
/** Horizontal/vertical spacing that was applied to font */
|
||||
public Spacing spacing = new Spacing();
|
||||
public int outline = 0;
|
||||
|
||||
/** Override metrics */
|
||||
public boolean hasOverrideMetrics;
|
||||
public float ascent;
|
||||
public float descent;
|
||||
public float down;
|
||||
public float capHeight;
|
||||
public float lineHeight;
|
||||
public float spaceXAdvance;
|
||||
public float xHeight;
|
||||
|
||||
public FontInfo () {
|
||||
}
|
||||
|
||||
public FontInfo (String face, int size) {
|
||||
this.face = face;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public void overrideMetrics (BitmapFontData data) {
|
||||
hasOverrideMetrics = true;
|
||||
ascent = data.ascent;
|
||||
descent = data.descent;
|
||||
down = data.down;
|
||||
capHeight = data.capHeight;
|
||||
lineHeight = data.lineHeight;
|
||||
spaceXAdvance = data.spaceXadvance;
|
||||
xHeight = data.xHeight;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static String quote (Object params) {
|
||||
return quote(params, false);
|
||||
}
|
||||
|
||||
private static String quote (Object params, boolean spaceAfter) {
|
||||
if (BitmapFontWriter.getOutputFormat() == OutputFormat.XML)
|
||||
return "\"" + params.toString().trim() + "\"" + (spaceAfter ? " " : "");
|
||||
else
|
||||
return params.toString();
|
||||
}
|
||||
|
||||
/** Writes the given BitmapFontData to a file, using the specified <tt>pageRefs</tt> strings as the image paths for each
|
||||
* texture page. The glyphs in BitmapFontData have a "page" id, which references the index of the pageRef you specify here.
|
||||
*
|
||||
* The FontInfo parameter is useful for cleaner output; such as including a size and font face name hint. However, it can be
|
||||
* null to use default values. LibGDX ignores most of the "info" line when reading back fonts, only padding is used. Padding
|
||||
* also affects the size, location, and offset of the glyphs that are output.
|
||||
*
|
||||
* Likewise, the scaleW and scaleH are only for cleaner output. They are currently ignored by LibGDX's reader. For maximum
|
||||
* compatibility with other BMFont tools, you should use the width and height of your texture pages (each page should be the
|
||||
* same size).
|
||||
*
|
||||
* @param fontData the bitmap font
|
||||
* @param pageRefs the references to each texture page image file, generally in the same folder as outFntFile
|
||||
* @param outFntFile the font file to save to (typically ends with '.fnt')
|
||||
* @param info the optional info for the file header; can be null
|
||||
* @param scaleW the width of your texture pages
|
||||
* @param scaleH the height of your texture pages */
|
||||
public static void writeFont (BitmapFontData fontData, String[] pageRefs, FileHandle outFntFile, FontInfo info, int scaleW,
|
||||
int scaleH) {
|
||||
if (info == null) {
|
||||
info = new FontInfo();
|
||||
info.face = outFntFile.nameWithoutExtension();
|
||||
}
|
||||
|
||||
int lineHeight = (int)fontData.lineHeight;
|
||||
int pages = pageRefs.length;
|
||||
int packed = 0;
|
||||
int base = (int)((fontData.capHeight) + (fontData.flipped ? -fontData.ascent : fontData.ascent));
|
||||
OutputFormat fmt = BitmapFontWriter.getOutputFormat();
|
||||
boolean xml = fmt == OutputFormat.XML;
|
||||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
if (xml) {
|
||||
buf.append("<font>\n");
|
||||
}
|
||||
String xmlOpen = xml ? "\t<" : "";
|
||||
String xmlCloseSelf = xml ? "/>" : "";
|
||||
String xmlTab = xml ? "\t" : "";
|
||||
String xmlClose = xml ? ">" : "";
|
||||
|
||||
String xmlQuote = xml ? "\"" : "";
|
||||
String alphaChnlParams = xml ? " alphaChnl=\"0\" redChnl=\"0\" greenChnl=\"0\" blueChnl=\"0\""
|
||||
: " alphaChnl=0 redChnl=0 greenChnl=0 blueChnl=0";
|
||||
|
||||
// INFO LINE
|
||||
buf.append(xmlOpen).append("info face=\"").append(info.face == null ? "" : TextUtil.fastReplace(info.face,"\"", "'"))
|
||||
.append("\" size=").append(quote(info.size)).append(" bold=").append(quote(info.bold ? 1 : 0)).append(" italic=")
|
||||
.append(quote(info.italic ? 1 : 0)).append(" charset=\"").append(info.charset == null ? "" : info.charset)
|
||||
.append("\" unicode=").append(quote(info.unicode ? 1 : 0)).append(" stretchH=").append(quote(info.stretchH))
|
||||
.append(" smooth=").append(quote(info.smooth ? 1 : 0)).append(" aa=").append(quote(info.aa)).append(" padding=")
|
||||
.append(xmlQuote).append(info.padding.up).append(",").append(info.padding.right).append(",").append(info.padding.down)
|
||||
.append(",").append(info.padding.left).append(xmlQuote).append(" spacing=").append(xmlQuote)
|
||||
.append(info.spacing.horizontal).append(",").append(info.spacing.vertical).append(xmlQuote).append(xmlCloseSelf)
|
||||
.append("\n");
|
||||
|
||||
// COMMON line
|
||||
buf.append(xmlOpen).append("common lineHeight=").append(quote(lineHeight)).append(" base=").append(quote(base))
|
||||
.append(" scaleW=").append(quote(scaleW)).append(" scaleH=").append(quote(scaleH)).append(" pages=").append(quote(pages))
|
||||
.append(" packed=").append(quote(packed)).append(alphaChnlParams).append(xmlCloseSelf).append("\n");
|
||||
|
||||
if (xml) buf.append("\t<pages>\n");
|
||||
|
||||
// PAGES
|
||||
for (int i = 0; i < pageRefs.length; i++) {
|
||||
buf.append(xmlTab).append(xmlOpen).append("page id=").append(quote(i)).append(" file=\"").append(pageRefs[i])
|
||||
.append("\"").append(xmlCloseSelf).append("\n");
|
||||
}
|
||||
|
||||
if (xml) buf.append("\t</pages>\n");
|
||||
|
||||
// CHARS
|
||||
Array<Glyph> glyphs = new Array<Glyph>(256);
|
||||
for (int i = 0; i < fontData.glyphs.length; i++) {
|
||||
if (fontData.glyphs[i] == null) continue;
|
||||
|
||||
for (int j = 0; j < fontData.glyphs[i].length; j++) {
|
||||
if (fontData.glyphs[i][j] != null) {
|
||||
glyphs.add(fontData.glyphs[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf.append(xmlOpen).append("chars count=").append(quote(glyphs.size)).append(xmlClose).append("\n");
|
||||
|
||||
int padLeft = 0, padRight = 0, padTop = 0, padX = 0, padY = 0;
|
||||
if (info != null) {
|
||||
padTop = info.padding.up;
|
||||
padLeft = info.padding.left;
|
||||
padRight = info.padding.right;
|
||||
padX = padLeft + padRight;
|
||||
padY = info.padding.up + info.padding.down;
|
||||
}
|
||||
|
||||
// CHAR definitions
|
||||
for (int i = 0; i < glyphs.size; i++) {
|
||||
Glyph g = glyphs.get(i);
|
||||
boolean empty = g.width == 0 || g.height == 0;
|
||||
buf.append(xmlTab).append(xmlOpen).append("char id=").append(quote(String.format("%-6s", g.id), true)).append("x=")
|
||||
.append(quote(String.format("%-5s", empty ? 0 : g.srcX), true)).append("y=")
|
||||
.append(quote(String.format("%-5s", empty ? 0 : g.srcY), true)).append("width=")
|
||||
.append(quote(String.format("%-5s", empty ? 0 : g.width), true)).append("height=")
|
||||
.append(quote(String.format("%-5s", empty ? 0 : g.height), true)).append("xoffset=")
|
||||
.append(quote(String.format("%-5s", g.xoffset - padLeft), true)).append("yoffset=")
|
||||
.append(quote(String.format("%-5s", fontData.flipped ? g.yoffset + padTop : -(g.height + (g.yoffset + padTop))), true))
|
||||
.append("xadvance=").append(quote(String.format("%-5s", g.xadvance), true)).append("page=")
|
||||
.append(quote(String.format("%-5s", g.page), true)).append("chnl=").append(quote(0, true)).append(xmlCloseSelf)
|
||||
.append("\n");
|
||||
}
|
||||
|
||||
if (xml) buf.append("\t</chars>\n");
|
||||
|
||||
// KERNINGS
|
||||
int kernCount = 0;
|
||||
StringBuilder kernBuf = new StringBuilder();
|
||||
for (int i = 0; i < glyphs.size; i++) {
|
||||
for (int j = 0; j < glyphs.size; j++) {
|
||||
Glyph first = glyphs.get(i);
|
||||
Glyph second = glyphs.get(j);
|
||||
int kern = first.getKerning((char)second.id);
|
||||
if (kern != 0) {
|
||||
kernCount++;
|
||||
kernBuf.append(xmlTab).append(xmlOpen).append("kerning first=").append(quote(first.id)).append(" second=")
|
||||
.append(quote(second.id)).append(" amount=").append(quote(kern, true)).append(xmlCloseSelf).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// KERN info
|
||||
buf.append(xmlOpen).append("kernings count=").append(quote(kernCount)).append(xmlClose).append("\n");
|
||||
buf.append(kernBuf);
|
||||
|
||||
if (xml) {
|
||||
buf.append("\t</kernings>\n");
|
||||
}
|
||||
|
||||
// Override metrics
|
||||
if (info.hasOverrideMetrics) {
|
||||
if (xml) buf.append("\t<metrics>\n");
|
||||
|
||||
buf.append(xmlTab).append(xmlOpen)
|
||||
.append("metrics ascent=").append(quote(info.ascent, true))
|
||||
.append(" descent=").append(quote(info.descent, true))
|
||||
.append(" down=").append(quote(info.down, true))
|
||||
.append(" capHeight=").append(quote(info.capHeight, true))
|
||||
.append(" lineHeight=").append(quote(info.lineHeight, true))
|
||||
.append(" spaceXAdvance=").append(quote(info.spaceXAdvance, true))
|
||||
.append(" xHeight=").append(quote(info.xHeight, true))
|
||||
.append(xmlCloseSelf).append("\n");
|
||||
|
||||
if (xml) buf.append("\t</metrics>\n");
|
||||
}
|
||||
|
||||
if (xml) {
|
||||
buf.append("</font>");
|
||||
}
|
||||
|
||||
String charset = info.charset;
|
||||
if (charset != null && charset.length() == 0) charset = null;
|
||||
|
||||
outFntFile.writeString(buf.toString(), false, charset);
|
||||
}
|
||||
|
||||
/** A utility method which writes the given font data to a file.
|
||||
*
|
||||
* The specified pixmaps are written to the parent directory of <tt>outFntFile</tt>, using that file's name without an
|
||||
* extension for the PNG file name(s).
|
||||
*
|
||||
* The specified FontInfo is optional, and can be null.
|
||||
*
|
||||
* Typical usage looks like this:
|
||||
*
|
||||
* <pre>
|
||||
* BitmapFontWriter.writeFont(myFontData, myFontPixmaps, Gdx.files.external("fonts/output.fnt"), new FontInfo("Arial", 16));
|
||||
* </pre>
|
||||
*
|
||||
* @param fontData the font data
|
||||
* @param pages the pixmaps to write as PNGs
|
||||
* @param outFntFile the output file for the font definition
|
||||
* @param info the optional font info for the header file, can be null */
|
||||
public static void writeFont (BitmapFontData fontData, Pixmap[] pages, FileHandle outFntFile, FontInfo info) {
|
||||
String[] pageRefs = writePixmaps(pages, outFntFile.parent(), outFntFile.nameWithoutExtension());
|
||||
|
||||
// write the font data
|
||||
writeFont(fontData, pageRefs, outFntFile, info, pages[0].getWidth(), pages[0].getHeight());
|
||||
}
|
||||
|
||||
/** A utility method to write the given array of pixmaps to the given output directory, with the specified file name. If the
|
||||
* pages array is of length 1, then the resulting file ref will look like: "fileName.png".
|
||||
*
|
||||
* If the pages array is greater than length 1, the resulting file refs will be appended with "_N", such as "fileName_0.png",
|
||||
* "fileName_1.png", "fileName_2.png" etc.
|
||||
*
|
||||
* The returned string array can then be passed to the <tt>writeFont</tt> method.
|
||||
*
|
||||
* Note: None of the pixmaps will be disposed.
|
||||
*
|
||||
* @param pages the pages of pixmap data to write
|
||||
* @param outputDir the output directory
|
||||
* @param fileName the file names for the output images
|
||||
* @return the array of string references to be used with <tt>writeFont</tt> */
|
||||
public static String[] writePixmaps (Pixmap[] pages, FileHandle outputDir, String fileName) {
|
||||
if (pages == null || pages.length == 0) throw new IllegalArgumentException("no pixmaps supplied to BitmapFontWriter.write");
|
||||
|
||||
String[] pageRefs = new String[pages.length];
|
||||
|
||||
for (int i = 0; i < pages.length; i++) {
|
||||
String ref = pages.length == 1 ? (fileName + ".png") : (fileName + "_" + i + ".png");
|
||||
|
||||
// the ref for this image
|
||||
pageRefs[i] = ref;
|
||||
|
||||
// write the PNG in that directory
|
||||
PixmapIO.writePNG(outputDir.child(ref), pages[i]);
|
||||
}
|
||||
return pageRefs;
|
||||
}
|
||||
|
||||
/** A convenience method to write pixmaps by page; typically returned from a PixmapPacker when used alongside
|
||||
* FreeTypeFontGenerator.
|
||||
*
|
||||
* @param pages the pages containing the Pixmaps
|
||||
* @param outputDir the output directory
|
||||
* @param fileName the file name
|
||||
* @return the file refs */
|
||||
public static String[] writePixmaps (Array<Page> pages, FileHandle outputDir, String fileName) {
|
||||
Pixmap[] pix = new Pixmap[pages.size];
|
||||
for (int i = 0; i < pages.size; i++) {
|
||||
pix[i] = pages.get(i).getPixmap();
|
||||
}
|
||||
return writePixmaps(pix, outputDir, fileName);
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.Pixmap.Format;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
|
||||
import com.badlogic.gdx.math.Matrix4;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.gui.FThreads;
|
||||
|
||||
//Special graphics object for rendering to a texture
|
||||
public abstract class FBufferedImage extends FImageComplex {
|
||||
private final float width, height, opacity;
|
||||
private FrameBuffer frameBuffer;
|
||||
|
||||
public FBufferedImage(float width0, float height0) {
|
||||
this(width0, height0, 1);
|
||||
}
|
||||
public FBufferedImage(float width0, float height0, float opacity0) {
|
||||
width = width0;
|
||||
height = height0;
|
||||
opacity = opacity0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegionX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegionY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Texture getTexture() {
|
||||
if (frameBuffer == null) {
|
||||
Gdx.gl.glDisable(GL20.GL_SCISSOR_TEST); //prevent buffered image being clipped
|
||||
|
||||
//render texture to frame buffer if needed
|
||||
frameBuffer = new FrameBuffer(Format.RGBA8888, (int)width, (int)height, false);
|
||||
frameBuffer.begin();
|
||||
|
||||
//frame graphics must be given a projection matrix
|
||||
//so stuff is rendered properly to custom sized frame buffer
|
||||
Graphics frameGraphics = new Graphics();
|
||||
Matrix4 matrix = new Matrix4();
|
||||
matrix.setToOrtho2D(0, 0, width, height);
|
||||
frameGraphics.setProjectionMatrix(matrix);
|
||||
|
||||
frameGraphics.begin(width, height);
|
||||
draw(frameGraphics, width, height);
|
||||
frameGraphics.end();
|
||||
|
||||
frameBuffer.end();
|
||||
frameGraphics.dispose();
|
||||
|
||||
Gdx.gl.glEnable(GL20.GL_SCISSOR_TEST);
|
||||
}
|
||||
return frameBuffer.getColorBufferTexture();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
final FrameBuffer fb = frameBuffer;
|
||||
if (fb != null) {
|
||||
frameBuffer = null;
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fb.dispose(); //must be disposed on EDT thread
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void draw(Graphics g, float w, float h);
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
if (opacity < 1) {
|
||||
g.setAlphaComposite(opacity);
|
||||
}
|
||||
g.drawFlippedImage(getTexture(), x, y, w, h); //need to draw image flipped because of how FrameBuffer works
|
||||
if (opacity < 1) {
|
||||
g.resetAlphaComposite();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
|
||||
//Special wrapper for a texture to be loaded later when it's needed
|
||||
public class FDelayLoadImage extends FImageComplex {
|
||||
private final String filename;
|
||||
private Texture texture;
|
||||
|
||||
public FDelayLoadImage(String filename0) {
|
||||
filename = filename0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidth() {
|
||||
return getTexture().getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHeight() {
|
||||
return getTexture().getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Texture getTexture() {
|
||||
if (texture == null) {
|
||||
texture = new Texture(Gdx.files.absolute(filename));
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegionX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegionY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
g.drawImage(getTexture(), x, y, w, h);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.localinstance.skin.ISkinImage;
|
||||
|
||||
public interface FImage extends ISkinImage {
|
||||
float getWidth();
|
||||
float getHeight();
|
||||
void draw(Graphics g, float x, float y, float w, float h);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
|
||||
public abstract class FImageComplex implements FImage {
|
||||
public abstract Texture getTexture();
|
||||
public abstract int getRegionX();
|
||||
public abstract int getRegionY();
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.localinstance.properties.ForgePreferences.FPref;
|
||||
import forge.model.FModel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FLanguage {
|
||||
|
||||
public static void changeLanguage(final String languageName) {
|
||||
final ForgePreferences prefs = FModel.getPreferences();
|
||||
if (languageName.equals(prefs.getPref(FPref.UI_LANGUAGE))) { return; }
|
||||
|
||||
//save language preference
|
||||
prefs.setPref(FPref.UI_LANGUAGE, languageName);
|
||||
prefs.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the languages.
|
||||
*
|
||||
* @return the languages
|
||||
*/
|
||||
public static Iterable<String> getAllLanguages() {
|
||||
final List<String> allLanguages = new ArrayList<>();
|
||||
|
||||
final FileHandle dir = Gdx.files.absolute(ForgeConstants.LANG_DIR);
|
||||
for (FileHandle languageFile : dir.list()) {
|
||||
String languageName = languageFile.name();
|
||||
if (!languageName.endsWith(".properties")) { continue; }
|
||||
allLanguages.add(languageName.replace(".properties", ""));
|
||||
}
|
||||
|
||||
return allLanguages;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
|
||||
public class FRotatedImage extends FImageComplex {
|
||||
private final Texture texture;
|
||||
private final int srcX, srcY, srcWidth, srcHeight;
|
||||
private final boolean clockwise;
|
||||
|
||||
public FRotatedImage(Texture texture0, int srcX0, int srcY0, int srcWidth0, int srcHeight0, boolean clockwise0) {
|
||||
texture = texture0;
|
||||
srcX = srcX0;
|
||||
srcY = srcY0;
|
||||
srcWidth = srcWidth0;
|
||||
srcHeight = srcHeight0;
|
||||
clockwise = clockwise0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidth() {
|
||||
return srcHeight; //width and height are swapped since image rotated
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHeight() {
|
||||
return srcWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Texture getTexture() {
|
||||
return texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegionX() {
|
||||
return srcX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegionY() {
|
||||
return srcY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
float originX, originY, rotation;
|
||||
if (clockwise) {
|
||||
originX = x + w / 2;
|
||||
originY = y + w / 2;
|
||||
rotation = -90;
|
||||
}
|
||||
else {
|
||||
originX = x + h / 2;
|
||||
originY = y + h / 2;
|
||||
rotation = 90;
|
||||
}
|
||||
g.drawRotatedImage(texture, x, y, h, w, originX, originY, srcX, srcY, srcWidth, srcHeight, rotation);
|
||||
}
|
||||
}
|
||||
@@ -1,475 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
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.TextureRegion;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.assets.FSkinImage.SourceFile;
|
||||
import forge.adventure.libgdxgui.card.CardFaceSymbols;
|
||||
import forge.adventure.util.Config;
|
||||
import forge.gui.FThreads;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.localinstance.properties.ForgePreferences.FPref;
|
||||
import forge.localinstance.skin.FSkinProp;
|
||||
import forge.model.FModel;
|
||||
import forge.adventure.libgdxgui.screens.LoadingOverlay;
|
||||
import forge.adventure.libgdxgui.screens.SplashScreen;
|
||||
import forge.adventure.libgdxgui.toolbox.FProgressBar;
|
||||
import forge.util.WordUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class FSkin {
|
||||
private static final Map<FSkinProp, FSkinImage> images = new HashMap<>(512);
|
||||
private static final Map<Integer, TextureRegion> avatars = new HashMap<>(150);
|
||||
private static final Map<Integer, TextureRegion> sleeves = new HashMap<>(64);
|
||||
private static final Map<Integer, TextureRegion> borders = new HashMap<>();
|
||||
private static final Map<Integer, TextureRegion> deckbox = new HashMap<>();
|
||||
|
||||
private static Array<String> allSkins;
|
||||
private static FileHandle preferredDir;
|
||||
private static String preferredName;
|
||||
private static boolean loaded = false;
|
||||
public static Texture hdLogo = null;
|
||||
|
||||
public static void changeSkin(final String skinName) {
|
||||
final ForgePreferences prefs = FModel.getPreferences();
|
||||
if (skinName.equals(prefs.getPref(FPref.UI_SKIN))) { return; }
|
||||
|
||||
//save skin preference
|
||||
prefs.setPref(FPref.UI_SKIN, skinName);
|
||||
prefs.save();
|
||||
|
||||
//load skin
|
||||
loaded = false; //reset this temporarily until end of loadFull()
|
||||
|
||||
final LoadingOverlay loader = new LoadingOverlay("Loading new theme...");
|
||||
loader.show(); //show loading overlay then delay running remaining logic so UI can respond
|
||||
FThreads.invokeInBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
FThreads.invokeInEdtLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
loadLight(skinName, null);
|
||||
loadFull(null);
|
||||
loader.setCaption("Loading fonts...");
|
||||
FThreads.invokeInBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
FSkinFont.deleteCachedFiles(); //delete cached font files so font can be update for new skin
|
||||
FSkinFont.updateAll();
|
||||
//CardImageRenderer.forceStaticFieldUpdate();
|
||||
FThreads.invokeInEdtLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
loader.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads a "light" version of FSkin, just enough for the splash screen:
|
||||
* skin name. Generates custom skin settings, fonts, and backgrounds.
|
||||
*
|
||||
*
|
||||
* @param skinName
|
||||
* the skin name
|
||||
*/
|
||||
public static void loadLight(String skinName, final SplashScreen splashScreen) {
|
||||
preferredName = skinName.toLowerCase().replace(' ', '_');
|
||||
|
||||
//reset hd buttons/icons
|
||||
Forge.hdbuttons = false;
|
||||
Forge.hdstart = false;
|
||||
preferredDir = Config.instance().getFile("skin");
|
||||
|
||||
FSkinTexture.BG_TEXTURE.load(); //load background texture early for splash screen
|
||||
|
||||
if (splashScreen != null) {
|
||||
final FileHandle f = getSkinFile("bg_splash.png");
|
||||
final FileHandle f2 = getSkinFile("bg_splash_hd.png"); //HD Splashscreen
|
||||
final FileHandle f3 = getSkinFile("hd_logo.png");
|
||||
|
||||
if (!f.exists()) {
|
||||
if (!skinName.equals("default")) {
|
||||
FSkin.loadLight("default", splashScreen);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Texture txSplash = new Texture(f);
|
||||
final int w = txSplash.getWidth();
|
||||
final int h = txSplash.getHeight();
|
||||
|
||||
if (f2.exists()) {
|
||||
Texture txSplashHD = new Texture(f2, true);
|
||||
txSplashHD.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
splashScreen.setBackground(new TextureRegion(txSplashHD));
|
||||
} else {
|
||||
splashScreen.setBackground(new TextureRegion(txSplash, 0, 0, w, h - 100));
|
||||
}
|
||||
|
||||
if (f3.exists()) {
|
||||
Texture txOverlay = new Texture(f3, true);
|
||||
txOverlay.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
hdLogo = txOverlay;
|
||||
} else {
|
||||
hdLogo = null;
|
||||
}
|
||||
|
||||
Pixmap pxSplash = new Pixmap(f);
|
||||
FProgressBar.BACK_COLOR = new Color(pxSplash.getPixel(25, h - 75));
|
||||
FProgressBar.FORE_COLOR = new Color(pxSplash.getPixel(75, h - 75));
|
||||
FProgressBar.SEL_BACK_COLOR = new Color(pxSplash.getPixel(25, h - 25));
|
||||
FProgressBar.SEL_FORE_COLOR = new Color(pxSplash.getPixel(75, h - 25));
|
||||
}
|
||||
catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads two sprites: the default (which should be a complete
|
||||
* collection of all symbols) and the preferred (which may be
|
||||
* incomplete).
|
||||
*
|
||||
* Font must be present in the skin folder, and will not
|
||||
* be replaced by default. The fonts are pre-derived
|
||||
* in this method and saved in a HashMap for future access.
|
||||
*
|
||||
* Color swatches must be present in the preferred
|
||||
* sprite, and will not be replaced by default.
|
||||
*
|
||||
* Background images must be present in skin folder,
|
||||
* and will not be replaced by default.
|
||||
*
|
||||
* Icons, however, will be pulled from the two sprites. Obviously,
|
||||
* preferred takes precedence over default, but if something is
|
||||
* missing, the default picture is retrieved.
|
||||
*/
|
||||
public static void loadFull(final SplashScreen splashScreen) {
|
||||
if (splashScreen != null) {
|
||||
// Preferred skin name must be called via loadLight() method,
|
||||
// which does some cleanup and init work.
|
||||
if (FSkin.preferredName.isEmpty()) { FSkin.loadLight("default", splashScreen); }
|
||||
}
|
||||
|
||||
avatars.clear();
|
||||
sleeves.clear();
|
||||
|
||||
boolean textureFilter = Forge.isTextureFilteringEnabled();
|
||||
|
||||
final Map<String, Texture> textures = new HashMap<>();
|
||||
|
||||
// Grab and test various sprite files.
|
||||
final FileHandle f1 = getDefaultSkinFile(SourceFile.ICONS.getFilename());
|
||||
final FileHandle f2 = getSkinFile(SourceFile.ICONS.getFilename());
|
||||
final FileHandle f3 = getDefaultSkinFile(SourceFile.FOILS.getFilename());
|
||||
final FileHandle f4 = getDefaultSkinFile(ForgeConstants.SPRITE_AVATARS_FILE);
|
||||
final FileHandle f5 = getSkinFile(ForgeConstants.SPRITE_AVATARS_FILE);
|
||||
final FileHandle f6 = getDefaultSkinFile(SourceFile.OLD_FOILS.getFilename());
|
||||
final FileHandle f7 = getSkinFile(ForgeConstants.SPRITE_MANAICONS_FILE);
|
||||
final FileHandle f8 = getDefaultSkinFile(ForgeConstants.SPRITE_SLEEVES_FILE);
|
||||
final FileHandle f9 = getDefaultSkinFile(ForgeConstants.SPRITE_SLEEVES2_FILE);
|
||||
final FileHandle f10 = getDefaultSkinFile(ForgeConstants.SPRITE_BORDER_FILE);
|
||||
final FileHandle f11 = getSkinFile(ForgeConstants.SPRITE_BUTTONS_FILE);
|
||||
final FileHandle f12 = getSkinFile(ForgeConstants.SPRITE_START_FILE);
|
||||
final FileHandle f13 = getDefaultSkinFile(ForgeConstants.SPRITE_DECKBOX_FILE);
|
||||
|
||||
try {
|
||||
textures.put(f1.path(), new Texture(f1));
|
||||
Pixmap preferredIcons = new Pixmap(f1);
|
||||
if (f2.exists()) {
|
||||
textures.put(f2.path(), new Texture(f2));
|
||||
preferredIcons = new Pixmap(f2);
|
||||
}
|
||||
|
||||
textures.put(f3.path(), new Texture(f3));
|
||||
if (f6.exists()) {
|
||||
textures.put(f6.path(), new Texture(f6));
|
||||
}
|
||||
else {
|
||||
textures.put(f6.path(), textures.get(f3.path()));
|
||||
}
|
||||
if (f7.exists()){
|
||||
Texture t = new Texture(f7, true);
|
||||
//t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
textures.put(f7.path(), t);
|
||||
}
|
||||
|
||||
//hdbuttons
|
||||
if (f11.exists()) {
|
||||
if (GuiBase.isAndroid() && Forge.totalDeviceRAM <5000) {
|
||||
Forge.hdbuttons = false;
|
||||
} else {
|
||||
Texture t = new Texture(f11, true);
|
||||
t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
textures.put(f11.path(), t);
|
||||
Forge.hdbuttons = true;
|
||||
}
|
||||
} else { Forge.hdbuttons = false; } //how to refresh buttons when a theme don't have hd buttons?
|
||||
if (f12.exists()) {
|
||||
if (GuiBase.isAndroid() && Forge.totalDeviceRAM <5000) {
|
||||
Forge.hdstart = false;
|
||||
} else {
|
||||
Texture t = new Texture(f12, true);
|
||||
t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
textures.put(f12.path(), t);
|
||||
Forge.hdstart = true;
|
||||
}
|
||||
} else { Forge.hdstart = false; }
|
||||
//update colors
|
||||
for (final FSkinColor.Colors c : FSkinColor.Colors.values()) {
|
||||
c.setColor(new Color(preferredIcons.getPixel(c.getX(), c.getY())));
|
||||
}
|
||||
|
||||
//load images
|
||||
for (FSkinImage image : FSkinImage.values()) {
|
||||
if (GuiBase.isAndroid()) {
|
||||
if (Forge.totalDeviceRAM>5000)
|
||||
image.load(textures, preferredIcons);
|
||||
else if (image.toString().equals("HDMULTI"))
|
||||
image.load(textures, preferredIcons);
|
||||
else if (!image.toString().startsWith("HD"))
|
||||
image.load(textures, preferredIcons);
|
||||
} else {
|
||||
image.load(textures, preferredIcons);
|
||||
}
|
||||
}
|
||||
for (FSkinTexture texture : FSkinTexture.values()) {
|
||||
if (texture != FSkinTexture.BG_TEXTURE) {
|
||||
texture.load();
|
||||
}
|
||||
}
|
||||
|
||||
//assemble avatar textures
|
||||
int counter = 0;
|
||||
int scount = 0;
|
||||
Color pxTest;
|
||||
Pixmap pxDefaultAvatars, pxPreferredAvatars, pxDefaultSleeves;
|
||||
Texture txDefaultAvatars, txPreferredAvatars, txDefaultSleeves;
|
||||
|
||||
pxDefaultAvatars = new Pixmap(f4);
|
||||
pxDefaultSleeves = new Pixmap(f8);
|
||||
txDefaultAvatars = new Texture(f4, textureFilter);
|
||||
if (textureFilter)
|
||||
txDefaultAvatars.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
txDefaultSleeves = new Texture(f8, textureFilter);
|
||||
if (textureFilter)
|
||||
txDefaultSleeves.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
|
||||
if (f5.exists()) {
|
||||
pxPreferredAvatars = new Pixmap(f5);
|
||||
txPreferredAvatars = new Texture(f5, textureFilter);
|
||||
if (textureFilter)
|
||||
txPreferredAvatars.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
|
||||
final int pw = pxPreferredAvatars.getWidth();
|
||||
final int ph = pxPreferredAvatars.getHeight();
|
||||
|
||||
for (int j = 0; j < ph; j += 100) {
|
||||
for (int i = 0; i < pw; i += 100) {
|
||||
if (i == 0 && j == 0) { continue; }
|
||||
pxTest = new Color(pxPreferredAvatars.getPixel(i + 50, j + 50));
|
||||
if (pxTest.a == 0) { continue; }
|
||||
FSkin.avatars.put(counter++, new TextureRegion(txPreferredAvatars, i, j, 100, 100));
|
||||
}
|
||||
}
|
||||
pxPreferredAvatars.dispose();
|
||||
} else if (!FSkin.preferredName.isEmpty()){
|
||||
//workaround bug crash fix if missing sprite avatar on preferred theme for quest tournament...
|
||||
//i really don't know why it needs to populate the avatars twice.... needs investigation
|
||||
final int pw = pxDefaultAvatars.getWidth();
|
||||
final int ph = pxDefaultAvatars.getHeight();
|
||||
|
||||
for (int j = 0; j < ph; j += 100) {
|
||||
for (int i = 0; i < pw; i += 100) {
|
||||
if (i == 0 && j == 0) { continue; }
|
||||
pxTest = new Color(pxDefaultAvatars.getPixel(i + 50, j + 50));
|
||||
if (pxTest.a == 0) { continue; }
|
||||
FSkin.avatars.put(counter++, new TextureRegion(txDefaultAvatars, i, j, 100, 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final int aw = pxDefaultAvatars.getWidth();
|
||||
final int ah = pxDefaultAvatars.getHeight();
|
||||
|
||||
for (int j = 0; j < ah; j += 100) {
|
||||
for (int i = 0; i < aw; i += 100) {
|
||||
if (i == 0 && j == 0) { continue; }
|
||||
pxTest = new Color(pxDefaultAvatars.getPixel(i + 50, j + 50));
|
||||
if (pxTest.a == 0) { continue; }
|
||||
FSkin.avatars.put(counter++, new TextureRegion(txDefaultAvatars, i, j, 100, 100));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final int sw = pxDefaultSleeves.getWidth();
|
||||
final int sh = pxDefaultSleeves.getHeight();
|
||||
|
||||
for (int j = 0; j < sh; j += 500) {
|
||||
for (int i = 0; i < sw; i += 360) {
|
||||
pxTest = new Color(pxDefaultSleeves.getPixel(i + 180, j + 250));
|
||||
if (pxTest.a == 0) { continue; }
|
||||
FSkin.sleeves.put(scount++, new TextureRegion(txDefaultSleeves, i, j, 360, 500));
|
||||
}
|
||||
}
|
||||
|
||||
//re init second set of sleeves
|
||||
pxDefaultSleeves = new Pixmap(f9);
|
||||
txDefaultSleeves = new Texture(f9, textureFilter);
|
||||
if (textureFilter)
|
||||
txDefaultSleeves.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
|
||||
final int sw2 = pxDefaultSleeves.getWidth();
|
||||
final int sh2 = pxDefaultSleeves.getHeight();
|
||||
|
||||
for (int j = 0; j < sh2; j += 500) {
|
||||
for (int i = 0; i < sw2; i += 360) {
|
||||
pxTest = new Color(pxDefaultSleeves.getPixel(i + 180, j + 250));
|
||||
if (pxTest.a == 0) { continue; }
|
||||
FSkin.sleeves.put(scount++, new TextureRegion(txDefaultSleeves, i, j, 360, 500));
|
||||
}
|
||||
}
|
||||
//borders
|
||||
Texture bordersBW = new Texture(f10);
|
||||
FSkin.borders.put(0, new TextureRegion(bordersBW, 2, 2, 672, 936));
|
||||
FSkin.borders.put(1, new TextureRegion(bordersBW, 676, 2, 672, 936));
|
||||
//deckboxes
|
||||
Texture deckboxes = new Texture(f13, textureFilter);
|
||||
if (textureFilter)
|
||||
deckboxes.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
//gold bg
|
||||
FSkin.deckbox.put(0, new TextureRegion(deckboxes, 2, 2, 488, 680));
|
||||
//deck box for card art
|
||||
FSkin.deckbox.put(1, new TextureRegion(deckboxes, 492, 2, 488, 680));
|
||||
//generic deck box
|
||||
FSkin.deckbox.put(2, new TextureRegion(deckboxes, 982, 2, 488, 680));
|
||||
|
||||
preferredIcons.dispose();
|
||||
pxDefaultAvatars.dispose();
|
||||
pxDefaultSleeves.dispose();
|
||||
}
|
||||
catch (final Exception e) {
|
||||
System.err.println("FSkin$loadFull: Missing a sprite (default icons, "
|
||||
+ "preferred icons, or foils.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Run through enums and load their coords.
|
||||
FSkinColor.updateAll();
|
||||
|
||||
// Images loaded; can start UI init.
|
||||
loaded = true;
|
||||
|
||||
if (splashScreen != null) {
|
||||
CardFaceSymbols.loadImages();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name.
|
||||
*
|
||||
* @return Name of the current skin.
|
||||
*/
|
||||
public static String getName() {
|
||||
return FSkin.preferredName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a FileHandle for a file within the directory where skin files should be stored
|
||||
*/
|
||||
public static FileHandle getSkinFile(String filename) {
|
||||
return preferredDir.child(filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a FileHandle for a file within the directory where the default skin files should be stored
|
||||
*/
|
||||
public static FileHandle getDefaultSkinFile(String filename) {
|
||||
return Gdx.files.absolute(ForgeConstants.DEFAULT_SKINS_DIR + filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a FileHandle for a file within the planechase cache directory
|
||||
*/
|
||||
public static FileHandle getCachePlanechaseFile(String filename) {
|
||||
return Gdx.files.absolute(ForgeConstants.CACHE_PLANECHASE_PICS_DIR + filename);
|
||||
}
|
||||
|
||||
public static FileHandle getSkinDir() {
|
||||
return preferredDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the skins.
|
||||
*
|
||||
* @return the skins
|
||||
*/
|
||||
public static Array<String> getSkinDirectoryNames() {
|
||||
final Array<String> mySkins = new Array<>();
|
||||
|
||||
final FileHandle dir = Gdx.files.absolute(ForgeConstants.CACHE_SKINS_DIR);
|
||||
for (FileHandle skinFile : dir.list()) {
|
||||
String skinName = skinFile.name();
|
||||
if (skinName.equalsIgnoreCase(".svn")) { continue; }
|
||||
if (skinName.equalsIgnoreCase(".DS_Store")) { continue; }
|
||||
mySkins.add(skinName);
|
||||
}
|
||||
|
||||
return mySkins;
|
||||
}
|
||||
|
||||
public static Iterable<String> getAllSkins() {
|
||||
if (allSkins != null) {
|
||||
allSkins.clear();
|
||||
allSkins.add("Default"); //init default
|
||||
final Array<String> skinDirectoryNames = getSkinDirectoryNames();
|
||||
for (final String skinDirectoryName : skinDirectoryNames) {
|
||||
allSkins.add(WordUtil.capitalize(skinDirectoryName.replace('_', ' ')));
|
||||
}
|
||||
allSkins.sort();
|
||||
}
|
||||
return allSkins;
|
||||
}
|
||||
|
||||
public static Map<FSkinProp, FSkinImage> getImages() {
|
||||
return images;
|
||||
}
|
||||
|
||||
public static Map<Integer, TextureRegion> getAvatars() {
|
||||
return avatars;
|
||||
}
|
||||
|
||||
public static Map<Integer, TextureRegion> getSleeves() {
|
||||
return sleeves;
|
||||
}
|
||||
|
||||
public static Map<Integer, TextureRegion> getBorders() {
|
||||
return borders;
|
||||
}
|
||||
|
||||
public static Map<Integer, TextureRegion> getDeckbox() {
|
||||
return deckbox;
|
||||
}
|
||||
|
||||
public static boolean isLoaded() { return loaded; }
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
|
||||
public class FSkinBorder {
|
||||
private final FSkinColor color;
|
||||
private final float thickness;
|
||||
|
||||
public FSkinBorder(FSkinColor color0, float thickness0) {
|
||||
color = color0;
|
||||
thickness = thickness0;
|
||||
}
|
||||
|
||||
public FSkinColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public float getThickness() {
|
||||
return thickness;
|
||||
}
|
||||
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
x -= thickness;
|
||||
y -= thickness;
|
||||
w += 2 * thickness;
|
||||
h += 2 * thickness;
|
||||
g.fillRect(color, x, y, w, h); //draw filled rectangle behind object
|
||||
}
|
||||
}
|
||||
@@ -1,268 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import forge.localinstance.skin.FSkinProp;
|
||||
import forge.adventure.libgdxgui.screens.match.TargetingOverlay;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class FSkinColor {
|
||||
public enum Colors {
|
||||
CLR_THEME (FSkinProp.CLR_THEME),
|
||||
CLR_BORDERS (FSkinProp.CLR_BORDERS),
|
||||
CLR_ZEBRA (FSkinProp.CLR_ZEBRA),
|
||||
CLR_HOVER (FSkinProp.CLR_HOVER),
|
||||
CLR_ACTIVE (FSkinProp.CLR_ACTIVE),
|
||||
CLR_INACTIVE (FSkinProp.CLR_INACTIVE),
|
||||
CLR_TEXT (FSkinProp.CLR_TEXT),
|
||||
CLR_PHASE_INACTIVE_ENABLED (FSkinProp.CLR_PHASE_INACTIVE_ENABLED),
|
||||
CLR_PHASE_INACTIVE_DISABLED (FSkinProp.CLR_PHASE_INACTIVE_DISABLED),
|
||||
CLR_PHASE_ACTIVE_ENABLED (FSkinProp.CLR_PHASE_ACTIVE_ENABLED),
|
||||
CLR_PHASE_ACTIVE_DISABLED (FSkinProp.CLR_PHASE_ACTIVE_DISABLED),
|
||||
CLR_THEME2 (FSkinProp.CLR_THEME2),
|
||||
CLR_OVERLAY (FSkinProp.CLR_OVERLAY),
|
||||
CLR_COMBAT_TARGETING_ARROW (FSkinProp.CLR_COMBAT_TARGETING_ARROW),
|
||||
CLR_NORMAL_TARGETING_ARROW (FSkinProp.CLR_NORMAL_TARGETING_ARROW),
|
||||
CLR_PWATTK_TARGETING_ARROW (FSkinProp.CLR_PWATTK_TARGETING_ARROW);
|
||||
|
||||
private Color color;
|
||||
private final int x, y;
|
||||
private final FSkinProp skinProp;
|
||||
|
||||
Colors(final FSkinProp skinProp0) {
|
||||
skinProp = skinProp0;
|
||||
int[] coords = skinProp.getCoords();
|
||||
x = coords[0];
|
||||
y = coords[1];
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setColor(Color color0) {
|
||||
color = color0;
|
||||
}
|
||||
|
||||
public static Colors fromSkinProp(FSkinProp skinProp) {
|
||||
for (final Colors c : Colors.values()) {
|
||||
if (c.skinProp == skinProp) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static FSkinColor get(final Colors c0) {
|
||||
return baseColors.get(c0);
|
||||
}
|
||||
|
||||
public static FSkinColor getStandardColor(int r, int g, int b) {
|
||||
return getStandardColor(fromRGB(r, g, b));
|
||||
}
|
||||
public static FSkinColor getStandardColor(final Color c0) {
|
||||
return new FSkinColor(c0, NO_BRIGHTNESS_DELTA, NO_STEP, NO_STEP, NO_ALPHA);
|
||||
}
|
||||
|
||||
private static final HashMap<Colors, FSkinColor> baseColors = new HashMap<>();
|
||||
private static final HashMap<String, FSkinColor> derivedColors = new HashMap<>();
|
||||
private static final int NO_BRIGHTNESS_DELTA = 0;
|
||||
private static final int NO_STEP = -999; //needs to be large negative since small negative values are valid
|
||||
private static final int NO_ALPHA = -1;
|
||||
|
||||
private final Colors baseColor;
|
||||
private final int brightnessDelta;
|
||||
private final int step;
|
||||
private final int contrastStep;
|
||||
private final float alpha;
|
||||
protected Color color;
|
||||
|
||||
public Color getColor() { return color; }
|
||||
|
||||
private FSkinColor(Colors baseColor0) {
|
||||
this(baseColor0, NO_BRIGHTNESS_DELTA, NO_STEP, NO_STEP, NO_ALPHA);
|
||||
}
|
||||
private FSkinColor(Colors baseColor0, int brightnessDelta0, int step0, int contrastStep0, float alpha0) {
|
||||
baseColor = baseColor0;
|
||||
brightnessDelta = brightnessDelta0;
|
||||
step = step0;
|
||||
contrastStep = contrastStep0;
|
||||
alpha = alpha0;
|
||||
updateColor();
|
||||
}
|
||||
private FSkinColor(Color color0, int brightnessDelta0, int step0, int contrastStep0, float alpha0) {
|
||||
color = color0;
|
||||
baseColor = null;
|
||||
brightnessDelta = brightnessDelta0;
|
||||
step = step0;
|
||||
contrastStep = contrastStep0;
|
||||
alpha = alpha0;
|
||||
updateColor();
|
||||
}
|
||||
|
||||
private FSkinColor getDerivedColor(int brightnessDelta0, int step0, int contrastStep0, float alpha0) {
|
||||
if (baseColor == null) { //handle deriving from standard color
|
||||
return new FSkinColor(color, brightnessDelta0, step0, contrastStep0, alpha0);
|
||||
}
|
||||
String key = baseColor.name() + "|" + brightnessDelta0 + "|" + step0 + "|" + contrastStep0 + "|" + alpha0;
|
||||
FSkinColor derivedColor = derivedColors.get(key);
|
||||
if (derivedColor == null) {
|
||||
derivedColor = new FSkinColor(baseColor, brightnessDelta0, step0, contrastStep0, alpha0);
|
||||
derivedColors.put(key, derivedColor);
|
||||
}
|
||||
return derivedColor;
|
||||
}
|
||||
|
||||
public FSkinColor brighter() {
|
||||
return getDerivedColor(brightnessDelta + 1, step, contrastStep, alpha);
|
||||
}
|
||||
|
||||
public FSkinColor darker() {
|
||||
return getDerivedColor(brightnessDelta - 1, step, contrastStep, alpha);
|
||||
}
|
||||
|
||||
public FSkinColor stepColor(int step0) {
|
||||
if (step != NO_STEP) {
|
||||
step0 += step;
|
||||
}
|
||||
return getDerivedColor(brightnessDelta, step0, contrastStep, alpha);
|
||||
}
|
||||
|
||||
public FSkinColor getContrastColor(int contrastStep0) {
|
||||
if (contrastStep != NO_STEP) {
|
||||
contrastStep0 += contrastStep;
|
||||
}
|
||||
return getDerivedColor(brightnessDelta, step, contrastStep0, alpha);
|
||||
}
|
||||
|
||||
public FSkinColor getHighContrastColor() {
|
||||
return getContrastColor(255);
|
||||
}
|
||||
|
||||
public FSkinColor alphaColor(float alpha0) {
|
||||
return getDerivedColor(brightnessDelta, step, contrastStep, alpha0);
|
||||
}
|
||||
|
||||
protected void updateColor() {
|
||||
if (baseColor != null) {
|
||||
color = baseColor.color;
|
||||
}
|
||||
if (brightnessDelta != NO_BRIGHTNESS_DELTA) {
|
||||
if (brightnessDelta < 0) {
|
||||
for (int i = 0; i > brightnessDelta; i--) {
|
||||
color = FSkinColor.stepColor(color, -20);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < brightnessDelta; i++) {
|
||||
color = FSkinColor.stepColor(color, 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (step != NO_STEP) {
|
||||
color = FSkinColor.stepColor(color, step);
|
||||
}
|
||||
if (contrastStep != NO_STEP) {
|
||||
color = FSkinColor.stepColor(color, FSkinColor.isColorBright(color) ? -contrastStep : contrastStep);
|
||||
}
|
||||
if (alpha != NO_ALPHA) {
|
||||
color = FSkinColor.alphaColor(color, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
/** Steps RGB components of a color up or down.
|
||||
* Returns opaque (non-alpha) stepped color.
|
||||
* Plus for lighter, minus for darker.
|
||||
*
|
||||
* @param clr0 {Color}
|
||||
* @param step int
|
||||
* @return {@link Color}
|
||||
*/
|
||||
public static Color stepColor(Color clr0, int step) {
|
||||
float r = clr0.r * 255;
|
||||
float g = clr0.g * 255;
|
||||
float b = clr0.b * 255;
|
||||
|
||||
// Darker
|
||||
if (step < 0) {
|
||||
r = ((r + step > 0) ? r + step : 0);
|
||||
g = ((g + step > 0) ? g + step : 0);
|
||||
b = ((b + step > 0) ? b + step : 0);
|
||||
}
|
||||
else {
|
||||
r = ((r + step < 255) ? r + step : 255);
|
||||
g = ((g + step < 255) ? g + step : 255);
|
||||
b = ((b + step < 255) ? b + step : 255);
|
||||
}
|
||||
|
||||
return new Color(r / 255, g / 255, b / 255, clr0.a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns RGB components of a color, with a new
|
||||
* value for alpha. 0f = transparent, 1f = opaque.
|
||||
*/
|
||||
public static Color alphaColor(Color clr0, float alpha) {
|
||||
return new Color(clr0.r, clr0.g, clr0.b, alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* see http://www.nbdtech.com/Blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx
|
||||
*/
|
||||
public static boolean isColorBright(Color c) {
|
||||
double v = Math.sqrt(
|
||||
c.r * c.r * 0.241 +
|
||||
c.g * c.g * 0.691 +
|
||||
c.b * c.b * 0.068);
|
||||
return v > 0.5;
|
||||
}
|
||||
|
||||
public static Color getHighContrastColor(Color c) {
|
||||
return isColorBright(c) ? Color.BLACK : Color.WHITE;
|
||||
}
|
||||
|
||||
public static Color tintColor(Color source, Color tint, float alpha) {
|
||||
float r = (tint.r - source.r) * alpha + source.r;
|
||||
float g = (tint.g - source.g) * alpha + source.g;
|
||||
float b = (tint.b - source.b) * alpha + source.b;
|
||||
return new Color(r, g, b, 1f);
|
||||
}
|
||||
|
||||
public static Color[] tintColors(Color source, Color[] tints, float alpha) {
|
||||
Color[] tintedColors = new Color[tints.length];
|
||||
for (int i = 0; i < tints.length; i++) {
|
||||
tintedColors[i] = tintColor(source, tints[i], alpha);
|
||||
}
|
||||
return tintedColors;
|
||||
}
|
||||
|
||||
public static Color fromRGB(int r, int g, int b) {
|
||||
return new Color((float)r / 255f, (float)g / 255f, (float)b / 255f, 1f);
|
||||
}
|
||||
|
||||
public static void updateAll() {
|
||||
if (FSkinColor.baseColors.size() == 0) { //initialize base skin colors if needed
|
||||
for (final Colors c : Colors.values()) {
|
||||
FSkinColor.baseColors.put(c, new FSkinColor(c));
|
||||
}
|
||||
}
|
||||
else { //update existing FSkinColors if baseColors already initialized
|
||||
for (final FSkinColor c : FSkinColor.baseColors.values()) {
|
||||
c.updateColor();
|
||||
}
|
||||
for (final FSkinColor c : FSkinColor.derivedColors.values()) {
|
||||
c.updateColor();
|
||||
}
|
||||
}
|
||||
TargetingOverlay.updateColors();
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
return color.a;
|
||||
}
|
||||
}
|
||||
@@ -1,476 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
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.Batch;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont.BitmapFontData;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont.Glyph;
|
||||
import com.badlogic.gdx.graphics.g2d.PixmapPacker;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
|
||||
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
|
||||
import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.util.TextBounds;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
import forge.gui.FThreads;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.util.FileUtil;
|
||||
import forge.util.LineReader;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public class FSkinFont {
|
||||
private static final int MIN_FONT_SIZE = 8;
|
||||
private static int MAX_FONT_SIZE = 72;
|
||||
|
||||
private static final int MAX_FONT_SIZE_LESS_GLYPHS = 72;
|
||||
private static final int MAX_FONT_SIZE_MANY_GLYPHS = 36;
|
||||
|
||||
private static final String TTF_FILE = "font1.ttf";
|
||||
private static final Map<Integer, FSkinFont> fonts = new HashMap<>();
|
||||
|
||||
private static final String commonCharacterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm"
|
||||
+ "nopqrstuvwxyz1234567890\"!?'.,;:()[]{}<>|/@\\^$-%+=#_&*\u2014"
|
||||
+ "\u2022ÁÉÍÓÚáéíóúÀÈÌÒÙàèìòùÑñÄËÏÖÜäëïöüẞß¿¡";
|
||||
private static final Map<String, String> langUniqueCharacterSet = new HashMap<>();
|
||||
|
||||
static {
|
||||
FileUtil.ensureDirectoryExists(ForgeConstants.FONTS_DIR);
|
||||
}
|
||||
|
||||
public static FSkinFont get(final int unscaledSize) {
|
||||
return _get((int) Utils.scale(unscaledSize));
|
||||
}
|
||||
public static FSkinFont _get(final int scaledSize) {
|
||||
FSkinFont skinFont = fonts.get(scaledSize);
|
||||
if (skinFont == null) {
|
||||
skinFont = new FSkinFont(scaledSize);
|
||||
fonts.put(scaledSize, skinFont);
|
||||
}
|
||||
return skinFont;
|
||||
}
|
||||
|
||||
public static FSkinFont forHeight(final float height) {
|
||||
int size = MIN_FONT_SIZE + 1;
|
||||
while (true) {
|
||||
if (_get(size).getLineHeight() > height) {
|
||||
return _get(size - 1);
|
||||
}
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
||||
//pre-load all supported font sizes
|
||||
public static void preloadAll(String language) {
|
||||
//todo:really check the language glyph is a lot
|
||||
MAX_FONT_SIZE = (language.equals("zh-CN") || language.equals("ja-JP")) ? MAX_FONT_SIZE_MANY_GLYPHS : MAX_FONT_SIZE_LESS_GLYPHS;
|
||||
for (int size = MIN_FONT_SIZE; size <= MAX_FONT_SIZE; size++) {
|
||||
_get(size);
|
||||
}
|
||||
}
|
||||
|
||||
//delete all cached font files
|
||||
public static void deleteCachedFiles() {
|
||||
final FileHandle dir = Gdx.files.absolute(ForgeConstants.FONTS_DIR);
|
||||
for (FileHandle fontFile : dir.list()) {
|
||||
String name = fontFile.name();
|
||||
if (name.endsWith(".fnt") || name.endsWith(".png")) {
|
||||
fontFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateAll() {
|
||||
for (FSkinFont skinFont : fonts.values()) {
|
||||
skinFont.updateFont();
|
||||
}
|
||||
}
|
||||
|
||||
private final int fontSize;
|
||||
private final float scale;
|
||||
private BitmapFont font;
|
||||
|
||||
private FSkinFont(int fontSize0) {
|
||||
if (fontSize0 > MAX_FONT_SIZE) {
|
||||
scale = (float)fontSize0 / MAX_FONT_SIZE;
|
||||
}
|
||||
else if (fontSize0 < MIN_FONT_SIZE) {
|
||||
scale = (float)fontSize0 / MIN_FONT_SIZE;
|
||||
}
|
||||
else {
|
||||
scale = 1;
|
||||
}
|
||||
fontSize = fontSize0;
|
||||
updateFont();
|
||||
}
|
||||
static int indexOf (CharSequence text, char ch, int start) {
|
||||
final int n = text.length();
|
||||
for (; start < n; start++)
|
||||
if (text.charAt(start) == ch) return start;
|
||||
return n;
|
||||
|
||||
}
|
||||
public int computeVisibleGlyphs (CharSequence str, int start, int end, float availableWidth) {
|
||||
BitmapFontData data = font.getData();
|
||||
int index = start;
|
||||
float width = 0;
|
||||
Glyph lastGlyph = null;
|
||||
availableWidth /= data.scaleX;
|
||||
|
||||
for (; index < end; index++) {
|
||||
char ch = str.charAt(index);
|
||||
if (ch == '[' && data.markupEnabled) {
|
||||
index++;
|
||||
if (!(index < end && str.charAt(index) == '[')) { // non escaped '['
|
||||
while (index < end && str.charAt(index) != ']')
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Glyph g = data.getGlyph(ch);
|
||||
|
||||
if (g != null) {
|
||||
if (lastGlyph != null) width += lastGlyph.getKerning(ch);
|
||||
if ((width + g.xadvance) - availableWidth > 0.001f) break;
|
||||
width += g.xadvance;
|
||||
lastGlyph = g;
|
||||
}
|
||||
}
|
||||
|
||||
return index - start;
|
||||
}
|
||||
public boolean isBreakChar (char c) {
|
||||
BitmapFontData data = font.getData();
|
||||
if (data.breakChars == null) return false;
|
||||
for (char br : data.breakChars)
|
||||
if (c == br) return true;
|
||||
return false;
|
||||
}
|
||||
static boolean isWhitespace (char c) {
|
||||
switch (c) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case ' ':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Expose methods from font that updates scale as needed
|
||||
public TextBounds getBounds(CharSequence str) {
|
||||
updateScale(); //must update scale before measuring text
|
||||
return getBounds(str, 0, str.length());
|
||||
}
|
||||
public TextBounds getBounds(CharSequence str, int start, int end) {
|
||||
BitmapFontData data = font.getData();
|
||||
//int start = 0;
|
||||
//int end = str.length();
|
||||
int width = 0;
|
||||
Glyph lastGlyph = null;
|
||||
|
||||
while (start < end) {
|
||||
char ch = str.charAt(start++);
|
||||
if (ch == '[' && data.markupEnabled) {
|
||||
if (!(start < end && str.charAt(start) == '[')) { // non escaped '['
|
||||
while (start < end && str.charAt(start) != ']')
|
||||
start++;
|
||||
start++;
|
||||
continue;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
lastGlyph = data.getGlyph(ch);
|
||||
if (lastGlyph != null) {
|
||||
width = lastGlyph.xadvance;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (start < end) {
|
||||
char ch = str.charAt(start++);
|
||||
if (ch == '[' && data.markupEnabled) {
|
||||
if (!(start < end && str.charAt(start) == '[')) { // non escaped '['
|
||||
while (start < end && str.charAt(start) != ']')
|
||||
start++;
|
||||
start++;
|
||||
continue;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
|
||||
Glyph g = data.getGlyph(ch);
|
||||
if (g != null) {
|
||||
width += lastGlyph.getKerning(ch);
|
||||
lastGlyph = g;
|
||||
width += g.xadvance;
|
||||
}
|
||||
}
|
||||
|
||||
return new TextBounds(width * data.scaleX, data.capHeight);
|
||||
|
||||
}
|
||||
public TextBounds getMultiLineBounds(CharSequence str) {
|
||||
updateScale();
|
||||
BitmapFontData data = font.getData();
|
||||
int start = 0;
|
||||
float maxWidth = 0;
|
||||
int numLines = 0;
|
||||
int length = str.length();
|
||||
|
||||
while (start < length) {
|
||||
int lineEnd = indexOf(str, '\n', start);
|
||||
float lineWidth = getBounds(str, start, lineEnd).width;
|
||||
maxWidth = Math.max(maxWidth, lineWidth);
|
||||
start = lineEnd + 1;
|
||||
numLines++;
|
||||
}
|
||||
|
||||
return new TextBounds(maxWidth, data.capHeight + (numLines - 1) * data.lineHeight);
|
||||
|
||||
}
|
||||
public TextBounds getWrappedBounds(CharSequence str, float wrapWidth) {
|
||||
updateScale();
|
||||
BitmapFontData data = font.getData();
|
||||
if (wrapWidth <= 0) wrapWidth = Integer.MAX_VALUE;
|
||||
int start = 0;
|
||||
int numLines = 0;
|
||||
int length = str.length();
|
||||
float maxWidth = 0;
|
||||
while (start < length) {
|
||||
int newLine = indexOf(str, '\n', start);
|
||||
int lineEnd = start + computeVisibleGlyphs(str, start, newLine, wrapWidth);
|
||||
int nextStart = lineEnd + 1;
|
||||
if (lineEnd < newLine) {
|
||||
// Find char to break on.
|
||||
while (lineEnd > start) {
|
||||
if (isWhitespace(str.charAt(lineEnd))) break;
|
||||
if (isBreakChar(str.charAt(lineEnd - 1))) break;
|
||||
lineEnd--;
|
||||
}
|
||||
|
||||
if (lineEnd == start) {
|
||||
|
||||
if (nextStart > start + 1) nextStart--;
|
||||
|
||||
lineEnd = nextStart; // If no characters to break, show all.
|
||||
|
||||
} else {
|
||||
nextStart = lineEnd;
|
||||
|
||||
// Eat whitespace at start of wrapped line.
|
||||
|
||||
while (nextStart < length) {
|
||||
char c = str.charAt(nextStart);
|
||||
if (!isWhitespace(c)) break;
|
||||
nextStart++;
|
||||
if (c == '\n') break; // Eat only the first wrapped newline.
|
||||
}
|
||||
|
||||
// Eat whitespace at end of line.
|
||||
while (lineEnd > start) {
|
||||
|
||||
if (!isWhitespace(str.charAt(lineEnd - 1))) break;
|
||||
lineEnd--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lineEnd > start) {
|
||||
float lineWidth = getBounds(str, start, lineEnd).width;
|
||||
maxWidth = Math.max(maxWidth, lineWidth);
|
||||
}
|
||||
start = nextStart;
|
||||
numLines++;
|
||||
}
|
||||
|
||||
return new TextBounds(maxWidth, data.capHeight + (numLines - 1) * data.lineHeight);
|
||||
}
|
||||
public float getAscent() {
|
||||
updateScale();
|
||||
return font.getAscent();
|
||||
}
|
||||
public float getCapHeight() {
|
||||
updateScale();
|
||||
return font.getCapHeight();
|
||||
}
|
||||
public float getLineHeight() {
|
||||
updateScale();
|
||||
return font.getLineHeight();
|
||||
}
|
||||
|
||||
public void draw(Batch batch, String text, Color color, float x, float y, float w, boolean wrap, int horzAlignment) {
|
||||
updateScale();
|
||||
font.setColor(color);
|
||||
font.draw(batch, text, x, y, w, horzAlignment, wrap);
|
||||
}
|
||||
|
||||
//update scale of font if needed
|
||||
private void updateScale() {
|
||||
if (font.getScaleX() != scale) {
|
||||
font.getData().setScale(scale);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canShrink() {
|
||||
return fontSize > MIN_FONT_SIZE;
|
||||
}
|
||||
|
||||
public FSkinFont shrink() {
|
||||
return _get(fontSize - 1);
|
||||
}
|
||||
|
||||
public String getCharacterSet(String langCode) {
|
||||
if (langUniqueCharacterSet.containsKey(langCode)) {
|
||||
return langUniqueCharacterSet.get(langCode);
|
||||
}
|
||||
StringBuilder characters = new StringBuilder(commonCharacterSet);
|
||||
Set<Integer> characterSet = new HashSet<>();
|
||||
for (int offset = 0; offset < commonCharacterSet.length();) {
|
||||
final int codePoint = commonCharacterSet.codePointAt(offset);
|
||||
characterSet.add(codePoint);
|
||||
offset += Character.charCount(codePoint);
|
||||
}
|
||||
String[] translationFilePaths = { ForgeConstants.LANG_DIR + "cardnames-" + langCode + ".txt",
|
||||
ForgeConstants.LANG_DIR + langCode + ".properties" };
|
||||
for (int i = 0; i < translationFilePaths.length; i++) {
|
||||
try (LineReader translationFile = new LineReader(new FileInputStream(translationFilePaths[i]),
|
||||
StandardCharsets.UTF_8)) {
|
||||
for (String fileLine : translationFile.readLines()) {
|
||||
final int stringLength = fileLine.length();
|
||||
for (int offset = 0; offset < stringLength;) {
|
||||
final int codePoint = fileLine.codePointAt(offset);
|
||||
if (!characterSet.contains(codePoint)) {
|
||||
characterSet.add(codePoint);
|
||||
characters.append(Character.toChars(codePoint));
|
||||
}
|
||||
offset += Character.charCount(codePoint);
|
||||
}
|
||||
}
|
||||
translationFile.close();
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error reading translation file: " + translationFilePaths[i]);
|
||||
}
|
||||
}
|
||||
langUniqueCharacterSet.put(langCode, characters.toString());
|
||||
|
||||
return characters.toString();
|
||||
}
|
||||
|
||||
private void updateFont() {
|
||||
if (scale != 1) { //re-use font inside range if possible
|
||||
if (fontSize > MAX_FONT_SIZE) {
|
||||
font = _get(MAX_FONT_SIZE).font;
|
||||
} else {
|
||||
font = _get(MIN_FONT_SIZE).font;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
String fontName = "f" + fontSize;
|
||||
if (Forge.locale.equals("zh-CN") || Forge.locale.equals("ja-JP")) {
|
||||
fontName += Forge.locale;
|
||||
}
|
||||
FileHandle fontFile = Gdx.files.absolute(ForgeConstants.FONTS_DIR + fontName + ".fnt");
|
||||
if (fontFile != null && fontFile.exists()) {
|
||||
final BitmapFontData data = new BitmapFontData(fontFile, false);
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override
|
||||
public void run() { //font must be initialized on UI thread
|
||||
font = new BitmapFont(data, (TextureRegion)null, true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (Forge.locale.equals("zh-CN") || Forge.locale.equals("ja-JP")) {
|
||||
String ttfName = Forge.CJK_Font;
|
||||
FileHandle ttfFile = Gdx.files.absolute(ForgeConstants.FONTS_DIR + ttfName + ".ttf");
|
||||
if (ttfFile != null && ttfFile.exists()) {
|
||||
generateFont(ttfFile, fontName, fontSize);
|
||||
}
|
||||
} else {
|
||||
generateFont(FSkin.getSkinFile(TTF_FILE), fontName, fontSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateFont(final FileHandle ttfFile, final String fontName, final int fontSize) {
|
||||
if (!ttfFile.exists()) { return; }
|
||||
|
||||
final FreeTypeFontGenerator generator = new FreeTypeFontGenerator(ttfFile);
|
||||
|
||||
//approximate optimal page size
|
||||
int pageSize;
|
||||
if (fontSize >= 28) {
|
||||
pageSize = 256;
|
||||
}
|
||||
else {
|
||||
pageSize = 128;
|
||||
}
|
||||
|
||||
final PixmapPacker packer = new PixmapPacker(pageSize, pageSize, Pixmap.Format.RGBA8888, 2, false);
|
||||
final FreeTypeFontParameter parameter = new FreeTypeFontParameter();
|
||||
parameter.characters = getCharacterSet(Forge.locale);
|
||||
parameter.size = fontSize;
|
||||
parameter.packer = packer;
|
||||
final FreeTypeFontGenerator.FreeTypeBitmapFontData fontData = generator.generateData(parameter);
|
||||
final Array<PixmapPacker.Page> pages = packer.getPages();
|
||||
|
||||
//finish generating font on UI thread
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Array<TextureRegion> textureRegions = new Array<>();
|
||||
for (int i = 0; i < pages.size; i++) {
|
||||
PixmapPacker.Page p = pages.get(i);
|
||||
Texture texture = new Texture(new PixmapTextureData(p.getPixmap(), p.getPixmap().getFormat(), false, false)) {
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
getTextureData().consumePixmap().dispose();
|
||||
}
|
||||
};
|
||||
texture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
|
||||
textureRegions.addAll(new TextureRegion(texture));
|
||||
}
|
||||
|
||||
font = new BitmapFont(fontData, textureRegions, true);
|
||||
|
||||
//create .fnt and .png files for font
|
||||
FileHandle pixmapDir = Gdx.files.absolute(ForgeConstants.FONTS_DIR);
|
||||
if (pixmapDir != null) {
|
||||
FileHandle fontFile = pixmapDir.child(fontName + ".fnt");
|
||||
BitmapFontWriter.setOutputFormat(BitmapFontWriter.OutputFormat.Text);
|
||||
|
||||
String[] pageRefs = BitmapFontWriter.writePixmaps(packer.getPages(), pixmapDir, fontName);
|
||||
BitmapFontWriter.writeFont(font.getData(), pageRefs, fontFile, new BitmapFontWriter.FontInfo(fontName, fontSize), 1, 1);
|
||||
}
|
||||
|
||||
generator.dispose();
|
||||
packer.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Iterable<String> getAllCJKFonts() {
|
||||
final List<String> allCJKFonts = new ArrayList<>();
|
||||
|
||||
allCJKFonts.add("None");
|
||||
final FileHandle dir = Gdx.files.absolute(ForgeConstants.FONTS_DIR);
|
||||
for (FileHandle fontFile : dir.list()) {
|
||||
String fontName = fontFile.name();
|
||||
if (!fontName.endsWith(".ttf")) { continue; }
|
||||
allCJKFonts.add(fontName.replace(".ttf", ""));
|
||||
}
|
||||
|
||||
return allCJKFonts;
|
||||
}
|
||||
}
|
||||
@@ -1,575 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
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.TextureRegion;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.skin.FSkinProp;
|
||||
import forge.util.ImageUtil;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/** Properties of various components that make up the skin.
|
||||
* This interface allows all enums to be under the same roof.
|
||||
* It also enforces a getter for coordinate locations in sprites. */
|
||||
public enum FSkinImage implements FImage {
|
||||
//Zones
|
||||
HAND (FSkinProp.IMG_ZONE_HAND, SourceFile.ICONS),
|
||||
HDHAND (FSkinProp.IMG_HDZONE_HAND, SourceFile.BUTTONS),
|
||||
|
||||
LIBRARY (FSkinProp.IMG_ZONE_LIBRARY, SourceFile.ICONS),
|
||||
HDLIBRARY (FSkinProp.IMG_HDZONE_LIBRARY, SourceFile.BUTTONS),
|
||||
|
||||
EXILE (FSkinProp.IMG_ZONE_EXILE, SourceFile.ICONS),
|
||||
HDEXILE (FSkinProp.IMG_HDZONE_EXILE, SourceFile.BUTTONS),
|
||||
|
||||
FLASHBACK (FSkinProp.IMG_ZONE_FLASHBACK, SourceFile.ICONS),
|
||||
HDFLASHBACK (FSkinProp.IMG_HDZONE_FLASHBACK, SourceFile.BUTTONS),
|
||||
|
||||
GRAVEYARD (FSkinProp.IMG_ZONE_GRAVEYARD, SourceFile.ICONS),
|
||||
HDGRAVEYARD (FSkinProp.IMG_HDZONE_GRAVEYARD, SourceFile.BUTTONS),
|
||||
|
||||
HDMANAPOOL (FSkinProp.IMG_HDZONE_MANAPOOL, SourceFile.BUTTONS),
|
||||
|
||||
POISON (FSkinProp.IMG_ZONE_POISON, SourceFile.ICONS),
|
||||
|
||||
//Mana symbols
|
||||
MANA_COLORLESS (FSkinProp.IMG_MANA_COLORLESS, SourceFile.MANAICONS),
|
||||
MANA_B (FSkinProp.IMG_MANA_B, SourceFile.MANAICONS),
|
||||
MANA_R (FSkinProp.IMG_MANA_R, SourceFile.MANAICONS),
|
||||
MANA_U (FSkinProp.IMG_MANA_U, SourceFile.MANAICONS),
|
||||
MANA_G (FSkinProp.IMG_MANA_G, SourceFile.MANAICONS),
|
||||
MANA_W (FSkinProp.IMG_MANA_W, SourceFile.MANAICONS),
|
||||
MANA_2B (FSkinProp.IMG_MANA_2B, SourceFile.MANAICONS),
|
||||
MANA_2G (FSkinProp.IMG_MANA_2G, SourceFile.MANAICONS),
|
||||
MANA_2R (FSkinProp.IMG_MANA_2R, SourceFile.MANAICONS),
|
||||
MANA_2U (FSkinProp.IMG_MANA_2U, SourceFile.MANAICONS),
|
||||
MANA_2W (FSkinProp.IMG_MANA_2W, SourceFile.MANAICONS),
|
||||
MANA_HYBRID_BG (FSkinProp.IMG_MANA_HYBRID_BG, SourceFile.MANAICONS),
|
||||
MANA_HYBRID_BR (FSkinProp.IMG_MANA_HYBRID_BR, SourceFile.MANAICONS),
|
||||
MANA_HYBRID_GU (FSkinProp.IMG_MANA_HYBRID_GU, SourceFile.MANAICONS),
|
||||
MANA_HYBRID_GW (FSkinProp.IMG_MANA_HYBRID_GW, SourceFile.MANAICONS),
|
||||
MANA_HYBRID_RG (FSkinProp.IMG_MANA_HYBRID_RG, SourceFile.MANAICONS),
|
||||
MANA_HYBRID_RW (FSkinProp.IMG_MANA_HYBRID_RW, SourceFile.MANAICONS),
|
||||
MANA_HYBRID_UB (FSkinProp.IMG_MANA_HYBRID_UB, SourceFile.MANAICONS),
|
||||
MANA_HYBRID_UR (FSkinProp.IMG_MANA_HYBRID_UR, SourceFile.MANAICONS),
|
||||
MANA_HYBRID_WB (FSkinProp.IMG_MANA_HYBRID_WB, SourceFile.MANAICONS),
|
||||
MANA_HYBRID_WU (FSkinProp.IMG_MANA_HYBRID_WU, SourceFile.MANAICONS),
|
||||
MANA_PHRYX_U (FSkinProp.IMG_MANA_PHRYX_U, SourceFile.MANAICONS),
|
||||
MANA_PHRYX_W (FSkinProp.IMG_MANA_PHRYX_W, SourceFile.MANAICONS),
|
||||
MANA_PHRYX_R (FSkinProp.IMG_MANA_PHRYX_R, SourceFile.MANAICONS),
|
||||
MANA_PHRYX_G (FSkinProp.IMG_MANA_PHRYX_G, SourceFile.MANAICONS),
|
||||
MANA_PHRYX_B (FSkinProp.IMG_MANA_PHRYX_B, SourceFile.MANAICONS),
|
||||
MANA_SNOW (FSkinProp.IMG_MANA_SNOW, SourceFile.MANAICONS),
|
||||
MANA_0 (FSkinProp.IMG_MANA_0, SourceFile.MANAICONS),
|
||||
MANA_1 (FSkinProp.IMG_MANA_1, SourceFile.MANAICONS),
|
||||
MANA_2 (FSkinProp.IMG_MANA_2, SourceFile.MANAICONS),
|
||||
MANA_3 (FSkinProp.IMG_MANA_3, SourceFile.MANAICONS),
|
||||
MANA_4 (FSkinProp.IMG_MANA_4, SourceFile.MANAICONS),
|
||||
MANA_5 (FSkinProp.IMG_MANA_5, SourceFile.MANAICONS),
|
||||
MANA_6 (FSkinProp.IMG_MANA_6, SourceFile.MANAICONS),
|
||||
MANA_7 (FSkinProp.IMG_MANA_7, SourceFile.MANAICONS),
|
||||
MANA_8 (FSkinProp.IMG_MANA_8, SourceFile.MANAICONS),
|
||||
MANA_9 (FSkinProp.IMG_MANA_9, SourceFile.MANAICONS),
|
||||
MANA_10 (FSkinProp.IMG_MANA_10, SourceFile.MANAICONS),
|
||||
MANA_11 (FSkinProp.IMG_MANA_11, SourceFile.MANAICONS),
|
||||
MANA_12 (FSkinProp.IMG_MANA_12, SourceFile.MANAICONS),
|
||||
MANA_13 (FSkinProp.IMG_MANA_13, SourceFile.MANAICONS),
|
||||
MANA_14 (FSkinProp.IMG_MANA_14, SourceFile.MANAICONS),
|
||||
MANA_15 (FSkinProp.IMG_MANA_15, SourceFile.MANAICONS),
|
||||
MANA_16 (FSkinProp.IMG_MANA_16, SourceFile.MANAICONS),
|
||||
MANA_17 (FSkinProp.IMG_MANA_17, SourceFile.MANAICONS),
|
||||
MANA_18 (FSkinProp.IMG_MANA_18, SourceFile.MANAICONS),
|
||||
MANA_19 (FSkinProp.IMG_MANA_19, SourceFile.MANAICONS),
|
||||
MANA_20 (FSkinProp.IMG_MANA_20, SourceFile.MANAICONS),
|
||||
MANA_X (FSkinProp.IMG_MANA_X, SourceFile.MANAICONS),
|
||||
MANA_Y (FSkinProp.IMG_MANA_Y, SourceFile.MANAICONS),
|
||||
MANA_Z (FSkinProp.IMG_MANA_Z, SourceFile.MANAICONS),
|
||||
|
||||
//CMC ranges
|
||||
CMC_LOW (FSkinProp.IMG_CMC_LOW, SourceFile.MANAICONS),
|
||||
CMC_LOW_MID (FSkinProp.IMG_CMC_LOW_MID, SourceFile.MANAICONS),
|
||||
CMC_MID_HIGH (FSkinProp.IMG_CMC_MID_HIGH, SourceFile.MANAICONS),
|
||||
CMC_HIGH (FSkinProp.IMG_CMC_HIGH, SourceFile.MANAICONS),
|
||||
|
||||
//Gameplay
|
||||
TAP (FSkinProp.IMG_TAP, SourceFile.MANAICONS),
|
||||
UNTAP (FSkinProp.IMG_UNTAP, SourceFile.MANAICONS),
|
||||
CHAOS (FSkinProp.IMG_CHAOS, SourceFile.ICONS),
|
||||
SLASH (FSkinProp.IMG_SLASH, SourceFile.ICONS),
|
||||
ATTACK (FSkinProp.IMG_ATTACK, SourceFile.ICONS),
|
||||
DEFEND (FSkinProp.IMG_DEFEND, SourceFile.ICONS),
|
||||
SUMMONSICK (FSkinProp.IMG_SUMMONSICK, SourceFile.ICONS),
|
||||
PHASING (FSkinProp.IMG_PHASING, SourceFile.ICONS),
|
||||
COSTRESERVED (FSkinProp.IMG_COSTRESERVED, SourceFile.ICONS),
|
||||
COUNTERS1 (FSkinProp.IMG_COUNTERS1, SourceFile.ICONS),
|
||||
COUNTERS2 (FSkinProp.IMG_COUNTERS2, SourceFile.ICONS),
|
||||
COUNTERS3 (FSkinProp.IMG_COUNTERS3, SourceFile.ICONS),
|
||||
COUNTERS_MULTI (FSkinProp.IMG_COUNTERS_MULTI, SourceFile.ICONS),
|
||||
ENERGY (FSkinProp.IMG_ENERGY, SourceFile.ICONS),
|
||||
|
||||
//Dock Icons
|
||||
SHORTCUTS (FSkinProp.ICO_SHORTCUTS, SourceFile.ICONS),
|
||||
SETTINGS (FSkinProp.ICO_SETTINGS, SourceFile.ICONS),
|
||||
ENDTURN (FSkinProp.ICO_ENDTURN, SourceFile.ICONS),
|
||||
CONCEDE (FSkinProp.ICO_CONCEDE, SourceFile.ICONS),
|
||||
REVERTLAYOUT (FSkinProp.ICO_REVERTLAYOUT, SourceFile.ICONS),
|
||||
OPENLAYOUT (FSkinProp.ICO_OPENLAYOUT, SourceFile.ICONS),
|
||||
SAVELAYOUT (FSkinProp.ICO_SAVELAYOUT, SourceFile.ICONS),
|
||||
DECKLIST (FSkinProp.ICO_DECKLIST, SourceFile.ICONS),
|
||||
ALPHASTRIKE (FSkinProp.ICO_ALPHASTRIKE, SourceFile.ICONS),
|
||||
ARCSOFF (FSkinProp.ICO_ARCSOFF, SourceFile.ICONS),
|
||||
ARCSON (FSkinProp.ICO_ARCSON, SourceFile.ICONS),
|
||||
ARCSHOVER (FSkinProp.ICO_ARCSHOVER, SourceFile.ICONS),
|
||||
|
||||
//choice-search-misc
|
||||
HDCHOICE (FSkinProp.ICO_HDCHOICE, SourceFile.BUTTONS),
|
||||
HDSIDEBOARD (FSkinProp.ICO_HDSIDEBOARD, SourceFile.BUTTONS),
|
||||
HDPREFERENCE (FSkinProp.ICO_HDPREFERENCE, SourceFile.BUTTONS),
|
||||
HDIMPORT (FSkinProp.ICO_HDIMPORT, SourceFile.BUTTONS),
|
||||
HDEXPORT (FSkinProp.ICO_HDEXPORT, SourceFile.BUTTONS),
|
||||
HDYIELD (FSkinProp.ICO_HDYIELD, SourceFile.BUTTONS),
|
||||
BLANK (FSkinProp.ICO_BLANK, SourceFile.ICONS),
|
||||
|
||||
//Achievement Trophies
|
||||
COMMON_TROPHY (FSkinProp.IMG_COMMON_TROPHY, SourceFile.TROPHIES),
|
||||
UNCOMMON_TROPHY (FSkinProp.IMG_UNCOMMON_TROPHY, SourceFile.TROPHIES),
|
||||
RARE_TROPHY (FSkinProp.IMG_RARE_TROPHY, SourceFile.TROPHIES),
|
||||
MYTHIC_TROPHY (FSkinProp.IMG_MYTHIC_TROPHY, SourceFile.TROPHIES),
|
||||
SPECIAL_TROPHY (FSkinProp.IMG_SPECIAL_TROPHY, SourceFile.TROPHIES),
|
||||
TROPHY_PLATE (FSkinProp.IMG_TROPHY_PLATE, SourceFile.TROPHIES),
|
||||
TROPHY_CASE_TOP (FSkinProp.IMG_TROPHY_CASE_TOP, SourceFile.TROPHIES),
|
||||
TROPHY_SHELF (FSkinProp.IMG_TROPHY_SHELF, SourceFile.TROPHIES),
|
||||
|
||||
//Planar Conquest Images
|
||||
PLANE_MONITOR (FSkinProp.IMG_PLANE_MONITOR, SourceFile.PLANAR_CONQUEST),
|
||||
AETHER_SHARD (FSkinProp.IMG_AETHER_SHARD, SourceFile.PLANAR_CONQUEST),
|
||||
MULTIVERSE (FSkinProp.IMG_MULTIVERSE, SourceFile.PLANAR_CONQUEST),
|
||||
SPELLBOOK (FSkinProp.IMG_SPELLBOOK, SourceFile.PLANAR_CONQUEST),
|
||||
PW_BADGE_COMMON (FSkinProp.IMG_PW_BADGE_COMMON, SourceFile.PLANAR_CONQUEST),
|
||||
PW_BADGE_UNCOMMON (FSkinProp.IMG_PW_BADGE_UNCOMMON, SourceFile.PLANAR_CONQUEST),
|
||||
PW_BADGE_RARE (FSkinProp.IMG_PW_BADGE_RARE, SourceFile.PLANAR_CONQUEST),
|
||||
PW_BADGE_MYTHIC (FSkinProp.IMG_PW_BADGE_MYTHIC, SourceFile.PLANAR_CONQUEST),
|
||||
|
||||
//Quest Icons
|
||||
QUEST_ZEP (FSkinProp.ICO_QUEST_ZEP, SourceFile.ICONS),
|
||||
QUEST_GEAR (FSkinProp.ICO_QUEST_GEAR, SourceFile.ICONS),
|
||||
QUEST_GOLD (FSkinProp.ICO_QUEST_GOLD, SourceFile.ICONS),
|
||||
QUEST_ELIXIR (FSkinProp.ICO_QUEST_ELIXIR, SourceFile.ICONS),
|
||||
QUEST_BOOK (FSkinProp.ICO_QUEST_BOOK, SourceFile.ICONS),
|
||||
QUEST_BOTTLES (FSkinProp.ICO_QUEST_BOTTLES, SourceFile.ICONS),
|
||||
QUEST_BOX (FSkinProp.ICO_QUEST_BOX, SourceFile.ICONS),
|
||||
QUEST_COIN (FSkinProp.ICO_QUEST_COIN, SourceFile.ICONS),
|
||||
QUEST_CHARM (FSkinProp.ICO_QUEST_CHARM, SourceFile.ICONS),
|
||||
QUEST_FOX (FSkinProp.ICO_QUEST_FOX, SourceFile.ICONS),
|
||||
QUEST_LEAF (FSkinProp.ICO_QUEST_LEAF, SourceFile.ICONS),
|
||||
QUEST_LIFE (FSkinProp.ICO_QUEST_LIFE, SourceFile.ICONS),
|
||||
QUEST_COINSTACK (FSkinProp.ICO_QUEST_COINSTACK, SourceFile.ICONS),
|
||||
QUEST_MAP (FSkinProp.ICO_QUEST_MAP, SourceFile.ICONS),
|
||||
QUEST_NOTES (FSkinProp.ICO_QUEST_NOTES, SourceFile.ICONS),
|
||||
QUEST_HEART (FSkinProp.ICO_QUEST_HEART, SourceFile.ICONS),
|
||||
QUEST_BREW (FSkinProp.ICO_QUEST_BREW, SourceFile.ICONS),
|
||||
QUEST_STAKES (FSkinProp.ICO_QUEST_STAKES, SourceFile.ICONS),
|
||||
QUEST_MINUS (FSkinProp.ICO_QUEST_MINUS, SourceFile.ICONS),
|
||||
QUEST_PLUS (FSkinProp.ICO_QUEST_PLUS, SourceFile.ICONS),
|
||||
QUEST_PLUSPLUS (FSkinProp.ICO_QUEST_PLUSPLUS, SourceFile.ICONS),
|
||||
QUEST_BIG_ELIXIR (FSkinProp.ICO_QUEST_BIG_ELIXIR, SourceFile.ICONS),
|
||||
QUEST_BIG_BREW (FSkinProp.ICO_QUEST_BIG_BREW, SourceFile.ICONS),
|
||||
QUEST_BIG_BM (FSkinProp.ICO_QUEST_BIG_BM, SourceFile.ICONS),
|
||||
QUEST_BIG_STAKES (FSkinProp.ICO_QUEST_BIG_STAKES, SourceFile.ICONS),
|
||||
QUEST_BIG_HOUSE (FSkinProp.ICO_QUEST_BIG_HOUSE, SourceFile.ICONS),
|
||||
QUEST_BIG_COIN (FSkinProp.ICO_QUEST_BIG_COIN, SourceFile.ICONS),
|
||||
QUEST_BIG_BOOK (FSkinProp.ICO_QUEST_BIG_BOOK, SourceFile.ICONS),
|
||||
QUEST_BIG_MAP (FSkinProp.ICO_QUEST_BIG_MAP, SourceFile.ICONS),
|
||||
QUEST_BIG_ZEP (FSkinProp.ICO_QUEST_BIG_ZEP, SourceFile.ICONS),
|
||||
QUEST_BIG_CHARM (FSkinProp.ICO_QUEST_BIG_CHARM, SourceFile.ICONS),
|
||||
QUEST_BIG_BOOTS (FSkinProp.ICO_QUEST_BIG_BOOTS, SourceFile.ICONS),
|
||||
QUEST_BIG_SHIELD (FSkinProp.ICO_QUEST_BIG_SHIELD, SourceFile.ICONS),
|
||||
QUEST_BIG_ARMOR (FSkinProp.ICO_QUEST_BIG_ARMOR, SourceFile.ICONS),
|
||||
QUEST_BIG_AXE (FSkinProp.ICO_QUEST_BIG_AXE, SourceFile.ICONS),
|
||||
QUEST_BIG_SWORD (FSkinProp.ICO_QUEST_BIG_SWORD, SourceFile.ICONS),
|
||||
QUEST_BIG_BAG (FSkinProp.ICO_QUEST_BIG_BAG, SourceFile.ICONS),
|
||||
|
||||
//menu icon
|
||||
MENU_GALAXY (FSkinProp.ICO_MENU_GALAXY, SourceFile.ICONS),
|
||||
MENU_STATS (FSkinProp.ICO_MENU_STATS, SourceFile.ICONS),
|
||||
MENU_PUZZLE (FSkinProp.ICO_MENU_PUZZLE, SourceFile.ICONS),
|
||||
MENU_GAUNTLET (FSkinProp.ICO_MENU_GAUNTLET, SourceFile.ICONS),
|
||||
MENU_SEALED (FSkinProp.ICO_MENU_SEALED, SourceFile.ICONS),
|
||||
MENU_DRAFT (FSkinProp.ICO_MENU_DRAFT, SourceFile.ICONS),
|
||||
MENU_CONSTRUCTED (FSkinProp.ICO_MENU_CONSTRUCTED, SourceFile.ICONS),
|
||||
|
||||
//Interface icons
|
||||
QUESTION (FSkinProp.ICO_QUESTION, SourceFile.ICONS),
|
||||
INFORMATION (FSkinProp.ICO_INFORMATION, SourceFile.ICONS),
|
||||
WARNING (FSkinProp.ICO_WARNING, SourceFile.ICONS),
|
||||
ERROR (FSkinProp.ICO_ERROR, SourceFile.ICONS),
|
||||
|
||||
DELETE (FSkinProp.ICO_DELETE, SourceFile.ICONS),
|
||||
HDDELETE (FSkinProp.ICO_HDDELETE, SourceFile.BUTTONS),
|
||||
|
||||
DELETE_OVER (FSkinProp.ICO_DELETE_OVER, SourceFile.ICONS),
|
||||
|
||||
EDIT (FSkinProp.ICO_EDIT, SourceFile.ICONS),
|
||||
HDEDIT (FSkinProp.ICO_HDEDIT, SourceFile.BUTTONS),
|
||||
|
||||
EDIT_OVER (FSkinProp.ICO_EDIT_OVER, SourceFile.ICONS),
|
||||
|
||||
OPEN (FSkinProp.ICO_OPEN, SourceFile.ICONS),
|
||||
HDOPEN (FSkinProp.ICO_HDOPEN, SourceFile.BUTTONS),
|
||||
|
||||
MINUS (FSkinProp.ICO_MINUS, SourceFile.ICONS),
|
||||
HDMINUS (FSkinProp.ICO_HDMINUS, SourceFile.BUTTONS),
|
||||
|
||||
NEW (FSkinProp.ICO_NEW, SourceFile.ICONS),
|
||||
|
||||
PLUS (FSkinProp.ICO_PLUS, SourceFile.ICONS),
|
||||
HDPLUS (FSkinProp.ICO_HDPLUS, SourceFile.BUTTONS),
|
||||
|
||||
PRINT (FSkinProp.ICO_PRINT, SourceFile.ICONS),
|
||||
|
||||
SAVE (FSkinProp.ICO_SAVE, SourceFile.ICONS),
|
||||
HDSAVE (FSkinProp.ICO_HDSAVE, SourceFile.BUTTONS),
|
||||
SAVEAS (FSkinProp.ICO_SAVEAS, SourceFile.ICONS),
|
||||
HDSAVEAS (FSkinProp.ICO_HDSAVEAS, SourceFile.BUTTONS),
|
||||
|
||||
CLOSE (FSkinProp.ICO_CLOSE, SourceFile.ICONS),
|
||||
LIST (FSkinProp.ICO_LIST, SourceFile.ICONS),
|
||||
CARD_IMAGE (FSkinProp.ICO_CARD_IMAGE, SourceFile.ICONS),
|
||||
|
||||
FOLDER (FSkinProp.ICO_FOLDER, SourceFile.ICONS),
|
||||
HDFOLDER (FSkinProp.ICO_HDFOLDER, SourceFile.BUTTONS),
|
||||
|
||||
SEARCH (FSkinProp.ICO_SEARCH, SourceFile.ICONS),
|
||||
HDSEARCH (FSkinProp.ICO_HDSEARCH, SourceFile.BUTTONS),
|
||||
|
||||
UNKNOWN (FSkinProp.ICO_UNKNOWN, SourceFile.ICONS),
|
||||
LOGO (FSkinProp.ICO_LOGO, SourceFile.ICONS),
|
||||
|
||||
FLIPCARD (FSkinProp.ICO_FLIPCARD, SourceFile.ICONS),
|
||||
HDFLIPCARD (FSkinProp.ICO_HDFLIPCARD, SourceFile.BUTTONS),
|
||||
|
||||
FAVICON (FSkinProp.ICO_FAVICON, SourceFile.ICONS),
|
||||
LOCK (FSkinProp.ICO_LOCK, SourceFile.ICONS),
|
||||
|
||||
//Layout images
|
||||
HANDLE (FSkinProp.IMG_HANDLE, SourceFile.ICONS),
|
||||
CUR_L (FSkinProp.IMG_CUR_L, SourceFile.ICONS),
|
||||
CUR_R (FSkinProp.IMG_CUR_R, SourceFile.ICONS),
|
||||
CUR_T (FSkinProp.IMG_CUR_T, SourceFile.ICONS),
|
||||
CUR_B (FSkinProp.IMG_CUR_B, SourceFile.ICONS),
|
||||
CUR_TAB (FSkinProp.IMG_CUR_TAB, SourceFile.ICONS),
|
||||
|
||||
//Editor images
|
||||
STAR_OUTLINE (FSkinProp.IMG_STAR_OUTLINE, SourceFile.ICONS),
|
||||
HDSTAR_OUTLINE (FSkinProp.IMG_HDSTAR_OUTLINE, SourceFile.BUTTONS),
|
||||
STAR_FILLED (FSkinProp.IMG_STAR_FILLED, SourceFile.ICONS),
|
||||
HDSTAR_FILLED (FSkinProp.IMG_HDSTAR_FILLED, SourceFile.BUTTONS),
|
||||
|
||||
ARTIFACT (FSkinProp.IMG_ARTIFACT, SourceFile.MANAICONS),
|
||||
CREATURE (FSkinProp.IMG_CREATURE, SourceFile.MANAICONS),
|
||||
ENCHANTMENT (FSkinProp.IMG_ENCHANTMENT, SourceFile.MANAICONS),
|
||||
INSTANT (FSkinProp.IMG_INSTANT, SourceFile.MANAICONS),
|
||||
LAND (FSkinProp.IMG_LAND, SourceFile.MANAICONS),
|
||||
LANDLOGO (FSkinProp.IMG_LANDLOGO, SourceFile.MANAICONS),
|
||||
MULTI (FSkinProp.IMG_MULTI, SourceFile.ICONS),
|
||||
HDMULTI (FSkinProp.IMG_HDMULTI, SourceFile.MANAICONS),
|
||||
PLANESWALKER (FSkinProp.IMG_PLANESWALKER, SourceFile.MANAICONS),
|
||||
PACK (FSkinProp.IMG_PACK, SourceFile.ICONS),
|
||||
SORCERY (FSkinProp.IMG_SORCERY, SourceFile.MANAICONS),
|
||||
COMMANDER (FSkinProp.IMG_COMMANDER, SourceFile.ICONS),
|
||||
|
||||
//Buttons
|
||||
BTN_START_UP (FSkinProp.IMG_BTN_START_UP, SourceFile.ICONS),
|
||||
BTN_START_OVER (FSkinProp.IMG_BTN_START_OVER, SourceFile.ICONS),
|
||||
BTN_START_DOWN (FSkinProp.IMG_BTN_START_DOWN, SourceFile.ICONS),
|
||||
BTN_UP_LEFT (FSkinProp.IMG_BTN_UP_LEFT, SourceFile.ICONS),
|
||||
BTN_UP_CENTER (FSkinProp.IMG_BTN_UP_CENTER, SourceFile.ICONS),
|
||||
BTN_UP_RIGHT (FSkinProp.IMG_BTN_UP_RIGHT, SourceFile.ICONS),
|
||||
BTN_OVER_LEFT (FSkinProp.IMG_BTN_OVER_LEFT, SourceFile.ICONS),
|
||||
BTN_OVER_CENTER (FSkinProp.IMG_BTN_OVER_CENTER, SourceFile.ICONS),
|
||||
BTN_OVER_RIGHT (FSkinProp.IMG_BTN_OVER_RIGHT, SourceFile.ICONS),
|
||||
BTN_DOWN_LEFT (FSkinProp.IMG_BTN_DOWN_LEFT, SourceFile.ICONS),
|
||||
BTN_DOWN_CENTER (FSkinProp.IMG_BTN_DOWN_CENTER, SourceFile.ICONS),
|
||||
BTN_DOWN_RIGHT (FSkinProp.IMG_BTN_DOWN_RIGHT, SourceFile.ICONS),
|
||||
BTN_FOCUS_LEFT (FSkinProp.IMG_BTN_FOCUS_LEFT, SourceFile.ICONS),
|
||||
BTN_FOCUS_CENTER (FSkinProp.IMG_BTN_FOCUS_CENTER, SourceFile.ICONS),
|
||||
BTN_FOCUS_RIGHT (FSkinProp.IMG_BTN_FOCUS_RIGHT, SourceFile.ICONS),
|
||||
BTN_TOGGLE_LEFT (FSkinProp.IMG_BTN_TOGGLE_LEFT, SourceFile.ICONS),
|
||||
BTN_TOGGLE_CENTER (FSkinProp.IMG_BTN_TOGGLE_CENTER, SourceFile.ICONS),
|
||||
BTN_TOGGLE_RIGHT (FSkinProp.IMG_BTN_TOGGLE_RIGHT, SourceFile.ICONS),
|
||||
BTN_DISABLED_LEFT (FSkinProp.IMG_BTN_DISABLED_LEFT, SourceFile.ICONS),
|
||||
BTN_DISABLED_CENTER (FSkinProp.IMG_BTN_DISABLED_CENTER, SourceFile.ICONS),
|
||||
BTN_DISABLED_RIGHT (FSkinProp.IMG_BTN_DISABLED_RIGHT, SourceFile.ICONS),
|
||||
//Hdbuttons
|
||||
HDBTN_START_UP (FSkinProp.IMG_HDBTN_START_UP, SourceFile.BTNSTART),
|
||||
HDBTN_START_OVER (FSkinProp.IMG_HDBTN_START_OVER, SourceFile.BTNSTART),
|
||||
HDBTN_START_DOWN (FSkinProp.IMG_HDBTN_START_DOWN, SourceFile.BTNSTART),
|
||||
HDBTN_UP_LEFT (FSkinProp.IMG_HDBTN_UP_LEFT, SourceFile.BUTTONS),
|
||||
HDBTN_UP_CENTER (FSkinProp.IMG_HDBTN_UP_CENTER, SourceFile.BUTTONS),
|
||||
HDBTN_UP_RIGHT (FSkinProp.IMG_HDBTN_UP_RIGHT, SourceFile.BUTTONS),
|
||||
HDBTN_OVER_LEFT (FSkinProp.IMG_HDBTN_OVER_LEFT, SourceFile.BUTTONS),
|
||||
HDBTN_OVER_CENTER (FSkinProp.IMG_HDBTN_OVER_CENTER, SourceFile.BUTTONS),
|
||||
HDBTN_OVER_RIGHT (FSkinProp.IMG_HDBTN_OVER_RIGHT, SourceFile.BUTTONS),
|
||||
HDBTN_DOWN_LEFT (FSkinProp.IMG_HDBTN_DOWN_LEFT, SourceFile.BUTTONS),
|
||||
HDBTN_DOWN_CENTER (FSkinProp.IMG_HDBTN_DOWN_CENTER, SourceFile.BUTTONS),
|
||||
HDBTN_DOWN_RIGHT (FSkinProp.IMG_HDBTN_DOWN_RIGHT, SourceFile.BUTTONS),
|
||||
HDBTN_FOCUS_LEFT (FSkinProp.IMG_HDBTN_FOCUS_LEFT, SourceFile.BUTTONS),
|
||||
HDBTN_FOCUS_CENTER (FSkinProp.IMG_HDBTN_FOCUS_CENTER, SourceFile.BUTTONS),
|
||||
HDBTN_FOCUS_RIGHT (FSkinProp.IMG_HDBTN_FOCUS_RIGHT, SourceFile.BUTTONS),
|
||||
HDBTN_TOGGLE_LEFT (FSkinProp.IMG_HDBTN_TOGGLE_LEFT, SourceFile.BUTTONS),
|
||||
HDBTN_TOGGLE_CENTER (FSkinProp.IMG_HDBTN_TOGGLE_CENTER, SourceFile.BUTTONS),
|
||||
HDBTN_TOGGLE_RIGHT (FSkinProp.IMG_HDBTN_TOGGLE_RIGHT, SourceFile.BUTTONS),
|
||||
HDBTN_DISABLED_LEFT (FSkinProp.IMG_HDBTN_DISABLED_LEFT, SourceFile.BUTTONS),
|
||||
HDBTN_DISABLED_CENTER (FSkinProp.IMG_HDBTN_DISABLED_CENTER, SourceFile.BUTTONS),
|
||||
HDBTN_DISABLED_RIGHT (FSkinProp.IMG_HDBTN_DISABLED_RIGHT, SourceFile.BUTTONS),
|
||||
|
||||
//Foils
|
||||
FOIL_01 (FSkinProp.FOIL_01, SourceFile.FOILS),
|
||||
FOIL_02 (FSkinProp.FOIL_02, SourceFile.FOILS),
|
||||
FOIL_03 (FSkinProp.FOIL_03, SourceFile.FOILS),
|
||||
FOIL_04 (FSkinProp.FOIL_04, SourceFile.FOILS),
|
||||
FOIL_05 (FSkinProp.FOIL_05, SourceFile.FOILS),
|
||||
FOIL_06 (FSkinProp.FOIL_06, SourceFile.FOILS),
|
||||
FOIL_07 (FSkinProp.FOIL_07, SourceFile.FOILS),
|
||||
FOIL_08 (FSkinProp.FOIL_08, SourceFile.FOILS),
|
||||
FOIL_09 (FSkinProp.FOIL_09, SourceFile.FOILS),
|
||||
FOIL_10 (FSkinProp.FOIL_10, SourceFile.FOILS),
|
||||
|
||||
//Old Foils
|
||||
FOIL_11 (FSkinProp.FOIL_11, SourceFile.OLD_FOILS),
|
||||
FOIL_12 (FSkinProp.FOIL_12, SourceFile.OLD_FOILS),
|
||||
FOIL_13 (FSkinProp.FOIL_13, SourceFile.OLD_FOILS),
|
||||
FOIL_14 (FSkinProp.FOIL_14, SourceFile.OLD_FOILS),
|
||||
FOIL_15 (FSkinProp.FOIL_15, SourceFile.OLD_FOILS),
|
||||
FOIL_16 (FSkinProp.FOIL_16, SourceFile.OLD_FOILS),
|
||||
FOIL_17 (FSkinProp.FOIL_17, SourceFile.OLD_FOILS),
|
||||
FOIL_18 (FSkinProp.FOIL_18, SourceFile.OLD_FOILS),
|
||||
FOIL_19 (FSkinProp.FOIL_19, SourceFile.OLD_FOILS),
|
||||
FOIL_20 (FSkinProp.FOIL_20, SourceFile.OLD_FOILS),
|
||||
|
||||
//COMMANDER
|
||||
IMG_ABILITY_COMMANDER (FSkinProp.IMG_ABILITY_COMMANDER, SourceFile.ABILITIES),
|
||||
//ABILITY ICONS
|
||||
IMG_ABILITY_DEATHTOUCH (FSkinProp.IMG_ABILITY_DEATHTOUCH, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_DEFENDER (FSkinProp.IMG_ABILITY_DEFENDER, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_DOUBLE_STRIKE (FSkinProp.IMG_ABILITY_DOUBLE_STRIKE, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_FIRST_STRIKE (FSkinProp.IMG_ABILITY_FIRST_STRIKE, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_FEAR (FSkinProp.IMG_ABILITY_FEAR, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_FLASH (FSkinProp.IMG_ABILITY_FLASH, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_FLYING (FSkinProp.IMG_ABILITY_FLYING, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_HASTE (FSkinProp.IMG_ABILITY_HASTE, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_HEXPROOF (FSkinProp.IMG_ABILITY_HEXPROOF, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_HORSEMANSHIP (FSkinProp.IMG_ABILITY_HORSEMANSHIP, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_INDESTRUCTIBLE (FSkinProp.IMG_ABILITY_INDESTRUCTIBLE, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_INTIMIDATE (FSkinProp.IMG_ABILITY_INTIMIDATE, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_LANDWALK (FSkinProp.IMG_ABILITY_LANDWALK, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_LIFELINK (FSkinProp.IMG_ABILITY_LIFELINK, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_MENACE (FSkinProp.IMG_ABILITY_MENACE, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_REACH (FSkinProp.IMG_ABILITY_REACH, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_SHADOW (FSkinProp.IMG_ABILITY_SHADOW, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_SHROUD (FSkinProp.IMG_ABILITY_SHROUD, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_TRAMPLE (FSkinProp.IMG_ABILITY_TRAMPLE, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_VIGILANCE (FSkinProp.IMG_ABILITY_VIGILANCE, SourceFile.ABILITIES),
|
||||
//HEXPROOF FROM
|
||||
IMG_ABILITY_HEXPROOF_R (FSkinProp.IMG_ABILITY_HEXPROOF_R, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_HEXPROOF_G (FSkinProp.IMG_ABILITY_HEXPROOF_G, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_HEXPROOF_B (FSkinProp.IMG_ABILITY_HEXPROOF_B, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_HEXPROOF_U (FSkinProp.IMG_ABILITY_HEXPROOF_U, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_HEXPROOF_W (FSkinProp.IMG_ABILITY_HEXPROOF_W, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_HEXPROOF_C (FSkinProp.IMG_ABILITY_HEXPROOF_C, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_HEXPROOF_UB (FSkinProp.IMG_ABILITY_HEXPROOF_UB, SourceFile.ABILITIES),
|
||||
//token icon
|
||||
IMG_ABILITY_TOKEN (FSkinProp.IMG_ABILITY_TOKEN, SourceFile.ABILITIES),
|
||||
//border
|
||||
IMG_BORDER_BLACK (FSkinProp.IMG_BORDER_BLACK, SourceFile.BORDERS),
|
||||
IMG_BORDER_WHITE (FSkinProp.IMG_BORDER_WHITE, SourceFile.BORDERS),
|
||||
//PROTECT ICONS
|
||||
IMG_ABILITY_PROTECT_ALL (FSkinProp.IMG_ABILITY_PROTECT_ALL, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_B (FSkinProp.IMG_ABILITY_PROTECT_B, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_BU (FSkinProp.IMG_ABILITY_PROTECT_BU, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_BW (FSkinProp.IMG_ABILITY_PROTECT_BW, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_COLOREDSPELLS (FSkinProp.IMG_ABILITY_PROTECT_COLOREDSPELLS, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_G (FSkinProp.IMG_ABILITY_PROTECT_G, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_GB (FSkinProp.IMG_ABILITY_PROTECT_GB, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_GU (FSkinProp.IMG_ABILITY_PROTECT_GU, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_GW (FSkinProp.IMG_ABILITY_PROTECT_GW, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_GENERIC (FSkinProp.IMG_ABILITY_PROTECT_GENERIC, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_R (FSkinProp.IMG_ABILITY_PROTECT_R, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_RB (FSkinProp.IMG_ABILITY_PROTECT_RB, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_RG (FSkinProp.IMG_ABILITY_PROTECT_RG, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_RU (FSkinProp.IMG_ABILITY_PROTECT_RU, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_RW (FSkinProp.IMG_ABILITY_PROTECT_RW, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_U (FSkinProp.IMG_ABILITY_PROTECT_U, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_UW (FSkinProp.IMG_ABILITY_PROTECT_UW, SourceFile.ABILITIES),
|
||||
IMG_ABILITY_PROTECT_W (FSkinProp.IMG_ABILITY_PROTECT_W, SourceFile.ABILITIES);
|
||||
|
||||
public enum SourceFile {
|
||||
ICONS(ForgeConstants.SPRITE_ICONS_FILE),
|
||||
FOILS(ForgeConstants.SPRITE_FOILS_FILE),
|
||||
OLD_FOILS(ForgeConstants.SPRITE_OLD_FOILS_FILE),
|
||||
TROPHIES(ForgeConstants.SPRITE_TROPHIES_FILE),
|
||||
ABILITIES(ForgeConstants.SPRITE_ABILITY_FILE),
|
||||
BORDERS(ForgeConstants.SPRITE_BORDER_FILE),
|
||||
BUTTONS(ForgeConstants.SPRITE_BUTTONS_FILE),
|
||||
BTNSTART(ForgeConstants.SPRITE_START_FILE),
|
||||
MANAICONS(ForgeConstants.SPRITE_MANAICONS_FILE),
|
||||
PLANAR_CONQUEST(ForgeConstants.SPRITE_PLANAR_CONQUEST_FILE);
|
||||
|
||||
private final String filename;
|
||||
|
||||
SourceFile(String filename0) {
|
||||
filename = filename0;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
|
||||
private final int x, y, w, h;
|
||||
private final SourceFile sourceFile;
|
||||
private TextureRegion textureRegion;
|
||||
|
||||
FSkinImage(FSkinProp skinProp, SourceFile sourceFile0) {
|
||||
int[] coords = skinProp.getCoords();
|
||||
x = coords[0];
|
||||
y = coords[1];
|
||||
w = coords[2];
|
||||
h = coords[3];
|
||||
sourceFile = sourceFile0;
|
||||
FSkin.getImages().put(skinProp, this);
|
||||
}
|
||||
|
||||
public void load(Map<String, Texture> textures, Pixmap preferredIcons) {
|
||||
String filename = sourceFile.getFilename();
|
||||
FileHandle preferredFile = FSkin.getSkinFile(filename);
|
||||
Texture texture = textures.get(preferredFile.path());
|
||||
if (texture == null) {
|
||||
if (preferredFile.exists()) {
|
||||
try {
|
||||
if (Forge.isTextureFilteringEnabled()){
|
||||
texture = new Texture(preferredFile, true);
|
||||
texture.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
} else {
|
||||
texture = new Texture(preferredFile);
|
||||
}
|
||||
}
|
||||
catch (final Exception e) {
|
||||
System.err.println("Failed to load skin file: " + preferredFile);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (texture != null) {
|
||||
if (!(sourceFile == SourceFile.ICONS || sourceFile == SourceFile.MANAICONS)) { //just return region for preferred file if not icons file
|
||||
textureRegion = new TextureRegion(texture, x, y, w, h);
|
||||
return;
|
||||
}
|
||||
|
||||
int fullWidth = texture.getWidth();
|
||||
int fullHeight = texture.getHeight();
|
||||
|
||||
// Test if requested sub-image in inside bounds of preferred sprite.
|
||||
// (Height and width of preferred sprite were set in loadFontAndImages.)
|
||||
if (x + w <= fullWidth && y + h <= fullHeight) {
|
||||
// Test if various points of requested sub-image are transparent.
|
||||
// If any return true, image exists.
|
||||
int x0 = 0, y0 = 0;
|
||||
Color c;
|
||||
|
||||
// Center
|
||||
x0 = (x + w / 2);
|
||||
y0 = (y + h / 2);
|
||||
c = new Color(preferredIcons.getPixel(x0, y0));
|
||||
if (c.a != 0) {
|
||||
textureRegion = new TextureRegion(texture, x, y, w, h);
|
||||
return;
|
||||
}
|
||||
|
||||
x0 += 2;
|
||||
y0 += 2;
|
||||
c = new Color(preferredIcons.getPixel(x0, y0));
|
||||
if (c.a != 0) {
|
||||
textureRegion = new TextureRegion(texture, x, y, w, h);
|
||||
return;
|
||||
}
|
||||
|
||||
x0 -= 4;
|
||||
c = new Color(preferredIcons.getPixel(x0, y0));
|
||||
if (c.a != 0) {
|
||||
textureRegion = new TextureRegion(texture, x, y, w, h);
|
||||
return;
|
||||
}
|
||||
|
||||
y0 -= 4;
|
||||
c = new Color(preferredIcons.getPixel(x0, y0));
|
||||
if (c.a != 0) {
|
||||
textureRegion = new TextureRegion(texture, x, y, w, h);
|
||||
return;
|
||||
}
|
||||
|
||||
x0 += 4;
|
||||
c = new Color(preferredIcons.getPixel(x0, y0));
|
||||
if (c.a != 0) {
|
||||
textureRegion = new TextureRegion(texture, x, y, w, h);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//use default file if can't use preferred file
|
||||
FileHandle defaultFile = FSkin.getDefaultSkinFile(filename);
|
||||
texture = textures.get(defaultFile.path());
|
||||
if (texture == null) {
|
||||
if (defaultFile.exists()) {
|
||||
try {
|
||||
if (Forge.isTextureFilteringEnabled()){
|
||||
texture = new Texture(defaultFile, true);
|
||||
texture.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
} else {
|
||||
texture = new Texture(defaultFile);
|
||||
}
|
||||
}
|
||||
catch (final Exception e) {
|
||||
System.err.println("Failed to load skin file: " + defaultFile);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (texture != null) {
|
||||
textureRegion = new TextureRegion(texture, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidth() {
|
||||
return w;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHeight() {
|
||||
return h;
|
||||
}
|
||||
|
||||
public TextureRegion getTextureRegion() {
|
||||
return textureRegion;
|
||||
}
|
||||
|
||||
public float getNearestHQWidth(float baseWidth) {
|
||||
return ImageUtil.getNearestHQSize(baseWidth, w);
|
||||
}
|
||||
|
||||
public float getNearestHQHeight(float baseHeight) {
|
||||
return ImageUtil.getNearestHQSize(baseHeight, h);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
g.drawImage(textureRegion, x, y, w, h);
|
||||
}
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.Texture.TextureWrap;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public enum FSkinTexture implements FImage {
|
||||
BG_TEXTURE(ForgeConstants.TEXTURE_BG_FILE, true, false),
|
||||
BG_MATCH(ForgeConstants.MATCH_BG_FILE, false, false),
|
||||
BG_SPACE(ForgeConstants.SPACE_BG_FILE, false, false),
|
||||
BG_CHAOS_WHEEL(ForgeConstants.CHAOS_WHEEL_IMG_FILE, false, false),
|
||||
Academy_at_Tolaria_West(ForgeConstants.BG_1, false, true),
|
||||
Agyrem(ForgeConstants.BG_2, false, true),
|
||||
Akoum(ForgeConstants.BG_3, false, true),
|
||||
Aretopolis(ForgeConstants.BG_4, false, true),
|
||||
Astral_Arena(ForgeConstants.BG_5, false, true),
|
||||
Bant(ForgeConstants.BG_6, false, true),
|
||||
Bloodhill_Bastion(ForgeConstants.BG_7, false, true),
|
||||
Cliffside_Market(ForgeConstants.BG_8, false, true),
|
||||
Edge_of_Malacol(ForgeConstants.BG_9, false, true),
|
||||
Eloren_Wilds(ForgeConstants.BG_10, false, true),
|
||||
Feeding_Grounds(ForgeConstants.BG_11, false, true),
|
||||
Fields_of_Summer(ForgeConstants.BG_12, false, true),
|
||||
Furnace_Layer(ForgeConstants.BG_13, false, true),
|
||||
Gavony(ForgeConstants.BG_14, false, true),
|
||||
Glen_Elendra(ForgeConstants.BG_15, false, true),
|
||||
Glimmervoid_Basin(ForgeConstants.BG_16, false, true),
|
||||
Goldmeadow(ForgeConstants.BG_17, false, true),
|
||||
Grand_Ossuary(ForgeConstants.BG_18, false, true),
|
||||
Grixis(ForgeConstants.BG_19, false, true),
|
||||
Grove_of_the_Dreampods(ForgeConstants.BG_20, false, true),
|
||||
Hedron_Fields_of_Agadeem(ForgeConstants.BG_21, false, true),
|
||||
Immersturm(ForgeConstants.BG_22, false, true),
|
||||
Isle_of_Vesuva(ForgeConstants.BG_23, false, true),
|
||||
Izzet_Steam_Maze(ForgeConstants.BG_24, false, true),
|
||||
Jund(ForgeConstants.BG_25, false, true),
|
||||
Kessig(ForgeConstants.BG_26, false, true),
|
||||
Kharasha_Foothills(ForgeConstants.BG_27, false, true),
|
||||
Kilnspire_District(ForgeConstants.BG_28, false, true),
|
||||
Krosa(ForgeConstants.BG_29, false, true),
|
||||
Lair_of_the_Ashen_Idol(ForgeConstants.BG_30, false, true),
|
||||
Lethe_Lake(ForgeConstants.BG_31, false, true),
|
||||
Llanowar(ForgeConstants.BG_32, false, true),
|
||||
Minamo(ForgeConstants.BG_33, false, true),
|
||||
Mount_Keralia(ForgeConstants.BG_34, false, true),
|
||||
Murasa(ForgeConstants.BG_35, false, true),
|
||||
Naar_Isle(ForgeConstants.BG_36, false, true),
|
||||
Naya(ForgeConstants.BG_37, false, true),
|
||||
Nephalia(ForgeConstants.BG_38, false, true),
|
||||
Norns_Dominion(ForgeConstants.BG_39, false, true),
|
||||
Onakke_Catacomb(ForgeConstants.BG_40, false, true),
|
||||
Orochi_Colony(ForgeConstants.BG_41, false, true),
|
||||
Orzhova(ForgeConstants.BG_42, false, true),
|
||||
Otaria(ForgeConstants.BG_43, false, true),
|
||||
Panopticon(ForgeConstants.BG_44, false, true),
|
||||
Pools_of_Becoming(ForgeConstants.BG_45, false, true),
|
||||
Prahv(ForgeConstants.BG_46, false, true),
|
||||
Quicksilver_Sea(ForgeConstants.BG_47, false, true),
|
||||
Ravens_Run(ForgeConstants.BG_48, false, true),
|
||||
Sanctum_of_Serra(ForgeConstants.BG_49, false, true),
|
||||
Sea_of_Sand(ForgeConstants.BG_50, false, true),
|
||||
Selesnya_Loft_Gardens(ForgeConstants.BG_51, false, true),
|
||||
Shiv(ForgeConstants.BG_52, false, true),
|
||||
Skybreen(ForgeConstants.BG_53, false, true),
|
||||
Sokenzan(ForgeConstants.BG_54, false, true),
|
||||
Stairs_to_Infinity(ForgeConstants.BG_55, false, true),
|
||||
Stensia(ForgeConstants.BG_56, false, true),
|
||||
Stronghold_Furnace(ForgeConstants.BG_57, false, true),
|
||||
Takenuma(ForgeConstants.BG_58, false, true),
|
||||
Tazeem(ForgeConstants.BG_59, false, true),
|
||||
The_Aether_Flues(ForgeConstants.BG_60, false, true),
|
||||
The_Dark_Barony(ForgeConstants.BG_61, false, true),
|
||||
The_Eon_Fog(ForgeConstants.BG_62, false, true),
|
||||
The_Fourth_Sphere(ForgeConstants.BG_63, false, true),
|
||||
The_Great_Forest(ForgeConstants.BG_64, false, true),
|
||||
The_Hippodrome(ForgeConstants.BG_65, false, true),
|
||||
The_Maelstrom(ForgeConstants.BG_66, false, true),
|
||||
The_Zephyr_Maze(ForgeConstants.BG_67, false, true),
|
||||
Trail_of_the_MageRings(ForgeConstants.BG_68, false, true),
|
||||
Truga_Jungle(ForgeConstants.BG_69, false, true),
|
||||
Turri_Island(ForgeConstants.BG_70, false, true),
|
||||
Undercity_Reaches(ForgeConstants.BG_71, false, true),
|
||||
Velis_Vel(ForgeConstants.BG_72, false, true),
|
||||
Windriddle_Palaces(ForgeConstants.BG_73, false, true),
|
||||
Tember_City(ForgeConstants.BG_74, false, true),
|
||||
Celestine_Reef(ForgeConstants.BG_75, false, true),
|
||||
Horizon_Boughs(ForgeConstants.BG_76, false, true),
|
||||
Mirrored_Depths(ForgeConstants.BG_77, false, true),
|
||||
Talon_Gates(ForgeConstants.BG_78, false, true);
|
||||
|
||||
private final String filename;
|
||||
private final boolean repeat;
|
||||
private Texture texture;
|
||||
private final boolean isPlane;
|
||||
private static final List<String> PlanesValue;
|
||||
|
||||
FSkinTexture(String filename0, boolean repeat0, boolean isPlane0) {
|
||||
filename = filename0;
|
||||
repeat = repeat0;
|
||||
isPlane = isPlane0;
|
||||
}
|
||||
|
||||
static {
|
||||
PlanesValue = new ArrayList<>();
|
||||
for (FSkinTexture PlanesEnum : FSkinTexture.values()) {
|
||||
PlanesValue.add(PlanesEnum.filename
|
||||
.replace(".jpg", "")
|
||||
.replace("'", "")
|
||||
.replace("-", ""));
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getValues() {
|
||||
return Collections.unmodifiableList(PlanesValue);
|
||||
}
|
||||
|
||||
public void load() {
|
||||
FileHandle preferredFile = isPlane ? FSkin.getCachePlanechaseFile(filename) : FSkin.getSkinFile(filename);
|
||||
if (preferredFile.exists()) {
|
||||
try {
|
||||
texture = new Texture(preferredFile);
|
||||
}
|
||||
catch (final Exception e) {
|
||||
System.err.println("Failed to load skin file: " + preferredFile);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (texture == null) {
|
||||
//use default file if can't use preferred file
|
||||
FileHandle defaultFile = FSkin.getDefaultSkinFile(filename);
|
||||
if(isPlane) {
|
||||
defaultFile = FSkin.getSkinFile(ForgeConstants.MATCH_BG_FILE);
|
||||
if(!defaultFile.exists())
|
||||
defaultFile = FSkin.getDefaultSkinFile(ForgeConstants.MATCH_BG_FILE);
|
||||
}
|
||||
|
||||
if (defaultFile.exists()) {
|
||||
try {
|
||||
texture = new Texture(defaultFile);
|
||||
}
|
||||
catch (final Exception e) {
|
||||
System.err.println("Failed to load skin file: " + defaultFile);
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
System.err.println("Failed to load skin file: " + defaultFile);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (repeat) {
|
||||
texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidth() {
|
||||
return texture.getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHeight() {
|
||||
return texture.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
if (repeat) {
|
||||
g.drawRepeatingImage(texture, x, y, w, h);
|
||||
}
|
||||
else {
|
||||
g.drawImage(texture, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawRotated(Graphics g, float x, float y, float w, float h, float rotation) {
|
||||
g.drawRotatedImage(texture, x, y, w, h, x + w / 2, y + h / 2, rotation);
|
||||
}
|
||||
|
||||
public void drawFlipped(Graphics g, float x, float y, float w, float h) {
|
||||
g.drawFlippedImage(texture, x, y, w, h);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
|
||||
public class FTextureImage extends FImageComplex {
|
||||
private final Texture texture;
|
||||
|
||||
public FTextureImage(Texture texture0) {
|
||||
texture = texture0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidth() {
|
||||
return texture.getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHeight() {
|
||||
return texture.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Texture getTexture() {
|
||||
return texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegionX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegionY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
g.drawImage(texture, x, y, w, h);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
|
||||
public class FTextureRegionImage extends FImageComplex {
|
||||
private final TextureRegion textureRegion;
|
||||
|
||||
public FTextureRegionImage(TextureRegion textureRegion0) {
|
||||
textureRegion = textureRegion0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidth() {
|
||||
return textureRegion.getRegionWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHeight() {
|
||||
return textureRegion.getRegionHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Texture getTexture() {
|
||||
return textureRegion.getTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegionX() {
|
||||
return textureRegion.getRegionX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegionY() {
|
||||
return textureRegion.getRegionY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
g.drawImage(textureRegion, x, y, w, h);
|
||||
}
|
||||
}
|
||||
@@ -1,337 +0,0 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Pixmap.Format;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.cache.RemovalListener;
|
||||
import com.google.common.cache.RemovalNotification;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.ImageKeys;
|
||||
import forge.adventure.libgdxgui.card.CardRenderer;
|
||||
import forge.card.CardEdition;
|
||||
import forge.deck.Deck;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.IHasIcon;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.item.PaperCard;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.model.FModel;
|
||||
import forge.util.ImageUtil;
|
||||
import forge.util.TextUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* This class stores ALL card images in a cache with soft values. this means
|
||||
* that the images may be collected when they are not needed any more, but will
|
||||
* be kept as long as possible.
|
||||
* <p/>
|
||||
* The keys are the following:
|
||||
* <ul>
|
||||
* <li>Keys start with the file name, extension is skipped</li>
|
||||
* <li>The key without suffix belongs to the unmodified image from the file</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: ImageCache.java 24769 2014-02-09 13:56:04Z Hellfish $
|
||||
*/
|
||||
public class ImageCache {
|
||||
// short prefixes to save memory
|
||||
|
||||
private static final Set<String> missingIconKeys = new HashSet<>();
|
||||
private static LoadingCache<String, Texture> cache;
|
||||
public static void initCache(int capacity) {
|
||||
cache = CacheBuilder.newBuilder()
|
||||
.maximumSize(capacity)
|
||||
.expireAfterAccess(15, TimeUnit.MINUTES)
|
||||
.removalListener(new RemovalListener<String, Texture>() {
|
||||
@Override
|
||||
public void onRemoval(RemovalNotification<String, Texture> removalNotification) {
|
||||
if (removalNotification.wasEvicted()) {
|
||||
if (removalNotification.getValue() != ImageCache.defaultImage)
|
||||
removalNotification.getValue().dispose();
|
||||
|
||||
CardRenderer.clearcardArtCache();
|
||||
}
|
||||
}
|
||||
})
|
||||
.build(new ImageLoader());
|
||||
System.out.println("Card Texture Cache Size: "+capacity);
|
||||
}
|
||||
private static final LoadingCache<String, Texture> otherCache = CacheBuilder.newBuilder().build(new OtherImageLoader());
|
||||
public static final Texture defaultImage;
|
||||
public static FImage BlackBorder = FSkinImage.IMG_BORDER_BLACK;
|
||||
public static FImage WhiteBorder = FSkinImage.IMG_BORDER_WHITE;
|
||||
private static final Map<String, Pair<String, Boolean>> imageBorder = new HashMap<>(1024);
|
||||
|
||||
private static boolean imageLoaded, delayLoadRequested;
|
||||
public static void allowSingleLoad() {
|
||||
imageLoaded = false; //reset at the beginning of each render
|
||||
delayLoadRequested = false;
|
||||
}
|
||||
|
||||
static {
|
||||
Texture defImage = null;
|
||||
try {
|
||||
defImage = new Texture(Gdx.files.absolute(ForgeConstants.NO_CARD_FILE));
|
||||
} catch (Exception ex) {
|
||||
System.err.println("could not load default card image");
|
||||
} finally {
|
||||
defaultImage = (null == defImage) ? new Texture(10, 10, Format.RGBA8888) : defImage;
|
||||
}
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
cache.invalidateAll();
|
||||
cache.cleanUp();
|
||||
missingIconKeys.clear();
|
||||
}
|
||||
|
||||
public static void disposeTexture(){
|
||||
CardRenderer.clearcardArtCache();
|
||||
clear();
|
||||
}
|
||||
|
||||
public static Texture getImage(InventoryItem ii) {
|
||||
String imageKey = ii.getImageKey(false);
|
||||
if (imageKey != null) {
|
||||
if(imageKey.startsWith(ImageKeys.CARD_PREFIX) || imageKey.startsWith(ImageKeys.TOKEN_PREFIX))
|
||||
return getImage(ii.getImageKey(false), true, false);
|
||||
}
|
||||
return getImage(ii.getImageKey(false), true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve an icon from the cache. returns the current skin's ICO_UNKNOWN if the icon image is not found
|
||||
* in the cache and cannot be loaded from disk.
|
||||
*/
|
||||
public static FImage getIcon(IHasIcon ihi) {
|
||||
String imageKey = ihi.getIconImageKey();
|
||||
final Texture icon;
|
||||
if (missingIconKeys.contains(imageKey) || (icon = getImage(ihi.getIconImageKey(), false, true)) == null) {
|
||||
missingIconKeys.add(imageKey);
|
||||
return FSkinImage.UNKNOWN;
|
||||
}
|
||||
return new FTextureImage(icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks the card image exists from the disk.
|
||||
*/
|
||||
public static boolean imageKeyFileExists(String imageKey) {
|
||||
if (StringUtils.isEmpty(imageKey))
|
||||
return false;
|
||||
|
||||
if (imageKey.length() < 2)
|
||||
return false;
|
||||
|
||||
final String prefix = imageKey.substring(0, 2);
|
||||
|
||||
if (prefix.equals(ImageKeys.CARD_PREFIX)) {
|
||||
PaperCard paperCard = ImageUtil.getPaperCardFromImageKey(imageKey);
|
||||
if (paperCard == null)
|
||||
return false;
|
||||
|
||||
final boolean backFace = imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX);
|
||||
final String cardfilename = ImageUtil.getImageKey(paperCard, backFace, true);
|
||||
if (!new File(ForgeConstants.CACHE_CARD_PICS_DIR + "/" + cardfilename + ".jpg").exists())
|
||||
if (!new File(ForgeConstants.CACHE_CARD_PICS_DIR + "/" + cardfilename + ".png").exists())
|
||||
return new File(ForgeConstants.CACHE_CARD_PICS_DIR + "/" + TextUtil.fastReplace(cardfilename, ".full", ".fullborder") + ".jpg").exists();
|
||||
} else if (prefix.equals(ImageKeys.TOKEN_PREFIX)) {
|
||||
final String tokenfilename = imageKey.substring(2) + ".jpg";
|
||||
|
||||
return new File(ForgeConstants.CACHE_TOKEN_PICS_DIR, tokenfilename).exists();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This requests the original unscaled image from the cache for the given key.
|
||||
* If the image does not exist then it can return a default image if desired.
|
||||
* <p>
|
||||
* If the requested image is not present in the cache then it attempts to load
|
||||
* the image from file (slower) and then add it to the cache for fast future access.
|
||||
* </p>
|
||||
*/
|
||||
public static Texture getImage(String imageKey, boolean useDefaultIfNotFound) {
|
||||
return getImage(imageKey, useDefaultIfNotFound, false);
|
||||
}
|
||||
public static Texture getImage(String imageKey, boolean useDefaultIfNotFound, boolean useOtherCache) {
|
||||
if (StringUtils.isEmpty(imageKey)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean altState = imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX);
|
||||
if (altState) {
|
||||
imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.BACKFACE_POSTFIX.length());
|
||||
}
|
||||
if (imageKey.startsWith(ImageKeys.CARD_PREFIX)) {
|
||||
imageKey = ImageUtil.getImageKey(ImageUtil.getPaperCardFromImageKey(imageKey), altState, true);
|
||||
if (StringUtils.isBlank(imageKey)) {
|
||||
return defaultImage;
|
||||
}
|
||||
}
|
||||
|
||||
Texture image;
|
||||
if (useDefaultIfNotFound) {
|
||||
// Load from file and add to cache if not found in cache initially.
|
||||
image = useOtherCache ? otherCache.getIfPresent(imageKey) : cache.getIfPresent(imageKey);
|
||||
|
||||
if (image != null) { return image; }
|
||||
|
||||
if (imageLoaded) { //prevent loading more than one image each render for performance
|
||||
if (!delayLoadRequested) {
|
||||
//ensure images continue to load even if no input is being received
|
||||
delayLoadRequested = true;
|
||||
Gdx.graphics.requestRendering();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
imageLoaded = true;
|
||||
}
|
||||
|
||||
try { image = useOtherCache ? otherCache.get(imageKey) : cache.get(imageKey); }
|
||||
catch (final Exception ex) {
|
||||
image = null;
|
||||
}
|
||||
|
||||
// No image file exists for the given key so optionally associate with
|
||||
// a default "not available" image and add to cache for given key.
|
||||
if (image == null) {
|
||||
if (useDefaultIfNotFound) {
|
||||
image = defaultImage;
|
||||
if (useOtherCache)
|
||||
otherCache.put(imageKey, defaultImage);
|
||||
else
|
||||
cache.put(imageKey, defaultImage);
|
||||
if (imageBorder.get(image.toString()) == null)
|
||||
imageBorder.put(image.toString(), Pair.of(Color.valueOf("#171717").toString(), false)); //black border
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
public static void preloadCache(Iterable<String> keys) {
|
||||
if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DISABLE_CARD_IMAGES))
|
||||
return;
|
||||
for (String imageKey : keys){
|
||||
if(getImage(imageKey, false) == null)
|
||||
System.err.println("could not load card image:"+imageKey);
|
||||
}
|
||||
}
|
||||
public static void preloadCache(Deck deck) {
|
||||
if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DISABLE_CARD_IMAGES))
|
||||
return;
|
||||
if(deck == null||!Forge.enablePreloadExtendedArt)
|
||||
return;
|
||||
if (deck.getAllCardsInASinglePool().toFlatList().size() <= 100) {
|
||||
for (PaperCard p : deck.getAllCardsInASinglePool().toFlatList()) {
|
||||
if (getImage(p.getImageKey(false),false) == null)
|
||||
System.err.println("could not load card image:"+ p);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static TextureRegion croppedBorderImage(Texture image) {
|
||||
if (!image.toString().contains(".fullborder."))
|
||||
return new TextureRegion(image);
|
||||
float rscale = 0.96f;
|
||||
int rw = Math.round(image.getWidth()*rscale);
|
||||
int rh = Math.round(image.getHeight()*rscale);
|
||||
int rx = Math.round((image.getWidth() - rw)/2f);
|
||||
int ry = Math.round((image.getHeight() - rh)/2f)-2;
|
||||
return new TextureRegion(image, rx, ry, rw, rh);
|
||||
}
|
||||
public static Color borderColor(Texture t) {
|
||||
if (t == null)
|
||||
return Color.valueOf("#171717");
|
||||
return Color.valueOf(imageBorder.get(t.toString()).getLeft());
|
||||
}
|
||||
public static int getFSkinBorders(CardView c) {
|
||||
if (c == null)
|
||||
return 0;
|
||||
|
||||
CardView.CardStateView state = c.getCurrentState();
|
||||
CardEdition ed = FModel.getMagicDb().getEditions().get(state.getSetCode());
|
||||
// TODO: Treatment for silver here
|
||||
if (ed != null && ed.getBorderColor() == CardEdition.BorderColor.WHITE && state.getFoilIndex() == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
public static boolean isBorderlessCardArt(Texture t) {
|
||||
return ImageLoader.isBorderless(t);
|
||||
}
|
||||
public static void updateBorders(String textureString, Pair<String, Boolean> colorPair){
|
||||
imageBorder.put(textureString, colorPair);
|
||||
}
|
||||
public static FImage getBorder(String textureString) {
|
||||
if (imageBorder.get(textureString) == null)
|
||||
return BlackBorder;
|
||||
return imageBorder.get(textureString).getRight() ? WhiteBorder : BlackBorder;
|
||||
}
|
||||
public static FImage getBorderImage(String textureString, boolean canshow) {
|
||||
if (!canshow)
|
||||
return BlackBorder;
|
||||
return getBorder(textureString);
|
||||
}
|
||||
public static FImage getBorderImage(String textureString) {
|
||||
return getBorder(textureString);
|
||||
}
|
||||
public static Color getTint(CardView c, Texture t) {
|
||||
if (c == null)
|
||||
return borderColor(t);
|
||||
if (c.isFaceDown())
|
||||
return Color.valueOf("#171717");
|
||||
|
||||
CardView.CardStateView state = c.getCurrentState();
|
||||
if (state.getColors().isColorless()) { //Moonlace -> target spell or permanent becomes colorless.
|
||||
if (state.hasDevoid()) //devoid is colorless at all zones so return its corresponding border color...
|
||||
return borderColor(t);
|
||||
return Color.valueOf("#A0A6A4");
|
||||
}
|
||||
else if (state.getColors().isMonoColor()) {
|
||||
if (state.getColors().hasBlack())
|
||||
return Color.valueOf("#48494a");
|
||||
else if (state.getColors().hasBlue())
|
||||
return Color.valueOf("#62b5f8");
|
||||
else if (state.getColors().hasRed())
|
||||
return Color.valueOf("#f6532d");
|
||||
else if (state.getColors().hasGreen())
|
||||
return Color.valueOf("#66cb35");
|
||||
else if (state.getColors().hasWhite())
|
||||
return Color.valueOf("#EEEBE1");
|
||||
}
|
||||
else if (state.getColors().isMulticolor())
|
||||
return Color.valueOf("#F9E084");
|
||||
|
||||
return borderColor(t);
|
||||
}
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
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.TextureData;
|
||||
import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.ImageKeys;
|
||||
import forge.gui.FThreads;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.model.FModel;
|
||||
import forge.util.FileUtil;
|
||||
import forge.util.TextUtil;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import static forge.adventure.libgdxgui.assets.ImageCache.croppedBorderImage;
|
||||
|
||||
final class ImageLoader extends CacheLoader<String, Texture> {
|
||||
private static final List<String> borderlessCardlistKey = FileUtil.readFile(ForgeConstants.BORDERLESS_CARD_LIST_FILE);
|
||||
|
||||
Texture n;
|
||||
@Override
|
||||
public Texture load(String key) {
|
||||
if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DISABLE_CARD_IMAGES))
|
||||
return null;
|
||||
|
||||
boolean extendedArt = isBorderless(key) && Forge.enableUIMask.equals("Full");
|
||||
boolean textureFilter = Forge.isTextureFilteringEnabled();
|
||||
File file = ImageKeys.getImageFile(key);
|
||||
if (file != null) {
|
||||
FileHandle fh = new FileHandle(file);
|
||||
try {
|
||||
Texture t = new Texture(fh, textureFilter);
|
||||
//update
|
||||
ImageCache.updateBorders(t.toString(), extendedArt ? Pair.of(Color.valueOf("#171717").toString(), false): isCloserToWhite(getpixelColor(t)));
|
||||
if (textureFilter)
|
||||
t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
if (extendedArt)
|
||||
return generateTexture(fh, t, textureFilter);
|
||||
return t;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Forge.log("Could not read image file " + fh.path() + "\nException:\n" + ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Texture generateTexture(FileHandle fh, Texture t, boolean textureFilter) {
|
||||
if (t == null || fh == null)
|
||||
return t;
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Pixmap pImage = new Pixmap(fh);
|
||||
int w = pImage.getWidth();
|
||||
int h = pImage.getHeight();
|
||||
int radius = (h - w) / 8;
|
||||
Pixmap pMask = createRoundedRectangle(w, h, radius, Color.RED);
|
||||
drawPixelstoMask(pImage, pMask);
|
||||
TextureData textureData = new PixmapTextureData(
|
||||
pMask, //pixmap to use
|
||||
Pixmap.Format.RGBA8888,
|
||||
textureFilter, //use mipmaps
|
||||
false, true);
|
||||
n = new Texture(textureData);
|
||||
if (textureFilter)
|
||||
n.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
pImage.dispose();
|
||||
pMask.dispose();
|
||||
}
|
||||
});
|
||||
return n;
|
||||
}
|
||||
public Pixmap createRoundedRectangle(int width, int height, int cornerRadius, Color color) {
|
||||
Pixmap pixmap = new Pixmap(width, height, Pixmap.Format.RGBA8888);
|
||||
Pixmap ret = new Pixmap(width, height, Pixmap.Format.RGBA8888);
|
||||
pixmap.setColor(color);
|
||||
//round corners
|
||||
pixmap.fillCircle(cornerRadius, cornerRadius, cornerRadius);
|
||||
pixmap.fillCircle(width - cornerRadius - 1, cornerRadius, cornerRadius);
|
||||
pixmap.fillCircle(cornerRadius, height - cornerRadius - 1, cornerRadius);
|
||||
pixmap.fillCircle(width - cornerRadius - 1, height - cornerRadius - 1, cornerRadius);
|
||||
//two rectangle parts
|
||||
pixmap.fillRectangle(cornerRadius, 0, width - cornerRadius * 2, height);
|
||||
pixmap.fillRectangle(0, cornerRadius, width, height - cornerRadius * 2);
|
||||
//draw rounded rectangle
|
||||
ret.setColor(color);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
if (pixmap.getPixel(x, y) != 0) ret.drawPixel(x, y);
|
||||
}
|
||||
}
|
||||
pixmap.dispose();
|
||||
return ret;
|
||||
}
|
||||
public void drawPixelstoMask(Pixmap pixmap, Pixmap mask){
|
||||
int pixmapWidth = mask.getWidth();
|
||||
int pixmapHeight = mask.getHeight();
|
||||
Color pixelColor = new Color();
|
||||
for (int x=0; x<pixmapWidth; x++){
|
||||
for (int y=0; y<pixmapHeight; y++){
|
||||
if (mask.getPixel(x, y) != 0) {
|
||||
Color.rgba8888ToColor(pixelColor, pixmap.getPixel(x, y));
|
||||
mask.setColor(pixelColor);
|
||||
mask.drawPixel(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBorderless(String imagekey) {
|
||||
if(borderlessCardlistKey.isEmpty())
|
||||
return false;
|
||||
if (imagekey.length() > 7) {
|
||||
if ((!imagekey.substring(0, 7).contains("MPS_KLD"))&&(imagekey.substring(0, 4).contains("MPS_"))) //MPS_ sets except MPD_KLD
|
||||
return true;
|
||||
}
|
||||
return borderlessCardlistKey.contains(TextUtil.fastReplace(imagekey,".full",".fullborder"));
|
||||
}
|
||||
|
||||
public static boolean isBorderless(Texture t) {
|
||||
if(borderlessCardlistKey.isEmpty())
|
||||
return false;
|
||||
//generated texture/pixmap?
|
||||
if (t.toString().contains("com.badlogic.gdx.graphics.Texture@"))
|
||||
return true;
|
||||
for (String key : borderlessCardlistKey) {
|
||||
if (t.toString().contains(key))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getpixelColor(Texture i) {
|
||||
if (!i.getTextureData().isPrepared()) {
|
||||
i.getTextureData().prepare(); //prepare texture
|
||||
}
|
||||
//get pixmap from texture data
|
||||
Pixmap pixmap = i.getTextureData().consumePixmap();
|
||||
//get pixel color from x,y texture coordinate based on the image fullborder or not
|
||||
Color color = new Color(pixmap.getPixel(croppedBorderImage(i).getRegionX()+1, croppedBorderImage(i).getRegionY()+1));
|
||||
pixmap.dispose();
|
||||
return color.toString();
|
||||
}
|
||||
public static Pair<String, Boolean> isCloserToWhite(String c){
|
||||
if (c == null || c == "")
|
||||
return Pair.of(Color.valueOf("#171717").toString(), false);
|
||||
int c_r = Integer.parseInt(c.substring(0,2),16);
|
||||
int c_g = Integer.parseInt(c.substring(2,4),16);
|
||||
int c_b = Integer.parseInt(c.substring(4,6),16);
|
||||
int brightness = ((c_r * 299) + (c_g * 587) + (c_b * 114)) / 1000;
|
||||
return Pair.of(c,brightness > 155);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.ImageKeys;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
final class OtherImageLoader extends CacheLoader<String, Texture> {
|
||||
@Override
|
||||
public Texture load(String key) {
|
||||
File file = ImageKeys.getImageFile(key);
|
||||
if (file != null) {
|
||||
FileHandle fh = new FileHandle(file);
|
||||
try {
|
||||
if (Forge.isTextureFilteringEnabled()) {
|
||||
Texture t = new Texture(fh, true);
|
||||
t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
return t;
|
||||
} else {
|
||||
return new Texture(fh);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Forge.log("Could not read image file " + fh.path() + "\n\nException:\n" + ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,649 +0,0 @@
|
||||
package forge.adventure.libgdxgui.assets;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.card.CardFaceSymbols;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.localinstance.properties.ForgePreferences.FPref;
|
||||
import forge.model.FModel;
|
||||
import forge.adventure.libgdxgui.util.TextBounds;
|
||||
|
||||
import java.text.BreakIterator;
|
||||
import java.util.*;
|
||||
|
||||
//Encodes text for drawing with symbols and reminder text
|
||||
public class TextRenderer {
|
||||
private static final Map<String, FSkinImage> symbolLookup = new HashMap<>(64);
|
||||
static {
|
||||
symbolLookup.put("C", FSkinImage.MANA_COLORLESS);
|
||||
symbolLookup.put("W", FSkinImage.MANA_W);
|
||||
symbolLookup.put("U", FSkinImage.MANA_U);
|
||||
symbolLookup.put("B", FSkinImage.MANA_B);
|
||||
symbolLookup.put("R", FSkinImage.MANA_R);
|
||||
symbolLookup.put("G", FSkinImage.MANA_G);
|
||||
symbolLookup.put("W/U", FSkinImage.MANA_HYBRID_WU);
|
||||
symbolLookup.put("U/B", FSkinImage.MANA_HYBRID_UB);
|
||||
symbolLookup.put("B/R", FSkinImage.MANA_HYBRID_BR);
|
||||
symbolLookup.put("R/G", FSkinImage.MANA_HYBRID_RG);
|
||||
symbolLookup.put("G/W", FSkinImage.MANA_HYBRID_GW);
|
||||
symbolLookup.put("W/B", FSkinImage.MANA_HYBRID_WB);
|
||||
symbolLookup.put("U/R", FSkinImage.MANA_HYBRID_UR);
|
||||
symbolLookup.put("B/G", FSkinImage.MANA_HYBRID_BG);
|
||||
symbolLookup.put("R/W", FSkinImage.MANA_HYBRID_RW);
|
||||
symbolLookup.put("G/U", FSkinImage.MANA_HYBRID_GU);
|
||||
symbolLookup.put("2/W", FSkinImage.MANA_2W);
|
||||
symbolLookup.put("2/U", FSkinImage.MANA_2U);
|
||||
symbolLookup.put("2/B", FSkinImage.MANA_2B);
|
||||
symbolLookup.put("2/R", FSkinImage.MANA_2R);
|
||||
symbolLookup.put("2/G", FSkinImage.MANA_2G);
|
||||
symbolLookup.put("P/W", FSkinImage.MANA_PHRYX_W);
|
||||
symbolLookup.put("P/U", FSkinImage.MANA_PHRYX_U);
|
||||
symbolLookup.put("P/B", FSkinImage.MANA_PHRYX_B);
|
||||
symbolLookup.put("P/R", FSkinImage.MANA_PHRYX_R);
|
||||
symbolLookup.put("P/G", FSkinImage.MANA_PHRYX_G);
|
||||
symbolLookup.put("W/P", FSkinImage.MANA_PHRYX_W);
|
||||
symbolLookup.put("U/P", FSkinImage.MANA_PHRYX_U);
|
||||
symbolLookup.put("B/P", FSkinImage.MANA_PHRYX_B);
|
||||
symbolLookup.put("R/P", FSkinImage.MANA_PHRYX_R);
|
||||
symbolLookup.put("G/P", FSkinImage.MANA_PHRYX_G);
|
||||
for (int i = 0; i <= 20; i++) {
|
||||
symbolLookup.put(String.valueOf(i), FSkinImage.valueOf("MANA_" + i));
|
||||
}
|
||||
symbolLookup.put("X", FSkinImage.MANA_X);
|
||||
symbolLookup.put("Y", FSkinImage.MANA_Y);
|
||||
symbolLookup.put("Z", FSkinImage.MANA_Z);
|
||||
symbolLookup.put("CHAOS", FSkinImage.CHAOS);
|
||||
symbolLookup.put("Q", FSkinImage.UNTAP);
|
||||
symbolLookup.put("S", FSkinImage.MANA_SNOW);
|
||||
symbolLookup.put("T", FSkinImage.TAP);
|
||||
symbolLookup.put("E", FSkinImage.ENERGY);
|
||||
symbolLookup.put("AE", FSkinImage.AETHER_SHARD);
|
||||
symbolLookup.put("PW", FSkinImage.PW_BADGE_COMMON);
|
||||
symbolLookup.put("CR", FSkinImage.QUEST_COINSTACK);
|
||||
}
|
||||
|
||||
public static String startColor(Color color) {
|
||||
return "<clr " + Color.rgba8888(color) + ">";
|
||||
}
|
||||
public static String endColor() {
|
||||
return "</clr>";
|
||||
}
|
||||
|
||||
private final boolean parseReminderText;
|
||||
private String fullText = "";
|
||||
private float width, height, totalHeight;
|
||||
private FSkinFont baseFont, font;
|
||||
private boolean wrap, needClip;
|
||||
private final List<Piece> pieces = new ArrayList<>();
|
||||
private final List<Float> lineWidths = new ArrayList<>();
|
||||
private final BreakIterator boundary = BreakIterator.getLineInstance(new Locale(Forge.locale));
|
||||
|
||||
public TextRenderer() {
|
||||
this(false);
|
||||
}
|
||||
public TextRenderer(boolean parseReminderText0) {
|
||||
parseReminderText = parseReminderText0;
|
||||
}
|
||||
|
||||
//break text in pieces
|
||||
private void updatePieces(FSkinFont font0) {
|
||||
pieces.clear();
|
||||
lineWidths.clear();
|
||||
font = font0;
|
||||
needClip = false;
|
||||
if (fullText == null || fullText.isEmpty()) { return; }
|
||||
|
||||
totalHeight = font.getCapHeight();
|
||||
if (totalHeight > height) {
|
||||
//immediately try one font size smaller if no room for anything
|
||||
if (font.canShrink()) {
|
||||
updatePieces(font.shrink());
|
||||
return;
|
||||
}
|
||||
needClip = true;
|
||||
}
|
||||
|
||||
boundary.setText(fullText);
|
||||
ForgePreferences prefs = FModel.getPreferences();
|
||||
boolean hideReminderText = prefs != null && prefs.getPrefBoolean(FPref.UI_HIDE_REMINDER_TEXT);
|
||||
|
||||
char ch;
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float pieceWidth = 0;
|
||||
float lineHeight = font.getLineHeight();
|
||||
int nextSpaceIdx = boundary.first();
|
||||
int lastSpaceIdx = -1;
|
||||
int lineNum = 0;
|
||||
StringBuilder text = new StringBuilder();
|
||||
int inSymbolCount = 0;
|
||||
int consecutiveSymbols = 0;
|
||||
int inKeywordCount = 0;
|
||||
boolean atReminderTextEnd = false;
|
||||
int inReminderTextCount = 0;
|
||||
Color colorOverride = null;
|
||||
|
||||
for (int i = 0; i < fullText.length(); i++) {
|
||||
atReminderTextEnd = false;
|
||||
if (i == nextSpaceIdx) {
|
||||
lastSpaceIdx = text.length();
|
||||
nextSpaceIdx = boundary.next();
|
||||
}
|
||||
ch = fullText.charAt(i);
|
||||
switch (ch) {
|
||||
case '\r':
|
||||
continue; //skip '\r' character
|
||||
case '\n':
|
||||
if (inSymbolCount > 0) {
|
||||
inSymbolCount = 0;
|
||||
text.insert(0, '{'); //if not a symbol, render as text
|
||||
}
|
||||
lineWidths.add(x + pieceWidth);
|
||||
if (text.length() > 0) {
|
||||
addPiece(new TextPiece(text.toString(), colorOverride, inReminderTextCount > 0), lineNum, x, y, pieceWidth, lineHeight);
|
||||
pieceWidth = 0;
|
||||
text.setLength(0);
|
||||
consecutiveSymbols = 0;
|
||||
}
|
||||
lastSpaceIdx = -1;
|
||||
x = 0;
|
||||
y += lineHeight;
|
||||
totalHeight += lineHeight;
|
||||
lineNum++;
|
||||
if (totalHeight > height) {
|
||||
//try next font size down if out of space
|
||||
if (font.canShrink()) {
|
||||
updatePieces(font.shrink());
|
||||
return;
|
||||
}
|
||||
needClip = true;
|
||||
}
|
||||
continue; //skip new line character
|
||||
case '{':
|
||||
if (inSymbolCount == 0 && text.length() > 0) { //add current text if just entering symbol
|
||||
addPiece(new TextPiece(text.toString(), colorOverride,inReminderTextCount > 0), lineNum, x, y, pieceWidth, lineHeight);
|
||||
x += pieceWidth;
|
||||
pieceWidth = 0;
|
||||
text.setLength(0);
|
||||
lastSpaceIdx = -1;
|
||||
consecutiveSymbols = 0;
|
||||
}
|
||||
inSymbolCount++;
|
||||
continue; //skip '{' character
|
||||
case '}':
|
||||
if (inSymbolCount > 0) {
|
||||
inSymbolCount--;
|
||||
if (text.length() > 0) {
|
||||
FSkinImage symbol = symbolLookup.get(text.toString());
|
||||
if (symbol != null) {
|
||||
pieceWidth = lineHeight * CardFaceSymbols.FONT_SIZE_FACTOR;
|
||||
if (x + pieceWidth > width) {
|
||||
if (wrap) {
|
||||
y += lineHeight;
|
||||
totalHeight += lineHeight;
|
||||
lineNum++;
|
||||
if (totalHeight > height) {
|
||||
//try next font size down if out of space
|
||||
if (font.canShrink()) {
|
||||
updatePieces(font.shrink());
|
||||
return;
|
||||
}
|
||||
needClip = true;
|
||||
}
|
||||
if (consecutiveSymbols == 0) {
|
||||
lineWidths.add(x);
|
||||
x = 0;
|
||||
}
|
||||
else { //make previous consecutive symbols wrap too if needed
|
||||
x = 0;
|
||||
int startSymbolIdx = pieces.size() - consecutiveSymbols;
|
||||
lineWidths.add(pieces.get(startSymbolIdx).x);
|
||||
for (int j = startSymbolIdx; j < pieces.size(); j++) {
|
||||
Piece piece = pieces.get(j);
|
||||
piece.x = x;
|
||||
piece.y += lineHeight;
|
||||
piece.lineNum++;
|
||||
x += piece.w;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (font.canShrink()) {
|
||||
//try next font size down if out of space
|
||||
updatePieces(font.shrink());
|
||||
return;
|
||||
}
|
||||
else {
|
||||
needClip = true;
|
||||
}
|
||||
}
|
||||
addPiece(new SymbolPiece(symbol, inReminderTextCount > 0), lineNum, x, y - font.getAscent() + (lineHeight - pieceWidth) / 2, pieceWidth, pieceWidth);
|
||||
x += pieceWidth;
|
||||
pieceWidth = 0;
|
||||
text.setLength(0);
|
||||
lastSpaceIdx = -1;
|
||||
consecutiveSymbols++;
|
||||
continue; //skip '}' character
|
||||
}
|
||||
}
|
||||
if (!hideReminderText || inReminderTextCount == 0) {
|
||||
text.insert(0, '{'); //if not a symbol, render as text
|
||||
if (lastSpaceIdx >= 0) {
|
||||
lastSpaceIdx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '<':
|
||||
if (inSymbolCount > 0) {
|
||||
inSymbolCount = 0;
|
||||
text.insert(0, '{'); //if not a symbol, render as text
|
||||
if (lastSpaceIdx >= 0) {
|
||||
lastSpaceIdx++;
|
||||
}
|
||||
}
|
||||
if (inKeywordCount == 0 && text.length() > 0) { //add current text if starting a keyword
|
||||
addPiece(new TextPiece(text.toString(), colorOverride,false), lineNum, x, y, pieceWidth, lineHeight);
|
||||
x += pieceWidth;
|
||||
pieceWidth = 0;
|
||||
text.setLength(0);
|
||||
lastSpaceIdx = -1;
|
||||
consecutiveSymbols = 0;
|
||||
}
|
||||
inKeywordCount++;
|
||||
break;
|
||||
case '>':
|
||||
if (inSymbolCount > 0) {
|
||||
inSymbolCount = 0;
|
||||
text.insert(0, '{'); //if not a symbol, render as text
|
||||
if (lastSpaceIdx >= 0) {
|
||||
lastSpaceIdx++;
|
||||
}
|
||||
}
|
||||
if (inKeywordCount > 0) {
|
||||
inKeywordCount--;
|
||||
if (inKeywordCount == 0 && text.length() > 0) {
|
||||
String keyword, value;
|
||||
text.deleteCharAt(0); //trim leading '<'
|
||||
if (text.charAt(0) == '/') {
|
||||
keyword = text.substring(1);
|
||||
value = null;
|
||||
}
|
||||
else {
|
||||
int idx = text.indexOf(" ");
|
||||
if (idx != -1) {
|
||||
keyword = text.substring(0, idx);
|
||||
value = text.substring(idx + 1);
|
||||
}
|
||||
else {
|
||||
keyword = text.toString();
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
boolean validKeyword = true;
|
||||
switch (keyword) {
|
||||
case "clr":
|
||||
colorOverride = value != null ? new Color(Integer.parseInt(value)) : null;
|
||||
break;
|
||||
default:
|
||||
validKeyword = false;
|
||||
break;
|
||||
}
|
||||
if (validKeyword) {
|
||||
text.setLength(0);
|
||||
lastSpaceIdx = -1;
|
||||
continue; //skip '>' character
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '(':
|
||||
if (inSymbolCount > 0) {
|
||||
inSymbolCount = 0;
|
||||
text.insert(0, '{'); //if not a symbol, render as text
|
||||
if (lastSpaceIdx >= 0) {
|
||||
lastSpaceIdx++;
|
||||
}
|
||||
}
|
||||
if (parseReminderText) {
|
||||
if (inReminderTextCount == 0 && text.length() > 0) { //add current text if just entering reminder text
|
||||
addPiece(new TextPiece(text.toString(), colorOverride,false), lineNum, x, y, pieceWidth, lineHeight);
|
||||
x += pieceWidth;
|
||||
pieceWidth = 0;
|
||||
text.setLength(0);
|
||||
lastSpaceIdx = -1;
|
||||
consecutiveSymbols = 0;
|
||||
}
|
||||
inReminderTextCount++;
|
||||
}
|
||||
break;
|
||||
case ')':
|
||||
if (inSymbolCount > 0) {
|
||||
inSymbolCount = 0;
|
||||
text.insert(0, '{'); //if not a symbol, render as text
|
||||
if (lastSpaceIdx >= 0) {
|
||||
lastSpaceIdx++;
|
||||
}
|
||||
}
|
||||
if (inReminderTextCount > 0) {
|
||||
inReminderTextCount--;
|
||||
if (inReminderTextCount == 0) {
|
||||
atReminderTextEnd = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
if (inKeywordCount == 0 && inSymbolCount > 0) {
|
||||
inSymbolCount = 0;
|
||||
text.insert(0, '{'); //if not a symbol, render as text
|
||||
if (lastSpaceIdx >= 0) {
|
||||
lastSpaceIdx++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (hideReminderText && (inReminderTextCount > 0 || atReminderTextEnd)) {
|
||||
continue;
|
||||
}
|
||||
text.append(ch);
|
||||
if (inSymbolCount == 0 && inKeywordCount == 0) {
|
||||
pieceWidth = font.getBounds(text).width;
|
||||
if (x + pieceWidth > width) { //wrap or shrink if needed
|
||||
if (wrap && (lastSpaceIdx >= 0 || consecutiveSymbols > 0)) {
|
||||
if (lastSpaceIdx < 0) {
|
||||
//no space between symbols and end of line, wrap those symbols along with text
|
||||
x = 0;
|
||||
int startSymbolIdx = pieces.size() - consecutiveSymbols;
|
||||
lineWidths.add(pieces.get(startSymbolIdx).x);
|
||||
for (int j = startSymbolIdx; j < pieces.size(); j++) {
|
||||
Piece piece = pieces.get(j);
|
||||
piece.x = x;
|
||||
piece.y += lineHeight;
|
||||
piece.lineNum++;
|
||||
x += piece.w;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int endIdx = lastSpaceIdx;
|
||||
if (lastSpaceIdx > 0 && text.charAt(lastSpaceIdx - 1) == ' ') {
|
||||
endIdx = lastSpaceIdx - 1;
|
||||
}
|
||||
String currentLineText = text.substring(0, endIdx);
|
||||
if (!currentLineText.isEmpty()) {
|
||||
pieceWidth = font.getBounds(currentLineText).width;
|
||||
addPiece(new TextPiece(currentLineText, colorOverride,inReminderTextCount > 0 || atReminderTextEnd), lineNum, x, y, pieceWidth, lineHeight);
|
||||
consecutiveSymbols = 0;
|
||||
}
|
||||
else {
|
||||
pieceWidth = 0;
|
||||
}
|
||||
lineWidths.add(x + pieceWidth);
|
||||
text.delete(0, lastSpaceIdx);
|
||||
x = 0;
|
||||
}
|
||||
lastSpaceIdx = -1;
|
||||
pieceWidth = text.length() == 0 ? 0 : font.getBounds(text).width;
|
||||
y += lineHeight;
|
||||
totalHeight += lineHeight;
|
||||
lineNum++;
|
||||
if (totalHeight > height) {
|
||||
//try next font size down if out of space
|
||||
if (font.canShrink()) {
|
||||
updatePieces(font.shrink());
|
||||
return;
|
||||
}
|
||||
needClip = true;
|
||||
}
|
||||
}
|
||||
else if (x > 0 && pieceWidth <= width) {
|
||||
//if current piece starting past beginning of line and no spaces found,
|
||||
//wrap current piece being built up along with part of previous pieces as needed
|
||||
int lastPieceIdx;
|
||||
for (lastPieceIdx = pieces.size() - 1; lastPieceIdx >= 0; lastPieceIdx--) {
|
||||
Piece lastPiece = pieces.get(lastPieceIdx);
|
||||
if (lastPiece.lineNum < lineNum) {
|
||||
lastPieceIdx = pieces.size() - 1; //don't re-wrap anything if reached previous line
|
||||
break;
|
||||
}
|
||||
if (lastPiece instanceof TextPiece) {
|
||||
TextPiece textPiece = (TextPiece)lastPiece;
|
||||
int index = textPiece.text.lastIndexOf(' ');
|
||||
if (index != -1) {
|
||||
if (index == 0) {
|
||||
textPiece.text = textPiece.text.substring(1);
|
||||
textPiece.w = font.getBounds(textPiece.text).width;
|
||||
lastPieceIdx--;
|
||||
}
|
||||
else if (index == textPiece.text.length() - 1) {
|
||||
textPiece.text = textPiece.text.substring(0, textPiece.text.length() - 1);
|
||||
textPiece.w = font.getBounds(textPiece.text).width;
|
||||
}
|
||||
else {
|
||||
TextPiece splitPiece = new TextPiece(textPiece.text.substring(index + 1), textPiece.colorOverride, textPiece.inReminderText);
|
||||
textPiece.text = textPiece.text.substring(0, index);
|
||||
textPiece.w = font.getBounds(textPiece.text).width;
|
||||
splitPiece.x = textPiece.x + textPiece.w;
|
||||
splitPiece.y = textPiece.y;
|
||||
splitPiece.w = font.getBounds(splitPiece.text).width;
|
||||
splitPiece.h = textPiece.h;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastPieceIdx >= 0) {
|
||||
Piece lastPiece = pieces.get(lastPieceIdx);
|
||||
lineWidths.add(lastPiece.x + lastPiece.w);
|
||||
x = 0;
|
||||
for (int j = lastPieceIdx + 1; j < pieces.size(); j++) {
|
||||
Piece piece = pieces.get(j);
|
||||
piece.x = x;
|
||||
piece.y += lineHeight;
|
||||
piece.lineNum++;
|
||||
x += piece.w;
|
||||
}
|
||||
y += lineHeight;
|
||||
totalHeight += lineHeight;
|
||||
lineNum++;
|
||||
if (totalHeight > height) {
|
||||
//try next font size down if out of space
|
||||
if (font.canShrink()) {
|
||||
updatePieces(font.shrink());
|
||||
return;
|
||||
}
|
||||
needClip = true;
|
||||
}
|
||||
} else {
|
||||
if (font.canShrink()) {
|
||||
//try next font size down if out of space
|
||||
updatePieces(font.shrink());
|
||||
return;
|
||||
}
|
||||
needClip = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (font.canShrink()) {
|
||||
//try next font size down if out of space
|
||||
updatePieces(font.shrink());
|
||||
return;
|
||||
}
|
||||
needClip = true;
|
||||
}
|
||||
}
|
||||
if (atReminderTextEnd && text.length() > 0) { //ensure final piece of reminder text added right away
|
||||
addPiece(new TextPiece(text.toString(), colorOverride, true), lineNum, x, y, pieceWidth, lineHeight);
|
||||
x += pieceWidth;
|
||||
pieceWidth = 0;
|
||||
text.setLength(0);
|
||||
lastSpaceIdx = -1;
|
||||
consecutiveSymbols = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lineWidths.add(x + pieceWidth);
|
||||
if (text.length() > 0) {
|
||||
addPiece(new TextPiece(text.toString(), colorOverride, inReminderTextCount > 0), lineNum, x, y, pieceWidth, lineHeight);
|
||||
consecutiveSymbols = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void addPiece(Piece piece, int lineNum, float x, float y, float w, float h) {
|
||||
piece.lineNum = lineNum;
|
||||
piece.x = x;
|
||||
piece.y = y;
|
||||
piece.w = w;
|
||||
piece.h = h;
|
||||
pieces.add(piece);
|
||||
}
|
||||
|
||||
private void setProps(String text, FSkinFont skinFont, float w, float h, boolean wrap0) {
|
||||
boolean needUpdate = false;
|
||||
if (!fullText.equals(text)) {
|
||||
fullText = text;
|
||||
needUpdate = true;
|
||||
}
|
||||
if (skinFont != baseFont) {
|
||||
baseFont = skinFont;
|
||||
needUpdate = true;
|
||||
}
|
||||
if (width != w) {
|
||||
width = w;
|
||||
needUpdate = true;
|
||||
}
|
||||
if (height != h) {
|
||||
height = h;
|
||||
needUpdate = true;
|
||||
}
|
||||
if (wrap != wrap0) {
|
||||
wrap = wrap0;
|
||||
needUpdate = true;
|
||||
}
|
||||
if (needUpdate) {
|
||||
updatePieces(baseFont);
|
||||
}
|
||||
}
|
||||
|
||||
private TextBounds getCurrentBounds() {
|
||||
float maxWidth = 0;
|
||||
for (Float lineWidth : lineWidths) {
|
||||
if (lineWidth > maxWidth) {
|
||||
maxWidth = lineWidth;
|
||||
}
|
||||
}
|
||||
TextBounds bounds = new TextBounds();
|
||||
bounds.width = maxWidth;
|
||||
bounds.height = totalHeight;
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public TextBounds getBounds(String text, FSkinFont skinFont) {
|
||||
setProps(text, skinFont, Float.MAX_VALUE, Float.MAX_VALUE, false);
|
||||
return getCurrentBounds();
|
||||
}
|
||||
public TextBounds getWrappedBounds(String text, FSkinFont skinFont, float maxWidth) {
|
||||
setProps(text, skinFont, maxWidth, Float.MAX_VALUE, true);
|
||||
return getCurrentBounds();
|
||||
}
|
||||
|
||||
public void drawText(Graphics g, String text, FSkinFont skinFont, FSkinColor skinColor, float x, float y, float w, float h, float visibleStartY, float visibleHeight, boolean wrap0, int horzAlignment, boolean centerVertically) {
|
||||
drawText(g, text, skinFont, skinColor.getColor(), x, y, w, h, visibleStartY, visibleHeight, wrap0, horzAlignment, centerVertically);
|
||||
}
|
||||
public void drawText(Graphics g, String text, FSkinFont skinFont, Color color, float x, float y, float w, float h, float visibleStartY, float visibleHeight, boolean wrap0, int horzAlignment, boolean centerVertically) {
|
||||
setProps(text, skinFont, w, h, wrap0);
|
||||
if (needClip) { //prevent text flowing outside region if couldn't shrink it to fit
|
||||
g.startClip(x, y, w, h);
|
||||
}
|
||||
if (height > totalHeight && centerVertically) {
|
||||
y += (height - totalHeight) / 2;
|
||||
}
|
||||
float[] alignmentOffsets = new float[lineWidths.size()];
|
||||
for (int i = 0; i < lineWidths.size(); i++) {
|
||||
switch (horzAlignment) {
|
||||
case Align.left:
|
||||
alignmentOffsets[i] = 0;
|
||||
break;
|
||||
case Align.center:
|
||||
alignmentOffsets[i] = Math.max((width - lineWidths.get(i)) / 2, 0);
|
||||
break;
|
||||
case Align.right:
|
||||
alignmentOffsets[i] = Math.max(width - lineWidths.get(i), 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
visibleStartY -= y; //subtract y to make calculation quicker
|
||||
float visibleEndY = visibleStartY + visibleHeight;
|
||||
|
||||
for (Piece piece : pieces) {
|
||||
if (piece.y + piece.h < visibleStartY) {
|
||||
continue;
|
||||
}
|
||||
if (piece.y >= visibleEndY) {
|
||||
break;
|
||||
}
|
||||
piece.draw(g, color, x + alignmentOffsets[piece.lineNum], y);
|
||||
}
|
||||
if (needClip) {
|
||||
g.endClip();
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class Piece {
|
||||
protected static final float ALPHA_COMPOSITE = 0.5f;
|
||||
|
||||
protected final boolean inReminderText;
|
||||
protected float x, y, w, h;
|
||||
protected int lineNum;
|
||||
|
||||
protected Piece(boolean inReminderText0) {
|
||||
inReminderText = inReminderText0;
|
||||
}
|
||||
|
||||
public abstract void draw(Graphics g, Color color, float offsetX, float offsetY);
|
||||
}
|
||||
|
||||
private class TextPiece extends Piece {
|
||||
private String text;
|
||||
private final Color colorOverride;
|
||||
|
||||
private TextPiece(String text0, Color colorOverride0, boolean inReminderText0) {
|
||||
super(inReminderText0);
|
||||
text = text0;
|
||||
colorOverride = colorOverride0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g, Color color, float offsetX, float offsetY) {
|
||||
if (colorOverride != null) {
|
||||
color = colorOverride;
|
||||
}
|
||||
else if (inReminderText) {
|
||||
color = FSkinColor.alphaColor(color, ALPHA_COMPOSITE);
|
||||
}
|
||||
g.drawText(text, font, color, x + offsetX, y + offsetY, w, h, false, Align.left, false);
|
||||
}
|
||||
}
|
||||
|
||||
private class SymbolPiece extends Piece {
|
||||
private final FSkinImage image;
|
||||
|
||||
private SymbolPiece(FSkinImage image0, boolean inReminderText0) {
|
||||
super(inReminderText0);
|
||||
image = image0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g, Color color, float offsetX, float offsetY) {
|
||||
if (inReminderText) {
|
||||
g.setAlphaComposite(ALPHA_COMPOSITE);
|
||||
}
|
||||
g.drawImage(image, x + offsetX, y + offsetY, w, h);
|
||||
if (inReminderText) {
|
||||
g.resetAlphaComposite();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package forge.adventure.libgdxgui.card;
|
||||
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FImage;
|
||||
import forge.adventure.libgdxgui.assets.ImageCache;
|
||||
import forge.item.PaperCard;
|
||||
|
||||
public class CardAvatarImage implements FImage {
|
||||
private final String imageKey;
|
||||
private FImage image;
|
||||
|
||||
public CardAvatarImage(PaperCard card0) {
|
||||
this(card0.getImageKey(false));
|
||||
}
|
||||
public CardAvatarImage(String imageKey0) {
|
||||
imageKey = imageKey0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidth() {
|
||||
return getHeight(); //image will be drawn at its height
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHeight() {
|
||||
if (image != null) {
|
||||
return image.getHeight();
|
||||
}
|
||||
return ImageCache.defaultImage.getHeight() * CardRenderer.CARD_ART_HEIGHT_PERCENTAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
//force to get the avatar since the the cardartcache & loadingcache is always cleared on screen change or the battle bar will display black
|
||||
image = CardRenderer.getCardArt(imageKey, false, false, false);
|
||||
if (image == null) {
|
||||
return; //can't draw anything if can't be loaded yet
|
||||
}
|
||||
|
||||
//draw scaled image into clipped region so it fills box while maintain aspect ratio
|
||||
g.startClip(x, y, w, h);
|
||||
|
||||
float aspectRatio = w / h;
|
||||
float imageAspectRatio = image.getWidth() / image.getHeight();
|
||||
if (imageAspectRatio > aspectRatio) {
|
||||
float w0 = w * imageAspectRatio / aspectRatio;
|
||||
x -= (w0 - w) / 2;
|
||||
w = w0;
|
||||
}
|
||||
else {
|
||||
float h0 = h * aspectRatio / imageAspectRatio;
|
||||
y -= (h0 - h) / 2;
|
||||
h = h0;
|
||||
}
|
||||
|
||||
image.draw(g, x, y, w, h);
|
||||
|
||||
g.endClip();
|
||||
}
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.adventure.libgdxgui.card;
|
||||
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinImage;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.gui.error.BugReporter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
|
||||
public class CardFaceSymbols {
|
||||
public static final float FONT_SIZE_FACTOR = 0.85f;
|
||||
private static final Map<String, FSkinImage> MANA_IMAGES = new HashMap<>(128);
|
||||
|
||||
public static void loadImages() {
|
||||
for (int i = 0; i <= 20; i++) {
|
||||
MANA_IMAGES.put(String.valueOf(i), FSkinImage.valueOf("MANA_" + i));
|
||||
}
|
||||
MANA_IMAGES.put("X", FSkinImage.MANA_X);
|
||||
MANA_IMAGES.put("Y", FSkinImage.MANA_Y);
|
||||
MANA_IMAGES.put("Z", FSkinImage.MANA_Z);
|
||||
|
||||
MANA_IMAGES.put("C", FSkinImage.MANA_COLORLESS);
|
||||
MANA_IMAGES.put("B", FSkinImage.MANA_B);
|
||||
MANA_IMAGES.put("BG", FSkinImage.MANA_HYBRID_BG);
|
||||
MANA_IMAGES.put("BR", FSkinImage.MANA_HYBRID_BR);
|
||||
MANA_IMAGES.put("G", FSkinImage.MANA_G);
|
||||
MANA_IMAGES.put("GU", FSkinImage.MANA_HYBRID_GU);
|
||||
MANA_IMAGES.put("GW", FSkinImage.MANA_HYBRID_GW);
|
||||
MANA_IMAGES.put("R", FSkinImage.MANA_R);
|
||||
MANA_IMAGES.put("RG", FSkinImage.MANA_HYBRID_RG);
|
||||
MANA_IMAGES.put("RW", FSkinImage.MANA_HYBRID_RW);
|
||||
MANA_IMAGES.put("U", FSkinImage.MANA_U);
|
||||
MANA_IMAGES.put("UB", FSkinImage.MANA_HYBRID_UB);
|
||||
MANA_IMAGES.put("UR", FSkinImage.MANA_HYBRID_UR);
|
||||
MANA_IMAGES.put("W", FSkinImage.MANA_W);
|
||||
MANA_IMAGES.put("WB", FSkinImage.MANA_HYBRID_WB);
|
||||
MANA_IMAGES.put("WU", FSkinImage.MANA_HYBRID_WU);
|
||||
MANA_IMAGES.put("PW", FSkinImage.MANA_PHRYX_W);
|
||||
MANA_IMAGES.put("PR", FSkinImage.MANA_PHRYX_R);
|
||||
MANA_IMAGES.put("PU", FSkinImage.MANA_PHRYX_U);
|
||||
MANA_IMAGES.put("PB", FSkinImage.MANA_PHRYX_B);
|
||||
MANA_IMAGES.put("PG", FSkinImage.MANA_PHRYX_G);
|
||||
MANA_IMAGES.put("2W", FSkinImage.MANA_2W);
|
||||
MANA_IMAGES.put("2U", FSkinImage.MANA_2U);
|
||||
MANA_IMAGES.put("2R", FSkinImage.MANA_2R);
|
||||
MANA_IMAGES.put("2G", FSkinImage.MANA_2G);
|
||||
MANA_IMAGES.put("2B", FSkinImage.MANA_2B);
|
||||
|
||||
MANA_IMAGES.put("S", FSkinImage.MANA_SNOW);
|
||||
MANA_IMAGES.put("T", FSkinImage.TAP);
|
||||
MANA_IMAGES.put("E", FSkinImage.ENERGY);
|
||||
MANA_IMAGES.put("slash", FSkinImage.SLASH);
|
||||
MANA_IMAGES.put("attack", FSkinImage.ATTACK);
|
||||
MANA_IMAGES.put("defend", FSkinImage.DEFEND);
|
||||
MANA_IMAGES.put("summonsick", FSkinImage.SUMMONSICK);
|
||||
MANA_IMAGES.put("phasing", FSkinImage.PHASING);
|
||||
MANA_IMAGES.put("sacrifice", FSkinImage.COSTRESERVED);
|
||||
MANA_IMAGES.put("counters1", FSkinImage.COUNTERS1);
|
||||
MANA_IMAGES.put("counters2", FSkinImage.COUNTERS2);
|
||||
MANA_IMAGES.put("counters3", FSkinImage.COUNTERS3);
|
||||
MANA_IMAGES.put("countersMulti", FSkinImage.COUNTERS_MULTI);
|
||||
|
||||
MANA_IMAGES.put("foil01", FSkinImage.FOIL_01);
|
||||
MANA_IMAGES.put("foil02", FSkinImage.FOIL_02);
|
||||
MANA_IMAGES.put("foil03", FSkinImage.FOIL_03);
|
||||
MANA_IMAGES.put("foil04", FSkinImage.FOIL_04);
|
||||
MANA_IMAGES.put("foil05", FSkinImage.FOIL_05);
|
||||
MANA_IMAGES.put("foil06", FSkinImage.FOIL_06);
|
||||
MANA_IMAGES.put("foil07", FSkinImage.FOIL_07);
|
||||
MANA_IMAGES.put("foil08", FSkinImage.FOIL_08);
|
||||
MANA_IMAGES.put("foil09", FSkinImage.FOIL_09);
|
||||
MANA_IMAGES.put("foil10", FSkinImage.FOIL_10);
|
||||
|
||||
MANA_IMAGES.put("foil11", FSkinImage.FOIL_11);
|
||||
MANA_IMAGES.put("foil12", FSkinImage.FOIL_12);
|
||||
MANA_IMAGES.put("foil13", FSkinImage.FOIL_13);
|
||||
MANA_IMAGES.put("foil14", FSkinImage.FOIL_14);
|
||||
MANA_IMAGES.put("foil15", FSkinImage.FOIL_15);
|
||||
MANA_IMAGES.put("foil16", FSkinImage.FOIL_16);
|
||||
MANA_IMAGES.put("foil17", FSkinImage.FOIL_17);
|
||||
MANA_IMAGES.put("foil18", FSkinImage.FOIL_18);
|
||||
MANA_IMAGES.put("foil19", FSkinImage.FOIL_19);
|
||||
MANA_IMAGES.put("foil20", FSkinImage.FOIL_20);
|
||||
|
||||
MANA_IMAGES.put("commander", FSkinImage.IMG_ABILITY_COMMANDER);
|
||||
|
||||
MANA_IMAGES.put("deathtouch", FSkinImage.IMG_ABILITY_DEATHTOUCH);
|
||||
MANA_IMAGES.put("defender", FSkinImage.IMG_ABILITY_DEFENDER);
|
||||
MANA_IMAGES.put("doublestrike", FSkinImage.IMG_ABILITY_DOUBLE_STRIKE);
|
||||
MANA_IMAGES.put("firststrike", FSkinImage.IMG_ABILITY_FIRST_STRIKE);
|
||||
MANA_IMAGES.put("fear", FSkinImage.IMG_ABILITY_FEAR);
|
||||
MANA_IMAGES.put("flash", FSkinImage.IMG_ABILITY_FLASH);
|
||||
MANA_IMAGES.put("flying", FSkinImage.IMG_ABILITY_FLYING);
|
||||
MANA_IMAGES.put("haste", FSkinImage.IMG_ABILITY_HASTE);
|
||||
MANA_IMAGES.put("hexproof", FSkinImage.IMG_ABILITY_HEXPROOF);
|
||||
MANA_IMAGES.put("horsemanship", FSkinImage.IMG_ABILITY_HORSEMANSHIP);
|
||||
MANA_IMAGES.put("indestructible", FSkinImage.IMG_ABILITY_INDESTRUCTIBLE);
|
||||
MANA_IMAGES.put("intimidate", FSkinImage.IMG_ABILITY_INTIMIDATE);
|
||||
MANA_IMAGES.put("landwalk", FSkinImage.IMG_ABILITY_LANDWALK);
|
||||
MANA_IMAGES.put("lifelink", FSkinImage.IMG_ABILITY_LIFELINK);
|
||||
MANA_IMAGES.put("menace", FSkinImage.IMG_ABILITY_MENACE);
|
||||
MANA_IMAGES.put("reach", FSkinImage.IMG_ABILITY_REACH);
|
||||
MANA_IMAGES.put("shadow", FSkinImage.IMG_ABILITY_SHADOW);
|
||||
MANA_IMAGES.put("shroud", FSkinImage.IMG_ABILITY_SHROUD);
|
||||
MANA_IMAGES.put("trample", FSkinImage.IMG_ABILITY_TRAMPLE);
|
||||
MANA_IMAGES.put("vigilance", FSkinImage.IMG_ABILITY_VIGILANCE);
|
||||
//hexproof from
|
||||
MANA_IMAGES.put("hexproofR", FSkinImage.IMG_ABILITY_HEXPROOF_R);
|
||||
MANA_IMAGES.put("hexproofG", FSkinImage.IMG_ABILITY_HEXPROOF_G);
|
||||
MANA_IMAGES.put("hexproofB", FSkinImage.IMG_ABILITY_HEXPROOF_B);
|
||||
MANA_IMAGES.put("hexproofU", FSkinImage.IMG_ABILITY_HEXPROOF_U);
|
||||
MANA_IMAGES.put("hexproofW", FSkinImage.IMG_ABILITY_HEXPROOF_W);
|
||||
MANA_IMAGES.put("hexproofC", FSkinImage.IMG_ABILITY_HEXPROOF_C);
|
||||
MANA_IMAGES.put("hexproofUB", FSkinImage.IMG_ABILITY_HEXPROOF_UB);
|
||||
//token icon
|
||||
MANA_IMAGES.put("token", FSkinImage.IMG_ABILITY_TOKEN);
|
||||
//protection from
|
||||
MANA_IMAGES.put("protectAll", FSkinImage.IMG_ABILITY_PROTECT_ALL);
|
||||
MANA_IMAGES.put("protectB", FSkinImage.IMG_ABILITY_PROTECT_B);
|
||||
MANA_IMAGES.put("protectBU", FSkinImage.IMG_ABILITY_PROTECT_BU);
|
||||
MANA_IMAGES.put("protectBW", FSkinImage.IMG_ABILITY_PROTECT_BW);
|
||||
MANA_IMAGES.put("protectColoredSpells", FSkinImage.IMG_ABILITY_PROTECT_COLOREDSPELLS);
|
||||
MANA_IMAGES.put("protectG", FSkinImage.IMG_ABILITY_PROTECT_G);
|
||||
MANA_IMAGES.put("protectGB", FSkinImage.IMG_ABILITY_PROTECT_GB);
|
||||
MANA_IMAGES.put("protectGU", FSkinImage.IMG_ABILITY_PROTECT_GU);
|
||||
MANA_IMAGES.put("protectGW", FSkinImage.IMG_ABILITY_PROTECT_GW);
|
||||
MANA_IMAGES.put("protectGeneric", FSkinImage.IMG_ABILITY_PROTECT_GENERIC);
|
||||
MANA_IMAGES.put("protectR", FSkinImage.IMG_ABILITY_PROTECT_R);
|
||||
MANA_IMAGES.put("protectRB", FSkinImage.IMG_ABILITY_PROTECT_RB);
|
||||
MANA_IMAGES.put("protectRG", FSkinImage.IMG_ABILITY_PROTECT_RG);
|
||||
MANA_IMAGES.put("protectRU", FSkinImage.IMG_ABILITY_PROTECT_RU);
|
||||
MANA_IMAGES.put("protectRW", FSkinImage.IMG_ABILITY_PROTECT_RW);
|
||||
MANA_IMAGES.put("protectU", FSkinImage.IMG_ABILITY_PROTECT_U);
|
||||
MANA_IMAGES.put("protectUW", FSkinImage.IMG_ABILITY_PROTECT_UW);
|
||||
MANA_IMAGES.put("protectW", FSkinImage.IMG_ABILITY_PROTECT_W);
|
||||
}
|
||||
|
||||
public static void drawManaCost(Graphics g, ManaCost manaCost, float x, float y, final float imageSize) {
|
||||
if (manaCost.isNoCost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int genericManaCost = manaCost.getGenericCost();
|
||||
final boolean hasGeneric = (genericManaCost > 0) || manaCost.isPureGeneric();
|
||||
final float dx = imageSize;
|
||||
|
||||
if (hasGeneric) {
|
||||
for (final ManaCostShard s : manaCost) { //render X shards before generic
|
||||
if (s == ManaCostShard.X) {
|
||||
drawSymbol(s.getImageKey(), g, x, y, imageSize, imageSize);
|
||||
x += dx;
|
||||
}
|
||||
}
|
||||
|
||||
final String sGeneric = Integer.toString(genericManaCost);
|
||||
drawSymbol(sGeneric, g, x, y, imageSize, imageSize);
|
||||
x += dx;
|
||||
|
||||
for (final ManaCostShard s : manaCost) { //render non-X shards after generic
|
||||
if (s != ManaCostShard.X) {
|
||||
drawSymbol(s.getImageKey(), g, x, y, imageSize, imageSize);
|
||||
x += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { //if no generic, just render shards in order
|
||||
for (final ManaCostShard s : manaCost) {
|
||||
drawSymbol(s.getImageKey(), g, x, y, imageSize, imageSize);
|
||||
x += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawColorSet(Graphics g, ColorSet colorSet, float x, float y, final float imageSize) {
|
||||
drawColorSet(g, colorSet, x, y, imageSize, false);
|
||||
}
|
||||
public static void drawColorSet(Graphics g, ColorSet colorSet, float x, float y, final float imageSize, boolean vertical) {
|
||||
final float dx = imageSize;
|
||||
|
||||
for (final ManaCostShard s : colorSet.getOrderedShards()) {
|
||||
drawSymbol(s.getImageKey(), g, x, y, imageSize, imageSize);
|
||||
if (!vertical)
|
||||
x += dx;
|
||||
else
|
||||
y += dx;
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawOther(final Graphics g, String s, float x, final float y, final float w, final float h, boolean rotate) {
|
||||
if (s.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final float dx = w;
|
||||
|
||||
StringTokenizer tok = new StringTokenizer(s, " ");
|
||||
while (tok.hasMoreTokens()) {
|
||||
String symbol = tok.nextToken();
|
||||
FSkinImage image = MANA_IMAGES.get(symbol);
|
||||
if (image == null) {
|
||||
BugReporter.reportBug("Symbol not recognized \"" + symbol + "\" in string: " + s);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(rotate) {
|
||||
g.drawRotatedImage(image.getTextureRegion(), x, y, w, h, x+w /2, y+h /2,90);
|
||||
}
|
||||
else
|
||||
g.drawImage(image, x, y, w, h);
|
||||
|
||||
x += dx;
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawSymbol(final String imageName, final Graphics g, final float x, final float y, final float w, final float h) {
|
||||
g.drawImage(MANA_IMAGES.get(imageName), x, y, w, h);
|
||||
}
|
||||
|
||||
public static float getWidth(final ManaCost manaCost, float imageSize) {
|
||||
return manaCost.getGlyphCount() * imageSize;
|
||||
}
|
||||
|
||||
public static float getWidth(final ColorSet colorSet, float imageSize) {
|
||||
return Math.max(colorSet.countColors(), 1) * imageSize;
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package forge.adventure.libgdxgui.card;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FImage;
|
||||
import forge.adventure.libgdxgui.assets.ImageCache;
|
||||
import forge.adventure.libgdxgui.card.CardRenderer.CardStackPosition;
|
||||
import forge.game.card.CardView;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.toolbox.FCardPanel;
|
||||
|
||||
public class CardImage implements FImage {
|
||||
private final PaperCard card;
|
||||
private Texture image;
|
||||
|
||||
public CardImage(PaperCard card0) {
|
||||
card = card0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidth() {
|
||||
if (image != null) {
|
||||
return image.getWidth();
|
||||
}
|
||||
return ImageCache.defaultImage.getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHeight() {
|
||||
return getWidth() * FCardPanel.ASPECT_RATIO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
if (image == null) { //attempt to retrieve card image if needed
|
||||
image = ImageCache.getImage(card);
|
||||
if (image == null) {
|
||||
if (!Forge.enableUIMask.equals("Off")) //render this if mask is still loading
|
||||
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(card), false, x, y, w, h, CardStackPosition.Top);
|
||||
|
||||
return; //can't draw anything if can't be loaded yet
|
||||
}
|
||||
}
|
||||
|
||||
if (image == ImageCache.defaultImage) {
|
||||
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(card), false, x, y, w, h, CardStackPosition.Top);
|
||||
}
|
||||
else {
|
||||
if (Forge.enableUIMask.equals("Full")) {
|
||||
if (ImageCache.isBorderlessCardArt(image))
|
||||
g.drawImage(image, x, y, w, h);
|
||||
else {
|
||||
float radius = (h - w)/8;
|
||||
g.drawborderImage(ImageCache.borderColor(image), x, y, w, h);
|
||||
g.drawImage(ImageCache.croppedBorderImage(image), x+radius/2.2f, y+radius/2, w*0.96f, h*0.96f);
|
||||
}
|
||||
} else if (Forge.enableUIMask.equals("Crop")) {
|
||||
g.drawImage(ImageCache.croppedBorderImage(image), x, y, w, h);
|
||||
} else
|
||||
g.drawImage(image, x, y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,587 +0,0 @@
|
||||
package forge.adventure.libgdxgui.card;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.*;
|
||||
import forge.card.CardEdition;
|
||||
import forge.card.CardRarity;
|
||||
import forge.adventure.libgdxgui.card.CardRenderer.CardStackPosition;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.card.CardView.CardStateView;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.card.CardDetailUtil;
|
||||
import forge.gui.card.CardDetailUtil.DetailColors;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.model.FModel;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.screens.match.MatchController;
|
||||
import forge.util.CardTranslation;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static forge.adventure.libgdxgui.card.CardRenderer.CROP_MULTIPLIER;
|
||||
import static forge.adventure.libgdxgui.card.CardRenderer.isModernFrame;
|
||||
|
||||
public class CardImageRenderer {
|
||||
private static final float BASE_IMAGE_WIDTH = 360;
|
||||
private static final float BASE_IMAGE_HEIGHT = 504;
|
||||
private static float MANA_SYMBOL_SIZE, PT_BOX_WIDTH, HEADER_PADDING, BORDER_THICKNESS;
|
||||
private static FSkinFont NAME_FONT, TYPE_FONT, TEXT_FONT, PT_FONT;
|
||||
private static float prevImageWidth, prevImageHeight;
|
||||
private static final float BLACK_BORDER_THICKNESS_RATIO = 0.021f;
|
||||
|
||||
public static void forceStaticFieldUpdate() {
|
||||
//force static fields to be updated the next time a card image is rendered
|
||||
prevImageWidth = 0;
|
||||
prevImageHeight = 0;
|
||||
forgeArt.clear();
|
||||
}
|
||||
|
||||
private static void updateStaticFields(float w, float h) {
|
||||
if (w == prevImageWidth && h == prevImageHeight) {
|
||||
//for performance sake, only update static fields if card image size is different than previous rendered card
|
||||
return;
|
||||
}
|
||||
|
||||
float ratio = Math.min(w / BASE_IMAGE_WIDTH, h / BASE_IMAGE_HEIGHT);
|
||||
|
||||
MANA_SYMBOL_SIZE = 20 * ratio;
|
||||
PT_BOX_WIDTH = 56 * ratio;
|
||||
HEADER_PADDING = 5 * ratio;
|
||||
NAME_FONT = FSkinFont.forHeight(MANA_SYMBOL_SIZE);
|
||||
TYPE_FONT = FSkinFont.forHeight(MANA_SYMBOL_SIZE * 0.9f);
|
||||
TEXT_FONT = FSkinFont.forHeight(MANA_SYMBOL_SIZE * 0.95f);
|
||||
PT_FONT = NAME_FONT;
|
||||
BORDER_THICKNESS = Math.max(1.5f * ratio, 1f); //don't let border go below 1
|
||||
|
||||
prevImageWidth = w;
|
||||
prevImageHeight = h;
|
||||
}
|
||||
|
||||
public static void drawFaceDownCard(CardView card, Graphics g, float x, float y, float w, float h) {
|
||||
//try to draw the card sleeves first
|
||||
if (FSkin.getSleeves().get(card.getOwner()) != null)
|
||||
g.drawImage(FSkin.getSleeves().get(card.getOwner()), x, y, w, h);
|
||||
else
|
||||
drawArt(g, x, y, w, h);
|
||||
}
|
||||
|
||||
public static void drawCardImage(Graphics g, CardView card, boolean altState, float x, float y, float w, float h, CardStackPosition pos) {
|
||||
updateStaticFields(w, h);
|
||||
|
||||
float blackBorderThickness = w * BLACK_BORDER_THICKNESS_RATIO;
|
||||
g.fillRect(Color.BLACK, x, y, w, h);
|
||||
x += blackBorderThickness;
|
||||
y += blackBorderThickness;
|
||||
w -= 2 * blackBorderThickness;
|
||||
h -= 2 * blackBorderThickness;
|
||||
|
||||
final CardStateView state = card.getState(altState);
|
||||
final boolean canShow = MatchController.instance.mayView(card);
|
||||
|
||||
if (!canShow) {
|
||||
drawFaceDownCard(card, g, x, y, w, h);
|
||||
return;
|
||||
}
|
||||
|
||||
//determine colors for borders
|
||||
final List<DetailColors> borderColors;
|
||||
final boolean isFaceDown = card.isFaceDown();
|
||||
if (isFaceDown) {
|
||||
borderColors = ImmutableList.of(DetailColors.FACE_DOWN);
|
||||
}
|
||||
else {
|
||||
borderColors = CardDetailUtil.getBorderColors(state, canShow);
|
||||
}
|
||||
Color[] colors = fillColorBackground(g, borderColors, x, y, w, h);
|
||||
|
||||
float artInset = blackBorderThickness * 0.5f;
|
||||
float outerBorderThickness = 2 * blackBorderThickness - artInset;
|
||||
x += outerBorderThickness;
|
||||
y += outerBorderThickness;
|
||||
w -= 2 * outerBorderThickness;
|
||||
float headerHeight = Math.max(MANA_SYMBOL_SIZE + 2 * HEADER_PADDING, 2 * NAME_FONT.getCapHeight()) + 2;
|
||||
|
||||
//draw header containing name and mana cost
|
||||
Color[] headerColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.NAME_BOX_TINT);
|
||||
drawHeader(g, card, state, headerColors, x, y, w, headerHeight);
|
||||
|
||||
if (pos == CardStackPosition.BehindVert) { return; } //remaining rendering not needed if card is behind another card in a vertical stack
|
||||
boolean onTop = (pos == CardStackPosition.Top);
|
||||
|
||||
y += headerHeight;
|
||||
|
||||
float artWidth = w - 2 * artInset;
|
||||
float artHeight = artWidth / CardRenderer.CARD_ART_RATIO;
|
||||
float typeBoxHeight = 2 * TYPE_FONT.getCapHeight();
|
||||
float ptBoxHeight = 0;
|
||||
float textBoxHeight = h - headerHeight - artHeight - typeBoxHeight - outerBorderThickness - artInset;
|
||||
if (state.isCreature() || state.isPlaneswalker() || state.getType().hasSubtype("Vehicle")) {
|
||||
//if P/T box needed, make room for it
|
||||
ptBoxHeight = 2 * PT_FONT.getCapHeight();
|
||||
textBoxHeight -= ptBoxHeight;
|
||||
}
|
||||
else {
|
||||
textBoxHeight -= 2 * artInset;
|
||||
}
|
||||
float minTextBoxHeight = 2 * headerHeight;
|
||||
if (textBoxHeight < minTextBoxHeight) {
|
||||
if (textBoxHeight < minTextBoxHeight) {
|
||||
artHeight -= (minTextBoxHeight - textBoxHeight); //subtract from art height if text box not big enough otherwise
|
||||
textBoxHeight = minTextBoxHeight;
|
||||
if (artHeight < 0) {
|
||||
textBoxHeight += artHeight;
|
||||
artHeight = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//draw art box with Forge icon
|
||||
if (artHeight > 0) {
|
||||
drawArt(g, x + artInset, y, artWidth, artHeight);
|
||||
y += artHeight;
|
||||
}
|
||||
|
||||
//draw type line
|
||||
drawTypeLine(g, card, state, canShow, headerColors, x, y, w, typeBoxHeight);
|
||||
y += typeBoxHeight;
|
||||
|
||||
//draw text box
|
||||
Color[] textBoxColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.TEXT_BOX_TINT);
|
||||
drawTextBox(g, card, state, textBoxColors, x + artInset, y, w - 2 * artInset, textBoxHeight, onTop);
|
||||
y += textBoxHeight;
|
||||
|
||||
//draw P/T box
|
||||
if (onTop && ptBoxHeight > 0) {
|
||||
//only needed if on top since otherwise P/T will be hidden
|
||||
Color[] ptColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.PT_BOX_TINT);
|
||||
drawPtBox(g, card, state, ptColors, x, y - 2 * artInset, w, ptBoxHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawHeader(Graphics g, CardView card, CardStateView state, Color[] colors, float x, float y, float w, float h) {
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
||||
|
||||
float padding = h / 8;
|
||||
|
||||
//draw mana cost for card
|
||||
float manaCostWidth = 0;
|
||||
ManaCost mainManaCost = state.getManaCost();
|
||||
if (card.isSplitCard() && card.getAlternateState() != null) {
|
||||
//handle rendering both parts of split card
|
||||
mainManaCost = card.getLeftSplitState().getManaCost();
|
||||
ManaCost otherManaCost = card.getAlternateState().getManaCost();
|
||||
manaCostWidth = CardFaceSymbols.getWidth(otherManaCost, MANA_SYMBOL_SIZE) + HEADER_PADDING;
|
||||
CardFaceSymbols.drawManaCost(g, otherManaCost, x + w - manaCostWidth, y + (h - MANA_SYMBOL_SIZE) / 2, MANA_SYMBOL_SIZE);
|
||||
//draw "//" between two parts of mana cost
|
||||
manaCostWidth += NAME_FONT.getBounds("//").width + HEADER_PADDING;
|
||||
g.drawText("//", NAME_FONT, Color.BLACK, x + w - manaCostWidth, y, w, h, false, Align.left, true);
|
||||
}
|
||||
manaCostWidth += CardFaceSymbols.getWidth(mainManaCost, MANA_SYMBOL_SIZE) + HEADER_PADDING;
|
||||
CardFaceSymbols.drawManaCost(g, mainManaCost, x + w - manaCostWidth, y + (h - MANA_SYMBOL_SIZE) / 2, MANA_SYMBOL_SIZE);
|
||||
|
||||
//draw name for card
|
||||
x += padding;
|
||||
w -= 2 * padding;
|
||||
g.drawText(CardTranslation.getTranslatedName(state.getName()), NAME_FONT, Color.BLACK, x, y, w - manaCostWidth - padding, h, false, Align.left, true);
|
||||
}
|
||||
|
||||
public static final FBufferedImage forgeArt;
|
||||
static {
|
||||
final float logoWidth = FSkinImage.LOGO.getWidth();
|
||||
final float logoHeight = FSkinImage.LOGO.getHeight();
|
||||
float h = logoHeight * 1.1f;
|
||||
float w = h * CardRenderer.CARD_ART_RATIO;
|
||||
forgeArt = new FBufferedImage(w, h) {
|
||||
@Override
|
||||
protected void draw(Graphics g, float w, float h) {
|
||||
g.drawImage(FSkinTexture.BG_TEXTURE, 0, 0, w, h);
|
||||
g.fillRect(FScreen.TEXTURE_OVERLAY_COLOR, 0, 0, w, h);
|
||||
g.drawImage(FSkinImage.LOGO, (w - logoWidth) / 2, (h - logoHeight) / 2, logoWidth, logoHeight);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static void drawArt(Graphics g, float x, float y, float w, float h) {
|
||||
g.drawImage(forgeArt, x, y, w, h);
|
||||
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
||||
}
|
||||
|
||||
private static void drawTypeLine(Graphics g, CardView card, CardStateView state, boolean canShow, Color[] colors, float x, float y, float w, float h) {
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
||||
|
||||
float padding = h / 8;
|
||||
|
||||
//draw square icon for rarity
|
||||
float iconSize = h * 0.55f;
|
||||
float iconPadding = (h - iconSize) / 2;
|
||||
w -= iconSize + iconPadding * 2;
|
||||
g.fillRect(CardRenderer.getRarityColor(state.getRarity()), x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
||||
|
||||
//draw type
|
||||
x += padding;
|
||||
g.drawText(CardDetailUtil.formatCardType(state, canShow), TYPE_FONT, Color.BLACK, x, y, w, h, false, Align.left, true);
|
||||
}
|
||||
|
||||
//use text renderer to handle mana symbols and reminder text
|
||||
private static final TextRenderer cardTextRenderer = new TextRenderer(true);
|
||||
|
||||
private static void drawTextBox(Graphics g, CardView card, CardStateView state, Color[] colors, float x, float y, float w, float h, boolean onTop) {
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
||||
|
||||
if (!onTop) { return; } //remaining rendering only needed if card on top
|
||||
|
||||
if (state.isBasicLand()) {
|
||||
//draw icons for basic lands
|
||||
FSkinImage image;
|
||||
switch (state.getName().replaceFirst("^Snow-Covered ", "")) {
|
||||
case "Plains":
|
||||
image = FSkinImage.MANA_W;
|
||||
break;
|
||||
case "Island":
|
||||
image = FSkinImage.MANA_U;
|
||||
break;
|
||||
case "Swamp":
|
||||
image = FSkinImage.MANA_B;
|
||||
break;
|
||||
case "Mountain":
|
||||
image = FSkinImage.MANA_R;
|
||||
break;
|
||||
case "Forest":
|
||||
image = FSkinImage.MANA_G;
|
||||
break;
|
||||
default:
|
||||
image = FSkinImage.MANA_COLORLESS;
|
||||
break;
|
||||
}
|
||||
float iconSize = h * 0.75f;
|
||||
g.drawImage(image, x + (w - iconSize) / 2, y + (h - iconSize) / 2, iconSize, iconSize);
|
||||
}
|
||||
else {
|
||||
boolean needTranslation = true;
|
||||
if (card.isToken()) {
|
||||
if (card.getCloneOrigin() == null)
|
||||
needTranslation = false;
|
||||
}
|
||||
final String text = !card.isSplitCard() ?
|
||||
card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(state.getName(), "") : null) :
|
||||
card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(card.getLeftSplitState().getName(), card.getRightSplitState().getName()) : null );
|
||||
if (StringUtils.isEmpty(text)) { return; }
|
||||
|
||||
float padding = TEXT_FONT.getCapHeight() * 0.75f;
|
||||
x += padding;
|
||||
y += padding;
|
||||
w -= 2 * padding;
|
||||
h -= 2 * padding;
|
||||
cardTextRenderer.drawText(g, text, TEXT_FONT, Color.BLACK, x, y, w, h, y, h, true, Align.left, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawPtBox(Graphics g, CardView card, CardStateView state, Color[] colors, float x, float y, float w, float h) {
|
||||
List<String> pieces = new ArrayList<>();
|
||||
if (state.isCreature()) {
|
||||
pieces.add(String.valueOf(state.getPower()));
|
||||
pieces.add("/");
|
||||
pieces.add(String.valueOf(state.getToughness()));
|
||||
}
|
||||
else if (state.isPlaneswalker()) {
|
||||
pieces.add(String.valueOf(state.getLoyalty()));
|
||||
}
|
||||
else if (state.getType().hasSubtype("Vehicle")) {
|
||||
// TODO Invert color box for Vehicles?
|
||||
pieces.add("[");
|
||||
pieces.add(String.valueOf(state.getPower()));
|
||||
pieces.add("/");
|
||||
pieces.add(String.valueOf(state.getToughness()));
|
||||
pieces.add("]");
|
||||
}
|
||||
else { return; }
|
||||
|
||||
float padding = Math.round(PT_FONT.getCapHeight() / 4);
|
||||
float totalPieceWidth = -padding;
|
||||
float[] pieceWidths = new float[pieces.size()];
|
||||
for (int i = 0; i < pieces.size(); i++) {
|
||||
float pieceWidth = PT_FONT.getBounds(pieces.get(i)).width + padding;
|
||||
pieceWidths[i] = pieceWidth;
|
||||
totalPieceWidth += pieceWidth;
|
||||
}
|
||||
float boxHeight = PT_FONT.getCapHeight() + PT_FONT.getAscent() + 3 * padding;
|
||||
|
||||
float boxWidth = Math.max(PT_BOX_WIDTH, totalPieceWidth + 2 * padding);
|
||||
x += w - boxWidth;
|
||||
y += h - boxHeight;
|
||||
w = boxWidth;
|
||||
h = boxHeight;
|
||||
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
||||
|
||||
x += (boxWidth - totalPieceWidth) / 2;
|
||||
for (int i = 0; i < pieces.size(); i++) {
|
||||
g.drawText(pieces.get(i), PT_FONT, Color.BLACK, x, y, w, h, false, Align.left, true);
|
||||
x += pieceWidths[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawZoom(Graphics g, CardView card, GameView gameView, boolean altState, float x, float y, float w, float h, float dispW, float dispH, boolean isCurrentCard) {
|
||||
boolean canshow = MatchController.instance.mayView(card);
|
||||
Texture image = null;
|
||||
try {
|
||||
image = ImageCache.getImage(card.getState(altState).getImageKey(), true);
|
||||
} catch (Exception ex) {
|
||||
//System.err.println(card.toString()+" : " +ex.getMessage());
|
||||
//TODO: don't know why this is needed, needs further investigation...
|
||||
if (!card.hasAlternateState()) {
|
||||
altState = false;
|
||||
image = ImageCache.getImage(card.getState(altState).getImageKey(), true);
|
||||
}
|
||||
}
|
||||
FImage sleeves = MatchController.getPlayerSleeve(card.getOwner());
|
||||
if (image == null) { //draw details if can't draw zoom
|
||||
drawDetails(g, card, gameView, altState, x, y, w, h);
|
||||
return;
|
||||
}
|
||||
if(card.isToken() && card.getCurrentState().getType().hasSubtype("Effect")
|
||||
&& FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DISABLE_IMAGES_EFFECT_CARDS)){
|
||||
drawDetails(g, card, gameView, altState, x, y, w, h);
|
||||
return;
|
||||
}
|
||||
|
||||
if (image == ImageCache.defaultImage) { //support drawing card image manually if card image not found
|
||||
drawCardImage(g, card, altState, x, y, w, h, CardStackPosition.Top);
|
||||
} else {
|
||||
float radius = (h - w)/8;
|
||||
float wh_Adj = ForgeConstants.isGdxPortLandscape && isCurrentCard ? 1.38f:1.0f;
|
||||
float new_w = w*wh_Adj;
|
||||
float new_h = h*wh_Adj;
|
||||
float new_x = ForgeConstants.isGdxPortLandscape && isCurrentCard ? (dispW - new_w) / 2:x;
|
||||
float new_y = ForgeConstants.isGdxPortLandscape && isCurrentCard ? (dispH - new_h) / 2:y;
|
||||
float new_xRotate = (dispW - new_h) /2;
|
||||
float new_yRotate = (dispH - new_w) /2;
|
||||
boolean rotateSplit = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_SPLIT_CARDS);
|
||||
boolean rotatePlane = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON);
|
||||
float croppedArea = isModernFrame(card) ? CROP_MULTIPLIER : 0.97f;
|
||||
float minusxy = isModernFrame(card) ? 0.0f : 0.13f*radius;
|
||||
if (card.getCurrentState().getSetCode().equals("LEA")||card.getCurrentState().getSetCode().equals("LEB")) {
|
||||
croppedArea = 0.975f;
|
||||
minusxy = 0.135f*radius;
|
||||
}
|
||||
if (rotatePlane && (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane())) {
|
||||
if (Forge.enableUIMask.equals("Full")){
|
||||
if (ImageCache.isBorderlessCardArt(image))
|
||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||
else {
|
||||
g.drawRotatedImage(FSkin.getBorders().get(0), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image), new_x+radius/2-minusxy, new_y+radius/2-minusxy, new_w*croppedArea, new_h*croppedArea, (new_x+radius/2-minusxy) + (new_w*croppedArea) / 2, (new_y+radius/2-minusxy) + (new_h*croppedArea) / 2, -90);
|
||||
}
|
||||
} else if (Forge.enableUIMask.equals("Crop")) {
|
||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||
} else
|
||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||
} else if (rotateSplit && isCurrentCard && card.isSplitCard() && canshow) {
|
||||
boolean isAftermath = card.getText().contains("Aftermath") || card.getAlternateState().getOracleText().contains("Aftermath");
|
||||
if (Forge.enableUIMask.equals("Full")) {
|
||||
if (ImageCache.isBorderlessCardArt(image))
|
||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||
else {
|
||||
g.drawRotatedImage(FSkin.getBorders().get(ImageCache.getFSkinBorders(card)), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image), new_x + radius / 2-minusxy, new_y + radius / 2-minusxy, new_w * croppedArea, new_h * croppedArea, (new_x + radius / 2-minusxy) + (new_w * croppedArea) / 2, (new_y + radius / 2-minusxy) + (new_h * croppedArea) / 2, isAftermath ? 90 : -90);
|
||||
}
|
||||
} else if (Forge.enableUIMask.equals("Crop")) {
|
||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||
} else
|
||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||
} else {
|
||||
if (Forge.enableUIMask.equals("Full") && canshow) {
|
||||
if (ImageCache.isBorderlessCardArt(image))
|
||||
g.drawImage(image, x, y, w, h);
|
||||
else {
|
||||
g.drawImage(ImageCache.getBorderImage(image.toString()), ImageCache.borderColor(image), x, y, w, h);
|
||||
g.drawImage(ImageCache.croppedBorderImage(image), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
|
||||
}
|
||||
} else if (Forge.enableUIMask.equals("Crop") && canshow) {
|
||||
g.drawImage(ImageCache.croppedBorderImage(image), x, y, w, h);
|
||||
} else {
|
||||
if (canshow)
|
||||
g.drawImage(image, x, y, w, h);
|
||||
else // sleeve
|
||||
g.drawImage(sleeves, x, y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
CardRenderer.drawFoilEffect(g, card, x, y, w, h, isCurrentCard && canshow && image != ImageCache.defaultImage);
|
||||
}
|
||||
|
||||
public static void drawDetails(Graphics g, CardView card, GameView gameView, boolean altState, float x, float y, float w, float h) {
|
||||
updateStaticFields(w, h);
|
||||
|
||||
float blackBorderThickness = w * BLACK_BORDER_THICKNESS_RATIO;
|
||||
g.fillRect(Color.BLACK, x, y, w, h);
|
||||
x += blackBorderThickness;
|
||||
y += blackBorderThickness;
|
||||
w -= 2 * blackBorderThickness;
|
||||
h -= 2 * blackBorderThickness;
|
||||
|
||||
final CardStateView state = card.getState(altState);
|
||||
final boolean canShow = MatchController.instance.mayView(card);
|
||||
|
||||
//determine colors for borders
|
||||
final List<DetailColors> borderColors;
|
||||
final boolean isFaceDown = card.isFaceDown();
|
||||
if (isFaceDown) {
|
||||
borderColors = ImmutableList.of(DetailColors.FACE_DOWN);
|
||||
}
|
||||
else {
|
||||
borderColors = CardDetailUtil.getBorderColors(state, canShow);
|
||||
}
|
||||
Color[] colors = fillColorBackground(g, borderColors, x, y, w, h);
|
||||
|
||||
Color idForeColor = FSkinColor.getHighContrastColor(colors[0]);
|
||||
|
||||
float outerBorderThickness = 2 * blackBorderThickness;
|
||||
x += outerBorderThickness;
|
||||
y += outerBorderThickness;
|
||||
w -= 2 * outerBorderThickness;
|
||||
float cardNameBoxHeight = Math.max(MANA_SYMBOL_SIZE + 2 * HEADER_PADDING, 2 * NAME_FONT.getCapHeight()) + 2 * TYPE_FONT.getCapHeight() + 2;
|
||||
|
||||
//draw name/type box
|
||||
Color[] nameBoxColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.NAME_BOX_TINT);
|
||||
drawDetailsNameBox(g, card, state, canShow, nameBoxColors, x, y, w, cardNameBoxHeight);
|
||||
|
||||
float innerBorderThickness = outerBorderThickness / 2;
|
||||
float ptBoxHeight = 2 * PT_FONT.getCapHeight();
|
||||
float textBoxHeight = h - cardNameBoxHeight - ptBoxHeight - outerBorderThickness - 3 * innerBorderThickness;
|
||||
|
||||
y += cardNameBoxHeight + innerBorderThickness;
|
||||
Color[] textBoxColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.TEXT_BOX_TINT);
|
||||
drawDetailsTextBox(g, state, gameView, canShow, textBoxColors, x, y, w, textBoxHeight);
|
||||
|
||||
y += textBoxHeight + innerBorderThickness;
|
||||
Color[] ptColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.PT_BOX_TINT);
|
||||
drawDetailsIdAndPtBox(g, card, state, canShow, idForeColor, ptColors, x, y, w, ptBoxHeight);
|
||||
}
|
||||
|
||||
public static Color[] fillColorBackground(Graphics g, List<DetailColors> backColors, float x, float y, float w, float h) {
|
||||
Color[] colors = new Color[backColors.size()];
|
||||
for (int i = 0; i < colors.length; i++) {
|
||||
DetailColors dc = backColors.get(i);
|
||||
colors[i] = FSkinColor.fromRGB(dc.r, dc.g, dc.b);
|
||||
}
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
return colors;
|
||||
}
|
||||
public static void fillColorBackground(Graphics g, Color[] colors, float x, float y, float w, float h) {
|
||||
switch (colors.length) {
|
||||
case 1:
|
||||
g.fillRect(colors[0], x, y, w, h);
|
||||
break;
|
||||
case 2:
|
||||
g.fillGradientRect(colors[0], colors[1], false, x, y, w, h);
|
||||
break;
|
||||
case 3:
|
||||
float halfWidth = w / 2;
|
||||
g.fillGradientRect(colors[0], colors[1], false, x, y, halfWidth, h);
|
||||
g.fillGradientRect(colors[1], colors[2], false, x + halfWidth, y, halfWidth, h);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawDetailsNameBox(Graphics g, CardView card, CardStateView state, boolean canShow, Color[] colors, float x, float y, float w, float h) {
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
||||
|
||||
float padding = h / 8;
|
||||
|
||||
//make sure name/mana cost row height is tall enough for both
|
||||
h = Math.max(MANA_SYMBOL_SIZE + 2 * HEADER_PADDING, 2 * NAME_FONT.getCapHeight());
|
||||
|
||||
//draw mana cost for card
|
||||
float manaCostWidth = 0;
|
||||
if (canShow) {
|
||||
ManaCost mainManaCost = state.getManaCost();
|
||||
if (card.isSplitCard() && card.hasAlternateState() && !card.isFaceDown() && card.getZone() != ZoneType.Stack) { //only display current state's mana cost when on stack
|
||||
//handle rendering both parts of split card
|
||||
mainManaCost = card.getLeftSplitState().getManaCost();
|
||||
ManaCost otherManaCost = card.getAlternateState().getManaCost();
|
||||
manaCostWidth = CardFaceSymbols.getWidth(otherManaCost, MANA_SYMBOL_SIZE) + HEADER_PADDING;
|
||||
CardFaceSymbols.drawManaCost(g, otherManaCost, x + w - manaCostWidth, y + (h - MANA_SYMBOL_SIZE) / 2, MANA_SYMBOL_SIZE);
|
||||
//draw "//" between two parts of mana cost
|
||||
manaCostWidth += NAME_FONT.getBounds("//").width + HEADER_PADDING;
|
||||
g.drawText("//", NAME_FONT, Color.BLACK, x + w - manaCostWidth, y, w, h, false, Align.left, true);
|
||||
}
|
||||
manaCostWidth += CardFaceSymbols.getWidth(mainManaCost, MANA_SYMBOL_SIZE) + HEADER_PADDING;
|
||||
CardFaceSymbols.drawManaCost(g, mainManaCost, x + w - manaCostWidth, y + (h - MANA_SYMBOL_SIZE) / 2, MANA_SYMBOL_SIZE);
|
||||
}
|
||||
|
||||
//draw name for card
|
||||
x += padding;
|
||||
w -= 2 * padding;
|
||||
g.drawText(CardDetailUtil.formatCardName(card, canShow, state == card.getAlternateState()), NAME_FONT, Color.BLACK, x, y, w - manaCostWidth - padding, h, false, Align.left, true);
|
||||
|
||||
//draw type and set label for card
|
||||
y += h;
|
||||
h = 2 * TYPE_FONT.getCapHeight();
|
||||
|
||||
String set = state.getSetCode();
|
||||
CardRarity rarity = state.getRarity();
|
||||
if (!canShow) {
|
||||
set = CardEdition.UNKNOWN.getCode();
|
||||
rarity = CardRarity.Unknown;
|
||||
}
|
||||
if (!StringUtils.isEmpty(set)) {
|
||||
float setWidth = CardRenderer.getSetWidth(TYPE_FONT, set);
|
||||
CardRenderer.drawSetLabel(g, TYPE_FONT, set, rarity, x + w + padding - setWidth - HEADER_PADDING + CardRenderer.SET_BOX_MARGIN, y + CardRenderer.SET_BOX_MARGIN, setWidth, h - CardRenderer.SET_BOX_MARGIN);
|
||||
w -= setWidth; //reduce available width for type
|
||||
}
|
||||
|
||||
g.drawText(CardDetailUtil.formatCardType(state, canShow), TYPE_FONT, Color.BLACK, x, y, w, h, false, Align.left, true);
|
||||
}
|
||||
|
||||
private static void drawDetailsTextBox(Graphics g, CardStateView state, GameView gameView, boolean canShow, Color[] colors, float x, float y, float w, float h) {
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
||||
|
||||
float padX = TEXT_FONT.getCapHeight() / 2;
|
||||
float padY = padX + Utils.scale(2); //add a little more vertical padding
|
||||
x += padX;
|
||||
y += padY;
|
||||
w -= 2 * padX;
|
||||
h -= 2 * padY;
|
||||
cardTextRenderer.drawText(g, CardDetailUtil.composeCardText(state, gameView, canShow), TEXT_FONT, Color.BLACK, x, y, w, h, y, h, true, Align.left, false);
|
||||
}
|
||||
|
||||
private static void drawDetailsIdAndPtBox(Graphics g, CardView card, CardStateView state, boolean canShow, Color idForeColor, Color[] colors, float x, float y, float w, float h) {
|
||||
float idWidth = 0;
|
||||
if (canShow) {
|
||||
String idText = CardDetailUtil.formatCardId(state);
|
||||
g.drawText(idText, TYPE_FONT, idForeColor, x, y + TYPE_FONT.getCapHeight() / 2, w, h, false, Align.left, false);
|
||||
idWidth = TYPE_FONT.getBounds(idText).width;
|
||||
}
|
||||
|
||||
String ptText = CardDetailUtil.formatPowerToughness(state, canShow);
|
||||
if (StringUtils.isEmpty(ptText)) { return; }
|
||||
|
||||
float padding = PT_FONT.getCapHeight() / 2;
|
||||
float boxWidth = Math.min(PT_FONT.getBounds(ptText).width + 2 * padding,
|
||||
w - idWidth - padding); //prevent box overlapping ID
|
||||
x += w - boxWidth;
|
||||
w = boxWidth;
|
||||
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
||||
g.drawText(ptText, PT_FONT, Color.BLACK, x, y, w, h, false, Align.center, true);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package forge.adventure.libgdxgui.card;
|
||||
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.toolbox.FChoiceList;
|
||||
import forge.adventure.libgdxgui.toolbox.FLabel;
|
||||
|
||||
public class CardListPreview extends FLabel {
|
||||
public static final float CARD_PREVIEW_RATIO = 0.5f;
|
||||
|
||||
private final FChoiceList<PaperCard> list;
|
||||
|
||||
public CardListPreview(FChoiceList<PaperCard> list0) {
|
||||
super(new FLabel.Builder().iconScaleFactor(1).insets(new Vector2(0, 0))
|
||||
.iconInBackground(true).align(Align.center));
|
||||
list = list0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
return zoom();
|
||||
}
|
||||
@Override
|
||||
public boolean longPress(float x, float y) {
|
||||
return zoom();
|
||||
}
|
||||
private boolean zoom() {
|
||||
int index = list.getSelectedIndex();
|
||||
if (index == -1) { return false; }
|
||||
CardZoom.show(list.extractListData(), index, list);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fling(float velocityX, float velocityY) {
|
||||
if (Math.abs(velocityX) > Math.abs(velocityY)) {
|
||||
int selectedIndex = list.getSelectedIndex();
|
||||
if (velocityX > 0) {
|
||||
if (selectedIndex > 0) {
|
||||
list.setSelectedIndex(selectedIndex - 1);
|
||||
}
|
||||
}
|
||||
else if (selectedIndex < list.getCount() - 1) {
|
||||
list.setSelectedIndex(selectedIndex + 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,384 +0,0 @@
|
||||
package forge.adventure.libgdxgui.card;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinImage;
|
||||
import forge.adventure.libgdxgui.screens.match.MatchController;
|
||||
import forge.adventure.libgdxgui.toolbox.FCardPanel;
|
||||
import forge.adventure.libgdxgui.toolbox.FDialog;
|
||||
import forge.adventure.libgdxgui.toolbox.FOverlay;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
import forge.deck.ArchetypeDeckGenerator;
|
||||
import forge.deck.CardThemedDeckGenerator;
|
||||
import forge.deck.CommanderDeckGenerator;
|
||||
import forge.deck.DeckProxy;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.gamemodes.planarconquest.ConquestCommander;
|
||||
import forge.item.IPaperCard;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.localinstance.properties.ForgePreferences.FPref;
|
||||
import forge.model.FModel;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.collect.FCollectionView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class CardZoom extends FOverlay {
|
||||
private static final float REQ_AMOUNT = Utils.AVG_FINGER_WIDTH;
|
||||
|
||||
private static final CardZoom cardZoom = new CardZoom();
|
||||
private static final ForgePreferences prefs = FModel.getPreferences();
|
||||
private static List<?> items;
|
||||
private static int currentIndex, initialIndex;
|
||||
private static CardView currentCard, prevCard, nextCard;
|
||||
private static boolean zoomMode = true;
|
||||
private static boolean oneCardView = prefs.getPrefBoolean(FPref.UI_SINGLE_CARD_ZOOM);
|
||||
private float totalZoomAmount;
|
||||
private static ActivateHandler activateHandler;
|
||||
private static String currentActivateAction;
|
||||
private static Rectangle flipIconBounds;
|
||||
private static Rectangle mutateIconBounds;
|
||||
private static boolean showAltState;
|
||||
private static boolean showBackSide = false;
|
||||
private static boolean showMerged = false;
|
||||
|
||||
public static void show(Object item) {
|
||||
show(item, false);
|
||||
}
|
||||
public static void show(Object item, boolean showbackside) {
|
||||
List<Object> items0 = new ArrayList<>();
|
||||
items0.add(item);
|
||||
showBackSide = showbackside; //reverse the displayed zoomed card for the choice list
|
||||
show(items0, 0, null);
|
||||
}
|
||||
public static void show(FCollectionView<?> items0, int currentIndex0, ActivateHandler activateHandler0) {
|
||||
show((List<?>)items0, currentIndex0, activateHandler0);
|
||||
}
|
||||
public static void show(final List<?> items0, int currentIndex0, ActivateHandler activateHandler0) {
|
||||
items = items0;
|
||||
activateHandler = activateHandler0;
|
||||
currentIndex = currentIndex0;
|
||||
initialIndex = currentIndex0;
|
||||
currentCard = getCardView(items.get(currentIndex));
|
||||
prevCard = currentIndex > 0 ? getCardView(items.get(currentIndex - 1)) : null;
|
||||
nextCard = currentIndex < items.size() - 1 ? getCardView(items.get(currentIndex + 1)) : null;
|
||||
onCardChanged();
|
||||
cardZoom.show();
|
||||
}
|
||||
|
||||
public static boolean isOpen() {
|
||||
return cardZoom.isVisible();
|
||||
}
|
||||
|
||||
public static void hideZoom() {
|
||||
cardZoom.hide();
|
||||
}
|
||||
|
||||
private CardZoom() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible0) {
|
||||
if (this.isVisible() == visible0) { return; }
|
||||
|
||||
super.setVisible(visible0);
|
||||
|
||||
//update selected index when hidden if current index is different than initial index
|
||||
if (!visible0 && activateHandler != null && currentIndex != initialIndex) {
|
||||
activateHandler.setSelectedIndex(currentIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void incrementCard(int dir) {
|
||||
if (dir > 0) {
|
||||
if (currentIndex == items.size() - 1) { return; }
|
||||
currentIndex++;
|
||||
|
||||
prevCard = currentCard;
|
||||
currentCard = nextCard;
|
||||
nextCard = currentIndex < items.size() - 1 ? getCardView(items.get(currentIndex + 1)) : null;
|
||||
}
|
||||
else {
|
||||
if (currentIndex == 0) { return; }
|
||||
currentIndex--;
|
||||
|
||||
nextCard = currentCard;
|
||||
currentCard = prevCard;
|
||||
prevCard = currentIndex > 0 ? getCardView(items.get(currentIndex - 1)) : null;
|
||||
}
|
||||
onCardChanged();
|
||||
}
|
||||
|
||||
private static void onCardChanged() {
|
||||
mutateIconBounds = null;
|
||||
if (activateHandler != null) {
|
||||
currentActivateAction = activateHandler.getActivateAction(currentIndex);
|
||||
}
|
||||
if (MatchController.instance.mayFlip(currentCard)) {
|
||||
flipIconBounds = new Rectangle();
|
||||
} else {
|
||||
flipIconBounds = null;
|
||||
}
|
||||
if (currentCard != null) {
|
||||
if (currentCard.getMergedCardsCollection() != null )
|
||||
if (currentCard.getMergedCardsCollection().size() > 0)
|
||||
mutateIconBounds = new Rectangle();
|
||||
}
|
||||
showAltState = false;
|
||||
}
|
||||
|
||||
private static CardView getCardView(Object item) {
|
||||
if (item instanceof Entry) {
|
||||
item = ((Entry<?, ?>)item).getKey();
|
||||
}
|
||||
if (item instanceof CardView) {
|
||||
return (CardView)item;
|
||||
}
|
||||
if (item instanceof DeckProxy) {
|
||||
if (item instanceof CardThemedDeckGenerator){
|
||||
return CardView.getCardForUi(((CardThemedDeckGenerator)item).getPaperCard());
|
||||
}else if (item instanceof CommanderDeckGenerator){
|
||||
return CardView.getCardForUi(((CommanderDeckGenerator)item).getPaperCard());
|
||||
}else if (item instanceof ArchetypeDeckGenerator){
|
||||
return CardView.getCardForUi(((ArchetypeDeckGenerator)item).getPaperCard());
|
||||
}else{
|
||||
DeckProxy deck = ((DeckProxy)item);
|
||||
return new CardView(-1, null, deck.getName(), null, deck.getImageKey(false));
|
||||
}
|
||||
|
||||
}
|
||||
if (item instanceof IPaperCard) {
|
||||
return CardView.getCardForUi((IPaperCard)item);
|
||||
}
|
||||
if (item instanceof ConquestCommander) {
|
||||
return CardView.getCardForUi(((ConquestCommander)item).getCard());
|
||||
}
|
||||
if (item instanceof InventoryItem) {
|
||||
InventoryItem ii = (InventoryItem)item;
|
||||
return new CardView(-1, null, ii.getName(), null, ii.getImageKey(false));
|
||||
}
|
||||
return new CardView(-1, null, item.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
if (mutateIconBounds != null && mutateIconBounds.contains(x, y)) {
|
||||
if(showMerged) {
|
||||
showMerged = false;
|
||||
} else {
|
||||
showMerged = true;
|
||||
show(currentCard.getMergedCardsCollection(), 0, null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (flipIconBounds != null && flipIconBounds.contains(x, y)) {
|
||||
if (currentCard.isFaceDown() && currentCard.getBackup() != null) {
|
||||
if (currentCard.getBackup().hasBackSide()) {
|
||||
show(currentCard.getBackup());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!showBackSide)
|
||||
showAltState = !showAltState;
|
||||
else
|
||||
showBackSide = !showBackSide;
|
||||
return true;
|
||||
}
|
||||
hide();
|
||||
showBackSide = false;
|
||||
showAltState = false;
|
||||
showMerged = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fling(float velocityX, float velocityY) {
|
||||
if (Math.abs(velocityX) > Math.abs(velocityY)) {
|
||||
incrementCard(velocityX > 0 ? -1 : 1);
|
||||
showBackSide = false;
|
||||
showAltState = false;
|
||||
return true;
|
||||
}
|
||||
if (velocityY > 0) {
|
||||
zoomMode = !zoomMode;
|
||||
showBackSide = false;
|
||||
showAltState = false;
|
||||
return true;
|
||||
}
|
||||
if (currentActivateAction != null && activateHandler != null) {
|
||||
hide();
|
||||
showBackSide = false;
|
||||
showAltState = false;
|
||||
activateHandler.activate(currentIndex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setOneCardView(boolean oneCardView0) {
|
||||
if (oneCardView == oneCardView0 || Forge.isLandscapeMode()) { return; } //don't allow changing this when in landscape mode
|
||||
|
||||
oneCardView = oneCardView0;
|
||||
prefs.setPref(FPref.UI_SINGLE_CARD_ZOOM, oneCardView0);
|
||||
prefs.save();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean zoom(float x, float y, float amount) {
|
||||
totalZoomAmount += amount;
|
||||
|
||||
if (totalZoomAmount >= REQ_AMOUNT) {
|
||||
setOneCardView(true);
|
||||
totalZoomAmount = 0;
|
||||
}
|
||||
else if (totalZoomAmount <= -REQ_AMOUNT) {
|
||||
setOneCardView(false);
|
||||
totalZoomAmount = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean longPress(float x, float y) {
|
||||
setOneCardView(!oneCardView);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOverlay(Graphics g) {
|
||||
final GameView gameView = MatchController.instance.getGameView();
|
||||
|
||||
float w = getWidth();
|
||||
float h = getHeight();
|
||||
float messageHeight = FDialog.MSG_HEIGHT;
|
||||
float AspectRatioMultiplier;
|
||||
switch (Forge.extrawide) {
|
||||
case "default":
|
||||
AspectRatioMultiplier = 3; //good for tablets with 16:10 or similar
|
||||
break;
|
||||
case "wide":
|
||||
AspectRatioMultiplier = 2.5f;
|
||||
break;
|
||||
case "extrawide":
|
||||
AspectRatioMultiplier = 2; //good for tall phones with 21:9 or similar
|
||||
break;
|
||||
default:
|
||||
AspectRatioMultiplier = 3;
|
||||
break;
|
||||
}
|
||||
float maxCardHeight = h - AspectRatioMultiplier * messageHeight; //maxheight of currently zoomed card
|
||||
|
||||
float cardWidth, cardHeight, y;
|
||||
|
||||
if (oneCardView && !Forge.isLandscapeMode()) {
|
||||
|
||||
cardWidth = w;
|
||||
cardHeight = FCardPanel.ASPECT_RATIO * cardWidth;
|
||||
|
||||
boolean rotateSplit = FModel.getPreferences().getPrefBoolean(FPref.UI_ROTATE_SPLIT_CARDS);
|
||||
if (currentCard.isSplitCard() && rotateSplit) {
|
||||
// card will be rotated. Make sure that the height does not exceed the width of the view
|
||||
if (cardHeight > Gdx.graphics.getWidth())
|
||||
{
|
||||
cardHeight = Gdx.graphics.getWidth();
|
||||
cardWidth = cardHeight / FCardPanel.ASPECT_RATIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
cardWidth = w * 0.5f;
|
||||
cardHeight = FCardPanel.ASPECT_RATIO * cardWidth;
|
||||
|
||||
float maxSideCardHeight = maxCardHeight * 5 / 7;
|
||||
if (cardHeight > maxSideCardHeight) { //prevent card overlapping message bars
|
||||
cardHeight = maxSideCardHeight;
|
||||
cardWidth = cardHeight / FCardPanel.ASPECT_RATIO;
|
||||
}
|
||||
y = (h - cardHeight) / 2;
|
||||
if (prevCard != null) {
|
||||
CardImageRenderer.drawZoom(g, prevCard, gameView, false, 0, y, cardWidth, cardHeight, getWidth(), getHeight(), false);
|
||||
}
|
||||
if (nextCard != null) {
|
||||
CardImageRenderer.drawZoom(g, nextCard, gameView, false, w - cardWidth, y, cardWidth, cardHeight, getWidth(), getHeight(), false);
|
||||
}
|
||||
|
||||
cardWidth = w * 0.7f;
|
||||
cardHeight = FCardPanel.ASPECT_RATIO * cardWidth;
|
||||
}
|
||||
|
||||
if (cardHeight > maxCardHeight) { //prevent card overlapping message bars
|
||||
cardHeight = maxCardHeight;
|
||||
cardWidth = cardHeight / FCardPanel.ASPECT_RATIO;
|
||||
}
|
||||
float x = (w - cardWidth) / 2;
|
||||
y = (h - cardHeight) / 2;
|
||||
if (zoomMode) {
|
||||
CardImageRenderer.drawZoom(g, currentCard, gameView, showBackSide? showBackSide : showAltState, x, y, cardWidth, cardHeight, getWidth(), getHeight(), true);
|
||||
} else {
|
||||
CardImageRenderer.drawDetails(g, currentCard, gameView, showBackSide? showBackSide : showAltState, x, y, cardWidth, cardHeight);
|
||||
}
|
||||
|
||||
if (!showMerged) {
|
||||
if (mutateIconBounds != null) {
|
||||
float oldAlpha = g.getfloatAlphaComposite();
|
||||
try {
|
||||
g.setAlphaComposite(0.6f);
|
||||
drawIconBounds(g, mutateIconBounds, Forge.hdbuttons ? FSkinImage.HDLIBRARY : FSkinImage.LIBRARY, x, y, cardWidth, cardHeight);
|
||||
g.setAlphaComposite(oldAlpha);
|
||||
} catch (Exception e) {
|
||||
mutateIconBounds = null;
|
||||
g.setAlphaComposite(oldAlpha);
|
||||
}
|
||||
} else if (flipIconBounds != null) {
|
||||
drawIconBounds(g, flipIconBounds, Forge.hdbuttons ? FSkinImage.HDFLIPCARD : FSkinImage.FLIPCARD, x, y, cardWidth, cardHeight);
|
||||
}
|
||||
} else if (flipIconBounds != null) {
|
||||
drawIconBounds(g, flipIconBounds, Forge.hdbuttons ? FSkinImage.HDFLIPCARD : FSkinImage.FLIPCARD, x, y, cardWidth, cardHeight);
|
||||
}
|
||||
|
||||
if (currentActivateAction != null) {
|
||||
g.fillRect(FDialog.MSG_BACK_COLOR, 0, 0, w, messageHeight);
|
||||
g.drawText(Localizer.getInstance().getMessage("lblSwipeUpTo").replace("%s", currentActivateAction), FDialog.MSG_FONT, FDialog.MSG_FORE_COLOR, 0, 0, w, messageHeight, false, Align.center, true);
|
||||
}
|
||||
g.fillRect(FDialog.MSG_BACK_COLOR, 0, h - messageHeight, w, messageHeight);
|
||||
g.drawText(zoomMode ? Localizer.getInstance().getMessage("lblSwipeDownDetailView") : Localizer.getInstance().getMessage("lblSwipeDownPictureView"), FDialog.MSG_FONT, FDialog.MSG_FORE_COLOR, 0, h - messageHeight, w, messageHeight, false, Align.center, true);
|
||||
|
||||
interrupt(false);
|
||||
}
|
||||
|
||||
private void drawIconBounds(Graphics g, Rectangle iconBounds, FSkinImage skinImage, float x, float y, float cardWidth, float cardHeight) {
|
||||
float imageWidth = cardWidth / 2;
|
||||
float imageHeight = imageWidth * skinImage.getHeight() / skinImage.getWidth();
|
||||
iconBounds.set(x + (cardWidth - imageWidth) / 2, y + (cardHeight - imageHeight) / 2, imageWidth, imageHeight);
|
||||
g.drawImage(skinImage, iconBounds.x, iconBounds.y, iconBounds.width, iconBounds.height);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
}
|
||||
|
||||
public interface ActivateHandler {
|
||||
String getActivateAction(int index);
|
||||
void setSelectedIndex(int index);
|
||||
void activate(int index);
|
||||
}
|
||||
|
||||
public void interrupt(boolean resume) {
|
||||
if (MatchController.instance.hasLocalPlayers())
|
||||
return;
|
||||
if(resume && MatchController.instance.isGamePaused()) {
|
||||
MatchController.instance.resumeMatch();
|
||||
return;
|
||||
}
|
||||
if(!MatchController.instance.isGamePaused())
|
||||
MatchController.instance.pauseMatch();
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package forge.adventure.libgdxgui.card;
|
||||
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FImage;
|
||||
import forge.adventure.libgdxgui.assets.FSkinImage;
|
||||
import forge.card.ColorSet;
|
||||
|
||||
public class ColorSetImage implements FImage {
|
||||
private final ColorSet colorSet;
|
||||
private final int shardCount;
|
||||
|
||||
public ColorSetImage(ColorSet colorSet0) {
|
||||
colorSet = colorSet0;
|
||||
shardCount = colorSet.getOrderedShards().length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidth() {
|
||||
return FSkinImage.MANA_W.getWidth() * shardCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHeight() {
|
||||
return FSkinImage.MANA_W.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
float imageSize = w / shardCount;
|
||||
if (imageSize > h) {
|
||||
imageSize = h;
|
||||
float w0 = imageSize * shardCount;
|
||||
x += (w - w0) / 2;
|
||||
w = w0;
|
||||
}
|
||||
CardFaceSymbols.drawColorSet(g, colorSet, x, y, imageSize);
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
package forge.adventure.libgdxgui.card;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FImage;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.assets.FSkinImage;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.screens.TabPageScreen;
|
||||
import forge.adventure.libgdxgui.toolbox.FChoiceList;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
import forge.adventure.libgdxgui.toolbox.FOptionPane;
|
||||
import forge.adventure.libgdxgui.toolbox.FTextField;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.util.Callback;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class GameEntityPicker extends TabPageScreen<GameEntityPicker> {
|
||||
private final FOptionPane optionPane;
|
||||
|
||||
public GameEntityPicker(String title, Collection<? extends GameEntityView> choiceList, Collection<CardView> revealList, String revealListCaption, FImage revealListImage, boolean isOptional, final Callback<GameEntityView> callback) {
|
||||
super(new PickerTab[] {
|
||||
new PickerTab(choiceList, Localizer.getInstance().getMessage("lblChoices"), Forge.hdbuttons ? FSkinImage.HDCHOICE : FSkinImage.DECKLIST, 1),
|
||||
new PickerTab(revealList, revealListCaption, revealListImage, 0)
|
||||
}, false);
|
||||
|
||||
setHeight(FOptionPane.getMaxDisplayObjHeight());
|
||||
|
||||
optionPane = new FOptionPane(null, null, title, null, this,
|
||||
isOptional ? ImmutableList.of(Localizer.getInstance().getMessage("lblOK"), Localizer.getInstance().getMessage("lblCancel")) : ImmutableList.of(Localizer.getInstance().getMessage("lblOK")), 0, new Callback<Integer>() {
|
||||
@Override
|
||||
public void run(Integer result) {
|
||||
if (result == 0) {
|
||||
callback.run(((PickerTab)tabPages[0]).list.getSelectedItem());
|
||||
}
|
||||
else {
|
||||
callback.run(null);
|
||||
}
|
||||
}
|
||||
}) {
|
||||
@Override
|
||||
protected boolean padAboveAndBelow() {
|
||||
return false; //allow list to go straight up against buttons
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void show() {
|
||||
optionPane.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canActivateTabPage() {
|
||||
return true; //always allow activating tab pages while this is open
|
||||
}
|
||||
|
||||
@Override
|
||||
public FScreen getLandscapeBackdropScreen() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class PickerTab extends TabPage<GameEntityPicker> {
|
||||
private final FTextField txtSearch;
|
||||
private final FChoiceList<GameEntityView> list;
|
||||
|
||||
private PickerTab(final Collection<? extends GameEntityView> items, String caption0, FImage icon0, final int maxChoices) {
|
||||
super(caption0 + " (" + items.size() + ")", icon0);
|
||||
txtSearch = add(new FTextField());
|
||||
txtSearch.setFont(FSkinFont.get(12));
|
||||
txtSearch.setGhostText(Localizer.getInstance().getMessage("lblSearch"));
|
||||
txtSearch.setChangedHandler(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
String pattern = txtSearch.getText().toLowerCase();
|
||||
list.clearSelection();
|
||||
if (pattern.isEmpty()) {
|
||||
list.setListData(items);
|
||||
}
|
||||
else {
|
||||
List<GameEntityView> filteredList = new ArrayList<>();
|
||||
for (GameEntityView option : items) {
|
||||
if (option.toString().toLowerCase().contains(pattern)) {
|
||||
filteredList.add(option);
|
||||
}
|
||||
}
|
||||
list.setListData(filteredList);
|
||||
}
|
||||
if (!list.isEmpty() && maxChoices > 0) {
|
||||
list.addSelectedIndex(0);
|
||||
}
|
||||
list.setScrollTop(0);
|
||||
}
|
||||
});
|
||||
list = add(new FChoiceList<GameEntityView>(items, maxChoices, maxChoices) {
|
||||
@Override
|
||||
protected void onItemActivate(Integer index, GameEntityView value) {
|
||||
if (maxChoices > 0) {
|
||||
parentScreen.optionPane.setResult(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOverlay(Graphics g) {
|
||||
//don't draw border
|
||||
}
|
||||
});
|
||||
if (maxChoices > 0) {
|
||||
list.addSelectedIndex(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivate() {
|
||||
if (parentScreen.optionPane != null) {
|
||||
parentScreen.optionPane.setButtonEnabled(0, list.getMaxChoices() > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
float padding = txtSearch.getHeight() * 0.25f;
|
||||
float y = padding;
|
||||
txtSearch.setBounds(0, y, width, txtSearch.getHeight());
|
||||
y += txtSearch.getHeight() + padding;
|
||||
list.setBounds(0, y, width, height - y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,424 +0,0 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.adventure.libgdxgui.deck;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.google.common.collect.Iterables;
|
||||
import forge.StaticData;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.assets.FSkinImage;
|
||||
import forge.adventure.libgdxgui.card.CardRenderer;
|
||||
import forge.adventure.libgdxgui.card.CardRenderer.CardStackPosition;
|
||||
import forge.adventure.libgdxgui.card.CardZoom;
|
||||
import forge.adventure.libgdxgui.toolbox.*;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
import forge.card.CardEdition;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckgenUtil;
|
||||
import forge.item.PaperCard;
|
||||
import forge.model.FModel;
|
||||
import forge.util.Callback;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
||||
public class AddBasicLandsDialog extends FDialog {
|
||||
private static final float ADD_BTN_SIZE = Utils.AVG_FINGER_HEIGHT * 0.75f;
|
||||
private static final float LAND_PANEL_PADDING = Utils.scale(3);
|
||||
|
||||
private final Deck currentDeck;
|
||||
|
||||
private final Callback<CardPool> callback;
|
||||
|
||||
private final FLabel lblLandSet = add(new FLabel.Builder().text(Localizer.getInstance().getMessage("lblLandSet") + ":").font(FSkinFont.get(12)).textColor(FLabel.INLINE_LABEL_COLOR).build());
|
||||
private final FComboBox<CardEdition> cbLandSet = add(new FComboBox<>(Iterables.filter(StaticData.instance().getEditions(), CardEdition.Predicates.hasBasicLands)));
|
||||
|
||||
private final FScrollPane scroller = add(new FScrollPane() {
|
||||
@Override
|
||||
protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) {
|
||||
float padding = FOptionPane.PADDING;
|
||||
float x = padding;
|
||||
float totalWidth = Forge.isLandscapeMode() ? visibleWidth : 2 * visibleWidth - ADD_BTN_SIZE;
|
||||
float panelWidth = (totalWidth - 6 * padding) / 5;
|
||||
|
||||
pnlPlains.setBounds(x, 0, panelWidth, visibleHeight);
|
||||
x += panelWidth + padding;
|
||||
pnlIsland.setBounds(x, 0, panelWidth, visibleHeight);
|
||||
x += panelWidth + padding;
|
||||
pnlSwamp.setBounds(x, 0, panelWidth, visibleHeight);
|
||||
x += panelWidth + padding;
|
||||
pnlMountain.setBounds(x, 0, panelWidth, visibleHeight);
|
||||
x += panelWidth + padding;
|
||||
pnlForest.setBounds(x, 0, panelWidth, visibleHeight);
|
||||
|
||||
return new ScrollBounds(totalWidth, visibleHeight);
|
||||
}
|
||||
});
|
||||
private final LandPanel pnlPlains = scroller.add(new LandPanel("Plains"));
|
||||
private final LandPanel pnlIsland = scroller.add(new LandPanel("Island"));
|
||||
private final LandPanel pnlSwamp = scroller.add(new LandPanel("Swamp"));
|
||||
private final LandPanel pnlMountain = scroller.add(new LandPanel("Mountain"));
|
||||
private final LandPanel pnlForest = scroller.add(new LandPanel("Forest"));
|
||||
|
||||
private final FTextArea lblDeckInfo = add(new FTextArea(true) {
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
if (count == 2) {
|
||||
Map<ManaCostShard, Integer> suggestionMap = DeckgenUtil.suggestBasicLandCount(currentDeck);
|
||||
pnlPlains.count = suggestionMap.get(ManaCostShard.WHITE);
|
||||
pnlIsland.count = suggestionMap.get(ManaCostShard.BLUE);
|
||||
pnlSwamp.count = suggestionMap.get(ManaCostShard.BLACK);
|
||||
pnlMountain.count = suggestionMap.get(ManaCostShard.RED);
|
||||
pnlForest.count = suggestionMap.get(ManaCostShard.GREEN);
|
||||
|
||||
pnlPlains.lblCount.setText(String.valueOf(pnlPlains.count));
|
||||
pnlIsland.lblCount.setText(String.valueOf(pnlIsland.count));
|
||||
pnlSwamp.lblCount.setText(String.valueOf(pnlSwamp.count));
|
||||
pnlMountain.lblCount.setText(String.valueOf(pnlMountain.count));
|
||||
pnlForest.lblCount.setText(String.valueOf(pnlForest.count));
|
||||
|
||||
updateDeckInfoLabel();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
private int nonLandCount, oldLandCount;
|
||||
private CardEdition landSet;
|
||||
|
||||
public AddBasicLandsDialog(Deck deck, CardEdition defaultLandSet, final Callback<CardPool> callback0) {
|
||||
super(Localizer.getInstance().getMessage("lblAddBasicLandsAutoSuggest").replace("%s", deck.getName()), 2);
|
||||
|
||||
callback = callback0;
|
||||
currentDeck = deck;
|
||||
|
||||
lblDeckInfo.setAlignment(Align.center);
|
||||
lblDeckInfo.setFont(FSkinFont.get(12));
|
||||
|
||||
cbLandSet.setFont(lblLandSet.getFont());
|
||||
cbLandSet.setChangedHandler(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
landSet = cbLandSet.getSelectedItem();
|
||||
pnlPlains.refreshArtChoices();
|
||||
pnlIsland.refreshArtChoices();
|
||||
pnlSwamp.refreshArtChoices();
|
||||
pnlMountain.refreshArtChoices();
|
||||
pnlForest.refreshArtChoices();
|
||||
}
|
||||
});
|
||||
cbLandSet.setSelectedItem(defaultLandSet);
|
||||
|
||||
initButton(0, Localizer.getInstance().getMessage("lblOK"), new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
CardPool landsToAdd = new CardPool();
|
||||
pnlPlains.addToCardPool(landsToAdd);
|
||||
pnlIsland.addToCardPool(landsToAdd);
|
||||
pnlSwamp.addToCardPool(landsToAdd);
|
||||
pnlMountain.addToCardPool(landsToAdd);
|
||||
pnlForest.addToCardPool(landsToAdd);
|
||||
|
||||
hide();
|
||||
|
||||
if (landsToAdd.countAll() > 0) {
|
||||
callback.run(landsToAdd);
|
||||
}
|
||||
}
|
||||
});
|
||||
initButton(1, Localizer.getInstance().getMessage("lblCancel"), new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
//initialize land counts based on current deck contents
|
||||
int halfCountW = 0; //track half shard count for each color to add to symbol count only if a full symbol is also found
|
||||
int halfCountU = 0;
|
||||
int halfCountB = 0;
|
||||
int halfCountR = 0;
|
||||
int halfCountG = 0;
|
||||
for (Entry<PaperCard, Integer> entry : deck.getMain()) {
|
||||
CardRules cardRules = entry.getKey().getRules();
|
||||
int count = entry.getValue();
|
||||
if (cardRules.getType().isLand()) {
|
||||
oldLandCount += count;
|
||||
}
|
||||
else {
|
||||
nonLandCount += count;
|
||||
|
||||
for (ManaCostShard shard : cardRules.getManaCost()) {
|
||||
boolean isMonoColor = shard.isMonoColor();
|
||||
if (shard.isWhite()) {
|
||||
if (isMonoColor) {
|
||||
pnlPlains.symbolCount += count;
|
||||
continue;
|
||||
}
|
||||
halfCountW += count;
|
||||
}
|
||||
if (shard.isBlue()) {
|
||||
if (isMonoColor) {
|
||||
pnlIsland.symbolCount += count;
|
||||
continue;
|
||||
}
|
||||
halfCountU += count;
|
||||
}
|
||||
if (shard.isBlack()) {
|
||||
if (isMonoColor) {
|
||||
pnlSwamp.symbolCount += count;
|
||||
continue;
|
||||
}
|
||||
halfCountB += count;
|
||||
}
|
||||
if (shard.isRed()) {
|
||||
if (isMonoColor) {
|
||||
pnlMountain.symbolCount += count;
|
||||
continue;
|
||||
}
|
||||
halfCountR += count;
|
||||
}
|
||||
if (shard.isGreen()) {
|
||||
if (isMonoColor) {
|
||||
pnlForest.symbolCount += count;
|
||||
continue;
|
||||
}
|
||||
halfCountG += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//only account for half shards if full shards exist for a given color
|
||||
if (pnlPlains.symbolCount > 0 && halfCountW > 0) {
|
||||
pnlPlains.symbolCount += halfCountW * 0.5;
|
||||
}
|
||||
if (pnlIsland.symbolCount > 0 && halfCountU > 0) {
|
||||
pnlIsland.symbolCount += halfCountU * 0.5;
|
||||
}
|
||||
if (pnlSwamp.symbolCount > 0 && halfCountB > 0) {
|
||||
pnlSwamp.symbolCount += halfCountB * 0.5;
|
||||
}
|
||||
if (pnlMountain.symbolCount > 0 && halfCountR > 0) {
|
||||
pnlMountain.symbolCount += halfCountR * 0.5;
|
||||
}
|
||||
if (pnlForest.symbolCount > 0 && halfCountG > 0) {
|
||||
pnlForest.symbolCount += halfCountG * 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
updateDeckInfoLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float layoutAndGetHeight(float width, float maxHeight) {
|
||||
float padding = FOptionPane.PADDING;
|
||||
float x = padding;
|
||||
float y = padding;
|
||||
float w = width - 2 * padding;
|
||||
|
||||
//layout land set combo box
|
||||
float comboBoxHeight = cbLandSet.getHeight();
|
||||
lblLandSet.setBounds(x, y, lblLandSet.getAutoSizeBounds().width, comboBoxHeight);
|
||||
cbLandSet.setBounds(x + lblLandSet.getWidth(), y, w - lblLandSet.getWidth(), comboBoxHeight);
|
||||
|
||||
//layout card panel scroller
|
||||
y += comboBoxHeight + padding;
|
||||
float panelExtraHeight = pnlPlains.cbLandArt.getHeight() + ADD_BTN_SIZE + 2 * LAND_PANEL_PADDING;
|
||||
float panelWidth;
|
||||
if (Forge.isLandscapeMode()) {
|
||||
panelWidth = (width - 6 * padding) / 5;
|
||||
}
|
||||
else {
|
||||
panelWidth = (2 * width - ADD_BTN_SIZE - 6 * padding) / 5;
|
||||
}
|
||||
float panelHeight = panelWidth * FCardPanel.ASPECT_RATIO + panelExtraHeight;
|
||||
scroller.setBounds(0, y, width, panelHeight);
|
||||
|
||||
//adjust scroll based on prevalent colors in deck
|
||||
if (pnlMountain.symbolCount + pnlForest.symbolCount > pnlPlains.symbolCount + pnlIsland.symbolCount) {
|
||||
scroller.scrollToRight();
|
||||
}
|
||||
else {
|
||||
scroller.scrollToLeft();
|
||||
}
|
||||
|
||||
//layout info label
|
||||
y += panelHeight + padding;
|
||||
lblDeckInfo.setBounds(x, y, w, lblDeckInfo.getPreferredHeight(w));
|
||||
|
||||
return y + lblDeckInfo.getHeight() + padding;
|
||||
}
|
||||
|
||||
private void updateDeckInfoLabel() {
|
||||
NumberFormat integer = NumberFormat.getIntegerInstance();
|
||||
NumberFormat percent = NumberFormat.getPercentInstance();
|
||||
int newLandCount = pnlPlains.count + pnlIsland.count + pnlSwamp.count + pnlMountain.count + pnlForest.count;
|
||||
double totalSymbolCount = pnlPlains.symbolCount + pnlIsland.symbolCount + pnlSwamp.symbolCount + pnlMountain.symbolCount + pnlForest.symbolCount;
|
||||
if (totalSymbolCount == 0) {
|
||||
totalSymbolCount = 1; //prevent divide by 0 error
|
||||
}
|
||||
int newTotalCount = nonLandCount + oldLandCount + newLandCount;
|
||||
lblDeckInfo.setText(
|
||||
String.format(Localizer.getInstance().getMessage("lblNonLandCount"), nonLandCount) + " + " +
|
||||
String.format(Localizer.getInstance().getMessage("lblOldLandCount"), oldLandCount) + " + " +
|
||||
String.format(Localizer.getInstance().getMessage("lblNewLandCount"), newLandCount) + " = " +
|
||||
String.format(Localizer.getInstance().getMessage("lblNewTotalCount"), newTotalCount) + "\n" +
|
||||
"{W} " + integer.format(pnlPlains.symbolCount) + " (" + percent.format(pnlPlains.symbolCount / totalSymbolCount) + ") | " +
|
||||
"{U} " + integer.format(pnlIsland.symbolCount) + " (" + percent.format(pnlIsland.symbolCount / totalSymbolCount) + ") | " +
|
||||
"{B} " + integer.format(pnlSwamp.symbolCount) + " (" + percent.format(pnlSwamp.symbolCount / totalSymbolCount) + ") | " +
|
||||
"{R} " + integer.format(pnlMountain.symbolCount) + " (" + percent.format(pnlMountain.symbolCount / totalSymbolCount) + ") | " +
|
||||
"{G} " + integer.format(pnlForest.symbolCount) + " (" + percent.format(pnlForest.symbolCount / totalSymbolCount) + ")");
|
||||
}
|
||||
|
||||
private class LandPanel extends FContainer {
|
||||
private final LandCardPanel cardPanel;
|
||||
private final FLabel lblCount, btnSubtract, btnAdd;
|
||||
private final FComboBox<String> cbLandArt;
|
||||
private final String cardName;
|
||||
private PaperCard card;
|
||||
private int count, maxCount;
|
||||
private double symbolCount;
|
||||
|
||||
private LandPanel(String cardName0) {
|
||||
cardName = cardName0;
|
||||
cardPanel = add(new LandCardPanel());
|
||||
cbLandArt = add(new FComboBox<>());
|
||||
cbLandArt.setFont(cbLandSet.getFont());
|
||||
cbLandArt.setChangedHandler(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
int artIndex = cbLandArt.getSelectedIndex();
|
||||
if (artIndex < 0) { return; }
|
||||
card = generateCard(artIndex); //generate card for display
|
||||
}
|
||||
});
|
||||
lblCount = add(new FLabel.Builder().text("0").font(FSkinFont.get(18)).align(Align.center).build());
|
||||
btnSubtract = add(new FLabel.ButtonBuilder().icon(Forge.hdbuttons ? FSkinImage.HDMINUS : FSkinImage.MINUS).command(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
if (count > 0) {
|
||||
count--;
|
||||
lblCount.setText(String.valueOf(count));
|
||||
updateDeckInfoLabel();
|
||||
}
|
||||
}
|
||||
}).build());
|
||||
btnAdd = add(new FLabel.ButtonBuilder().icon(Forge.hdbuttons ? FSkinImage.HDPLUS : FSkinImage.PLUS).command(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
if (maxCount == 0 || count < maxCount) {
|
||||
count++;
|
||||
lblCount.setText(String.valueOf(count));
|
||||
updateDeckInfoLabel();
|
||||
}
|
||||
}
|
||||
}).build());
|
||||
}
|
||||
|
||||
private void addToCardPool(CardPool pool) {
|
||||
if (count == 0) { return; }
|
||||
int artIndex = cbLandArt.getSelectedIndex();
|
||||
if (artIndex < 0) { return; }
|
||||
|
||||
if (artIndex > 0 && card != null) {
|
||||
pool.add(card, count); //simplify things if art index specified
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < count; i++) {
|
||||
pool.add(generateCard(artIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PaperCard generateCard(int artIndex) {
|
||||
PaperCard c = FModel.getMagicDb().getCommonCards().getCard(cardName, landSet.getCode(), artIndex);
|
||||
if (c == null) {
|
||||
//if can't find land for this set, fall back to Zendikar lands
|
||||
c = FModel.getMagicDb().getCommonCards().getCard(cardName, "ZEN");
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
private void refreshArtChoices() {
|
||||
cbLandArt.removeAllItems();
|
||||
if (landSet == null) { return; }
|
||||
|
||||
int artChoiceCount = FModel.getMagicDb().getCommonCards().getArtCount(cardName, landSet.getCode());
|
||||
cbLandArt.addItem(Localizer.getInstance().getMessage("lblAssortedArt"));
|
||||
for (int i = 1; i <= artChoiceCount; i++) {
|
||||
cbLandArt.addItem(Localizer.getInstance().getMessage("lblCardArtN", String.valueOf(i)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
float y = height - ADD_BTN_SIZE;
|
||||
float buttonWidth = ADD_BTN_SIZE;
|
||||
float labelWidth = width - 2 * ADD_BTN_SIZE;
|
||||
float minLabelWidth = lblCount.getFont().getBounds("0").width + 2 * lblCount.getInsets().x;
|
||||
if (labelWidth < minLabelWidth) { //ensure count label has enough room for display a single digit count at normal font size
|
||||
labelWidth = minLabelWidth;
|
||||
buttonWidth = (width - labelWidth) / 2;
|
||||
}
|
||||
btnSubtract.setBounds(0, y, buttonWidth, ADD_BTN_SIZE);
|
||||
lblCount.setBounds(buttonWidth, y, labelWidth, ADD_BTN_SIZE);
|
||||
btnAdd.setBounds(width - buttonWidth, y, buttonWidth, ADD_BTN_SIZE);
|
||||
|
||||
y -= cbLandArt.getHeight() + LAND_PANEL_PADDING;
|
||||
cbLandArt.setBounds(0, y, width, cbLandArt.getHeight());
|
||||
|
||||
float cardPanelHeight = y - LAND_PANEL_PADDING;
|
||||
float cardPanelWidth = cardPanelHeight / FCardPanel.ASPECT_RATIO;
|
||||
cardPanel.setBounds((width - cardPanelWidth) / 2, 0, cardPanelWidth, cardPanelHeight);
|
||||
}
|
||||
|
||||
private class LandCardPanel extends FDisplayObject {
|
||||
private LandCardPanel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
if (card == null) { return false; }
|
||||
CardZoom.show(card);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean longPress(float x, float y) {
|
||||
if (card == null) { return false; }
|
||||
CardZoom.show(card);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g) {
|
||||
if (card == null) { return; }
|
||||
CardRenderer.drawCard(g, card, 0, 0, getWidth(), getHeight(), CardStackPosition.Top);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,184 +0,0 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.adventure.libgdxgui.deck;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckImportController;
|
||||
import forge.deck.DeckRecognizer;
|
||||
import forge.deck.DeckRecognizer.TokenType;
|
||||
import forge.gui.FThreads;
|
||||
import forge.gui.util.SOptionPane;
|
||||
import forge.adventure.libgdxgui.toolbox.*;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
import forge.util.Callback;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class FDeckImportDialog extends FDialog {
|
||||
private final Callback<Deck> callback;
|
||||
|
||||
private final FTextArea txtInput = add(new FTextArea(true));
|
||||
private final FCheckBox newEditionCheck = add(new FCheckBox(Localizer.getInstance().getMessage("lblImportLatestVersionCard"), true));
|
||||
private final FCheckBox dateTimeCheck = add(new FCheckBox(Localizer.getInstance().getMessage("lblUseOnlySetsReleasedBefore"), false));
|
||||
/*setting onlyCoreExpCheck to false allow the copied cards to pass the check of deck contents
|
||||
forge-core\src\main\java\forge\deck\Deck.javaDeck.java starting @ Line 320 which is called by
|
||||
forge-gui-mobile\src\forge\deck\FDeckEditor.java starting @ Line 373
|
||||
(as of latest commit: 8e6655e3ee67688cff66b422d4722c58392eaa7e)
|
||||
*/
|
||||
private final FCheckBox onlyCoreExpCheck = add(new FCheckBox(Localizer.getInstance().getMessage("lblUseOnlyCoreAndExpansionSets"), false));
|
||||
|
||||
private final FComboBox<String> monthDropdown = add(new FComboBox<>()); //don't need wrappers since skin can't change while this dialog is open
|
||||
private final FComboBox<Integer> yearDropdown = add(new FComboBox<>());
|
||||
|
||||
private final boolean showOptions;
|
||||
private final DeckImportController controller;
|
||||
|
||||
private final static ImmutableList<String> importOrCancel = ImmutableList.of(Localizer.getInstance().getMessage("lblImport"), Localizer.getInstance().getMessage("lblCancel"));
|
||||
|
||||
public FDeckImportDialog(final boolean replacingDeck, final Callback<Deck> callback0) {
|
||||
super(Localizer.getInstance().getMessage("lblImportFromClipboard"), 2);
|
||||
|
||||
callback = callback0;
|
||||
controller = new DeckImportController(replacingDeck, newEditionCheck, dateTimeCheck, onlyCoreExpCheck, monthDropdown, yearDropdown);
|
||||
txtInput.setText(Forge.getClipboard().getContents()); //just pull import directly off the clipboard
|
||||
|
||||
initButton(0, Localizer.getInstance().getMessage("lblImport"), new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
FThreads.invokeInBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<DeckRecognizer.Token> tokens = controller.parseInput(txtInput.getText()); //ensure deck updated based on any changes to options
|
||||
|
||||
//if there are any unknown cards, let user know this and give them the option to cancel
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (DeckRecognizer.Token token : tokens) {
|
||||
if (token.getType() == TokenType.UnknownCard) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append("\n");
|
||||
}
|
||||
sb.append(token.getNumber()).append(" ").append(token.getText());
|
||||
}
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
if (SOptionPane.showOptionDialog(Localizer.getInstance().getMessage("lblFollowingCardsCannotBeImported") + "\n\n" + sb, Localizer.getInstance().getMessage("lblImportRemainingCards"), SOptionPane.INFORMATION_ICON, importOrCancel) == 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final Deck deck = controller.accept(); //must accept in background thread in case a dialog is shown
|
||||
if (deck == null) { return; }
|
||||
|
||||
FThreads.invokeInEdtLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
hide();
|
||||
callback.run(deck);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
initButton(1, Localizer.getInstance().getMessage("lblCancel"), new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
List<DeckRecognizer.Token> tokens = controller.parseInput(txtInput.getText());
|
||||
|
||||
//ensure at least one known card found on clipboard
|
||||
for (DeckRecognizer.Token token : tokens) {
|
||||
if (token.getType() == TokenType.KnownCard) {
|
||||
showOptions = true;
|
||||
|
||||
dateTimeCheck.setCommand(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
updateDropDownEnabled();
|
||||
}
|
||||
});
|
||||
updateDropDownEnabled();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
showOptions = false;
|
||||
setButtonEnabled(0, false);
|
||||
txtInput.setText(Localizer.getInstance().getMessage("lblNoKnownCardsOnClipboard"));
|
||||
}
|
||||
|
||||
private void updateDropDownEnabled() {
|
||||
boolean enabled = dateTimeCheck.isSelected();
|
||||
monthDropdown.setEnabled(enabled);
|
||||
yearDropdown.setEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOverlay(Graphics g) {
|
||||
super.drawOverlay(g);
|
||||
if (showOptions) {
|
||||
float y = txtInput.getTop() - FOptionPane.PADDING;
|
||||
g.drawLine(BORDER_THICKNESS, BORDER_COLOR, 0, y, getWidth(), y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float layoutAndGetHeight(float width, float maxHeight) {
|
||||
float padding = FOptionPane.PADDING;
|
||||
float x = padding;
|
||||
float y = padding;
|
||||
float w = width - 2 * padding;
|
||||
float h;
|
||||
if (showOptions) {
|
||||
h = monthDropdown.getHeight();
|
||||
float fieldPadding = padding / 2;
|
||||
|
||||
newEditionCheck.setBounds(x, y, w, h);
|
||||
y += h + fieldPadding;
|
||||
dateTimeCheck.setBounds(x, y, w, h);
|
||||
y += h + fieldPadding;
|
||||
|
||||
float dropDownWidth = (w - fieldPadding) / 2;
|
||||
monthDropdown.setBounds(x, y, dropDownWidth, h);
|
||||
yearDropdown.setBounds(x + dropDownWidth + fieldPadding, y, dropDownWidth, h);
|
||||
y += h + fieldPadding;
|
||||
|
||||
onlyCoreExpCheck.setBounds(x, y, w, h);
|
||||
y += h + 2 * padding;
|
||||
}
|
||||
h = txtInput.getPreferredHeight(w);
|
||||
float maxTextBoxHeight = maxHeight - y - padding;
|
||||
if (h > maxTextBoxHeight) {
|
||||
h = maxTextBoxHeight;
|
||||
}
|
||||
txtInput.setBounds(x, y, w, h);
|
||||
y += h + padding;
|
||||
if (showOptions) {
|
||||
h = newEditionCheck.getHeight();
|
||||
}
|
||||
return y;
|
||||
}
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
package forge.adventure.libgdxgui.deck;
|
||||
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.assets.*;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.itemmanager.CardManager;
|
||||
import forge.itemmanager.ItemManagerConfig;
|
||||
import forge.adventure.libgdxgui.itemmanager.filters.ItemFilter;
|
||||
import forge.adventure.libgdxgui.menu.FMenuItem;
|
||||
import forge.adventure.libgdxgui.menu.FPopupMenu;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.screens.match.MatchController;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
import forge.adventure.libgdxgui.toolbox.FOptionPane;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class FDeckViewer extends FScreen {
|
||||
private static FDeckViewer deckViewer;
|
||||
private static final FPopupMenu menu = new FPopupMenu() {
|
||||
@Override
|
||||
protected void buildMenu() {
|
||||
Deck deck = deckViewer.deck;
|
||||
for (Entry<DeckSection, CardPool> entry : deck) {
|
||||
final DeckSection section = entry.getKey();
|
||||
final CardPool pool = entry.getValue();
|
||||
int count = pool.countAll();
|
||||
if (count == 0) { continue; }
|
||||
|
||||
final String captionPrefix;
|
||||
final FImage icon;
|
||||
switch (section) {
|
||||
default:
|
||||
case Main:
|
||||
captionPrefix = Localizer.getInstance().getMessage("ttMain");
|
||||
icon = FDeckEditor.MAIN_DECK_ICON;
|
||||
break;
|
||||
case Sideboard:
|
||||
captionPrefix = Localizer.getInstance().getMessage("lblSideboard");
|
||||
icon = FDeckEditor.SIDEBOARD_ICON;
|
||||
break;
|
||||
case Commander:
|
||||
captionPrefix = Localizer.getInstance().getMessage("lblCommander");
|
||||
icon = FSkinImage.COMMANDER;
|
||||
break;
|
||||
case Avatar:
|
||||
captionPrefix = Localizer.getInstance().getMessage("lblAvatar");
|
||||
icon = new FTextureRegionImage(FSkin.getAvatars().get(0));
|
||||
break;
|
||||
case Planes:
|
||||
captionPrefix = Localizer.getInstance().getMessage("lblPlanes");
|
||||
icon = FSkinImage.CHAOS;
|
||||
break;
|
||||
case Schemes:
|
||||
captionPrefix = Localizer.getInstance().getMessage("lblSchemes");
|
||||
icon = FSkinImage.POISON;
|
||||
break;
|
||||
}
|
||||
|
||||
FMenuItem item = new FMenuItem(captionPrefix + " (" + count + ")", icon, new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
deckViewer.setCurrentSection(section);
|
||||
}
|
||||
});
|
||||
if (section == deckViewer.currentSection) {
|
||||
item.setSelected(true);
|
||||
}
|
||||
addItem(item);
|
||||
}
|
||||
addItem(new FMenuItem(Localizer.getInstance().getMessage("btnCopyToClipboard"), Forge.hdbuttons ? FSkinImage.HDEXPORT : FSkinImage.BLANK, new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
copyDeckToClipboard(deckViewer.deck);
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
public static void copyDeckToClipboard(Deck deck) {
|
||||
final String nl = System.getProperty("line.separator");
|
||||
final StringBuilder deckList = new StringBuilder();
|
||||
String dName = deck.getName();
|
||||
//fix copying a commander netdeck then importing it again...
|
||||
if (dName.startsWith("[Commander")||dName.contains("Commander"))
|
||||
dName = "";
|
||||
deckList.append(dName == null ? "" : dName + nl + nl);
|
||||
|
||||
for (DeckSection s : DeckSection.values()){
|
||||
CardPool cp = deck.get(s);
|
||||
if (cp == null || cp.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
deckList.append(s.toString()).append(": ");
|
||||
deckList.append(nl);
|
||||
for (final Entry<PaperCard, Integer> ev : cp) {
|
||||
deckList.append(ev.getValue()).append(" ").append(ev.getKey()).append(nl);
|
||||
}
|
||||
deckList.append(nl);
|
||||
}
|
||||
|
||||
Forge.getClipboard().setContents(deckList.toString());
|
||||
FOptionPane.showMessageDialog(Localizer.getInstance().getMessage("lblDeckListCopiedClipboard", deck.getName()));
|
||||
}
|
||||
|
||||
private final Deck deck;
|
||||
private final CardManager cardManager;
|
||||
private DeckSection currentSection;
|
||||
|
||||
public static void show(final Deck deck0) {
|
||||
show(deck0, false);
|
||||
}
|
||||
public static void show(final Deck deck0, boolean noPreload) {
|
||||
if (deck0 == null) { return; }
|
||||
|
||||
if (!noPreload){
|
||||
/*preload deck to cache*/
|
||||
ImageCache.preloadCache(deck0);
|
||||
}
|
||||
|
||||
deckViewer = new FDeckViewer(deck0);
|
||||
deckViewer.setRotate180(MatchController.getView() != null && MatchController.getView().isTopHumanPlayerActive());
|
||||
Forge.openScreen(deckViewer);
|
||||
}
|
||||
|
||||
private FDeckViewer(Deck deck0) {
|
||||
super(new MenuHeader(deck0.getName(), menu) {
|
||||
@Override
|
||||
protected boolean displaySidebarForLandscapeMode() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
deck = deck0;
|
||||
cardManager = new CardManager(false);
|
||||
cardManager.setPool(deck.getMain());
|
||||
|
||||
currentSection = DeckSection.Main;
|
||||
updateCaption();
|
||||
|
||||
add(cardManager);
|
||||
|
||||
cardManager.setup(ItemManagerConfig.DECK_VIEWER);
|
||||
}
|
||||
|
||||
private void setCurrentSection(DeckSection currentSection0) {
|
||||
if (currentSection == currentSection0) { return; }
|
||||
currentSection = currentSection0;
|
||||
cardManager.setPool(deck.get(currentSection));
|
||||
updateCaption();
|
||||
}
|
||||
|
||||
private void updateCaption() {
|
||||
cardManager.setCaption(currentSection.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float startY, float width, float height) {
|
||||
float x = 0;
|
||||
if (Forge.isLandscapeMode()) { //add some horizontal padding in landscape mode
|
||||
x = ItemFilter.PADDING;
|
||||
width -= 2 * x;
|
||||
}
|
||||
cardManager.setBounds(x, startY, width, height - startY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FScreen getLandscapeBackdropScreen() {
|
||||
return null; //never use backdrop for editor
|
||||
}
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
package forge.adventure.libgdxgui.deck;
|
||||
|
||||
import forge.adventure.libgdxgui.assets.FImage;
|
||||
import forge.deck.CardPool;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.itemmanager.CardManager;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager.ContextMenuBuilder;
|
||||
import forge.itemmanager.ItemManagerConfig;
|
||||
import forge.adventure.libgdxgui.menu.FDropDownMenu;
|
||||
import forge.adventure.libgdxgui.menu.FMenuItem;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.screens.TabPageScreen;
|
||||
import forge.adventure.libgdxgui.toolbox.FDialog;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
import forge.adventure.libgdxgui.toolbox.GuiChoose;
|
||||
import forge.util.Callback;
|
||||
import forge.util.Localizer;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FSideboardDialog extends FDialog {
|
||||
private final SideboardTabs tabs;
|
||||
private final Callback<List<PaperCard>> callback;
|
||||
|
||||
public FSideboardDialog(CardPool sideboard, CardPool main, final Callback<List<PaperCard>> callback0, String message) {
|
||||
super(String.format(Localizer.getInstance().getMessage("lblUpdateMainFromSideboard"), message), 1);
|
||||
|
||||
callback = callback0;
|
||||
tabs = add(new SideboardTabs(sideboard, main));
|
||||
initButton(0, Localizer.getInstance().getMessage("lblOK"), new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
if (sideboard.isEmpty()) { //show main deck by default if sideboard is empty
|
||||
tabs.setSelectedPage(tabs.getMainDeckPage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible0) {
|
||||
super.setVisible(visible0);
|
||||
if (!visible0) { //do callback when hidden to ensure you don't get stuck if Back pressed
|
||||
callback.run(tabs.getMainDeckPage().cardManager.getPool().toFlatList());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float layoutAndGetHeight(float width, float maxHeight) {
|
||||
tabs.setBounds(0, 0, width, maxHeight);
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
private static class SideboardTabs extends TabPageScreen<SideboardTabs> {
|
||||
private SideboardTabs(CardPool sideboard, CardPool main) {
|
||||
super(new TabPageBase[] {
|
||||
new SideboardPage(sideboard),
|
||||
new MainDeckPage(main)
|
||||
}, false);
|
||||
((SideboardPage)tabPages[0]).parent = this;
|
||||
((MainDeckPage)tabPages[1]).parent = this;
|
||||
}
|
||||
|
||||
private SideboardPage getSideboardPage() {
|
||||
return ((SideboardPage)tabPages[0]);
|
||||
}
|
||||
|
||||
private MainDeckPage getMainDeckPage() {
|
||||
return ((MainDeckPage)tabPages[1]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canActivateTabPage() {
|
||||
return true; //always allow activating tab pages while this is open
|
||||
}
|
||||
|
||||
@Override
|
||||
public FScreen getLandscapeBackdropScreen() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static abstract class TabPageBase extends TabPage<SideboardTabs> {
|
||||
protected SideboardTabs parent;
|
||||
protected final CardManager cardManager = add(new CardManager(false));
|
||||
|
||||
protected TabPageBase(CardPool cardPool, FImage icon0) {
|
||||
super("", icon0);
|
||||
|
||||
cardManager.setItemActivateHandler(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
onCardActivated(cardManager.getSelectedItem());
|
||||
}
|
||||
});
|
||||
cardManager.setContextMenuBuilder(new ContextMenuBuilder<PaperCard>() {
|
||||
@Override
|
||||
public void buildMenu(final FDropDownMenu menu, final PaperCard card) {
|
||||
TabPageBase.this.buildMenu(menu, card);
|
||||
}
|
||||
});
|
||||
cardManager.setup(ItemManagerConfig.SIDEBOARD);
|
||||
cardManager.setPool(new CardPool(cardPool)); //create copy of card pool to avoid modifying the original card pool
|
||||
updateCaption();
|
||||
}
|
||||
|
||||
protected void addCard(PaperCard card, int qty) {
|
||||
cardManager.addItem(card, qty);
|
||||
updateCaption();
|
||||
}
|
||||
|
||||
protected void removeCard(PaperCard card, int qty) {
|
||||
cardManager.removeItem(card, qty);
|
||||
updateCaption();
|
||||
}
|
||||
|
||||
protected void addItem(FDropDownMenu menu, final String verb, String dest, FImage icon, final Callback<Integer> callback) {
|
||||
String label = verb;
|
||||
if (!StringUtils.isEmpty(dest)) {
|
||||
label += " " + dest;
|
||||
}
|
||||
menu.addItem(new FMenuItem(label, icon, new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
PaperCard card = cardManager.getSelectedItem();
|
||||
int max = cardManager.getItemCount(card);
|
||||
if (max == 1) {
|
||||
callback.run(max);
|
||||
}
|
||||
else {
|
||||
GuiChoose.getInteger(card + " - " + verb + " " + Localizer.getInstance().getMessage("lblHowMany"), 1, max, 20, callback);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
protected abstract void updateCaption();
|
||||
protected abstract void onCardActivated(PaperCard card);
|
||||
protected abstract void buildMenu(final FDropDownMenu menu, final PaperCard card);
|
||||
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
cardManager.setBounds(0, 0, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SideboardPage extends TabPageBase {
|
||||
protected SideboardPage(CardPool cardPool) {
|
||||
super(cardPool, FDeckEditor.SIDEBOARD_ICON);
|
||||
cardManager.setCaption(Localizer.getInstance().getMessage("lblSideboard"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateCaption() {
|
||||
caption = Localizer.getInstance().getMessage("lblSideboard") + " (" + cardManager.getPool().countAll() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCardActivated(PaperCard card) {
|
||||
removeCard(card, 1);
|
||||
parent.getMainDeckPage().addCard(card, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildMenu(FDropDownMenu menu, final PaperCard card) {
|
||||
addItem(menu, Localizer.getInstance().getMessage("lblMove"), Localizer.getInstance().getMessage("lblToMainDeck"), FDeckEditor.MAIN_DECK_ICON, new Callback<Integer>() {
|
||||
@Override
|
||||
public void run(Integer result) {
|
||||
if (result == null || result <= 0) { return; }
|
||||
|
||||
removeCard(card, result);
|
||||
parent.getMainDeckPage().addCard(card, result);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static class MainDeckPage extends TabPageBase {
|
||||
protected MainDeckPage(CardPool cardPool) {
|
||||
super(cardPool, FDeckEditor.MAIN_DECK_ICON);
|
||||
cardManager.setCaption(Localizer.getInstance().getMessage("ttMain"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateCaption() {
|
||||
caption = Localizer.getInstance().getMessage("ttMain") + " (" + cardManager.getPool().countAll() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCardActivated(PaperCard card) {
|
||||
removeCard(card, 1);
|
||||
parent.getSideboardPage().addCard(card, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildMenu(FDropDownMenu menu, final PaperCard card) {
|
||||
addItem(menu, Localizer.getInstance().getMessage("lblMove"), Localizer.getInstance().getMessage("lbltosideboard"), FDeckEditor.SIDEBOARD_ICON, new Callback<Integer>() {
|
||||
@Override
|
||||
public void run(Integer result) {
|
||||
if (result == null || result <= 0) { return; }
|
||||
|
||||
removeCard(card, result);
|
||||
parent.getSideboardPage().addCard(card, result);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
package forge.adventure.libgdxgui.deck;
|
||||
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.deck.CardPool;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.itemmanager.CardManager;
|
||||
import forge.itemmanager.ItemManagerConfig;
|
||||
import forge.model.FModel;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.toolbox.FButton;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.Localizer;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
|
||||
public class FVanguardChooser extends FScreen {
|
||||
public static final float PADDING = Utils.scale(5);
|
||||
|
||||
private static final CardPool allHumanAvatars = new CardPool();
|
||||
private static final CardPool allAiAvatars = new CardPool();
|
||||
private static final CardPool nonRandomHumanAvatars = new CardPool();
|
||||
private static final CardPool nonRandomAiAvatars = new CardPool();
|
||||
|
||||
static {
|
||||
for (PaperCard c : FModel.getMagicDb().getVariantCards().getAllCards()) {
|
||||
if (c.getRules().getType().isVanguard()) {
|
||||
allHumanAvatars.add(c);
|
||||
if (!c.getRules().getAiHints().getRemRandomDecks()) {
|
||||
nonRandomHumanAvatars.add(c);
|
||||
}
|
||||
if (!c.getRules().getAiHints().getRemAIDecks()) {
|
||||
allAiAvatars.add(c);
|
||||
if (!c.getRules().getAiHints().getRemRandomDecks()) {
|
||||
nonRandomAiAvatars.add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final CardManager lstVanguards = add(new CardManager(true));
|
||||
private final FButton btnRandom = add(new FButton(Localizer.getInstance().getMessage("lblRandomVanguard")));
|
||||
private boolean isAi;
|
||||
|
||||
public FVanguardChooser(boolean isAi0, FEventHandler selectionChangedHandler) {
|
||||
super("");
|
||||
isAi = isAi0;
|
||||
lstVanguards.setItemActivateHandler(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
Forge.back();
|
||||
}
|
||||
});
|
||||
btnRandom.setCommand(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
selectRandom();
|
||||
Forge.back();
|
||||
}
|
||||
});
|
||||
lstVanguards.setup(ItemManagerConfig.VANGUARDS);
|
||||
lstVanguards.setPool(isAi ? allAiAvatars : allHumanAvatars, true);
|
||||
lstVanguards.setSelectionChangedHandler(selectionChangedHandler);
|
||||
selectRandom();
|
||||
}
|
||||
|
||||
private void selectRandom() {
|
||||
if (lstVanguards.getItemCount() == 0) { return; }
|
||||
|
||||
if (isAi) {
|
||||
lstVanguards.setSelectedItem(Aggregates.random(nonRandomAiAvatars).getKey());
|
||||
}
|
||||
else {
|
||||
lstVanguards.setSelectedItem(Aggregates.random(nonRandomHumanAvatars).getKey());
|
||||
}
|
||||
}
|
||||
|
||||
public void setIsAi(boolean isAi0) {
|
||||
if (isAi == isAi0) { return; }
|
||||
isAi = isAi0;
|
||||
|
||||
PaperCard lastSelection = lstVanguards.getSelectedItem();
|
||||
|
||||
lstVanguards.setPool(isAi ? allAiAvatars : allHumanAvatars, true);
|
||||
|
||||
if (lastSelection != null) {
|
||||
lstVanguards.setSelectedItem(lastSelection);
|
||||
}
|
||||
if (lstVanguards.getSelectedIndex() == -1) {
|
||||
selectRandom();
|
||||
}
|
||||
}
|
||||
|
||||
public CardManager getLstVanguards() {
|
||||
return lstVanguards;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float startY, float width, float height) {
|
||||
float x = PADDING;
|
||||
float y = startY;
|
||||
width -= 2 * x;
|
||||
|
||||
float buttonHeight = Utils.AVG_FINGER_HEIGHT;
|
||||
lstVanguards.setBounds(x, y, width, height - y - buttonHeight - 2 * PADDING); //leave room for buttons at bottom
|
||||
|
||||
y += lstVanguards.getHeight() + PADDING;
|
||||
btnRandom.setBounds(x, y, width, buttonHeight);
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
package forge.adventure.libgdxgui.error;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.toolbox.FButton;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent;
|
||||
import forge.adventure.libgdxgui.toolbox.FScrollPane;
|
||||
import forge.adventure.libgdxgui.toolbox.FTextArea;
|
||||
import forge.adventure.libgdxgui.util.TextBounds;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
import forge.gui.error.BugReporter;
|
||||
import forge.util.Callback;
|
||||
|
||||
public class BugReportDialog extends FScreen { //use screen rather than dialog so screen with bug isn't rendered
|
||||
private static final float PADDING = Utils.scale(5);
|
||||
private static final float BUTTON_HEIGHT = Utils.AVG_FINGER_HEIGHT * 0.75f;
|
||||
private static boolean isOpen;
|
||||
|
||||
public static void show(String title, String text, boolean showExitAppBtn) {
|
||||
if (isOpen || Forge.getCurrentScreen() == null) { return; } //don't allow showing if Forge not finished initializing yet
|
||||
|
||||
isOpen = true;
|
||||
Forge.openScreen(new BugReportDialog(title, text, showExitAppBtn));
|
||||
}
|
||||
|
||||
private final FTextArea lblHeader = add(new FTextArea(false, "Report Bug"));
|
||||
private final TemplateView tvDetails;
|
||||
private final FButton btnReport = add(new FButton(BugReporter.REPORT));
|
||||
private final FButton btnSave = add(new FButton(BugReporter.SAVE));
|
||||
private final FButton btnDiscard = add(new FButton(BugReporter.DISCARD));
|
||||
private final FButton btnExit = add(new FButton(BugReporter.EXIT));
|
||||
|
||||
private BugReportDialog(String title, String text0, boolean showExitAppBtn) {
|
||||
super(title);
|
||||
lblHeader.setFont(FSkinFont.get(12));
|
||||
tvDetails = add(new TemplateView(text0));
|
||||
btnReport.setCommand(new FEvent.FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
BugReporter.sendSentry();
|
||||
Forge.back();
|
||||
}
|
||||
});
|
||||
btnSave.setCommand(new FEvent.FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
BugReporter.saveToFile(tvDetails.text);
|
||||
}
|
||||
});
|
||||
btnDiscard.setCommand(new FEvent.FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
Forge.back();
|
||||
}
|
||||
});
|
||||
if (showExitAppBtn) {
|
||||
btnExit.setCommand(new FEvent.FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
Forge.exit(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
btnExit.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FScreen getLandscapeBackdropScreen() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Callback<Boolean> canCloseCallback) {
|
||||
super.onClose(canCloseCallback);
|
||||
isOpen = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float startY, float width, float height) {
|
||||
float x = PADDING;
|
||||
float y = startY + PADDING;
|
||||
float w = width - 2 * PADDING;
|
||||
|
||||
lblHeader.setBounds(x, y, w, lblHeader.getPreferredHeight(w));
|
||||
y += lblHeader.getHeight() + PADDING;
|
||||
|
||||
float buttonWidth, totalButtonHeight;
|
||||
float buttonHeight = BUTTON_HEIGHT;
|
||||
boolean landscapeMode = Forge.isLandscapeMode();
|
||||
if (landscapeMode) {
|
||||
buttonWidth = (w - 3 * PADDING) / 4;
|
||||
totalButtonHeight = buttonHeight;
|
||||
}
|
||||
else {
|
||||
buttonWidth = (w - PADDING) / 2;
|
||||
totalButtonHeight = 2 * buttonHeight + PADDING;
|
||||
}
|
||||
|
||||
tvDetails.setBounds(x, y, w, height - totalButtonHeight - 2 * PADDING - y);
|
||||
y += tvDetails.getHeight() + PADDING;
|
||||
|
||||
btnReport.setBounds(x, y, buttonWidth, buttonHeight);
|
||||
btnSave.setBounds(x + buttonWidth + PADDING, y, buttonWidth, buttonHeight);
|
||||
if (landscapeMode) {
|
||||
x += 2 * (buttonWidth + PADDING);
|
||||
}
|
||||
else {
|
||||
y += buttonHeight + PADDING;
|
||||
}
|
||||
if (btnExit.isVisible()) {
|
||||
btnDiscard.setBounds(x, y, buttonWidth, buttonHeight);
|
||||
btnExit.setBounds(x + buttonWidth + PADDING, y, buttonWidth, buttonHeight);
|
||||
}
|
||||
else {
|
||||
btnDiscard.setBounds(x, y, 2 * buttonWidth + PADDING, buttonHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private static class TemplateView extends FScrollPane {
|
||||
private static final FSkinFont FONT = FSkinFont.get(11);
|
||||
private static final FSkinColor BACK_COLOR = FSkinColor.get(FSkinColor.Colors.CLR_ZEBRA);
|
||||
private static final FSkinColor FORE_COLOR = FSkinColor.get(FSkinColor.Colors.CLR_TEXT);
|
||||
private static final FSkinColor BORDER_COLOR = FSkinColor.get(FSkinColor.Colors.CLR_BORDERS);
|
||||
private static final float PADDING = Utils.scale(3);
|
||||
|
||||
private final String text;
|
||||
|
||||
private TemplateView(String text0) {
|
||||
text = text0;
|
||||
setHeight(Forge.getScreenHeight() / 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) {
|
||||
TextBounds bounds = FONT.getMultiLineBounds(text);
|
||||
return new ScrollBounds(bounds.width + 2 * PADDING, bounds.height + 2 * PADDING +
|
||||
FONT.getLineHeight() - FONT.getCapHeight()); //account for height below baseline of final line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawBackground(Graphics g) {
|
||||
g.fillRect(BACK_COLOR, 0, 0, getWidth(), getHeight());
|
||||
g.drawText(text, FONT, FORE_COLOR, PADDING - getScrollLeft(), PADDING - getScrollTop(), getScrollWidth() - 2 * PADDING, getScrollHeight() - 2 * PADDING, false, Align.left, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOverlay(Graphics g) {
|
||||
super.drawOverlay(g);
|
||||
g.drawRect(1, BORDER_COLOR, 0, 0, getWidth(), getHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager;
|
||||
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.card.CardRenderer;
|
||||
import forge.adventure.libgdxgui.card.CardZoom;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.itemmanager.filters.*;
|
||||
import forge.adventure.libgdxgui.toolbox.FList;
|
||||
import forge.adventure.libgdxgui.toolbox.FList.CompactModeHandler;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* ItemManager for cards
|
||||
*/
|
||||
public class CardManager extends ItemManager<PaperCard> {
|
||||
public CardManager(boolean wantUnique0) {
|
||||
super(PaperCard.class, wantUnique0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDefaultFilters() {
|
||||
addDefaultFilters(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TextSearchFilter<PaperCard> createSearchFilter() {
|
||||
return createSearchFilter(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AdvancedSearchFilter<PaperCard> createAdvancedSearchFilter() {
|
||||
return createAdvancedSearchFilter(this);
|
||||
}
|
||||
|
||||
protected void onCardLongPress(int index, Entry<PaperCard, Integer> value, float x, float y) {
|
||||
CardZoom.show(model.getOrderedList(), index, CardManager.this);
|
||||
}
|
||||
|
||||
/* Static overrides shared with SpellShopManager*/
|
||||
|
||||
public static void addDefaultFilters(final ItemManager<? super PaperCard> itemManager) {
|
||||
itemManager.addFilter(new CardColorFilter(itemManager));
|
||||
itemManager.addFilter(new CardFormatFilter(itemManager));
|
||||
itemManager.addFilter(new CardTypeFilter(itemManager));
|
||||
}
|
||||
|
||||
public static TextSearchFilter<PaperCard> createSearchFilter(final ItemManager<? super PaperCard> itemManager) {
|
||||
return new CardSearchFilter(itemManager);
|
||||
}
|
||||
|
||||
public static AdvancedSearchFilter<PaperCard> createAdvancedSearchFilter(final ItemManager<? super PaperCard> itemManager) {
|
||||
return new AdvancedSearchFilter<>(itemManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemRenderer getListItemRenderer(final CompactModeHandler compactModeHandler) {
|
||||
return new ItemRenderer() {
|
||||
@Override
|
||||
public float getItemHeight() {
|
||||
return CardRenderer.getCardListItemHeight(compactModeHandler.isCompactMode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawValue(Graphics g, Entry<PaperCard, Integer> value, FSkinFont font, FSkinColor foreColor, FSkinColor backColor, boolean pressed, float x, float y, float w, float h) {
|
||||
CardRenderer.drawCardListItem(g, font, foreColor, value.getKey(), isInfinite() ? 0 : value.getValue(), getItemSuffix(value), x, y, w, h, compactModeHandler.isCompactMode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(Integer index, Entry<PaperCard, Integer> value, float x, float y, int count) {
|
||||
return CardRenderer.cardListItemTap(model.getOrderedList(), index, CardManager.this, x, y, count, compactModeHandler.isCompactMode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean longPress(Integer index, Entry<PaperCard, Integer> value, float x, float y) {
|
||||
if (CardRenderer.cardListItemTap(model.getOrderedList(), index, CardManager.this, x, y, 1, compactModeHandler.isCompactMode())) {
|
||||
return true; //avoid calling onCardLongPress if user long presses on card art
|
||||
}
|
||||
onCardLongPress(index, value, x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowPressEffect(FList<Entry<PaperCard, Integer>> list, float x, float y) {
|
||||
//only allow press effect if right of card art
|
||||
return x > CardRenderer.getCardListItemHeight(compactModeHandler.isCompactMode()) * CardRenderer.CARD_ART_RATIO;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.assets.FSkinImage;
|
||||
import forge.adventure.libgdxgui.card.CardFaceSymbols;
|
||||
import forge.adventure.libgdxgui.card.CardRenderer;
|
||||
import forge.adventure.libgdxgui.deck.FDeckViewer;
|
||||
import forge.adventure.libgdxgui.itemmanager.filters.AdvancedSearchFilter;
|
||||
import forge.adventure.libgdxgui.itemmanager.filters.DeckColorFilter;
|
||||
import forge.adventure.libgdxgui.itemmanager.filters.DeckFormatFilter;
|
||||
import forge.adventure.libgdxgui.itemmanager.filters.TextSearchFilter;
|
||||
import forge.adventure.libgdxgui.toolbox.FList;
|
||||
import forge.adventure.libgdxgui.toolbox.FList.CompactModeHandler;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
import forge.card.ColorSet;
|
||||
import forge.deck.DeckProxy;
|
||||
import forge.deck.io.DeckPreferences;
|
||||
import forge.game.GameType;
|
||||
import forge.game.IHasGameType;
|
||||
import forge.itemmanager.ItemManagerConfig;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* ItemManager for decks
|
||||
*/
|
||||
public final class DeckManager extends ItemManager<DeckProxy> implements IHasGameType {
|
||||
private final GameType gameType;
|
||||
|
||||
/**
|
||||
* Creates deck list for selected decks for quick deleting, editing, and
|
||||
* basic info. "selectable" and "editable" assumed true.
|
||||
*
|
||||
* @param gt
|
||||
*/
|
||||
public DeckManager(final GameType gt) {
|
||||
super(DeckProxy.class, true);
|
||||
gameType = gt;
|
||||
setCaption(Localizer.getInstance().getMessage("lblDecks"));
|
||||
}
|
||||
|
||||
public GameType getGameType() {
|
||||
return gameType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup(ItemManagerConfig config0) {
|
||||
boolean wasStringOnly = (getConfig() == ItemManagerConfig.STRING_ONLY);
|
||||
boolean isStringOnly = (config0 == ItemManagerConfig.STRING_ONLY);
|
||||
|
||||
super.setup(config0, null);
|
||||
|
||||
if (isStringOnly != wasStringOnly) {
|
||||
restoreDefaultFilters();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDefaultFilters() {
|
||||
if (getConfig() == ItemManagerConfig.STRING_ONLY) { return; }
|
||||
|
||||
addFilter(new DeckColorFilter(this));
|
||||
addFilter(new DeckFormatFilter(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TextSearchFilter<DeckProxy> createSearchFilter() {
|
||||
return new TextSearchFilter<>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AdvancedSearchFilter<DeckProxy> createAdvancedSearchFilter() {
|
||||
return new AdvancedSearchFilter<>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean allowSortChange() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final float IMAGE_SIZE = CardRenderer.MANA_SYMBOL_SIZE;
|
||||
|
||||
@Override
|
||||
public ItemRenderer getListItemRenderer(final CompactModeHandler compactModeHandler) {
|
||||
return new ItemRenderer() {
|
||||
@Override
|
||||
public float getItemHeight() {
|
||||
if (DeckManager.this.getConfig().getCols().size() == 1) {
|
||||
//if just string column, use normal list item height
|
||||
return Utils.AVG_FINGER_HEIGHT;
|
||||
}
|
||||
return CardRenderer.getCardListItemHeight(compactModeHandler.isCompactMode()); //use same height for decks as for cards
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(Integer index, Entry<DeckProxy, Integer> value, float x, float y, int count) {
|
||||
float bottomRight = IMAGE_SIZE + 2 * FList.PADDING;
|
||||
if (x <= bottomRight && y <= bottomRight) {
|
||||
DeckPreferences prefs = DeckPreferences.getPrefs(value.getKey());
|
||||
prefs.setStarCount((prefs.getStarCount() + 1) % 2); //TODO: consider supporting more than 1 star
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean longPress(Integer index, Entry<DeckProxy, Integer> value, float x, float y) {
|
||||
FDeckViewer.show(value.getKey().getDeck());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawValue(Graphics g, Entry<DeckProxy, Integer> value, FSkinFont font, FSkinColor foreColor, FSkinColor backColor, boolean pressed, float x, float y, float w, float h) {
|
||||
DeckProxy deck = value.getKey();
|
||||
|
||||
if (DeckManager.this.getConfig().getCols().size() == 1) {
|
||||
//if just string column, just draw deck string value
|
||||
g.drawText(deck.toString(), font, foreColor, x, y, w, h, false, Align.left, true);
|
||||
return;
|
||||
}
|
||||
|
||||
//draw favorite, name, path and color on first line
|
||||
if (Forge.hdbuttons)
|
||||
g.drawImage(DeckPreferences.getPrefs(deck).getStarCount() > 0 ?
|
||||
FSkinImage.HDSTAR_FILLED : FSkinImage.HDSTAR_OUTLINE, x, y, IMAGE_SIZE, IMAGE_SIZE);
|
||||
else
|
||||
g.drawImage(DeckPreferences.getPrefs(deck).getStarCount() > 0 ? FSkinImage.STAR_FILLED : FSkinImage.STAR_OUTLINE, x, y, IMAGE_SIZE, IMAGE_SIZE);
|
||||
|
||||
x += IMAGE_SIZE + FList.PADDING;
|
||||
ColorSet deckColor = deck.getColor();
|
||||
float availableNameWidth = w - CardFaceSymbols.getWidth(deckColor, IMAGE_SIZE) - IMAGE_SIZE - 2 * FList.PADDING;
|
||||
String name = deck.getName();
|
||||
if (!deck.getPath().isEmpty()) { //render path after name if needed
|
||||
name += " (" + deck.getPath().substring(1) + ")";
|
||||
}
|
||||
g.drawText(name, font, foreColor, x, y, availableNameWidth, IMAGE_SIZE, false, Align.left, true);
|
||||
x += availableNameWidth + FList.PADDING;
|
||||
CardFaceSymbols.drawColorSet(g, deckColor, x, y, IMAGE_SIZE);
|
||||
|
||||
if (compactModeHandler.isCompactMode()) {
|
||||
return; //skip second line if compact mode
|
||||
}
|
||||
|
||||
//draw formats, main/side, and set/highest rarity on second line
|
||||
font = FSkinFont.get(12);
|
||||
float lineHeight = font.getLineHeight();
|
||||
|
||||
x = FList.PADDING;
|
||||
y += IMAGE_SIZE + FList.PADDING + CardRenderer.SET_BOX_MARGIN;
|
||||
String set = deck.getEdition().getCode();
|
||||
float setWidth = CardRenderer.getSetWidth(font, set);
|
||||
float availableFormatWidth = w - setWidth + CardRenderer.SET_BOX_MARGIN;
|
||||
|
||||
int mainSize = deck.getMainSize();
|
||||
if (mainSize < 0) {
|
||||
mainSize = 0; //show main as 0 if empty
|
||||
}
|
||||
int sideSize = deck.getSideSize();
|
||||
if (sideSize < 0) {
|
||||
sideSize = 0; //show sideboard as 0 if empty
|
||||
}
|
||||
|
||||
g.drawText(deck.getFormatsString() + " (" + mainSize + " / " + sideSize + ")", font, foreColor, x, y, availableFormatWidth, lineHeight, false, Align.left, true);
|
||||
|
||||
x += availableFormatWidth + CardRenderer.SET_BOX_MARGIN;
|
||||
y -= CardRenderer.SET_BOX_MARGIN;
|
||||
CardRenderer.drawSetLabel(g, font, set, deck.getHighestRarity(), x, y, setWidth, lineHeight + 2 * CardRenderer.SET_BOX_MARGIN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowPressEffect(FList<Entry<DeckProxy, Integer>> list, float x, float y) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,984 +0,0 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.adventure.libgdxgui.itemmanager;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.assets.FSkinImage;
|
||||
import forge.adventure.libgdxgui.card.CardZoom.ActivateHandler;
|
||||
import forge.adventure.libgdxgui.itemmanager.filters.AdvancedSearchFilter;
|
||||
import forge.adventure.libgdxgui.itemmanager.filters.ItemFilter;
|
||||
import forge.adventure.libgdxgui.itemmanager.filters.TextSearchFilter;
|
||||
import forge.adventure.libgdxgui.itemmanager.views.ImageView;
|
||||
import forge.adventure.libgdxgui.itemmanager.views.ItemListView;
|
||||
import forge.adventure.libgdxgui.itemmanager.views.ItemView;
|
||||
import forge.adventure.libgdxgui.menu.FDropDownMenu;
|
||||
import forge.adventure.libgdxgui.menu.FMenuItem;
|
||||
import forge.adventure.libgdxgui.menu.FPopupMenu;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.toolbox.*;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventType;
|
||||
import forge.adventure.libgdxgui.toolbox.FList.CompactModeHandler;
|
||||
import forge.adventure.libgdxgui.util.LayoutHelper;
|
||||
import forge.gui.FThreads;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.itemmanager.*;
|
||||
import forge.util.ItemPool;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
||||
public abstract class ItemManager<T extends InventoryItem> extends FContainer implements IItemManager<T>, ActivateHandler {
|
||||
private ItemPool<T> pool;
|
||||
protected final ItemManagerModel<T> model;
|
||||
private Predicate<? super T> filterPredicate = null;
|
||||
private AdvancedSearchFilter<? extends T> advancedSearchFilter;
|
||||
private final List<ItemFilter<? extends T>> filters = new ArrayList<>();
|
||||
private boolean hideFilters = false;
|
||||
private boolean wantUnique = false;
|
||||
private boolean multiSelectMode = false;
|
||||
private FEventHandler selectionChangedHandler, itemActivateHandler;
|
||||
private ContextMenuBuilder<T> contextMenuBuilder;
|
||||
private ContextMenu contextMenu;
|
||||
private final Class<T> genericType;
|
||||
private ItemManagerConfig config;
|
||||
private Function<Entry<? extends InventoryItem, Integer>, Object> fnNewGet;
|
||||
private boolean viewUpdating, needSecondUpdate;
|
||||
private final List<ItemColumn> sortCols = new ArrayList<>();
|
||||
|
||||
private final TextSearchFilter<? extends T> searchFilter;
|
||||
|
||||
private final FLabel btnSearch = new FLabel.ButtonBuilder()
|
||||
.icon(Forge.hdbuttons ? FSkinImage.HDSEARCH : FSkinImage.SEARCH).iconScaleFactor(0.9f).build();
|
||||
private final FLabel btnView = new FLabel.ButtonBuilder()
|
||||
.iconScaleFactor(0.9f).build(); //icon set later
|
||||
private final FLabel btnAdvancedSearchOptions = new FLabel.Builder()
|
||||
.selectable(true).align(Align.center)
|
||||
.icon(Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS).iconScaleFactor(0.9f)
|
||||
.build();
|
||||
|
||||
private final FComboBox<ItemColumn> cbxSortOptions;
|
||||
|
||||
private final List<ItemView<T>> views = new ArrayList<>();
|
||||
private final ItemListView<T> listView;
|
||||
private final ImageView<T> imageView;
|
||||
private ItemView<T> currentView;
|
||||
private final boolean initialized;
|
||||
protected boolean lockFiltering;
|
||||
|
||||
/**
|
||||
* ItemManager Constructor.
|
||||
*
|
||||
* @param genericType0 the class of item that this table will contain
|
||||
* @param wantUnique0 whether this table should display only one item with the same name
|
||||
*/
|
||||
protected ItemManager(final Class<T> genericType0, final boolean wantUnique0) {
|
||||
genericType = genericType0;
|
||||
wantUnique = wantUnique0;
|
||||
model = new ItemManagerModel<>(genericType0);
|
||||
|
||||
searchFilter = createSearchFilter();
|
||||
|
||||
listView = new ItemListView<T>(this, model);
|
||||
imageView = createImageView(model);
|
||||
|
||||
views.add(listView);
|
||||
views.add(imageView);
|
||||
currentView = listView;
|
||||
btnView.setIcon(currentView.getIcon());
|
||||
|
||||
//build display
|
||||
add(searchFilter.getWidget());
|
||||
add(btnSearch);
|
||||
add(btnView);
|
||||
add(btnAdvancedSearchOptions);
|
||||
btnAdvancedSearchOptions.setSelected(!hideFilters);
|
||||
if (allowSortChange()) {
|
||||
cbxSortOptions = add(new FComboBox<>(Localizer.getInstance().getMessage("lblSort") + ": "));
|
||||
cbxSortOptions.setFont(FSkinFont.get(12));
|
||||
}
|
||||
else {
|
||||
cbxSortOptions = null;
|
||||
}
|
||||
add(currentView.getPnlOptions());
|
||||
add(currentView.getScroller());
|
||||
|
||||
btnSearch.setCommand(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
FPopupMenu menu = new FPopupMenu() {
|
||||
@Override
|
||||
protected void buildMenu() {
|
||||
addItem(new FMenuItem(Localizer.getInstance().getMessage("lblAdvancedSearch"), Forge.hdbuttons ? FSkinImage.HDSEARCH : FSkinImage.SEARCH, new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
if (advancedSearchFilter == null) {
|
||||
advancedSearchFilter = createAdvancedSearchFilter();
|
||||
ItemManager.this.add(advancedSearchFilter.getWidget());
|
||||
}
|
||||
advancedSearchFilter.edit();
|
||||
}
|
||||
}));
|
||||
addItem(new FMenuItem(Localizer.getInstance().getMessage("lblResetFilters"), Forge.hdbuttons ? FSkinImage.HDDELETE : FSkinImage.DELETE, new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
resetFilters();
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
menu.show(btnSearch, 0, btnSearch.getHeight());
|
||||
}
|
||||
});
|
||||
btnView.setCommand(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
FPopupMenu menu = new FPopupMenu() {
|
||||
@Override
|
||||
protected void buildMenu() {
|
||||
for (int i = 0; i < views.size(); i++) {
|
||||
final int index = i;
|
||||
ItemView<T> view = views.get(i);
|
||||
FMenuItem item = new FMenuItem(view.getCaption(), view.getIcon(), new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
setViewIndex(index);
|
||||
}
|
||||
});
|
||||
if (currentView == view) {
|
||||
item.setSelected(true);
|
||||
}
|
||||
addItem(item);
|
||||
}
|
||||
}
|
||||
};
|
||||
menu.show(btnView, 0, btnView.getHeight());
|
||||
}
|
||||
});
|
||||
btnAdvancedSearchOptions.setCommand(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
setHideFilters(!hideFilters);
|
||||
}
|
||||
});
|
||||
|
||||
//setup initial filters
|
||||
addDefaultFilters();
|
||||
|
||||
initialized = true; //must set flag just before applying filters
|
||||
if (!applyFilters()) {
|
||||
if (pool != null) { //ensure view updated even if filter predicate didn't change
|
||||
updateView(true, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected ImageView<T> createImageView(final ItemManagerModel<T> model0) {
|
||||
return new ImageView<T>(this, model0);
|
||||
}
|
||||
|
||||
public ItemManagerConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void setup(ItemManagerConfig config0) {
|
||||
setup(config0, null);
|
||||
}
|
||||
public void setup(ItemManagerConfig config0, Map<ColumnDef, ItemColumn> colOverrides) {
|
||||
config = config0;
|
||||
setWantUnique(config0.getUniqueCardsOnly());
|
||||
|
||||
//ensure sort cols ordered properly
|
||||
final List<ItemColumn> cols = new LinkedList<>();
|
||||
for (ItemColumnConfig colConfig : config.getCols().values()) {
|
||||
if (colOverrides == null || !colOverrides.containsKey(colConfig.getDef())) {
|
||||
cols.add(new ItemColumn(colConfig));
|
||||
}
|
||||
else {
|
||||
cols.add(colOverrides.get(colConfig.getDef()));
|
||||
}
|
||||
}
|
||||
Collections.sort(cols, new Comparator<ItemColumn>() {
|
||||
@Override
|
||||
public int compare(ItemColumn arg0, ItemColumn arg1) {
|
||||
return Integer.compare(arg0.getConfig().getIndex(), arg1.getConfig().getIndex());
|
||||
}
|
||||
});
|
||||
|
||||
sortCols.clear();
|
||||
if (cbxSortOptions != null) {
|
||||
cbxSortOptions.setDropDownItemTap(null);
|
||||
cbxSortOptions.removeAllItems();
|
||||
}
|
||||
|
||||
int modelIndex = 0;
|
||||
for (final ItemColumn col : cols) {
|
||||
col.setIndex(modelIndex++);
|
||||
if (col.isVisible()) { sortCols.add(col); }
|
||||
}
|
||||
|
||||
final ItemColumn[] sortcols = new ItemColumn[sortCols.size()];
|
||||
|
||||
// Assemble priority sort.
|
||||
for (ItemColumn col : sortCols) {
|
||||
if (cbxSortOptions != null) {
|
||||
cbxSortOptions.addItem(col);
|
||||
}
|
||||
if (col.getSortPriority() > 0 && col.getSortPriority() <= sortcols.length) {
|
||||
sortcols[col.getSortPriority() - 1] = col;
|
||||
}
|
||||
}
|
||||
|
||||
if (cbxSortOptions != null) {
|
||||
cbxSortOptions.setText("(" + Localizer.getInstance().getMessage("lblNone") + ")");
|
||||
}
|
||||
|
||||
model.getCascadeManager().reset();
|
||||
|
||||
for (int i = sortcols.length - 1; i >= 0; i--) {
|
||||
ItemColumn col = sortcols[i];
|
||||
if (col != null) {
|
||||
model.getCascadeManager().add(col, true);
|
||||
if (cbxSortOptions != null) {
|
||||
cbxSortOptions.setSelectedItem(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cbxSortOptions != null) {
|
||||
cbxSortOptions.setDropDownItemTap(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
model.getCascadeManager().add((ItemColumn)e.getArgs(), false);
|
||||
model.refreshSort();
|
||||
ItemManagerConfig.save();
|
||||
updateView(true, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (ItemView<T> view : views) {
|
||||
view.setup(config0, colOverrides);
|
||||
}
|
||||
setViewIndex(config0.getViewIndex());
|
||||
setHideFilters(config0.getHideFilters());
|
||||
|
||||
if (colOverrides == null || !colOverrides.containsKey(ColumnDef.NEW)) {
|
||||
fnNewGet = null;
|
||||
}
|
||||
else {
|
||||
fnNewGet = colOverrides.get(ColumnDef.NEW).getFnDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean allowSortChange() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected String getItemSuffix(Entry<T, Integer> item) {
|
||||
if (fnNewGet != null) {
|
||||
String suffix = fnNewGet.apply(item).toString();
|
||||
if (!suffix.isEmpty()) {
|
||||
return " *" + suffix + "*";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract class ItemRenderer {
|
||||
public abstract float getItemHeight();
|
||||
public abstract boolean allowPressEffect(FList<Entry<T, Integer>> list, float x, float y);
|
||||
public abstract boolean tap(Integer index, Entry<T, Integer> value, float x, float y, int count);
|
||||
public abstract boolean longPress(Integer index, Entry<T, Integer> value, float x, float y);
|
||||
public abstract void drawValue(Graphics g, Entry<T, Integer> value, FSkinFont font, FSkinColor foreColor, FSkinColor backColor, boolean pressed, float x, float y, float w, float h);
|
||||
}
|
||||
public abstract ItemRenderer getListItemRenderer(final CompactModeHandler compactModeHandler);
|
||||
|
||||
public void setViewIndex(int viewIndex) {
|
||||
if (viewIndex < 0 || viewIndex >= views.size()) { return; }
|
||||
ItemView<T> view = views.get(viewIndex);
|
||||
if (currentView == view) { return; }
|
||||
|
||||
if (config != null) {
|
||||
config.setViewIndex(viewIndex);
|
||||
}
|
||||
|
||||
final int backupIndexToSelect = currentView.getSelectedIndex();
|
||||
final Iterable<T> itemsToSelect; //only retain selected items if not single selection of first item
|
||||
if (backupIndexToSelect > 0 || currentView.getSelectionCount() > 1) {
|
||||
itemsToSelect = currentView.getSelectedItems();
|
||||
}
|
||||
else {
|
||||
itemsToSelect = null;
|
||||
}
|
||||
|
||||
remove(currentView.getPnlOptions());
|
||||
remove(currentView.getScroller());
|
||||
|
||||
currentView = view;
|
||||
btnView.setIcon(view.getIcon());
|
||||
|
||||
view.refresh(itemsToSelect, backupIndexToSelect, 0);
|
||||
|
||||
add(view.getPnlOptions());
|
||||
add(view.getScroller());
|
||||
revalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doLayout(float width, float height) {
|
||||
LayoutHelper helper = new LayoutHelper(this, ItemFilter.PADDING, ItemFilter.PADDING);
|
||||
float fieldHeight = searchFilter.getMainComponent().getHeight();
|
||||
float viewButtonWidth = fieldHeight;
|
||||
helper.offset(0, ItemFilter.PADDING);
|
||||
helper.fillLine(searchFilter.getWidget(), fieldHeight, (viewButtonWidth + helper.getGapX()) * 3); //leave room for search, view, and options buttons
|
||||
helper.include(btnSearch, viewButtonWidth, fieldHeight);
|
||||
helper.include(btnView, viewButtonWidth, fieldHeight);
|
||||
helper.include(btnAdvancedSearchOptions, viewButtonWidth, fieldHeight);
|
||||
helper.newLine();
|
||||
if (advancedSearchFilter != null && advancedSearchFilter.getWidget().isVisible()) {
|
||||
helper.fillLine(advancedSearchFilter.getWidget(), fieldHeight);
|
||||
}
|
||||
if (!hideFilters) {
|
||||
for (ItemFilter<? extends T> filter : filters) {
|
||||
helper.include(filter.getWidget(), filter.getPreferredWidth(helper.getRemainingLineWidth(), fieldHeight), fieldHeight);
|
||||
}
|
||||
if (allowSortChange()) {
|
||||
helper.fillLine(cbxSortOptions, fieldHeight);
|
||||
}
|
||||
helper.newLine(-ItemFilter.PADDING);
|
||||
if (currentView.getPnlOptions().getChildCount() > 0) {
|
||||
helper.fillLine(currentView.getPnlOptions(), fieldHeight + ItemFilter.PADDING);
|
||||
}
|
||||
else {
|
||||
helper.offset(0, -fieldHeight); //prevent showing whitespace for empty view options panel
|
||||
}
|
||||
}
|
||||
helper.fill(currentView.getScroller());
|
||||
}
|
||||
|
||||
public Class<T> getGenericType() {
|
||||
return genericType;
|
||||
}
|
||||
|
||||
public String getCaption() {
|
||||
return searchFilter.getCaption();
|
||||
}
|
||||
public void setCaption(String caption0) {
|
||||
searchFilter.setCaption(caption0);
|
||||
}
|
||||
|
||||
public ItemPool<T> getPool() {
|
||||
return pool;
|
||||
}
|
||||
public void setPool(final Iterable<T> items) {
|
||||
setPool(ItemPool.createFrom(items, genericType), false);
|
||||
}
|
||||
public void setPool(final ItemPool<T> pool0) {
|
||||
setPool(pool0, false);
|
||||
}
|
||||
public void setPool(final ItemPool<T> pool0, boolean infinite) {
|
||||
pool = pool0;
|
||||
model.clear();
|
||||
model.addItems(pool);
|
||||
model.setInfinite(infinite);
|
||||
updateView(true, null);
|
||||
}
|
||||
|
||||
public ItemView<T> getCurrentView() {
|
||||
return currentView;
|
||||
}
|
||||
|
||||
public int getItemCount() {
|
||||
return currentView.getCount();
|
||||
}
|
||||
|
||||
public int getSelectionCount() {
|
||||
return currentView.getSelectionCount();
|
||||
}
|
||||
|
||||
public T getSelectedItem() {
|
||||
return currentView.getSelectedItem();
|
||||
}
|
||||
|
||||
public Collection<T> getSelectedItems() {
|
||||
return currentView.getSelectedItems();
|
||||
}
|
||||
|
||||
public ItemPool<T> getSelectedItemPool() {
|
||||
ItemPool<T> selectedItemPool = new ItemPool<>(genericType);
|
||||
if (currentView == listView) {
|
||||
for (T item : getSelectedItems()) {
|
||||
selectedItemPool.add(item, getItemCount(item));
|
||||
}
|
||||
}
|
||||
else { //just add all flat for image view
|
||||
selectedItemPool.addAllFlat(getSelectedItems());
|
||||
}
|
||||
return selectedItemPool;
|
||||
}
|
||||
|
||||
public boolean setSelectedItem(T item) {
|
||||
return currentView.setSelectedItem(item);
|
||||
}
|
||||
|
||||
public boolean setSelectedItems(Iterable<T> items) {
|
||||
return currentView.setSelectedItems(items);
|
||||
}
|
||||
|
||||
public T stringToItem(String str) {
|
||||
for (Entry<T, Integer> itemEntry : pool) {
|
||||
if (itemEntry.getKey().toString().equals(str)) {
|
||||
return itemEntry.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean setSelectedString(String str) {
|
||||
T item = stringToItem(str);
|
||||
if (item != null) {
|
||||
return setSelectedItem(item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean setSelectedStrings(Iterable<String> strings) {
|
||||
List<T> items = new ArrayList<>();
|
||||
for (String str : strings) {
|
||||
T item = stringToItem(str);
|
||||
if (item != null) {
|
||||
items.add(item);
|
||||
}
|
||||
}
|
||||
return setSelectedItems(items);
|
||||
}
|
||||
|
||||
public boolean selectItemEntrys(Iterable<Entry<T, Integer>> itemEntrys) {
|
||||
List<T> items = new ArrayList<>();
|
||||
for (Entry<T, Integer> itemEntry : itemEntrys) {
|
||||
items.add(itemEntry.getKey());
|
||||
}
|
||||
return setSelectedItems(items);
|
||||
}
|
||||
|
||||
public void selectAll() {
|
||||
currentView.selectAll();
|
||||
}
|
||||
|
||||
public int getSelectedIndex() {
|
||||
return currentView.getSelectedIndex();
|
||||
}
|
||||
|
||||
public Iterable<Integer> getSelectedIndices() {
|
||||
return currentView.getSelectedIndices();
|
||||
}
|
||||
|
||||
public void setSelectedIndex(int index) {
|
||||
currentView.setSelectedIndex(index);
|
||||
}
|
||||
|
||||
public void setSelectedIndices(Integer[] indices) {
|
||||
currentView.setSelectedIndices(Arrays.asList(indices));
|
||||
}
|
||||
public void setSelectedIndices(Iterable<Integer> indices) {
|
||||
currentView.setSelectedIndices(indices);
|
||||
}
|
||||
|
||||
public void addItem(final T item, int qty) {
|
||||
pool.add(item, qty);
|
||||
if (isUnfiltered()) {
|
||||
model.addItem(item, qty);
|
||||
}
|
||||
List<T> items = new ArrayList<>();
|
||||
items.add(item);
|
||||
updateView(false, items);
|
||||
}
|
||||
|
||||
public void addItems(Iterable<Entry<T, Integer>> itemsToAdd) {
|
||||
pool.addAll(itemsToAdd);
|
||||
if (isUnfiltered()) {
|
||||
model.addItems(itemsToAdd);
|
||||
}
|
||||
|
||||
List<T> items = new ArrayList<>();
|
||||
for (Entry<T, Integer> item : itemsToAdd) {
|
||||
items.add(item.getKey());
|
||||
}
|
||||
updateView(false, items);
|
||||
}
|
||||
|
||||
public void addItemsFlat(Iterable<T> itemsToAdd) {
|
||||
pool.addAllFlat(itemsToAdd);
|
||||
if (isUnfiltered()) {
|
||||
for (T item : itemsToAdd) {
|
||||
model.addItem(item, 1);
|
||||
}
|
||||
}
|
||||
updateView(false, itemsToAdd);
|
||||
}
|
||||
|
||||
public void setItems(Iterable<Entry<T, Integer>> items) {
|
||||
pool.clear();
|
||||
model.clear();
|
||||
addItems(items);
|
||||
}
|
||||
|
||||
public void removeItem(final T item, int qty) {
|
||||
final Iterable<T> itemsToSelect = currentView == listView ? getSelectedItems() : null;
|
||||
|
||||
pool.remove(item, qty);
|
||||
if (isUnfiltered()) {
|
||||
model.removeItem(item, qty);
|
||||
}
|
||||
updateView(false, itemsToSelect);
|
||||
}
|
||||
|
||||
public void removeItems(Iterable<Entry<T, Integer>> itemsToRemove) {
|
||||
final Iterable<T> itemsToSelect = currentView == listView ? getSelectedItems() : null;
|
||||
|
||||
for (Entry<T, Integer> item : itemsToRemove) {
|
||||
pool.remove(item.getKey(), item.getValue());
|
||||
if (isUnfiltered()) {
|
||||
model.removeItem(item.getKey(), item.getValue());
|
||||
}
|
||||
}
|
||||
updateView(false, itemsToSelect);
|
||||
}
|
||||
|
||||
public void removeItemsFlat(Iterable<T> itemsToRemove) {
|
||||
final Iterable<T> itemsToSelect = currentView == listView ? getSelectedItems() : null;
|
||||
|
||||
pool.removeAllFlat(itemsToRemove);
|
||||
if (isUnfiltered()) {
|
||||
for (T item : itemsToRemove) {
|
||||
model.removeItem(item, 1);
|
||||
}
|
||||
}
|
||||
updateView(false, itemsToSelect);
|
||||
}
|
||||
|
||||
public void removeAllItems() {
|
||||
pool.clear();
|
||||
model.clear();
|
||||
updateView(false, null);
|
||||
}
|
||||
|
||||
public void replaceAll(final T item, final T replacement) {
|
||||
int count = pool.count(item);
|
||||
if (count == 0) { return; }
|
||||
|
||||
final Iterable<T> itemsToSelect = currentView == listView ? getSelectedItems() : null;
|
||||
|
||||
pool.removeAll(item);
|
||||
pool.add(replacement, count);
|
||||
if (isUnfiltered()) {
|
||||
model.replaceAll(item, replacement);
|
||||
}
|
||||
updateView(false, itemsToSelect);
|
||||
}
|
||||
|
||||
public void scrollSelectionIntoView() {
|
||||
currentView.scrollSelectionIntoView();
|
||||
}
|
||||
|
||||
public int getItemCount(final T item) {
|
||||
return model.isInfinite() ? Integer.MAX_VALUE : pool.count(item);
|
||||
}
|
||||
|
||||
public ItemPool<T> getFilteredItems() {
|
||||
return model.getItems();
|
||||
}
|
||||
|
||||
protected abstract void addDefaultFilters();
|
||||
protected abstract TextSearchFilter<? extends T> createSearchFilter();
|
||||
protected abstract AdvancedSearchFilter<? extends T> createAdvancedSearchFilter();
|
||||
|
||||
public void addFilter(final ItemFilter<? extends T> filter) {
|
||||
filters.add(filter);
|
||||
add(filter.getWidget());
|
||||
|
||||
boolean visible = !hideFilters;
|
||||
filter.getWidget().setVisible(visible);
|
||||
if (visible && initialized) {
|
||||
revalidate();
|
||||
applyNewOrModifiedFilter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
//apply filters and focus existing filter's main component if filtering not locked
|
||||
public void applyNewOrModifiedFilter(final ItemFilter<? extends T> filter) {
|
||||
if (lockFiltering) { return; }
|
||||
|
||||
if (filter == advancedSearchFilter) {
|
||||
//handle update the visibility of the advanced search filter
|
||||
boolean empty = filter.isEmpty();
|
||||
ItemFilter<? extends T>.Widget widget = filter.getWidget();
|
||||
if (widget.isVisible() == empty) {
|
||||
widget.setVisible(!empty);
|
||||
revalidate();
|
||||
}
|
||||
}
|
||||
|
||||
applyFilters();
|
||||
}
|
||||
|
||||
public void restoreDefaultFilters() {
|
||||
lockFiltering = true;
|
||||
for (ItemFilter<? extends T> filter : filters) {
|
||||
remove(filter.getWidget());
|
||||
}
|
||||
filters.clear();
|
||||
addDefaultFilters();
|
||||
lockFiltering = false;
|
||||
revalidate();
|
||||
applyFilters();
|
||||
}
|
||||
|
||||
public void resetFilters() {
|
||||
lockFiltering = true; //prevent updating filtering from this change until all filters reset
|
||||
for (final ItemFilter<? extends T> filter : filters) {
|
||||
filter.reset();
|
||||
}
|
||||
searchFilter.reset();
|
||||
if (advancedSearchFilter != null) {
|
||||
advancedSearchFilter.reset();
|
||||
ItemFilter<? extends T>.Widget widget = advancedSearchFilter.getWidget();
|
||||
if (widget.isVisible()) {
|
||||
widget.setVisible(false);
|
||||
revalidate();
|
||||
}
|
||||
}
|
||||
lockFiltering = false;
|
||||
|
||||
applyFilters();
|
||||
}
|
||||
|
||||
public void removeFilter(ItemFilter<? extends T> filter) {
|
||||
filters.remove(filter);
|
||||
remove(filter.getWidget());
|
||||
revalidate();
|
||||
applyFilters();
|
||||
}
|
||||
|
||||
public boolean applyFilters() {
|
||||
if (lockFiltering || !initialized) { return false; }
|
||||
|
||||
List<Predicate<? super T>> predicates = new ArrayList<>();
|
||||
for (ItemFilter<? extends T> filter : filters) {
|
||||
if (!filter.isEmpty()) {
|
||||
predicates.add(filter.buildPredicate(genericType));
|
||||
}
|
||||
}
|
||||
if (!searchFilter.isEmpty()) {
|
||||
predicates.add(searchFilter.buildPredicate(genericType));
|
||||
}
|
||||
if (advancedSearchFilter != null && !advancedSearchFilter.isEmpty()) {
|
||||
predicates.add(advancedSearchFilter.buildPredicate(genericType));
|
||||
}
|
||||
|
||||
Predicate<? super T> newFilterPredicate = predicates.size() == 0 ? null : Predicates.and(predicates);
|
||||
if (filterPredicate == newFilterPredicate) { return false; }
|
||||
|
||||
filterPredicate = newFilterPredicate;
|
||||
if (pool != null) {
|
||||
if (viewUpdating) {
|
||||
needSecondUpdate = true;
|
||||
}
|
||||
else {
|
||||
viewUpdating = true;
|
||||
FThreads.invokeInBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
do {
|
||||
needSecondUpdate = false;
|
||||
updateView(true, null);
|
||||
Gdx.graphics.requestRendering();
|
||||
} while (needSecondUpdate);
|
||||
viewUpdating = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isUnfiltered() {
|
||||
return filterPredicate == null;
|
||||
}
|
||||
|
||||
public boolean getHideFilters() {
|
||||
return hideFilters;
|
||||
}
|
||||
|
||||
public void setHideFilters(boolean hideFilters0) {
|
||||
if (hideFilters == hideFilters0) { return; }
|
||||
hideFilters = hideFilters0;
|
||||
|
||||
boolean visible = !hideFilters0;
|
||||
for (ItemFilter<? extends T> filter : filters) {
|
||||
filter.getWidget().setVisible(visible);
|
||||
}
|
||||
if (allowSortChange()) {
|
||||
cbxSortOptions.setVisible(visible);
|
||||
}
|
||||
for (ItemView<T> view : views) {
|
||||
view.getPnlOptions().setVisible(visible);
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
btnAdvancedSearchOptions.setSelected(visible);
|
||||
|
||||
revalidate();
|
||||
|
||||
if (config != null) {
|
||||
config.setHideFilters(hideFilters0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Refresh displayed items
|
||||
public void refresh() {
|
||||
updateView(true, getSelectedItems());
|
||||
}
|
||||
|
||||
public void updateView(final boolean forceFilter, final Iterable<T> itemsToSelect) {
|
||||
final boolean useFilter = (forceFilter && (filterPredicate != null)) || !isUnfiltered();
|
||||
|
||||
if (useFilter || forceFilter) {
|
||||
model.clear();
|
||||
|
||||
Iterable<Entry<T, Integer>> items = pool;
|
||||
if (useFilter) {
|
||||
Predicate<Entry<T, Integer>> pred = Predicates.compose(filterPredicate, pool.FN_GET_KEY);
|
||||
items = Iterables.filter(pool, pred);
|
||||
}
|
||||
model.addItems(items);
|
||||
}
|
||||
|
||||
currentView.refresh(itemsToSelect, getSelectedIndex(), forceFilter ? 0 : currentView.getScrollValue());
|
||||
|
||||
//update ratio of # in filtered pool / # in total pool
|
||||
ItemPool<T> filteredItems = getFilteredItems();
|
||||
int filteredCount = filteredItems.countAll();
|
||||
int totalCount = useFilter ? pool.countAll() : filteredCount;
|
||||
|
||||
searchFilter.setRatio("(" + filteredCount + " / " + totalCount + ")");
|
||||
}
|
||||
|
||||
public boolean isIncrementalSearchActive() {
|
||||
return currentView.isIncrementalSearchActive();
|
||||
}
|
||||
|
||||
public boolean getWantUnique() {
|
||||
return wantUnique;
|
||||
}
|
||||
|
||||
public void setWantUnique(boolean unique) {
|
||||
wantUnique = unique;
|
||||
}
|
||||
|
||||
public void setSelectionSupport(int minSelections0, int maxSelections0) {
|
||||
for (ItemView<T> view : views) {
|
||||
view.setSelectionSupport(minSelections0, maxSelections0);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getMultiSelectMode() {
|
||||
return multiSelectMode;
|
||||
}
|
||||
public void toggleMultiSelectMode(int indexToSelect) {
|
||||
multiSelectMode = !multiSelectMode;
|
||||
if (multiSelectMode) {
|
||||
setSelectionSupport(0, Integer.MAX_VALUE);
|
||||
}
|
||||
else {
|
||||
setSelectionSupport(0, 1);
|
||||
}
|
||||
if (isContextMenuOpen()) {
|
||||
contextMenu.hide(); //ensure context menu hidden
|
||||
}
|
||||
if (indexToSelect != -1) {
|
||||
setSelectedIndex(indexToSelect);
|
||||
}
|
||||
}
|
||||
|
||||
//whether item manager's pool of items is in infinite supply
|
||||
public boolean isInfinite() {
|
||||
return model.isInfinite();
|
||||
}
|
||||
|
||||
public void focusSearch() {
|
||||
setHideFilters(false); //ensure filters shown
|
||||
}
|
||||
|
||||
public FEventHandler getSelectionChangedHandler() {
|
||||
return selectionChangedHandler;
|
||||
}
|
||||
public void setSelectionChangedHandler(FEventHandler selectionChangedHandler0) {
|
||||
selectionChangedHandler = selectionChangedHandler0;
|
||||
}
|
||||
|
||||
public void setItemActivateHandler(FEventHandler itemActivateHandler0) {
|
||||
itemActivateHandler = itemActivateHandler0;
|
||||
}
|
||||
|
||||
public void activateSelectedItems() {
|
||||
if (itemActivateHandler != null) {
|
||||
itemActivateHandler.handleEvent(new FEvent(this, FEventType.ACTIVATE));
|
||||
}
|
||||
}
|
||||
|
||||
public void setContextMenuBuilder(ContextMenuBuilder<T> contextMenuBuilder0) {
|
||||
contextMenuBuilder = contextMenuBuilder0;
|
||||
}
|
||||
|
||||
public void showMenu(boolean delay) {
|
||||
if (contextMenuBuilder != null && getSelectionCount() > 0) {
|
||||
if (contextMenu == null) {
|
||||
contextMenu = new ContextMenu();
|
||||
}
|
||||
if (delay) { //delay showing menu to prevent it hiding right away
|
||||
FThreads.delayInEDT(50, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
contextMenu.show();
|
||||
Gdx.graphics.requestRendering();
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
contextMenu.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isContextMenuOpen() {
|
||||
return contextMenu != null && contextMenu.isVisible();
|
||||
}
|
||||
|
||||
public static abstract class ContextMenuBuilder<T> {
|
||||
public abstract void buildMenu(final FDropDownMenu menu, final T item);
|
||||
}
|
||||
|
||||
private class ContextMenu extends FDropDownMenu {
|
||||
@Override
|
||||
protected void buildMenu() {
|
||||
contextMenuBuilder.buildMenu(this, getSelectedItem());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hideBackdropOnPress(float x, float y) {
|
||||
Rectangle bounds = currentView.getSelectionBounds();
|
||||
return bounds != null && !bounds.contains(x, y); //don't hide on press if within selection bounds
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean preventOwnerHandlingBackupTap(float x, float y, int count) {
|
||||
//prevent view handling single tap, but allow it to handle double tap
|
||||
return count == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateSizeAndPosition() {
|
||||
FScreen screen = Forge.getCurrentScreen();
|
||||
float screenWidth = screen.getWidth();
|
||||
float screenHeight = screen.getHeight();
|
||||
|
||||
paneSize = updateAndGetPaneSize(screenWidth, screenHeight);
|
||||
float w = paneSize.getWidth();
|
||||
float h = paneSize.getHeight();
|
||||
|
||||
Rectangle bounds = currentView.getSelectionBounds();
|
||||
|
||||
//try displaying right of selection if possible
|
||||
float x = bounds.x + bounds.width;
|
||||
float y = bounds.y;
|
||||
if (x + w > screenWidth) {
|
||||
//try displaying left of selection if possible
|
||||
x = bounds.x - w;
|
||||
if (x < 0) {
|
||||
//display below selection if no room left or right of selection
|
||||
x = bounds.x;
|
||||
if (w < bounds.width) {
|
||||
//center below item if needed
|
||||
x += (bounds.width - w) / 2;
|
||||
}
|
||||
if (x + w > screenWidth) {
|
||||
x = screenWidth - w;
|
||||
}
|
||||
y += bounds.height;
|
||||
}
|
||||
}
|
||||
if (y + h > screenHeight) {
|
||||
if (y == bounds.y) {
|
||||
//if displaying to left or right, move up if not enough room
|
||||
y = screenHeight - h;
|
||||
}
|
||||
else {
|
||||
//if displaying below selection and not enough room, display above selection
|
||||
y -= bounds.height + h;
|
||||
}
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
if (h > bounds.y) {
|
||||
h = bounds.y; //cut off menu if not enough room above or below selection
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setBounds(Math.round(x), Math.round(y), Math.round(w), Math.round(h));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivateAction(int index) {
|
||||
if (contextMenuBuilder != null) {
|
||||
return Localizer.getInstance().getMessage("lblSelectCard");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate(int index) {
|
||||
setSelectedIndex(index);
|
||||
showMenu(true);
|
||||
}
|
||||
|
||||
public float getPileByWidth() {
|
||||
if (cbxSortOptions != null) {
|
||||
return cbxSortOptions.getWidth();
|
||||
}
|
||||
if(filters.isEmpty()){
|
||||
return 0f;
|
||||
}
|
||||
return filters.get(filters.size() - 1).getWidget().getWidth();
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.google.common.base.Function;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.assets.FSkinImage;
|
||||
import forge.adventure.libgdxgui.assets.ImageCache;
|
||||
import forge.adventure.libgdxgui.card.CardRenderer;
|
||||
import forge.gamemodes.quest.QuestSpellShop;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.itemmanager.filters.AdvancedSearchFilter;
|
||||
import forge.adventure.libgdxgui.itemmanager.filters.TextSearchFilter;
|
||||
import forge.adventure.libgdxgui.toolbox.FList;
|
||||
import forge.adventure.libgdxgui.toolbox.FList.CompactModeHandler;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
||||
public class SpellShopManager extends ItemManager<InventoryItem> {
|
||||
private final Function<Entry<? extends InventoryItem, Integer>, Object> fnGetPrice;
|
||||
|
||||
public SpellShopManager(boolean isShop0) {
|
||||
super(InventoryItem.class, false);
|
||||
|
||||
fnGetPrice = isShop0 ? QuestSpellShop.fnPriceGet : QuestSpellShop.fnPriceSellGet;
|
||||
if (!isShop0) {
|
||||
setCaption(Localizer.getInstance().getMessage("lblCards"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDefaultFilters() {
|
||||
CardManager.addDefaultFilters(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TextSearchFilter<? extends InventoryItem> createSearchFilter() {
|
||||
return CardManager.createSearchFilter(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AdvancedSearchFilter<? extends InventoryItem> createAdvancedSearchFilter() {
|
||||
return CardManager.createAdvancedSearchFilter(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemRenderer getListItemRenderer(final CompactModeHandler compactModeHandler) {
|
||||
return new ItemRenderer() {
|
||||
@Override
|
||||
public float getItemHeight() {
|
||||
return CardRenderer.getCardListItemHeight(compactModeHandler.isCompactMode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawValue(Graphics g, Entry<InventoryItem, Integer> value, FSkinFont font, FSkinColor foreColor, FSkinColor backColor, boolean pressed, float x, float y, float w, float h) {
|
||||
if (value.getValue() == null) { return; } //prevent crash after item removed on different thread
|
||||
|
||||
float totalHeight = h + 2 * FList.PADDING;
|
||||
float cardArtWidth = totalHeight * CardRenderer.CARD_ART_RATIO;
|
||||
|
||||
if (value.getKey() instanceof PaperCard) {
|
||||
CardRenderer.drawCardListItem(g, font, foreColor, (PaperCard)value.getKey(), value.getValue(), getItemSuffix(value), x, y, w, h, compactModeHandler.isCompactMode());
|
||||
}
|
||||
else {
|
||||
g.drawText(value.getValue() + " " + value.getKey().toString(), font, foreColor, x + cardArtWidth, y, w - cardArtWidth, h, false, Align.left, true);
|
||||
Texture image = ImageCache.getImage(value.getKey());
|
||||
if (image != null) {
|
||||
float imageRatio = (float)image.getWidth() / (float)image.getHeight();
|
||||
float imageHeight = totalHeight;
|
||||
float imageWidth = imageHeight * imageRatio;
|
||||
if (imageWidth > cardArtWidth) {
|
||||
imageWidth = cardArtWidth;
|
||||
imageHeight = imageWidth / imageRatio;
|
||||
}
|
||||
g.drawImage(image, x - FList.PADDING + (cardArtWidth - imageWidth) / 2, y - FList.PADDING + (totalHeight - imageHeight) / 2, imageWidth, imageHeight);
|
||||
}
|
||||
}
|
||||
|
||||
//render price on top of card art
|
||||
float priceHeight = font.getLineHeight();
|
||||
y += totalHeight - priceHeight - FList.PADDING;
|
||||
g.fillRect(backColor, x - FList.PADDING, y, cardArtWidth, priceHeight);
|
||||
g.drawImage(FSkinImage.QUEST_COINSTACK, x, y, priceHeight, priceHeight);
|
||||
float offset = priceHeight * 1.1f;
|
||||
g.drawText(fnGetPrice.apply(value).toString(), font, foreColor, x + offset, y, cardArtWidth - offset - 2 * FList.PADDING, priceHeight, false, Align.left, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(Integer index, Entry<InventoryItem, Integer> value, float x, float y, int count) {
|
||||
if (value.getKey() instanceof PaperCard) {
|
||||
return CardRenderer.cardListItemTap(model.getOrderedList(), index, SpellShopManager.this, x, y, count, compactModeHandler.isCompactMode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean longPress(Integer index, Entry<InventoryItem, Integer> value, float x, float y) {
|
||||
if (value.getKey() instanceof PaperCard && CardRenderer.cardListItemTap(model.getOrderedList(), index, SpellShopManager.this, x, y, 1, compactModeHandler.isCompactMode())) {
|
||||
return true; //avoid calling toggleMultiSelectMode if user long presses on card art
|
||||
}
|
||||
toggleMultiSelectMode(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowPressEffect(FList<Entry<InventoryItem, Integer>> list, float x, float y) {
|
||||
Entry<InventoryItem, Integer> value = list.getItemAtPoint(x, y);
|
||||
if (value != null && value.getKey() instanceof PaperCard) {
|
||||
//only allow press effect for cards if right of card art
|
||||
return x > CardRenderer.getCardListItemHeight(compactModeHandler.isCompactMode()) * CardRenderer.CARD_ART_RATIO;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,328 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.assets.FSkinImage;
|
||||
import forge.adventure.libgdxgui.assets.TextRenderer;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.adventure.libgdxgui.menu.FMenuItem;
|
||||
import forge.adventure.libgdxgui.menu.FPopupMenu;
|
||||
import forge.adventure.libgdxgui.menu.FTooltip;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.toolbox.*;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
import forge.gui.interfaces.IButton;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.itemmanager.AdvancedSearch;
|
||||
import forge.itemmanager.AdvancedSearch.IFilterControl;
|
||||
import forge.util.Callback;
|
||||
import forge.util.Localizer;
|
||||
|
||||
|
||||
public class AdvancedSearchFilter<T extends InventoryItem> extends ItemFilter<T> {
|
||||
private final AdvancedSearch.Model<T> model;
|
||||
|
||||
private FiltersLabel label;
|
||||
private EditScreen editScreen;
|
||||
|
||||
public AdvancedSearchFilter(ItemManager<? super T> itemManager0) {
|
||||
super(itemManager0);
|
||||
model = new AdvancedSearch.Model<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter<T> createCopy() {
|
||||
AdvancedSearchFilter<T> copy = new AdvancedSearchFilter<>(itemManager);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final Predicate<T> buildPredicate() {
|
||||
return model.getPredicate();
|
||||
}
|
||||
|
||||
public Predicate<? super T> getPredicate() {
|
||||
return model.getPredicate();
|
||||
}
|
||||
|
||||
public void edit() {
|
||||
if (editScreen == null) {
|
||||
editScreen = new EditScreen();
|
||||
}
|
||||
Forge.openScreen(editScreen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return model.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
model.reset();
|
||||
editScreen = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildWidget(Widget widget) {
|
||||
label = new FiltersLabel();
|
||||
model.setLabel(label);
|
||||
widget.add(label);
|
||||
widget.setVisible(!isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWidgetLayout(float width, float height) {
|
||||
label.setSize(width, height);
|
||||
}
|
||||
|
||||
private final Runnable onFilterChange = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//update expression when edit screen closed or a single filter is changed
|
||||
model.updateExpression();
|
||||
itemManager.applyNewOrModifiedFilter(AdvancedSearchFilter.this);
|
||||
}
|
||||
};
|
||||
|
||||
private class FiltersLabel extends FLabel {
|
||||
private String toolTipText;
|
||||
|
||||
private FiltersLabel() {
|
||||
super(new FLabel.Builder().align(Align.left).parseSymbols(true).font(ListLabelFilter.LABEL_FONT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolTipText() {
|
||||
return toolTipText;
|
||||
}
|
||||
@Override
|
||||
public void setToolTipText(String s0) {
|
||||
toolTipText = s0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
if (count == 1) {
|
||||
FPopupMenu menu = new FPopupMenu() {
|
||||
@Override
|
||||
protected void buildMenu() {
|
||||
//add a menu item for each filter to allow easily editing just that filter
|
||||
for (final IFilterControl<T> control : model.getControls()) {
|
||||
FMenuItem item = new FMenuItem(control.getFilter().toString(), Forge.hdbuttons ? FSkinImage.HDEDIT : FSkinImage.EDIT, new FEvent.FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
model.editFilterControl(control, onFilterChange);
|
||||
}
|
||||
});
|
||||
item.setTextRenderer(new TextRenderer()); //ensure symbols are displayed
|
||||
addItem(item);
|
||||
}
|
||||
addItem(new FMenuItem(Localizer.getInstance().getMessage("lblEditExpression"), Forge.hdbuttons ? FSkinImage.HDEDIT : FSkinImage.EDIT, new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
edit();
|
||||
}
|
||||
}));
|
||||
addItem(new FMenuItem(Localizer.getInstance().getMessage("lblRemoveFilter"), Forge.hdbuttons ? FSkinImage.HDDELETE : FSkinImage.DELETE, new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
reset();
|
||||
itemManager.applyNewOrModifiedFilter(AdvancedSearchFilter.this);
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
menu.show(this, x, y);
|
||||
}
|
||||
else if (count == 2) {
|
||||
edit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean longPress(float x, float y) {
|
||||
FTooltip tooltip = new FTooltip(toolTipText);
|
||||
tooltip.show(this, x, getHeight());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class EditScreen extends FScreen {
|
||||
private final FScrollPane scroller = add(new FScrollPane() {
|
||||
@Override
|
||||
protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) {
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float w = visibleWidth;
|
||||
float h = (FTextField.getDefaultHeight() + FList.PADDING) * 3;
|
||||
|
||||
for (FDisplayObject child : getChildren()) {
|
||||
child.setBounds(x, y, w, h);
|
||||
y += h;
|
||||
}
|
||||
|
||||
return new ScrollBounds(visibleWidth, y);
|
||||
}
|
||||
});
|
||||
|
||||
private EditScreen() {
|
||||
super(Localizer.getInstance().getMessage("lblAdvancedSearch"));
|
||||
Filter filter = new Filter();
|
||||
model.addFilterControl(filter);
|
||||
scroller.add(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivate() {
|
||||
super.onActivate();
|
||||
|
||||
//automatically edit first filter if search is empty
|
||||
if (model.isEmpty()) {
|
||||
model.editFilterControl(Iterables.getFirst(model.getControls(), null), onFilterChange);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Callback<Boolean> canCloseCallback) {
|
||||
onFilterChange.run();
|
||||
super.onClose(canCloseCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float startY, float width, float height) {
|
||||
scroller.setBounds(0, startY, width, height - startY);
|
||||
}
|
||||
|
||||
private void addNewFilter(Filter fromFilter) {
|
||||
if (scroller.getChildAt(scroller.getChildCount() - 1) == fromFilter) {
|
||||
Filter filter = new Filter();
|
||||
model.addFilterControl(filter);
|
||||
scroller.add(filter);
|
||||
scroller.revalidate();
|
||||
scroller.scrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void removeNextFilter(Filter fromFilter) {
|
||||
int index = scroller.indexOf(fromFilter);
|
||||
if (index < scroller.getChildCount() - 1) {
|
||||
Filter nextFilter = (Filter)scroller.getChildAt(index + 1);
|
||||
model.removeFilterControl(nextFilter);
|
||||
scroller.remove(nextFilter);
|
||||
scroller.revalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private class Filter extends FContainer implements IFilterControl<T> {
|
||||
private final FLabel btnNotBeforeParen, btnOpenParen, btnNotAfterParen;
|
||||
private final FLabel btnFilter;
|
||||
private final FLabel btnCloseParen, btnAnd, btnOr;
|
||||
private AdvancedSearch.Filter<T> filter;
|
||||
|
||||
private Filter() {
|
||||
btnNotBeforeParen = add(new FLabel.Builder().align(Align.center).text("NOT").selectable().build());
|
||||
btnOpenParen = add(new FLabel.Builder().align(Align.center).text("(").selectable().build());
|
||||
btnNotAfterParen = add(new FLabel.Builder().align(Align.center).text("NOT").selectable().build());
|
||||
btnFilter = add(new FLabel.ButtonBuilder().parseSymbols(true).build());
|
||||
btnCloseParen = add(new FLabel.Builder().align(Align.center).selectable().text(")").build());
|
||||
btnAnd = add(new FLabel.Builder().align(Align.center).text("AND").selectable().command(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
if (btnAnd.isSelected()) {
|
||||
btnOr.setSelected(false);
|
||||
addNewFilter(Filter.this);
|
||||
}
|
||||
else {
|
||||
removeNextFilter(Filter.this);
|
||||
}
|
||||
}
|
||||
}).build());
|
||||
btnOr = add(new FLabel.Builder().align(Align.center).text("OR").selectable().command(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
if (btnOr.isSelected()) {
|
||||
btnAnd.setSelected(false);
|
||||
addNewFilter(Filter.this);
|
||||
}
|
||||
else {
|
||||
removeNextFilter(Filter.this);
|
||||
}
|
||||
}
|
||||
}).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
float padding = FList.PADDING;
|
||||
float buttonWidth = (width - padding * 4) / 3;
|
||||
float buttonHeight = (height - padding * 3) / 3;
|
||||
|
||||
float x = padding;
|
||||
float y = padding;
|
||||
float dx = buttonWidth + padding;
|
||||
float dy = buttonHeight + padding;
|
||||
|
||||
btnNotBeforeParen.setBounds(x, y, buttonWidth, buttonHeight);
|
||||
x += dx;
|
||||
btnOpenParen.setBounds(x, y, buttonWidth, buttonHeight);
|
||||
x += dx;
|
||||
btnNotAfterParen.setBounds(x, y, buttonWidth, buttonHeight);
|
||||
x = padding;
|
||||
y += dy;
|
||||
btnFilter.setBounds(x, y, width - 2 * padding, buttonHeight);
|
||||
y += dy;
|
||||
btnCloseParen.setBounds(x, y, buttonWidth, buttonHeight);
|
||||
x += dx;
|
||||
btnAnd.setBounds(x, y, buttonWidth, buttonHeight);
|
||||
x += dx;
|
||||
btnOr.setBounds(x, y, buttonWidth, buttonHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IButton getBtnNotBeforeParen() {
|
||||
return btnNotBeforeParen;
|
||||
}
|
||||
@Override
|
||||
public IButton getBtnOpenParen() {
|
||||
return btnOpenParen;
|
||||
}
|
||||
@Override
|
||||
public IButton getBtnNotAfterParen() {
|
||||
return btnNotAfterParen;
|
||||
}
|
||||
@Override
|
||||
public IButton getBtnFilter() {
|
||||
return btnFilter;
|
||||
}
|
||||
@Override
|
||||
public IButton getBtnCloseParen() {
|
||||
return btnCloseParen;
|
||||
}
|
||||
@Override
|
||||
public IButton getBtnAnd() {
|
||||
return btnAnd;
|
||||
}
|
||||
@Override
|
||||
public IButton getBtnOr() {
|
||||
return btnOr;
|
||||
}
|
||||
@Override
|
||||
public AdvancedSearch.Filter<T> getFilter() {
|
||||
return filter;
|
||||
}
|
||||
@Override
|
||||
public void setFilter(AdvancedSearch.Filter<T> filter0) {
|
||||
filter = filter0;
|
||||
}
|
||||
@Override
|
||||
public Class<? super T> getGenericType() {
|
||||
return itemManager.getGenericType();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.CardRulesPredicates;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
|
||||
|
||||
public class CardCMCFilter extends ValueRangeFilter<PaperCard> {
|
||||
public CardCMCFilter(ItemManager<? super PaperCard> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter<PaperCard> createCopy() {
|
||||
return new CardCMCFilter(itemManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCaption() {
|
||||
return "Mana Value";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Predicate<PaperCard> buildPredicate() {
|
||||
Predicate<CardRules> predicate = getCardRulesFieldPredicate(CardRulesPredicates.LeafNumber.CardField.CMC);
|
||||
if (predicate == null) {
|
||||
return Predicates.alwaysTrue();
|
||||
}
|
||||
return Predicates.compose(predicate, PaperCard.FN_GET_RULES);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.itemmanager.SFilterUtil;
|
||||
import forge.itemmanager.SItemManagerUtil.StatTypes;
|
||||
|
||||
|
||||
public class CardColorFilter extends StatTypeFilter<PaperCard> {
|
||||
public CardColorFilter(ItemManager<? super PaperCard> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter<PaperCard> createCopy() {
|
||||
return new CardColorFilter(itemManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildWidget(Widget widget) {
|
||||
addToggleButton(widget, StatTypes.WHITE);
|
||||
addToggleButton(widget, StatTypes.BLUE);
|
||||
addToggleButton(widget, StatTypes.BLACK);
|
||||
addToggleButton(widget, StatTypes.RED);
|
||||
addToggleButton(widget, StatTypes.GREEN);
|
||||
addToggleButton(widget, StatTypes.COLORLESS);
|
||||
addToggleButton(widget, StatTypes.MULTICOLOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final Predicate<PaperCard> buildPredicate() {
|
||||
return SFilterUtil.buildColorFilter(buttonMap);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.CardRulesPredicates;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
|
||||
|
||||
public class CardColorlessCostFilter extends ValueRangeFilter<PaperCard> {
|
||||
public CardColorlessCostFilter(ItemManager<? super PaperCard> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter<PaperCard> createCopy() {
|
||||
return new CardColorlessCostFilter(itemManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCaption() {
|
||||
return "Generic Cost";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Predicate<PaperCard> buildPredicate() {
|
||||
Predicate<CardRules> predicate = getCardRulesFieldPredicate(CardRulesPredicates.LeafNumber.CardField.GENERIC_COST);
|
||||
if (predicate == null) {
|
||||
return Predicates.alwaysTrue();
|
||||
}
|
||||
return Predicates.compose(predicate, PaperCard.FN_GET_RULES);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
|
||||
|
||||
public class CardFormatFilter extends FormatFilter<PaperCard> {
|
||||
public CardFormatFilter(ItemManager<? super PaperCard> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter<PaperCard> createCopy() {
|
||||
CardFormatFilter copy = new CardFormatFilter(itemManager);
|
||||
copy.format = this.format;
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final Predicate<PaperCard> buildPredicate() {
|
||||
if (format == null) {
|
||||
return Predicates.alwaysTrue();
|
||||
}
|
||||
if (format.getName() == null) {
|
||||
return format.getFilterPrinted(); //if format is collection of sets, don't show reprints in other sets
|
||||
}
|
||||
return format.getFilterRules();
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.CardRulesPredicates;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
|
||||
|
||||
public class CardPowerFilter extends ValueRangeFilter<PaperCard> {
|
||||
public CardPowerFilter(ItemManager<? super PaperCard> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter<PaperCard> createCopy() {
|
||||
return new CardPowerFilter(itemManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCaption() {
|
||||
return "Power";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Predicate<PaperCard> buildPredicate() {
|
||||
Predicate<CardRules> predicate = getCardRulesFieldPredicate(CardRulesPredicates.LeafNumber.CardField.POWER);
|
||||
if (predicate == null) {
|
||||
return Predicates.alwaysTrue();
|
||||
}
|
||||
predicate = Predicates.and(predicate, CardRulesPredicates.Presets.IS_CREATURE);
|
||||
return Predicates.compose(predicate, PaperCard.FN_GET_RULES);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import forge.card.CardRarity;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
|
||||
public class CardRarityFilter extends ComboBoxFilter<PaperCard, CardRarity> {
|
||||
public CardRarityFilter(ItemManager<? super PaperCard> itemManager0) {
|
||||
super("Any Rarity", CardRarity.FILTER_OPTIONS, itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter<PaperCard> createCopy() {
|
||||
CardRarityFilter copy = new CardRarityFilter(itemManager);
|
||||
copy.filterValue = filterValue;
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDisplayText(CardRarity value) {
|
||||
return CardRarity.FN_GET_LONG_NAME.apply(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Predicate<PaperCard> buildPredicate() {
|
||||
return new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard input) {
|
||||
if (filterValue == null) {
|
||||
return true;
|
||||
}
|
||||
return input.getRarity() == filterValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.itemmanager.SFilterUtil;
|
||||
|
||||
|
||||
public class CardSearchFilter extends TextSearchFilter<PaperCard> {
|
||||
private final boolean inName, inType, inText, inCost;
|
||||
|
||||
public CardSearchFilter(ItemManager<? super PaperCard> itemManager0) {
|
||||
this(itemManager0, true, true, true, false);
|
||||
}
|
||||
|
||||
public CardSearchFilter(ItemManager<? super PaperCard> itemManager0, boolean inName0, boolean inType0, boolean inText0, boolean inCost0) {
|
||||
super(itemManager0);
|
||||
inName = inName0;
|
||||
inType = inType0;
|
||||
inText = inText0;
|
||||
inCost = inCost0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter<PaperCard> createCopy() {
|
||||
CardSearchFilter copy = new CardSearchFilter(itemManager, inName, inType, inText, inCost);
|
||||
copy.getWidget(); //initialize widget
|
||||
copy.txtSearch.setText(txtSearch.getText());
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Predicate<PaperCard> buildPredicate() {
|
||||
return SFilterUtil.buildTextFilter(
|
||||
txtSearch.getText(),
|
||||
false,
|
||||
inName,
|
||||
inType,
|
||||
inText,
|
||||
inCost);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <U extends InventoryItem> boolean showUnsupportedItem(U item) {
|
||||
//fallback to regular item text filter if item not PaperCard
|
||||
return SFilterUtil.buildItemTextFilter(txtSearch.getText()).apply(item);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.CardRulesPredicates;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
|
||||
|
||||
public class CardToughnessFilter extends ValueRangeFilter<PaperCard> {
|
||||
public CardToughnessFilter(ItemManager<? super PaperCard> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter<PaperCard> createCopy() {
|
||||
return new CardToughnessFilter(itemManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCaption() {
|
||||
return "Toughness";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Predicate<PaperCard> buildPredicate() {
|
||||
Predicate<CardRules> predicate = getCardRulesFieldPredicate(CardRulesPredicates.LeafNumber.CardField.TOUGHNESS);
|
||||
if (predicate == null) {
|
||||
return Predicates.alwaysTrue();
|
||||
}
|
||||
predicate = Predicates.and(predicate, CardRulesPredicates.Presets.IS_CREATURE);
|
||||
return Predicates.compose(predicate, PaperCard.FN_GET_RULES);
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import forge.card.CardRules;
|
||||
import forge.item.PaperCard;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.itemmanager.SItemManagerUtil.StatTypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class CardTypeFilter extends StatTypeFilter<PaperCard> {
|
||||
public CardTypeFilter(ItemManager<? super PaperCard> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter<PaperCard> createCopy() {
|
||||
return new CardTypeFilter(itemManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildWidget(Widget widget) {
|
||||
/*if (itemManager instanceof SpellShopManager) {
|
||||
addToggleButton(widget, StatTypes.PACK_OR_DECK);
|
||||
}*/
|
||||
addToggleButton(widget, StatTypes.LAND);
|
||||
addToggleButton(widget, StatTypes.ARTIFACT);
|
||||
addToggleButton(widget, StatTypes.CREATURE);
|
||||
addToggleButton(widget, StatTypes.ENCHANTMENT);
|
||||
addToggleButton(widget, StatTypes.PLANESWALKER);
|
||||
addToggleButton(widget, StatTypes.INSTANT);
|
||||
addToggleButton(widget, StatTypes.SORCERY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final Predicate<PaperCard> buildPredicate() {
|
||||
final List<Predicate<CardRules>> types = new ArrayList<>();
|
||||
|
||||
for (StatTypes s : buttonMap.keySet()) {
|
||||
if (s.predicate != null && buttonMap.get(s).isSelected()) {
|
||||
types.add(s.predicate);
|
||||
}
|
||||
}
|
||||
|
||||
if (types.size() == buttonMap.size()) {
|
||||
return new Predicate<PaperCard>() { //use custom return true delegate to validate the item is a card
|
||||
@Override
|
||||
public boolean apply(PaperCard card) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
return Predicates.compose(Predicates.or(types), PaperCard.FN_GET_RULES);
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.adventure.libgdxgui.toolbox.FComboBox;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
|
||||
public abstract class ComboBoxFilter<T extends InventoryItem, V> extends ItemFilter<T> {
|
||||
protected V filterValue;
|
||||
private boolean preventHandling = false;
|
||||
private final FComboBox<Object> comboBox = new FComboBox<Object>() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected String getDisplayText(Object item) {
|
||||
if (item instanceof String) {
|
||||
return (String)item;
|
||||
}
|
||||
return ComboBoxFilter.this.getDisplayText((V)item);
|
||||
}
|
||||
};
|
||||
|
||||
protected ComboBoxFilter(String allText, Iterable<V> values, ItemManager<? super T> itemManager0) {
|
||||
this(allText, itemManager0);
|
||||
for (V value : values) {
|
||||
comboBox.addItem(value);
|
||||
}
|
||||
}
|
||||
protected ComboBoxFilter(String allText, V[] values, ItemManager<? super T> itemManager0) {
|
||||
this(allText, itemManager0);
|
||||
for (V value : values) {
|
||||
comboBox.addItem(value);
|
||||
}
|
||||
}
|
||||
private ComboBoxFilter(String allText, ItemManager<? super T> itemManager0) {
|
||||
super(itemManager0);
|
||||
|
||||
comboBox.setFont(FSkinFont.get(12));
|
||||
comboBox.addItem(allText);
|
||||
comboBox.setChangedHandler(new FEventHandler() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
if (preventHandling) { return; }
|
||||
|
||||
int index = comboBox.getSelectedIndex();
|
||||
if (index == -1) {
|
||||
//Do nothing when index set to -1
|
||||
}
|
||||
else if (index == 0) {
|
||||
filterValue = null;
|
||||
applyChange();
|
||||
}
|
||||
else {
|
||||
filterValue = (V)comboBox.getSelectedItem();
|
||||
applyChange();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected String getDisplayText(V value) {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
preventHandling = true;
|
||||
comboBox.setSelectedIndex(0);
|
||||
preventHandling = false;
|
||||
filterValue = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FDisplayObject getMainComponent() {
|
||||
return comboBox;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return filterValue == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildWidget(Widget widget) {
|
||||
widget.add(comboBox);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWidgetLayout(float width, float height) {
|
||||
comboBox.setSize(width, height);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import forge.deck.DeckProxy;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.itemmanager.SFilterUtil;
|
||||
import forge.itemmanager.SItemManagerUtil.StatTypes;
|
||||
|
||||
|
||||
public class DeckColorFilter extends StatTypeFilter<DeckProxy> {
|
||||
public DeckColorFilter(ItemManager<? super DeckProxy> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter<DeckProxy> createCopy() {
|
||||
return new DeckColorFilter(itemManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildWidget(Widget widget) {
|
||||
addToggleButton(widget, StatTypes.DECK_WHITE);
|
||||
addToggleButton(widget, StatTypes.DECK_BLUE);
|
||||
addToggleButton(widget, StatTypes.DECK_BLACK);
|
||||
addToggleButton(widget, StatTypes.DECK_RED);
|
||||
addToggleButton(widget, StatTypes.DECK_GREEN);
|
||||
addToggleButton(widget, StatTypes.DECK_COLORLESS);
|
||||
addToggleButton(widget, StatTypes.DECK_MULTICOLOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final Predicate<DeckProxy> buildPredicate() {
|
||||
return SFilterUtil.buildDeckColorFilter(buttonMap);
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import forge.deck.DeckProxy;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class DeckFolderFilter extends ListLabelFilter<DeckProxy> {
|
||||
protected final Set<String> folders = new HashSet<>();
|
||||
|
||||
public DeckFolderFilter(ItemManager<? super DeckProxy> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
public DeckFolderFilter(ItemManager<? super DeckProxy> itemManager0, String folder0) {
|
||||
super(itemManager0);
|
||||
this.folders.add(folder0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter<DeckProxy> createCopy() {
|
||||
DeckFolderFilter copy = new DeckFolderFilter(itemManager);
|
||||
copy.folders.addAll(this.folders);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final Predicate<DeckProxy> buildPredicate() {
|
||||
return new Predicate<DeckProxy>() {
|
||||
@Override
|
||||
public boolean apply(DeckProxy input) {
|
||||
String path = input.getPath();
|
||||
for (String folder : folders) {
|
||||
if (path.startsWith(folder)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCaption() {
|
||||
return "Folder";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<String> getList() {
|
||||
return this.folders;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTooltip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getCount() {
|
||||
return this.folders.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.folders.clear();
|
||||
this.updateLabel();
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import forge.deck.DeckProxy;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
|
||||
|
||||
public class DeckFormatFilter extends FormatFilter<DeckProxy> {
|
||||
public DeckFormatFilter(ItemManager<? super DeckProxy> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter<DeckProxy> createCopy() {
|
||||
DeckFormatFilter copy = new DeckFormatFilter(itemManager);
|
||||
copy.format = format;
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final Predicate<DeckProxy> buildPredicate() {
|
||||
if (format == null) {
|
||||
return Predicates.alwaysTrue();
|
||||
}
|
||||
return new Predicate<DeckProxy>() {
|
||||
@Override
|
||||
public boolean apply(DeckProxy input) {
|
||||
return format.isDeckLegal(input.getDeck());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import forge.deck.DeckProxy;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
|
||||
public abstract class DeckStatTypeFilter extends StatTypeFilter<DeckProxy> {
|
||||
public DeckStatTypeFilter(ItemManager<? super DeckProxy> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <U extends InventoryItem> boolean showUnsupportedItem(U item) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,269 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.card.CardEdition;
|
||||
import forge.game.GameFormat;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.model.FModel;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.screens.settings.SettingsScreen;
|
||||
import forge.adventure.libgdxgui.toolbox.*;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
import forge.util.Callback;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.TextUtil;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
||||
|
||||
public abstract class FormatFilter<T extends InventoryItem> extends ItemFilter<T> {
|
||||
protected GameFormat format;
|
||||
private String selectedFormat;
|
||||
private boolean preventHandling = false;
|
||||
private final FComboBox<Object> cbxFormats = new FComboBox<>();
|
||||
|
||||
public FormatFilter(ItemManager<? super T> itemManager0) {
|
||||
super(itemManager0);
|
||||
|
||||
final Localizer localizer = Localizer.getInstance();
|
||||
cbxFormats.setFont(FSkinFont.get(12));
|
||||
cbxFormats.addItem(localizer.getMessage("lblAllSetsFormats"));
|
||||
for (GameFormat format : FModel.getFormats().getFilterList()) {
|
||||
cbxFormats.addItem(format);
|
||||
}
|
||||
cbxFormats.addItem(localizer.getMessage("lblOtherFormats"));
|
||||
cbxFormats.addItem(localizer.getMessage("lblChooseSets"));
|
||||
selectedFormat = cbxFormats.getText();
|
||||
|
||||
cbxFormats.setChangedHandler(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
if (preventHandling) { return; }
|
||||
|
||||
int index = cbxFormats.getSelectedIndex();
|
||||
if (index == -1) {
|
||||
//Do nothing when index set to -1
|
||||
}
|
||||
else if (index == 0) {
|
||||
format = null;
|
||||
applyChange();
|
||||
}
|
||||
else if (index == cbxFormats.getItemCount() - 2) {
|
||||
preventHandling = true;
|
||||
cbxFormats.setText(selectedFormat); //restore previous selection by default
|
||||
preventHandling = false;
|
||||
HistoricFormatSelect historicFormatSelect = new HistoricFormatSelect();
|
||||
historicFormatSelect.setOnCloseCallBack(new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
format = historicFormatSelect.getSelectedFormat();
|
||||
cbxFormats.setText(format.getName());
|
||||
applyChange();
|
||||
}
|
||||
});
|
||||
Forge.openScreen(historicFormatSelect);
|
||||
}
|
||||
else if (index == cbxFormats.getItemCount() - 1) {
|
||||
preventHandling = true;
|
||||
cbxFormats.setText(selectedFormat); //restore previous selection by default
|
||||
preventHandling = false;
|
||||
Forge.openScreen(new MultiSetSelect());
|
||||
}
|
||||
else {
|
||||
format = (GameFormat)cbxFormats.getSelectedItem();
|
||||
applyChange();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyChange() {
|
||||
selectedFormat = cbxFormats.getText(); //backup current text
|
||||
super.applyChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
preventHandling = true;
|
||||
cbxFormats.setSelectedIndex(0);
|
||||
preventHandling = false;
|
||||
format = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FDisplayObject getMainComponent() {
|
||||
return cbxFormats;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return format == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildWidget(Widget widget) {
|
||||
widget.add(cbxFormats);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWidgetLayout(float width, float height) {
|
||||
cbxFormats.setSize(width, height);
|
||||
}
|
||||
|
||||
private class MultiSetSelect extends FScreen {
|
||||
private final Set<CardEdition> selectedSets = new HashSet<>();
|
||||
private final FGroupList<CardEdition> lstSets = add(new FGroupList<>());
|
||||
|
||||
private MultiSetSelect() {
|
||||
super("Choose Sets");
|
||||
|
||||
lstSets.addGroup("Core Sets");
|
||||
lstSets.addGroup("Expansions");
|
||||
lstSets.addGroup("Starter Sets");
|
||||
lstSets.addGroup("Reprint Sets");
|
||||
lstSets.addGroup("Boxed Sets");
|
||||
|
||||
lstSets.addGroup("Collector's Edition");
|
||||
lstSets.addGroup("Duel Decks");
|
||||
lstSets.addGroup("Promo Sets");
|
||||
lstSets.addGroup("Digital Sets");
|
||||
|
||||
lstSets.addGroup("Draft Innovation Sets");
|
||||
|
||||
|
||||
|
||||
lstSets.addGroup("Commander Sets");
|
||||
lstSets.addGroup("Multiplayer Sets");
|
||||
lstSets.addGroup("Other Supplemental Sets");
|
||||
lstSets.addGroup("Funny Sets");
|
||||
|
||||
lstSets.addGroup("Custom Sets");
|
||||
|
||||
List<CardEdition> sets = FModel.getMagicDb().getSortedEditions();
|
||||
for (CardEdition set : sets) {
|
||||
switch (set.getType()) {
|
||||
case CORE:
|
||||
lstSets.addItem(set, 0);
|
||||
break;
|
||||
case EXPANSION:
|
||||
lstSets.addItem(set, 1);
|
||||
break;
|
||||
case STARTER:
|
||||
lstSets.addItem(set, 2);
|
||||
break;
|
||||
case REPRINT:
|
||||
lstSets.addItem(set, 3);
|
||||
break;
|
||||
case BOXED_SET:
|
||||
lstSets.addItem(set,4);
|
||||
break;
|
||||
case COLLECTOR_EDITION:
|
||||
lstSets.addItem(set, 5);
|
||||
break;
|
||||
case DUEL_DECK:
|
||||
lstSets.addItem(set, 6);
|
||||
break;
|
||||
case PROMO:
|
||||
lstSets.addItem(set, 7);
|
||||
break;
|
||||
case ONLINE:
|
||||
lstSets.addItem(set, 8);
|
||||
break;
|
||||
case DRAFT:
|
||||
lstSets.addItem(set, 9);
|
||||
break;
|
||||
case COMMANDER:
|
||||
lstSets.addItem(set, 10);
|
||||
break;
|
||||
case MULTIPLAYER:
|
||||
lstSets.addItem(set, 11);
|
||||
break;
|
||||
case OTHER:
|
||||
lstSets.addItem(set, 12);
|
||||
break;
|
||||
case FUNNY:
|
||||
lstSets.addItem(set, 13);
|
||||
break;
|
||||
default: // THIRDPARTY - Custom Sets
|
||||
lstSets.addItem(set, 14);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lstSets.setListItemRenderer(new SetRenderer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Callback<Boolean> canCloseCallback) {
|
||||
if (selectedSets.size() > 0) {
|
||||
List<String> setCodes = new ArrayList<>();
|
||||
List<CardEdition> sortedSets = new ArrayList<>(selectedSets);
|
||||
Collections.sort(sortedSets);
|
||||
for (CardEdition set : sortedSets) {
|
||||
setCodes.add(set.getCode());
|
||||
}
|
||||
format = new GameFormat(null, setCodes, null);
|
||||
cbxFormats.setText(sortedSets.size() > 1 ? TextUtil.join(setCodes, ", ") : sortedSets.get(0).toString());
|
||||
applyChange();
|
||||
}
|
||||
super.onClose(canCloseCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float startY, float width, float height) {
|
||||
lstSets.setBounds(0, startY, width, height - startY);
|
||||
}
|
||||
|
||||
private class SetRenderer extends FList.ListItemRenderer<CardEdition> {
|
||||
@Override
|
||||
public float getItemHeight() {
|
||||
return Utils.AVG_FINGER_HEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(Integer index, CardEdition value, float x, float y, int count) {
|
||||
if (selectedSets.contains(value)) {
|
||||
if (count == 2) {
|
||||
Forge.back(); //support double tap to confirm selection without unselecting double tapped item
|
||||
}
|
||||
else {
|
||||
selectedSets.remove(value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
selectedSets.add(value);
|
||||
if (count == 2) {
|
||||
Forge.back(); //support double tap to confirm selection after selecting double tapped item
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawValue(Graphics g, Integer index, CardEdition value, FSkinFont font, FSkinColor foreColor, FSkinColor backColor, boolean pressed, float x, float y, float w, float h) {
|
||||
float offset = SettingsScreen.getInsets(w) - FList.PADDING; //increase padding for settings items
|
||||
x += offset;
|
||||
y += offset;
|
||||
w -= 2 * offset;
|
||||
h -= 2 * offset;
|
||||
|
||||
float textHeight = h;
|
||||
h *= 0.66f;
|
||||
|
||||
g.drawText(value.toString(), font, foreColor, x, y, w - h - FList.PADDING, textHeight, false, Align.left, true);
|
||||
|
||||
x += w - h;
|
||||
y += (textHeight - h) / 2;
|
||||
FCheckBox.drawCheckBox(g, SettingsScreen.DESC_COLOR, foreColor, selectedSets.contains(value), x, y, h, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.game.GameFormat;
|
||||
import forge.model.FModel;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.screens.settings.SettingsScreen;
|
||||
import forge.adventure.libgdxgui.toolbox.FGroupList;
|
||||
import forge.adventure.libgdxgui.toolbox.FList;
|
||||
import forge.util.Callback;
|
||||
import forge.util.Localizer;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by maustin on 16/04/2018.
|
||||
*/
|
||||
public class HistoricFormatSelect extends FScreen {
|
||||
|
||||
private GameFormat selectedFormat;
|
||||
private final FGroupList<GameFormat> lstFormats = add(new FGroupList<>());
|
||||
private final Set<GameFormat.FormatSubType> historicSubTypes = new HashSet<>(Arrays.asList(GameFormat.FormatSubType.BLOCK,
|
||||
GameFormat.FormatSubType.STANDARD,GameFormat.FormatSubType.EXTENDED,GameFormat.FormatSubType.MODERN,
|
||||
GameFormat.FormatSubType.LEGACY, GameFormat.FormatSubType.VINTAGE));
|
||||
|
||||
private Runnable onCloseCallBack;
|
||||
|
||||
public HistoricFormatSelect() {
|
||||
super(Localizer.getInstance().getMessage("lblChooseFormat"));
|
||||
for (GameFormat.FormatType group:GameFormat.FormatType.values()){
|
||||
if (group == GameFormat.FormatType.HISTORIC){
|
||||
for (GameFormat.FormatSubType subgroup:GameFormat.FormatSubType.values()){
|
||||
if (historicSubTypes.contains(subgroup)){
|
||||
lstFormats.addGroup(group.name() + "-" + subgroup.name());
|
||||
}
|
||||
}
|
||||
}else {
|
||||
lstFormats.addGroup(group.name());
|
||||
}
|
||||
}
|
||||
for (GameFormat format: FModel.getFormats().getOrderedList()){
|
||||
switch(format.getFormatType()){
|
||||
case SANCTIONED:
|
||||
lstFormats.addItem(format, 0);
|
||||
break;
|
||||
case CASUAL:
|
||||
lstFormats.addItem(format, 1);
|
||||
break;
|
||||
case HISTORIC:
|
||||
switch (format.getFormatSubType()){
|
||||
case BLOCK:
|
||||
lstFormats.addItem(format, 2);
|
||||
break;
|
||||
case STANDARD:
|
||||
lstFormats.addItem(format, 3);
|
||||
break;
|
||||
case EXTENDED:
|
||||
lstFormats.addItem(format, 4);
|
||||
break;
|
||||
case MODERN:
|
||||
lstFormats.addItem(format, 5);
|
||||
break;
|
||||
case LEGACY:
|
||||
lstFormats.addItem(format, 6);
|
||||
break;
|
||||
case VINTAGE:
|
||||
lstFormats.addItem(format, 7);
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
case DIGITAL:
|
||||
lstFormats.addItem(format, 8);
|
||||
break;
|
||||
case CUSTOM:
|
||||
lstFormats.addItem(format, 9);
|
||||
}
|
||||
}
|
||||
lstFormats.setListItemRenderer(new FormatRenderer());
|
||||
}
|
||||
|
||||
public GameFormat getSelectedFormat() {
|
||||
return selectedFormat;
|
||||
}
|
||||
|
||||
public void setOnCloseCallBack(Runnable onCloseCallBack) {
|
||||
this.onCloseCallBack = onCloseCallBack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Callback<Boolean> canCloseCallback) {
|
||||
if (selectedFormat != null) {
|
||||
if (onCloseCallBack != null) {
|
||||
onCloseCallBack.run();
|
||||
}
|
||||
}
|
||||
super.onClose(canCloseCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float startY, float width, float height) {
|
||||
lstFormats.setBounds(0, startY, width, height - startY);
|
||||
}
|
||||
|
||||
private class FormatRenderer extends FList.ListItemRenderer<GameFormat>{
|
||||
@Override
|
||||
public float getItemHeight() {
|
||||
return Utils.AVG_FINGER_HEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(Integer index, GameFormat value, float x, float y, int count) {
|
||||
selectedFormat=value;
|
||||
Forge.back();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawValue(Graphics g, Integer index, GameFormat value, FSkinFont font, FSkinColor foreColor, FSkinColor backColor, boolean pressed, float x, float y, float w, float h) {
|
||||
float offset = SettingsScreen.getInsets(w) - FList.PADDING; //increase padding for settings items
|
||||
x += offset;
|
||||
y += offset;
|
||||
w -= 2 * offset;
|
||||
h -= 2 * offset;
|
||||
|
||||
float textHeight = h;
|
||||
h *= 0.66f;
|
||||
|
||||
g.drawText(value.toString(), font, foreColor, x, y, w - h - FList.PADDING, textHeight, false, Align.left, true);
|
||||
|
||||
x += w - h;
|
||||
y += (textHeight - h) / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.adventure.libgdxgui.toolbox.FContainer;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
|
||||
|
||||
public abstract class ItemFilter<T extends InventoryItem> {
|
||||
public static final float PADDING = Utils.scale(3);
|
||||
public static final FSkinFont DEFAULT_FONT = FSkinFont.get(11);
|
||||
|
||||
protected final ItemManager<? super T> itemManager;
|
||||
private Widget widget;
|
||||
|
||||
protected ItemFilter(ItemManager<? super T> itemManager0) {
|
||||
itemManager = itemManager0;
|
||||
}
|
||||
|
||||
public Widget getWidget() {
|
||||
if (widget == null) {
|
||||
widget = new Widget();
|
||||
buildWidget(widget);
|
||||
}
|
||||
return widget;
|
||||
}
|
||||
|
||||
public void refreshWidget() {
|
||||
if (widget == null) { return; }
|
||||
widget.clear();
|
||||
buildWidget(widget);
|
||||
}
|
||||
|
||||
public FDisplayObject getMainComponent() {
|
||||
return getWidget();
|
||||
}
|
||||
|
||||
protected void applyChange() {
|
||||
itemManager.applyFilters();
|
||||
}
|
||||
|
||||
public final <U extends InventoryItem> Predicate<U> buildPredicate(Class<U> genericType) {
|
||||
final Predicate<T> predicate = buildPredicate();
|
||||
return new Predicate<U>() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean apply(U item) {
|
||||
try {
|
||||
return predicate.apply((T)item);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return showUnsupportedItem(item); //if can't cast U to T, filter item out unless derived class can handle it
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected <U extends InventoryItem> boolean showUnsupportedItem(U item) {
|
||||
return false; //don't show unsupported items by default
|
||||
}
|
||||
|
||||
public abstract ItemFilter<T> createCopy();
|
||||
public abstract boolean isEmpty();
|
||||
public abstract void reset();
|
||||
|
||||
public float getPreferredWidth(float maxWidth, float height) {
|
||||
return maxWidth; //use maximum width by default
|
||||
}
|
||||
|
||||
protected abstract void buildWidget(Widget widget);
|
||||
protected abstract void doWidgetLayout(float width, float height);
|
||||
protected abstract Predicate<T> buildPredicate();
|
||||
|
||||
public class Widget extends FContainer {
|
||||
private Widget() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
doWidgetLayout(width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.adventure.libgdxgui.menu.FTooltip;
|
||||
import forge.adventure.libgdxgui.toolbox.FLabel;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
|
||||
public abstract class ListLabelFilter<T extends InventoryItem> extends ItemFilter<T> {
|
||||
public static final FSkinFont LABEL_FONT = FSkinFont.get(12);
|
||||
|
||||
private ListLabel label;
|
||||
|
||||
protected ListLabelFilter(ItemManager<? super T> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
protected abstract String getCaption();
|
||||
protected abstract Iterable<String> getList();
|
||||
protected abstract String getTooltip();
|
||||
protected abstract int getCount();
|
||||
|
||||
@Override
|
||||
public final boolean isEmpty() {
|
||||
return getCount() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void buildWidget(Widget widget) {
|
||||
label = new ListLabel();
|
||||
updateLabel();
|
||||
widget.add(label);
|
||||
}
|
||||
|
||||
protected void updateLabel() {
|
||||
StringBuilder labelBuilder = new StringBuilder();
|
||||
labelBuilder.append(getCaption());
|
||||
switch (getCount()) {
|
||||
case 0:
|
||||
labelBuilder.append("s: All");
|
||||
break;
|
||||
case 1:
|
||||
labelBuilder.append(": ").append(getList().iterator().next());
|
||||
break;
|
||||
default:
|
||||
labelBuilder.append("s: ").append(TextUtil.join(getList(), ", "));
|
||||
break;
|
||||
}
|
||||
label.setText(labelBuilder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWidgetLayout(float width, float height) {
|
||||
label.setSize(width, height);
|
||||
}
|
||||
|
||||
private class ListLabel extends FLabel {
|
||||
private ListLabel() {
|
||||
super(new FLabel.Builder().align(Align.left).font(LABEL_FONT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
FTooltip tooltip = new FTooltip(getTooltip());
|
||||
tooltip.show(this, x, getHeight());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import forge.adventure.libgdxgui.assets.FSkin;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.item.ItemPredicate;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.itemmanager.SFilterUtil;
|
||||
import forge.itemmanager.SItemManagerUtil.StatTypes;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
import forge.adventure.libgdxgui.toolbox.FLabel;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class StatTypeFilter<T extends InventoryItem> extends ToggleButtonsFilter<T> {
|
||||
protected final Map<StatTypes, FLabel> buttonMap;
|
||||
|
||||
public StatTypeFilter(ItemManager<? super T> itemManager0) {
|
||||
super(itemManager0);
|
||||
buttonMap = new HashMap<>();
|
||||
}
|
||||
|
||||
protected void addToggleButton(Widget widget, final StatTypes st) {
|
||||
final ToggleButton button = addToggleButton(widget, FSkin.getImages().get(st.skinProp));
|
||||
buttonMap.put(st, button);
|
||||
|
||||
//hook so long-pressing a button toggles itself on and toggles off all other buttons
|
||||
button.setLongPressHandler(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
lockFiltering = true;
|
||||
SFilterUtil.showOnlyStat(st, button, buttonMap);
|
||||
lockFiltering = false;
|
||||
applyChange();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <U extends InventoryItem> boolean showUnsupportedItem(U item) {
|
||||
FLabel btnPackOrDeck = buttonMap.get(StatTypes.PACK_OR_DECK); //support special pack/deck case
|
||||
if (btnPackOrDeck != null && btnPackOrDeck.isSelected()) {
|
||||
return ItemPredicate.Presets.IS_PACK_OR_DECK.apply(item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.itemmanager.SFilterUtil;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
import forge.adventure.libgdxgui.toolbox.FTextField;
|
||||
import forge.util.Localizer;
|
||||
|
||||
|
||||
public class TextSearchFilter<T extends InventoryItem> extends ItemFilter<T> {
|
||||
private static final FSkinFont FONT = FSkinFont.get(12);
|
||||
protected SearchField txtSearch;
|
||||
|
||||
public TextSearchFilter(ItemManager<? super T> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter<T> createCopy() {
|
||||
TextSearchFilter<T> copy = new TextSearchFilter<>(itemManager);
|
||||
copy.getWidget(); //initialize widget
|
||||
copy.txtSearch.setText(this.txtSearch.getText());
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return txtSearch.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
txtSearch.setText("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FDisplayObject getMainComponent() {
|
||||
return txtSearch;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildWidget(Widget widget) {
|
||||
txtSearch = new SearchField();
|
||||
widget.add(txtSearch);
|
||||
|
||||
txtSearch.setChangedHandler(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
applyChange();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWidgetLayout(float width, float height) {
|
||||
txtSearch.setSize(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Predicate<T> buildPredicate() {
|
||||
String text = txtSearch.getText();
|
||||
if (text.trim().isEmpty()) {
|
||||
return Predicates.alwaysTrue();
|
||||
}
|
||||
return SFilterUtil.buildItemTextFilter(text);
|
||||
}
|
||||
|
||||
public void setRatio(String ratio0) {
|
||||
txtSearch.ratio = ratio0;
|
||||
}
|
||||
|
||||
public String getCaption() {
|
||||
return txtSearch.getGhostText().substring((Localizer.getInstance().getMessage("lblSearch") + " ").length());
|
||||
}
|
||||
public void setCaption(String caption0) {
|
||||
txtSearch.setGhostText(Localizer.getInstance().getMessage("lblSearch") + " " + caption0);
|
||||
}
|
||||
|
||||
protected class SearchField extends FTextField {
|
||||
private String ratio = "(0 / 0)";
|
||||
|
||||
private SearchField() {
|
||||
setFont(FONT);
|
||||
setGhostText(Localizer.getInstance().getMessage("lblSearch"));
|
||||
setHeight(getDefaultHeight(DEFAULT_FONT)); //set height based on default filter font
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getRightPadding() {
|
||||
return renderedFont.getBounds(ratio).width + 2 * PADDING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g) {
|
||||
super.draw(g);
|
||||
g.drawText(ratio, renderedFont, GHOST_TEXT_COLOR, 0, 0, getWidth() - PADDING, getHeight(), false, Align.right, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.adventure.libgdxgui.assets.FImage;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventType;
|
||||
import forge.adventure.libgdxgui.toolbox.FLabel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public abstract class ToggleButtonsFilter<T extends InventoryItem> extends ItemFilter<T> {
|
||||
protected boolean lockFiltering;
|
||||
private final List<FLabel> buttons = new ArrayList<>();
|
||||
|
||||
protected ToggleButtonsFilter(ItemManager<? super T> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
protected ToggleButton addToggleButton(Widget widget, FImage icon) {
|
||||
final ToggleButton button = new ToggleButton(icon);
|
||||
|
||||
this.buttons.add(button);
|
||||
widget.add(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPreferredWidth(float maxWidth, float height) {
|
||||
return Math.min((height - FLabel.BORDER_THICKNESS) * buttons.size() + FLabel.BORDER_THICKNESS, maxWidth);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWidgetLayout(float width, float height) {
|
||||
float buttonWidth = (width + FLabel.BORDER_THICKNESS * (buttons.size() - 1)) / buttons.size();
|
||||
float buttonHeight = height;
|
||||
|
||||
float x = 0;
|
||||
for (FLabel btn : buttons) {
|
||||
btn.setBounds(x, 0, buttonWidth, buttonHeight);
|
||||
x += buttonWidth - FLabel.BORDER_THICKNESS;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isEmpty() {
|
||||
for (FLabel button : buttons) { //consider filter empty if any button isn't selected
|
||||
if (!button.isSelected()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
for (FLabel button : buttons) {
|
||||
button.setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
public class ToggleButton extends FLabel {
|
||||
private FEventHandler longPressHandler;
|
||||
|
||||
private ToggleButton(FImage icon) {
|
||||
super(new FLabel.Builder()
|
||||
.icon(icon).iconScaleFactor(1f)
|
||||
.align(Align.center)
|
||||
.selectable(true).selected(true)
|
||||
.command(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
if (lockFiltering) { return; }
|
||||
applyChange();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public void setLongPressHandler(FEventHandler longPressHandler0) {
|
||||
longPressHandler = longPressHandler0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean longPress(float x, float y) {
|
||||
if (longPressHandler != null) {
|
||||
longPressHandler.handleEvent(new FEvent(this, FEventType.LONG_PRESS));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.filters;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.google.common.base.Predicate;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.CardRulesPredicates;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.itemmanager.SFilterUtil;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
import forge.adventure.libgdxgui.toolbox.FLabel;
|
||||
import forge.adventure.libgdxgui.toolbox.FSpinner;
|
||||
import forge.util.ComparableOp;
|
||||
|
||||
|
||||
public abstract class ValueRangeFilter<T extends InventoryItem> extends ItemFilter<T> {
|
||||
private FLabel label;
|
||||
private FSpinner lowerBound, upperBound;
|
||||
|
||||
protected ValueRangeFilter(ItemManager<? super T> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
protected abstract String getCaption();
|
||||
|
||||
protected int minValue() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected int maxValue() {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isEmpty() {
|
||||
return lowerBound.getValue() == minValue() && upperBound.getValue() == maxValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
lowerBound.setValue(minValue());
|
||||
upperBound.setValue(maxValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FDisplayObject getMainComponent() {
|
||||
return lowerBound;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void buildWidget(Widget widget) {
|
||||
lowerBound = addSpinner(widget, true);
|
||||
|
||||
String text = "<= " + this.getCaption() + " <=";
|
||||
label = new FLabel.Builder().text(text).align(Align.center).font(ListLabelFilter.LABEL_FONT).build();
|
||||
widget.add(label);
|
||||
|
||||
upperBound = addSpinner(widget, false);
|
||||
|
||||
lowerBound.setChangedHandler(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
if (upperBound.getValue() < lowerBound.getValue()) {
|
||||
upperBound.setValue(lowerBound.getValue());
|
||||
}
|
||||
applyChange();
|
||||
}
|
||||
});
|
||||
|
||||
upperBound.setChangedHandler(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
if (lowerBound.getValue() > upperBound.getValue()) {
|
||||
lowerBound.setValue(upperBound.getValue());
|
||||
}
|
||||
applyChange();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWidgetLayout(float width, float height) {
|
||||
float x = 0;
|
||||
float spinnerWidth = height * 1.5f;
|
||||
lowerBound.setBounds(x, 0, spinnerWidth, height);
|
||||
x += lowerBound.getWidth();
|
||||
label.setBounds(x, 0, width - 2 * spinnerWidth, height);
|
||||
x += label.getWidth();
|
||||
upperBound.setBounds(x, 0, spinnerWidth, height);
|
||||
}
|
||||
|
||||
private FSpinner addSpinner(Widget widget, boolean lowerBound) {
|
||||
FSpinner spinner = new FSpinner(minValue(), maxValue(), lowerBound ? this.minValue() : this.maxValue());
|
||||
widget.add(spinner);
|
||||
return spinner;
|
||||
}
|
||||
|
||||
protected Predicate<CardRules> getCardRulesFieldPredicate(CardRulesPredicates.LeafNumber.CardField field) {
|
||||
int lowerValue = lowerBound.getValue();
|
||||
int upperValue = upperBound.getValue();
|
||||
boolean hasMin = lowerValue != minValue();
|
||||
boolean hasMax = upperValue != maxValue();
|
||||
|
||||
Predicate<CardRules> pLower = hasMin ? new CardRulesPredicates.LeafNumber(field, ComparableOp.GT_OR_EQUAL, lowerValue) : null;
|
||||
Predicate<CardRules> pUpper = hasMax ? new CardRulesPredicates.LeafNumber(field, ComparableOp.LT_OR_EQUAL, upperValue) : null;
|
||||
|
||||
return SFilterUtil.optimizedAnd(pLower, pUpper);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,331 +0,0 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Forge Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package forge.adventure.libgdxgui.itemmanager.views;
|
||||
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FImage;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor.Colors;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.assets.FSkinImage;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.adventure.libgdxgui.toolbox.FCheckBox;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.toolbox.FList;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.itemmanager.ColumnDef;
|
||||
import forge.itemmanager.ItemColumn;
|
||||
import forge.itemmanager.ItemManagerConfig;
|
||||
import forge.itemmanager.ItemManagerModel;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
||||
public final class ItemListView<T extends InventoryItem> extends ItemView<T> {
|
||||
private static final FSkinColor ROW_COLOR = FSkinColor.get(Colors.CLR_ZEBRA);
|
||||
private static final FSkinColor ALT_ROW_COLOR = ROW_COLOR.getContrastColor(-20);
|
||||
private static final FSkinColor SEL_COLOR = FSkinColor.get(Colors.CLR_ACTIVE);
|
||||
|
||||
private final ItemList list = new ItemList();
|
||||
private final ItemListModel listModel;
|
||||
private final List<Integer> selectedIndices = new ArrayList<>();
|
||||
|
||||
public ItemListModel getListModel() {
|
||||
return listModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* ItemListView Constructor.
|
||||
*
|
||||
* @param itemManager0
|
||||
* @param model0
|
||||
*/
|
||||
public ItemListView(ItemManager<T> itemManager0, ItemManagerModel<T> model0) {
|
||||
super(itemManager0, model0);
|
||||
listModel = new ItemListModel(model0);
|
||||
getPnlOptions().setVisible(false); //hide options panel by default
|
||||
getScroller().add(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup(ItemManagerConfig config, Map<ColumnDef, ItemColumn> colOverrides) {
|
||||
list.compactModeHandler.setCompactMode(config.getCompactListView());
|
||||
refresh(null, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FImage getIcon() {
|
||||
return FSkinImage.LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCaption() {
|
||||
return Localizer.getInstance().getMessage("lblListView");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSelectedIndex() {
|
||||
if (selectedIndices.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
return selectedIndices.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Integer> getSelectedIndices() {
|
||||
return selectedIndices;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetSelectedIndex(int index) {
|
||||
selectedIndices.clear();
|
||||
selectedIndices.add(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetSelectedIndices(Iterable<Integer> indices) {
|
||||
selectedIndices.clear();
|
||||
for (Integer index : indices) {
|
||||
selectedIndices.add(index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getScrollValue() {
|
||||
return list.getScrollTop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScrollValue(float value) {
|
||||
list.setScrollTop(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scrollSelectionIntoView() {
|
||||
list.scrollIntoView(getSelectedIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getSelectionBounds() {
|
||||
if (selectedIndices.isEmpty()) { return null; }
|
||||
|
||||
return new Rectangle(list.screenPos.x, list.screenPos.y + list.getItemStartPosition(getSelectedIndex()), list.getWidth(), list.getListItemRenderer().getItemHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectAll() {
|
||||
selectedIndices.clear();
|
||||
for (Integer i = 0; i < getCount(); i++) {
|
||||
selectedIndices.add(i);
|
||||
}
|
||||
onSelectionChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexOfItem(T item) {
|
||||
return listModel.itemToRow(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getItemAtIndex(int index) {
|
||||
Entry<T, Integer> itemEntry = listModel.rowToItem(index);
|
||||
return itemEntry != null ? itemEntry.getKey() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return list.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSelectionCount() {
|
||||
return selectedIndices.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexAtPoint(float x, float y) {
|
||||
return 0; //TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResize(float visibleWidth, float visibleHeight) {
|
||||
list.setSize(visibleWidth, visibleHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRefresh() {
|
||||
list.setListData(model.getOrderedList());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getScrollHeight() {
|
||||
return getScroller().getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void layoutOptionsPanel(float width, float height) {
|
||||
}
|
||||
|
||||
public final class ItemList extends FList<Entry<T, Integer>> {
|
||||
private final ItemManager<T>.ItemRenderer renderer;
|
||||
private final CompactModeHandler compactModeHandler;
|
||||
|
||||
private ItemList() {
|
||||
compactModeHandler = new CompactModeHandler();
|
||||
renderer = itemManager.getListItemRenderer(compactModeHandler);
|
||||
setListItemRenderer(new ListItemRenderer<Entry<T,Integer>>() {
|
||||
private int prevTapIndex = -1;
|
||||
|
||||
@Override
|
||||
public float getItemHeight() {
|
||||
return renderer.getItemHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(Integer index, Entry<T, Integer> value, float x, float y, int count) {
|
||||
if (maxSelections > 1) { //if multi-select
|
||||
//don't toggle checkbox if renderer handles tap
|
||||
if (!renderer.tap(index, value, x, y, count)) {
|
||||
if (selectedIndices.contains(index)) {
|
||||
//allow removing selection if it won't fall below min
|
||||
//or if max selected (since you need to be able to deselect an item before selecting a new item)
|
||||
if (selectedIndices.size() > minSelections || selectedIndices.size() == maxSelections) {
|
||||
selectedIndices.remove(index);
|
||||
onSelectionChange();
|
||||
}
|
||||
}
|
||||
else if (selectedIndices.size() < maxSelections) {
|
||||
selectedIndices.add(index);
|
||||
Collections.sort(selectedIndices); //ensure selected indices are sorted
|
||||
onSelectionChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
else { //if single-select
|
||||
setSelectedIndex(index);
|
||||
|
||||
//don't activate if renderer handles tap
|
||||
if (!renderer.tap(index, value, x, y, count)) {
|
||||
if (count == 1) {
|
||||
itemManager.showMenu(false);
|
||||
}
|
||||
else if (count == 2 && index == prevTapIndex) {
|
||||
itemManager.activateSelectedItems();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prevTapIndex = index;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showMenu(Integer index, Entry<T, Integer> value, FDisplayObject owner, float x, float y) {
|
||||
return renderer.longPress(index, value, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawValue(Graphics g, Integer index, Entry<T, Integer> value, FSkinFont font, FSkinColor foreColor, FSkinColor backColor, boolean pressed, float x, float y, float w, float h) {
|
||||
if (maxSelections > 1) {
|
||||
if (pressed) { //if multi-select mode, draw SEL_COLOR when pressed
|
||||
g.fillRect(SEL_COLOR, x - FList.PADDING, y - FList.PADDING, w + 2 * FList.PADDING, h + 2 * FList.PADDING);
|
||||
}
|
||||
//draw checkbox, with it checked based on whether item is selected
|
||||
float checkBoxSize = h * 0.4f;
|
||||
float padding = checkBoxSize / 2;
|
||||
w -= checkBoxSize + padding;
|
||||
FCheckBox.drawCheckBox(g, selectedIndices.contains(index), x + w, y + (h - checkBoxSize) / 2, checkBoxSize, checkBoxSize);
|
||||
w -= padding;
|
||||
}
|
||||
renderer.drawValue(g, value, font, foreColor, backColor, pressed, x + 1, y, w - 2, h); //x + 1 and w - 2 to account for left and right borders
|
||||
}
|
||||
});
|
||||
setFont(FSkinFont.get(14));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackground(Graphics g) {
|
||||
//draw no background by default
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean press(float x, float y) {
|
||||
if (renderer.allowPressEffect(this, x, y)) {
|
||||
return super.press(x, y);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FSkinColor getItemFillColor(int index) {
|
||||
if (maxSelections == 1 && selectedIndices.contains(index)) {
|
||||
return SEL_COLOR; //don't show SEL_COLOR if in multi-select mode
|
||||
}
|
||||
if (index % 2 == 1) {
|
||||
return ALT_ROW_COLOR;
|
||||
}
|
||||
return ROW_COLOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean drawLineSeparators() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean zoom(float x, float y, float amount) {
|
||||
if (compactModeHandler.update(amount)) {
|
||||
revalidate(); //update scroll bounds
|
||||
scrollSelectionIntoView(); //ensure selection remains in view
|
||||
|
||||
//update compact mode configuration
|
||||
itemManager.getConfig().setCompactListView(compactModeHandler.isCompactMode());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public final class ItemListModel {
|
||||
private final ItemManagerModel<T> model;
|
||||
|
||||
public ItemListModel(final ItemManagerModel<T> model0) {
|
||||
model = model0;
|
||||
}
|
||||
|
||||
public Entry<T, Integer> rowToItem(final int row) {
|
||||
final List<Entry<T, Integer>> orderedList = model.getOrderedList();
|
||||
return (row >= 0) && (row < orderedList.size()) ? orderedList.get(row) : null;
|
||||
}
|
||||
|
||||
public int itemToRow(final T item) { //TODO: Consider optimizing this if used frequently
|
||||
final List<Entry<T, Integer>> orderedList = model.getOrderedList();
|
||||
for (int i = 0; i < orderedList.size(); i++) {
|
||||
if (orderedList.get(i).getKey() == item) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,283 +0,0 @@
|
||||
package forge.adventure.libgdxgui.itemmanager.views;
|
||||
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FImage;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor.Colors;
|
||||
import forge.adventure.libgdxgui.itemmanager.ItemManager;
|
||||
import forge.adventure.libgdxgui.toolbox.FContainer;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventType;
|
||||
import forge.adventure.libgdxgui.toolbox.FScrollPane;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.itemmanager.ColumnDef;
|
||||
import forge.itemmanager.ItemColumn;
|
||||
import forge.itemmanager.ItemManagerConfig;
|
||||
import forge.itemmanager.ItemManagerModel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class ItemView<T extends InventoryItem> {
|
||||
protected static final float UNOWNED_ALPHA_COMPOSITE = 0.35f;
|
||||
private static final FSkinColor BORDER_COLOR = FSkinColor.get(Colors.CLR_TEXT);
|
||||
|
||||
protected final ItemManager<T> itemManager;
|
||||
protected final ItemManagerModel<T> model;
|
||||
protected int minSelections = 0;
|
||||
protected int maxSelections = 1;
|
||||
private final Scroller scroller = new Scroller();
|
||||
private final OptionsPanel pnlOptions = new OptionsPanel();
|
||||
|
||||
private float heightBackup;
|
||||
private final boolean isIncrementalSearchActive = false;
|
||||
|
||||
protected ItemView(ItemManager<T> itemManager0, ItemManagerModel<T> model0) {
|
||||
itemManager = itemManager0;
|
||||
model = model0;
|
||||
}
|
||||
|
||||
private class Scroller extends FScrollPane {
|
||||
@Override
|
||||
protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) {
|
||||
onResize(visibleWidth, visibleHeight);
|
||||
return new ScrollBounds(visibleWidth, ItemView.this.getScrollHeight());
|
||||
}
|
||||
|
||||
protected void setScrollPositionsAfterLayout(float scrollLeft0, float scrollTop0) {
|
||||
if (getHeight() != heightBackup) {
|
||||
heightBackup = getHeight();
|
||||
scrollSelectionIntoView(); //scroll selection into view whenever view height changes
|
||||
}
|
||||
else {
|
||||
super.setScrollPositionsAfterLayout(scrollLeft0, scrollTop0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
return ItemView.this.tap(x, y, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean zoom(float x, float y, float amount) {
|
||||
return ItemView.this.zoom(x, y, amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOverlay(Graphics g) {
|
||||
super.drawOverlay(g);
|
||||
g.drawRect(1.5f, BORDER_COLOR, 0, 0, getWidth(), getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean tap(float x, float y, int count) {
|
||||
return false;
|
||||
}
|
||||
protected boolean zoom(float x, float y, float amount) {
|
||||
return false;
|
||||
}
|
||||
protected abstract float getScrollHeight();
|
||||
protected abstract void layoutOptionsPanel(float width, float height);
|
||||
|
||||
private class OptionsPanel extends FContainer {
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
layoutOptionsPanel(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
public FScrollPane getScroller() {
|
||||
return scroller;
|
||||
}
|
||||
|
||||
public FContainer getPnlOptions() {
|
||||
return pnlOptions;
|
||||
}
|
||||
|
||||
public float getScrollValue() {
|
||||
return scroller.getScrollTop();
|
||||
}
|
||||
|
||||
public void setScrollValue(float value) {
|
||||
scroller.setScrollTop(value);
|
||||
}
|
||||
|
||||
public boolean isIncrementalSearchActive() {
|
||||
return isIncrementalSearchActive;
|
||||
}
|
||||
|
||||
public void refresh(final Iterable<T> itemsToSelect, final int backupIndexToSelect, final float scrollValueToRestore) {
|
||||
model.refreshSort();
|
||||
onRefresh();
|
||||
fixSelection(itemsToSelect, backupIndexToSelect, scrollValueToRestore);
|
||||
}
|
||||
protected abstract void onResize(float visibleWidth, float visibleHeight);
|
||||
protected abstract void onRefresh();
|
||||
protected void fixSelection(final Iterable<T> itemsToSelect, final int backupIndexToSelect, final float scrollValueToRestore) {
|
||||
if (itemsToSelect == null) {
|
||||
if (itemManager.getMultiSelectMode()) { //if in multi-select mode, clear selection
|
||||
setSelectedIndex(-1, false);
|
||||
}
|
||||
else { //otherwise select first item if no items to select
|
||||
setSelectedIndex(0, false);
|
||||
}
|
||||
setScrollValue(0); //ensure scrolled to top
|
||||
}
|
||||
else {
|
||||
if (!setSelectedItems(itemsToSelect)) {
|
||||
setSelectedIndex(backupIndexToSelect);
|
||||
|
||||
if (itemManager.getMultiSelectMode()) { //in multi-select mode, clear selection after scrolling into view
|
||||
setSelectedIndex(-1, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final T getSelectedItem() {
|
||||
return getItemAtIndex(getSelectedIndex());
|
||||
}
|
||||
|
||||
public final Collection<T> getSelectedItems() {
|
||||
List<T> items = new ArrayList<>();
|
||||
for (Integer i : getSelectedIndices()) {
|
||||
T item = getItemAtIndex(i);
|
||||
if (item != null) {
|
||||
items.add(item);
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
public final boolean setSelectedItem(T item) {
|
||||
return setSelectedItem(item, true);
|
||||
}
|
||||
public final boolean setSelectedItem(T item, boolean scrollIntoView) {
|
||||
int index = getIndexOfItem(item);
|
||||
if (index != -1) {
|
||||
setSelectedIndex(index, scrollIntoView);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public final boolean setSelectedItems(Iterable<T> items) {
|
||||
return setSelectedItems(items, true);
|
||||
}
|
||||
public final boolean setSelectedItems(Iterable<T> items, boolean scrollIntoView) {
|
||||
List<Integer> indices = new ArrayList<>();
|
||||
for (T item : items) {
|
||||
int index = getIndexOfItem(item);
|
||||
if (index != -1) {
|
||||
indices.add(index);
|
||||
}
|
||||
}
|
||||
if (indices.size() > 0) {
|
||||
onSetSelectedIndices(indices);
|
||||
if (scrollIntoView) {
|
||||
scrollSelectionIntoView();
|
||||
}
|
||||
onSelectionChange();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setSelectedIndex(int index) {
|
||||
setSelectedIndex(index, true);
|
||||
}
|
||||
public void setSelectedIndex(int index, boolean scrollIntoView) {
|
||||
int count = getCount();
|
||||
if (count == 0) { return; }
|
||||
if (maxSelections == 0) { return; }
|
||||
|
||||
if (index < 0) {
|
||||
if (index == -1 && minSelections == 0) { //allow passing -1 to clear selection if no selection allowed
|
||||
if (getSelectionCount() > 0) {
|
||||
onSetSelectedIndices(new ArrayList<>());
|
||||
onSelectionChange();
|
||||
}
|
||||
return;
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
else if (index >= count) {
|
||||
index = count - 1;
|
||||
}
|
||||
|
||||
onSetSelectedIndex(index);
|
||||
if (scrollIntoView) {
|
||||
scrollSelectionIntoView();
|
||||
}
|
||||
|
||||
onSelectionChange();
|
||||
}
|
||||
|
||||
public void setSelectedIndices(Iterable<Integer> indices) {
|
||||
setSelectedIndices(indices, true);
|
||||
}
|
||||
public void setSelectedIndices(Iterable<Integer> indices, boolean scrollIntoView) {
|
||||
int count = getCount();
|
||||
if (count == 0) { return; }
|
||||
|
||||
List<Integer> indexList = new ArrayList<>();
|
||||
for (Integer index : indices) {
|
||||
if (index >= 0 && index < count) {
|
||||
indexList.add(index);
|
||||
}
|
||||
}
|
||||
|
||||
if (indexList.isEmpty()) { //if no index in range, set selected index based on first index
|
||||
for (Integer index : indices) {
|
||||
setSelectedIndex(index);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
onSetSelectedIndices(indexList);
|
||||
if (scrollIntoView) {
|
||||
scrollSelectionIntoView();
|
||||
}
|
||||
|
||||
onSelectionChange();
|
||||
}
|
||||
|
||||
protected void onSelectionChange() {
|
||||
if (getSelectedIndex() != -1 || itemManager.getMultiSelectMode()) {
|
||||
if (itemManager.getSelectionChangedHandler() != null) {
|
||||
itemManager.getSelectionChangedHandler().handleEvent(new FEvent(itemManager, FEventType.CHANGE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setSelectionSupport(int minSelections0, int maxSelections0) {
|
||||
minSelections = minSelections0;
|
||||
maxSelections = maxSelections0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getCaption(); //return caption as string for display in combo box
|
||||
}
|
||||
|
||||
public abstract void setup(ItemManagerConfig config, Map<ColumnDef, ItemColumn> colOverrides);
|
||||
public abstract T getItemAtIndex(int index);
|
||||
public abstract int getIndexOfItem(T item);
|
||||
public abstract int getSelectedIndex();
|
||||
public abstract Iterable<Integer> getSelectedIndices();
|
||||
public abstract void selectAll();
|
||||
public abstract int getCount();
|
||||
public abstract int getSelectionCount();
|
||||
public abstract int getIndexAtPoint(float x, float y);
|
||||
public abstract void scrollSelectionIntoView();
|
||||
public abstract Rectangle getSelectionBounds();
|
||||
public abstract FImage getIcon();
|
||||
public abstract String getCaption();
|
||||
protected abstract void onSetSelectedIndex(int index);
|
||||
protected abstract void onSetSelectedIndices(Iterable<Integer> indices);
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package forge.adventure.libgdxgui.menu;
|
||||
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FImage;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor.Colors;
|
||||
import forge.adventure.libgdxgui.toolbox.FCheckBox;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
|
||||
public class FCheckBoxMenuItem extends FMenuItem {
|
||||
public static final float CHECKBOX_SIZE = HEIGHT * 0.45f;
|
||||
public static final float PADDING = (HEIGHT - CHECKBOX_SIZE) / 3;
|
||||
public static final FSkinColor FORE_COLOR = FSkinColor.get(Colors.CLR_TEXT);
|
||||
public static final FSkinColor CHECKBOX_COLOR = FORE_COLOR.alphaColor(0.5f);
|
||||
|
||||
private final boolean checked;
|
||||
|
||||
public FCheckBoxMenuItem(String text0, boolean checked0, FEventHandler handler0) {
|
||||
this(text0, checked0, null, handler0, true);
|
||||
}
|
||||
public FCheckBoxMenuItem(String text0, boolean checked0, FEventHandler handler0, boolean enabled0) {
|
||||
this(text0, checked0, null, handler0, enabled0);
|
||||
}
|
||||
public FCheckBoxMenuItem(String text0, boolean checked0, FImage icon0, FEventHandler handler0) {
|
||||
this(text0, checked0, icon0, handler0, true);
|
||||
}
|
||||
public FCheckBoxMenuItem(String text0, boolean checked0, FImage icon0, FEventHandler handler0, boolean enabled0) {
|
||||
super(text0, icon0, handler0, enabled0);
|
||||
checked = checked0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinWidth() {
|
||||
return super.getMinWidth() + CHECKBOX_SIZE + 2 * PADDING - GAP_X;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g) {
|
||||
super.draw(g);
|
||||
|
||||
float w = CHECKBOX_SIZE;
|
||||
float h = CHECKBOX_SIZE;
|
||||
float x = getWidth() - PADDING - w;
|
||||
float y = (getHeight() - h) / 2;
|
||||
FCheckBox.drawCheckBox(g, CHECKBOX_COLOR, FORE_COLOR, checked, x, y, w, h);
|
||||
}
|
||||
}
|
||||
@@ -1,244 +0,0 @@
|
||||
package forge.adventure.libgdxgui.menu;
|
||||
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor.Colors;
|
||||
import forge.adventure.libgdxgui.assets.FSkinTexture;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.toolbox.FContainer;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.toolbox.FOverlay;
|
||||
import forge.adventure.libgdxgui.toolbox.FScrollPane;
|
||||
|
||||
public abstract class FDropDown extends FScrollPane {
|
||||
public static final FSkinColor BORDER_COLOR = FSkinColor.get(Colors.CLR_BORDERS);
|
||||
|
||||
private Backdrop backdrop;
|
||||
private FMenuTab menuTab;
|
||||
private FContainer dropDownContainer;
|
||||
protected ScrollBounds paneSize;
|
||||
|
||||
public FDropDown() {
|
||||
super.setVisible(false); //hide by default
|
||||
}
|
||||
|
||||
public FMenuTab getMenuTab() {
|
||||
return menuTab;
|
||||
}
|
||||
public void setMenuTab(FMenuTab menuTab0) {
|
||||
menuTab = menuTab0;
|
||||
}
|
||||
|
||||
public FContainer getDropDownContainer() {
|
||||
return dropDownContainer;
|
||||
}
|
||||
public void setDropDownContainer(FContainer dropDownContainer0) {
|
||||
dropDownContainer = dropDownContainer0;
|
||||
}
|
||||
|
||||
protected FContainer getContainer() {
|
||||
FContainer container = dropDownContainer;
|
||||
if (container == null) {
|
||||
container = FOverlay.getTopOverlay();
|
||||
if (container == null) {
|
||||
container = Forge.getCurrentScreen();
|
||||
}
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (isVisible()) {
|
||||
updateSizeAndPosition();
|
||||
}
|
||||
}
|
||||
|
||||
public void show() {
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean press(float x, float y) {
|
||||
return true; //prevent auto-hiding when drop down pressed
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
if (autoHide()) {
|
||||
hide(); //hide when tapped by default if configured for auto-hide
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean longPress(float x, float y) {
|
||||
return true; //prevent objects behind drop down handling long press
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean flick(float x, float y) {
|
||||
return true; //prevent objects behind drop down handling flick
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible0) {
|
||||
if (isVisible() == visible0) { return; }
|
||||
|
||||
//add/remove drop down from its container, current screen, or top overlay when its visibility changes
|
||||
FContainer container = getContainer();
|
||||
if (visible0) {
|
||||
updateSizeAndPosition();
|
||||
|
||||
if (autoHide()) { //add invisible backdrop if needed to allow auto-hiding when pressing outside drop down
|
||||
backdrop = new Backdrop();
|
||||
backdrop.setSize(container.getWidth(), container.getHeight());
|
||||
container.add(backdrop);
|
||||
}
|
||||
container.add(this);
|
||||
}
|
||||
else {
|
||||
container.remove(this);
|
||||
if (backdrop != null) {
|
||||
backdrop.setVisible(false);
|
||||
container.remove(backdrop);
|
||||
backdrop = null;
|
||||
}
|
||||
onHidden();
|
||||
}
|
||||
super.setVisible(visible0);
|
||||
}
|
||||
|
||||
protected void onHidden() {
|
||||
}
|
||||
|
||||
protected abstract boolean autoHide();
|
||||
protected abstract ScrollBounds updateAndGetPaneSize(float maxWidth, float maxVisibleHeight);
|
||||
|
||||
protected void updateSizeAndPosition() {
|
||||
if (menuTab == null) { return; }
|
||||
|
||||
Rectangle boundary = Forge.getCurrentScreen().getDropDownBoundary();
|
||||
|
||||
float x = menuTab.screenPos.x;
|
||||
float y = menuTab.screenPos.y + menuTab.getHeight();
|
||||
boolean showAbove;
|
||||
float maxVisibleHeight;
|
||||
if (y < boundary.y + boundary.height / 2) {
|
||||
showAbove = false;
|
||||
maxVisibleHeight = boundary.y + boundary.height - y; //prevent covering prompt
|
||||
}
|
||||
else { //handle drop downs at near bottom of screen
|
||||
showAbove = true;
|
||||
y = menuTab.screenPos.y;
|
||||
maxVisibleHeight = y - boundary.y;
|
||||
}
|
||||
|
||||
paneSize = updateAndGetPaneSize(boundary.width, maxVisibleHeight);
|
||||
|
||||
//round width and height so borders appear properly
|
||||
paneSize = new ScrollBounds(Math.round(paneSize.getWidth()), Math.round(paneSize.getHeight()));
|
||||
if (x + paneSize.getWidth() > boundary.x + boundary.width) {
|
||||
x = boundary.x + boundary.width - paneSize.getWidth();
|
||||
}
|
||||
float height = Math.min(paneSize.getHeight(), maxVisibleHeight);
|
||||
if (showAbove) {
|
||||
//make drop down appear above
|
||||
y -= height;
|
||||
}
|
||||
|
||||
setBounds(Math.round(x), Math.round(y), paneSize.getWidth(), height);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) {
|
||||
return paneSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackground(Graphics g) {
|
||||
float w = getWidth();
|
||||
float h = getHeight();
|
||||
g.drawImage(FSkinTexture.BG_TEXTURE, 0, 0, w, h);
|
||||
g.fillRect(FScreen.TEXTURE_OVERLAY_COLOR, 0, 0, w, h);
|
||||
}
|
||||
|
||||
protected boolean drawAboveOverlay() {
|
||||
return true; //draw drop downs above screen overlay by default
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawOverlay(Graphics g) {
|
||||
super.drawOverlay(g);
|
||||
float w = getWidth();
|
||||
float h = getHeight();
|
||||
g.drawRect(2, BORDER_COLOR, 0, 0, w, h); //ensure border shows up on all sides
|
||||
}
|
||||
|
||||
protected FDisplayObject getDropDownOwner() {
|
||||
return menuTab;
|
||||
}
|
||||
|
||||
protected boolean hideBackdropOnPress(float x, float y) {
|
||||
FDisplayObject owner = getDropDownOwner();
|
||||
return owner == null || !owner.screenPos.contains(x, y); //auto-hide when backdrop pressed unless over owner
|
||||
}
|
||||
|
||||
protected boolean preventOwnerHandlingBackupTap(float x, float y, int count) {
|
||||
//prevent owner handling this tap unless it's a sub menu and not over it
|
||||
FDisplayObject owner = getDropDownOwner();
|
||||
if (owner instanceof FSubMenu) {
|
||||
return owner.contains(owner.getLeft() + owner.screenToLocalX(x), owner.getTop() + owner.screenToLocalY(y));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private class Backdrop extends FDisplayObject {
|
||||
private Backdrop() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean press(float x, float y) {
|
||||
if (hideBackdropOnPress(localToScreenX(x), y)) {
|
||||
hide();
|
||||
}
|
||||
return false; //allow press to pass through to object behind backdrop
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
if (!isVisible()) { return false; }
|
||||
hide(); //always hide if tapped
|
||||
|
||||
return preventOwnerHandlingBackupTap(x, y, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pan(float x, float y, float deltaX, float deltaY, boolean moreVertical) {
|
||||
hide(); //always hide if backdrop panned
|
||||
return false; //allow pan to pass through to object behind backdrop
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fling(float velocityX, float velocityY) {
|
||||
hide(); //always hide if backdrop flung
|
||||
return false; //allow fling to pass through to object behind backdrop
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean zoom(float x, float y, float amount) {
|
||||
hide(); //always hide if backdrop zoomed
|
||||
return false; //allow zoom to pass through to object behind backdrop
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g) {
|
||||
//draw nothing for backdrop
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package forge.adventure.libgdxgui.menu;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class FDropDownMenu extends FDropDown {
|
||||
protected final List<FMenuItem> items = new ArrayList<>();
|
||||
|
||||
public FDropDownMenu() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoHide() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract void buildMenu();
|
||||
|
||||
@Override
|
||||
protected ScrollBounds updateAndGetPaneSize(float maxWidth, float maxVisibleHeight) {
|
||||
clear();
|
||||
items.clear();
|
||||
|
||||
buildMenu();
|
||||
|
||||
//ensure text is all aligned if some items have icons and others don't
|
||||
boolean allowForIcon = false;
|
||||
for (FMenuItem item : items) {
|
||||
if (item.hasIcon()) {
|
||||
allowForIcon = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (FMenuItem item : items) {
|
||||
item.setAllowForIcon(allowForIcon);
|
||||
}
|
||||
|
||||
//determine needed width of menu
|
||||
float width = determineMenuWidth();
|
||||
if (width > maxWidth) {
|
||||
width = maxWidth;
|
||||
}
|
||||
|
||||
//set bounds for each item
|
||||
float y = 0;
|
||||
for (FMenuItem item : items) {
|
||||
item.setBounds(0, y, width, FMenuItem.HEIGHT);
|
||||
y += FMenuItem.HEIGHT;
|
||||
}
|
||||
|
||||
return new ScrollBounds(width, y);
|
||||
}
|
||||
|
||||
protected float determineMenuWidth() {
|
||||
float width = 0;
|
||||
for (FMenuItem item : items) {
|
||||
float minWidth = item.getMinWidth();
|
||||
if (width < minWidth) {
|
||||
width = minWidth;
|
||||
}
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
public void addItem(FMenuItem item) {
|
||||
if (item.isVisible()) {
|
||||
items.add(add(item));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
super.tap(x, y, count);
|
||||
return !(getDropDownOwner() instanceof FSubMenu); //return false so owning sub menu can be hidden
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package forge.adventure.libgdxgui.menu;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.assets.TextRenderer;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.util.TextBounds;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
|
||||
public class FMagnifyView extends FDropDown {
|
||||
private static final float PADDING = Utils.scale(5);
|
||||
|
||||
private FDisplayObject owner;
|
||||
private String text;
|
||||
private FSkinColor foreColor, backColor;
|
||||
private FSkinFont font;
|
||||
private TextRenderer renderer;
|
||||
|
||||
public static void show(FDisplayObject owner0, String text0, FSkinColor foreColor0, FSkinColor backColor0, FSkinFont font0, boolean parseReminderText0) {
|
||||
FMagnifyView view = new FMagnifyView();
|
||||
view.owner = owner0;
|
||||
view.text = text0;
|
||||
view.foreColor = foreColor0;
|
||||
view.backColor = backColor0;
|
||||
view.font = font0;
|
||||
view.renderer = new TextRenderer(parseReminderText0);
|
||||
view.show();
|
||||
}
|
||||
private FMagnifyView() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateSizeAndPosition() {
|
||||
float x = owner.screenPos.x;
|
||||
float y = owner.screenPos.y + owner.getHeight();
|
||||
paneSize = updateAndGetPaneSize(owner.getWidth(), y);
|
||||
float height = paneSize.getHeight();
|
||||
if (height > y) {
|
||||
height = y;
|
||||
}
|
||||
y -= height;
|
||||
|
||||
setBounds(Math.round(x), Math.round(y), Math.round(owner.getWidth()), Math.round(height));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoHide() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FDisplayObject getDropDownOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScrollBounds updateAndGetPaneSize(float maxWidth, float maxVisibleHeight) {
|
||||
TextBounds bounds = renderer.getWrappedBounds(text, font, maxWidth - 2 * PADDING);
|
||||
return new ScrollBounds(maxWidth, bounds.height + 2 * PADDING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawBackground(Graphics g) {
|
||||
super.drawBackground(g);
|
||||
g.fillRect(backColor, 0, 0, getWidth(), getHeight());
|
||||
renderer.drawText(g, text, font, foreColor, PADDING - getScrollLeft(), PADDING - getScrollTop(), getScrollWidth() - 2 * PADDING, getScrollHeight() - 2 * PADDING, 0, getHeight(), true, Align.left, false);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package forge.adventure.libgdxgui.menu;
|
||||
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.screens.FScreen.Header;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FMenuBar extends Header {
|
||||
private final List<FMenuTab> tabs = new ArrayList<>();
|
||||
|
||||
public void addTab(String text0, FDropDown dropDown0) {
|
||||
FMenuTab tab = new FMenuTab(text0, this, dropDown0, tabs.size());
|
||||
dropDown0.setMenuTab(tab);
|
||||
tabs.add(add(tab));
|
||||
}
|
||||
|
||||
public float getPreferredHeight() {
|
||||
return Math.round(FMenuTab.FONT.getLineHeight() * 2f/*fixes touch for tall devices - old value 1.5f*/ + 2 * FMenuTab.PADDING);
|
||||
}
|
||||
|
||||
public int getTabCount() {
|
||||
return tabs.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
int visibleTabCount = 0;
|
||||
float minWidth = 0;
|
||||
for (FMenuTab tab : tabs) {
|
||||
if (tab.isVisible()) {
|
||||
minWidth += tab.getMinWidth();
|
||||
visibleTabCount++;
|
||||
}
|
||||
}
|
||||
int tabWidth;
|
||||
int x = 0;
|
||||
float dx = (width - minWidth) / visibleTabCount;
|
||||
for (FMenuTab tab : tabs) {
|
||||
if (tab.isVisible()) {
|
||||
tabWidth = Math.round(tab.getMinWidth() + dx);
|
||||
if (x + tabWidth > width) {
|
||||
tabWidth = Math.round(width - x); //prevent final tab extending off screen
|
||||
}
|
||||
tab.setBounds(x, 0, tabWidth, height);
|
||||
x += tabWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackground(Graphics g) {
|
||||
float w = getWidth();
|
||||
float h = getHeight();
|
||||
g.fillRect(BACK_COLOR, 0, 0, w, h);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float doLandscapeLayout(float screenWidth, float screenHeight) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
package forge.adventure.libgdxgui.menu;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.badlogic.gdx.utils.Timer;
|
||||
import com.badlogic.gdx.utils.Timer.Task;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FImage;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor.Colors;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.assets.TextRenderer;
|
||||
import forge.gui.UiCommand;
|
||||
import forge.gui.interfaces.IButton;
|
||||
import forge.localinstance.skin.FSkinProp;
|
||||
import forge.adventure.libgdxgui.screens.FScreen.Header;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventHandler;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent.FEventType;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
|
||||
public class FMenuItem extends FDisplayObject implements IButton {
|
||||
public static final float HEIGHT = Utils.AVG_FINGER_HEIGHT * 0.8f;
|
||||
protected static final float DIVOT_WIDTH = HEIGHT / 6;
|
||||
protected static final float GAP_X = HEIGHT * 0.1f;
|
||||
private static final float ICON_SIZE = ((int)((HEIGHT - 2 * GAP_X) / 20f)) * 20; //round down to nearest multiple of 20
|
||||
|
||||
private static final FSkinFont FONT = FSkinFont.get(12);
|
||||
protected static final FSkinColor FORE_COLOR = FSkinColor.get(Colors.CLR_TEXT);
|
||||
private static final FSkinColor PRESSED_COLOR = FSkinColor.get(Colors.CLR_ACTIVE).alphaColor(0.9f);
|
||||
private static final FSkinColor SEPARATOR_COLOR = FORE_COLOR.alphaColor(0.5f);
|
||||
private static final FSkinColor TAB_SEPARATOR_COLOR = Header.BACK_COLOR.stepColor(-40);
|
||||
|
||||
private final String text;
|
||||
private final FImage icon;
|
||||
private final FEventHandler handler;
|
||||
private boolean pressed, allowForIcon, selected, tabMode;
|
||||
private final float textWidth;
|
||||
private TextRenderer textRenderer;
|
||||
|
||||
public FMenuItem(String text0, FEventHandler handler0) {
|
||||
this(text0, null, handler0, true);
|
||||
}
|
||||
public FMenuItem(String text0, FEventHandler handler0, boolean enabled0) {
|
||||
this(text0, null, handler0, enabled0);
|
||||
}
|
||||
public FMenuItem(String text0, FImage icon0, FEventHandler handler0) {
|
||||
this(text0, icon0, handler0, true);
|
||||
}
|
||||
public FMenuItem(String text0, FImage icon0, FEventHandler handler0, boolean enabled0) {
|
||||
text = text0;
|
||||
icon = icon0;
|
||||
handler = handler0;
|
||||
setEnabled(enabled0);
|
||||
|
||||
textWidth = FONT.getBounds(text).width;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public boolean hasIcon() {
|
||||
return icon != null;
|
||||
}
|
||||
|
||||
public void setAllowForIcon(boolean allowForIcon0) {
|
||||
allowForIcon = allowForIcon0;
|
||||
}
|
||||
|
||||
public void setTabMode(boolean tabMode0) {
|
||||
tabMode = tabMode0;
|
||||
}
|
||||
|
||||
public void setTextRenderer(TextRenderer textRenderer0) {
|
||||
textRenderer = textRenderer0;
|
||||
}
|
||||
|
||||
public float getMinWidth() {
|
||||
//pretend there's a divot even if there isn't to provide extra right padding and allow menu items to line up nicer
|
||||
float width = textWidth + DIVOT_WIDTH + 4 * GAP_X;
|
||||
if (allowForIcon) {
|
||||
width += ICON_SIZE + GAP_X;
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean press(float x, float y) {
|
||||
pressed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release(float x, float y) {
|
||||
pressed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private final Task handleTapTask = new Task() {
|
||||
@Override
|
||||
public void run () {
|
||||
handler.handleEvent(new FEvent(FMenuItem.this, FEventType.TAP));
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
Timer.schedule(handleTapTask, 0.1f); //delay handling tap just long enough for menu to be hidden
|
||||
return false; //return false so parent can use event to hide menu
|
||||
}
|
||||
|
||||
protected boolean showPressedColor() {
|
||||
return (pressed && !tabMode) || selected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g) {
|
||||
float w = getWidth();
|
||||
float h = HEIGHT;
|
||||
|
||||
if (showPressedColor()) {
|
||||
g.fillRect(PRESSED_COLOR, 0, 0, w, h);
|
||||
}
|
||||
|
||||
float x = GAP_X;
|
||||
|
||||
if (allowForIcon) {
|
||||
if (icon != null) {
|
||||
g.drawImage(icon, x, (h - ICON_SIZE) / 2, ICON_SIZE, ICON_SIZE);
|
||||
}
|
||||
//account for not having icon but having been given icon size for alignment with other items
|
||||
x += ICON_SIZE + GAP_X;
|
||||
}
|
||||
|
||||
if (textRenderer == null) {
|
||||
g.drawText(text, FONT, FORE_COLOR, x, 0, w - x - GAP_X, h, false, Align.left, true);
|
||||
}
|
||||
else {
|
||||
textRenderer.drawText(g, text, FONT, FORE_COLOR, x, 0, w - x - GAP_X, h, 0, h, false, Align.left, true);
|
||||
}
|
||||
|
||||
//draw separator line
|
||||
if (tabMode) {
|
||||
g.drawLine(1, TAB_SEPARATOR_COLOR, 0, h, w, h);
|
||||
}
|
||||
else {
|
||||
g.drawLine(1, SEPARATOR_COLOR, 0, h, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(String text0) {
|
||||
}
|
||||
@Override
|
||||
public boolean isSelected() {
|
||||
return selected;
|
||||
}
|
||||
@Override
|
||||
public void setSelected(boolean b0) {
|
||||
selected = b0;
|
||||
}
|
||||
@Override
|
||||
public boolean requestFocusInWindow() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public void setCommand(UiCommand command0) {
|
||||
}
|
||||
@Override
|
||||
public void setImage(FSkinProp color) {
|
||||
}
|
||||
@Override
|
||||
public void setTextColor(int r, int g, int b) {
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package forge.adventure.libgdxgui.menu;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor.Colors;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
|
||||
public class FMenuTab extends FDisplayObject {
|
||||
public static final FSkinFont FONT = FSkinFont.get(12);
|
||||
private static final FSkinColor SEL_BACK_COLOR = FSkinColor.get(Colors.CLR_ACTIVE);
|
||||
private static final FSkinColor SEL_BORDER_COLOR = FDropDown.BORDER_COLOR;
|
||||
private static final FSkinColor SEL_FORE_COLOR = FSkinColor.get(Colors.CLR_TEXT);
|
||||
private static final FSkinColor FORE_COLOR = SEL_FORE_COLOR.alphaColor(0.5f);
|
||||
private static final FSkinColor SEPARATOR_COLOR = SEL_FORE_COLOR.alphaColor(0.3f);
|
||||
public static final float PADDING = Utils.scale(2);
|
||||
private static final float SEPARATOR_WIDTH = Utils.scale(1);
|
||||
|
||||
private final FMenuBar menuBar;
|
||||
private final FDropDown dropDown;
|
||||
|
||||
private String text;
|
||||
private float minWidth;
|
||||
private final int index;
|
||||
|
||||
public FMenuTab(String text0, FMenuBar menuBar0, FDropDown dropDown0, int index0) {
|
||||
menuBar = menuBar0;
|
||||
dropDown = dropDown0;
|
||||
index = index0;
|
||||
setText(text0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
if (dropDown.isVisible()) {
|
||||
dropDown.hide();
|
||||
}
|
||||
else {
|
||||
dropDown.show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setText(String text0) {
|
||||
text = text0;
|
||||
minWidth = FONT.getBounds(text).width;
|
||||
menuBar.revalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible0) {
|
||||
if (isVisible() == visible0) { return; }
|
||||
super.setVisible(visible0);
|
||||
if (!visible0) {
|
||||
dropDown.hide();
|
||||
}
|
||||
if (menuBar != null) {
|
||||
menuBar.revalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public float getMinWidth() {
|
||||
return minWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g) {
|
||||
float x, y, w, h;
|
||||
|
||||
FSkinColor foreColor;
|
||||
if (dropDown.isVisible()) {
|
||||
x = PADDING; //round so lines show up reliably
|
||||
y = PADDING;
|
||||
w = getWidth() - 2 * x + 1;
|
||||
h = getHeight() - y + 1;
|
||||
|
||||
g.startClip(x, y, w, h);
|
||||
g.fillRect(SEL_BACK_COLOR, x, y, w, h);
|
||||
g.drawRect(2, SEL_BORDER_COLOR, x, y, w, h);
|
||||
g.endClip();
|
||||
|
||||
foreColor = SEL_FORE_COLOR;
|
||||
}
|
||||
else {
|
||||
foreColor = FORE_COLOR;
|
||||
}
|
||||
|
||||
//draw right separator
|
||||
if (index < menuBar.getTabCount() - 1) {
|
||||
x = getWidth();
|
||||
y = getHeight() / 4;
|
||||
g.drawLine(SEPARATOR_WIDTH, SEPARATOR_COLOR, x, y, x, getHeight() - y);
|
||||
}
|
||||
|
||||
x = PADDING;
|
||||
y = PADDING;
|
||||
w = getWidth() - 2 * PADDING;
|
||||
h = getHeight() - 2 * PADDING;
|
||||
g.drawText(text, FONT, foreColor, x, y, w, h, false, Align.center, true);
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
package forge.adventure.libgdxgui.menu;
|
||||
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.toolbox.FButton;
|
||||
import forge.adventure.libgdxgui.toolbox.FLabel;
|
||||
|
||||
public abstract class FPopupMenu extends FDropDownMenu {
|
||||
private FDisplayObject owner;
|
||||
private float x, y;
|
||||
private Vector2 pressPoint, fixedSize;
|
||||
|
||||
public void show(FDisplayObject owner0, float x0, float y0) {
|
||||
owner = owner0;
|
||||
x = owner.localToScreenX(x0);
|
||||
y = owner.localToScreenY(y0);
|
||||
|
||||
if (owner instanceof FLabel || owner instanceof FButton) {
|
||||
//if owner is FLabel or FButton, keep them pressed while menu open
|
||||
owner.press(x0, y0);
|
||||
pressPoint = new Vector2(x0, y0);
|
||||
}
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
public void show(float screenX, float screenY, float fixedWidth, float fixedHeight) {
|
||||
x = screenX;
|
||||
y = screenY;
|
||||
fixedSize = new Vector2(fixedWidth, fixedHeight);
|
||||
setDropDownContainer(Forge.getCurrentScreen());
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FDisplayObject getDropDownOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHidden() {
|
||||
if (pressPoint != null) {
|
||||
//if owner kept pressed while open, release when menu hidden
|
||||
owner.release(pressPoint.x, pressPoint.y);
|
||||
pressPoint = null;
|
||||
}
|
||||
owner = null;
|
||||
fixedSize = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateSizeAndPosition() {
|
||||
if (fixedSize != null) {
|
||||
paneSize = updateAndGetPaneSize(fixedSize.x, fixedSize.y);
|
||||
setBounds(x, y, fixedSize.x, fixedSize.y);
|
||||
for (FMenuItem item : items) {
|
||||
item.setTabMode(true); //ensure items in fixed size menu are treated as tabs
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
FScreen screen = Forge.getCurrentScreen();
|
||||
float screenWidth = screen.getWidth();
|
||||
float screenHeight = screen.getHeight();
|
||||
|
||||
paneSize = updateAndGetPaneSize(screenWidth, screenHeight);
|
||||
|
||||
//round width and height so borders appear properly
|
||||
paneSize = new ScrollBounds(Math.round(paneSize.getWidth()), Math.round(paneSize.getHeight()));
|
||||
|
||||
if (x + paneSize.getWidth() > screenWidth) {
|
||||
x = screenWidth - paneSize.getWidth();
|
||||
}
|
||||
if (y + paneSize.getHeight() > screenHeight) {
|
||||
y = screenHeight - paneSize.getHeight();
|
||||
}
|
||||
|
||||
setBounds(Math.round(x), Math.round(y), paneSize.getWidth(), paneSize.getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float determineMenuWidth() {
|
||||
if (fixedSize != null) {
|
||||
return fixedSize.x;
|
||||
}
|
||||
return super.determineMenuWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoHide() {
|
||||
return fixedSize == null; //don't auto-hide if menu has fixed size
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackground(Graphics g) {
|
||||
if (fixedSize == null) { //avoid showing background if menu has fixed size
|
||||
super.drawBackground(g);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawOverlay(Graphics g) {
|
||||
if (fixedSize == null) { //avoid showing overlay if menu has fixed size
|
||||
super.drawOverlay(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package forge.adventure.libgdxgui.menu;
|
||||
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FImage;
|
||||
|
||||
public class FSubMenu extends FMenuItem {
|
||||
FPopupMenu popupMenu;
|
||||
|
||||
public FSubMenu(String text0, FPopupMenu popupMenu0) {
|
||||
this(text0, null, popupMenu0, true);
|
||||
}
|
||||
public FSubMenu(String text0, FPopupMenu popupMenu0, boolean enabled0) {
|
||||
this(text0, null, popupMenu0, enabled0);
|
||||
}
|
||||
public FSubMenu(String text0, FImage icon0, final FPopupMenu popupMenu0) {
|
||||
this(text0, icon0, popupMenu0, true);
|
||||
}
|
||||
public FSubMenu(String text0, FImage icon0, final FPopupMenu popupMenu0, boolean enabled0) {
|
||||
super(text0, icon0, null, enabled0);
|
||||
popupMenu = popupMenu0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean showPressedColor() {
|
||||
return super.showPressedColor() || popupMenu.isVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
if (popupMenu.isVisible()) {
|
||||
popupMenu.hide();
|
||||
}
|
||||
else {
|
||||
popupMenu.show(this, getWidth(), 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g) {
|
||||
super.draw(g);
|
||||
|
||||
float divotWidth = DIVOT_WIDTH;
|
||||
float divotHeight = divotWidth * 2f;
|
||||
float x2 = getWidth() - GAP_X - 1;
|
||||
float x1 = x2 - divotWidth;
|
||||
float x3 = x1;
|
||||
float y2 = getHeight() / 2;
|
||||
float y1 = y2 - divotHeight / 2;
|
||||
float y3 = y2 + divotHeight / 2;
|
||||
g.fillTriangle(FORE_COLOR, x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package forge.adventure.libgdxgui.menu;
|
||||
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor.Colors;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.screens.FScreen;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.util.TextBounds;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
|
||||
public class FTooltip extends FDropDown {
|
||||
private static final FSkinFont FONT = FSkinFont.get(12);
|
||||
private static final FSkinColor FORE_COLOR = FSkinColor.get(Colors.CLR_TEXT);
|
||||
private static final float PADDING = Utils.scale(5);
|
||||
|
||||
private FDisplayObject owner;
|
||||
private float x, y;
|
||||
private final String text;
|
||||
|
||||
public void show(FDisplayObject owner0, float x0, float y0) {
|
||||
owner = owner0;
|
||||
x = owner.localToScreenX(x0);
|
||||
y = owner.localToScreenY(y0);
|
||||
show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateSizeAndPosition() {
|
||||
FScreen screen = Forge.getCurrentScreen();
|
||||
float screenWidth = screen.getWidth();
|
||||
float screenHeight = screen.getHeight();
|
||||
|
||||
paneSize = updateAndGetPaneSize(screenWidth, screenHeight);
|
||||
if (x + paneSize.getWidth() > screenWidth) {
|
||||
x = screenWidth - paneSize.getWidth();
|
||||
}
|
||||
if (y + paneSize.getHeight() > screenHeight) {
|
||||
y = screenHeight - paneSize.getHeight();
|
||||
}
|
||||
|
||||
setBounds(Math.round(x), Math.round(y), Math.round(paneSize.getWidth()), Math.round(paneSize.getHeight()));
|
||||
}
|
||||
|
||||
public FTooltip(String text0) {
|
||||
text = text0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoHide() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FDisplayObject getDropDownOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScrollBounds updateAndGetPaneSize(float maxWidth, float maxVisibleHeight) {
|
||||
TextBounds bounds = FONT.getWrappedBounds(text, maxWidth - 2 * PADDING);
|
||||
return new ScrollBounds(Math.min(maxWidth, bounds.width + 2 * PADDING), bounds.height + 2 * PADDING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawBackground(Graphics g) {
|
||||
super.drawBackground(g);
|
||||
g.drawText(text, FONT, FORE_COLOR, PADDING - getScrollLeft(), PADDING - getScrollTop(), getScrollWidth() - 2 * PADDING, getScrollHeight() - 2 * PADDING, true, Align.left, false);
|
||||
}
|
||||
}
|
||||
@@ -1,397 +0,0 @@
|
||||
package forge.adventure.libgdxgui.screens;
|
||||
|
||||
import com.badlogic.gdx.Input.Keys;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FImage;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.assets.FSkinTexture;
|
||||
import forge.adventure.libgdxgui.menu.FPopupMenu;
|
||||
import forge.adventure.libgdxgui.screens.settings.SettingsScreen;
|
||||
import forge.adventure.libgdxgui.toolbox.FContainer;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.toolbox.FEvent;
|
||||
import forge.adventure.libgdxgui.toolbox.FLabel;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.util.Callback;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class FScreen extends forge.adventure.libgdxgui.toolbox.FContainer {
|
||||
public static final FSkinColor TEXTURE_OVERLAY_COLOR = FSkinColor.get(FSkinColor.Colors.CLR_THEME);
|
||||
|
||||
private final Header header;
|
||||
|
||||
protected FScreen(String headerCaption) {
|
||||
this(headerCaption == null ? null : new DefaultHeader(headerCaption));
|
||||
}
|
||||
protected FScreen(String headerCaption, FPopupMenu menu) {
|
||||
this(new MenuHeader(headerCaption, menu));
|
||||
}
|
||||
protected FScreen(Header header0) {
|
||||
header = header0;
|
||||
if (header != null) {
|
||||
add(header);
|
||||
}
|
||||
}
|
||||
|
||||
public Header getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public void setHeaderCaption(String headerCaption) {
|
||||
if (header instanceof DefaultHeader) {
|
||||
((DefaultHeader)header).lblCaption.setText(headerCaption);
|
||||
}
|
||||
}
|
||||
|
||||
public Rectangle getDropDownBoundary() {
|
||||
return new Rectangle(0, 0, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
public void onActivate() {
|
||||
}
|
||||
|
||||
public void onSwitchAway(Callback<Boolean> canSwitchCallback) {
|
||||
canSwitchCallback.run(true);
|
||||
}
|
||||
|
||||
public void onClose(Callback<Boolean> canCloseCallback) {
|
||||
if (canCloseCallback != null) { //will be null if app exited
|
||||
canCloseCallback.run(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void showMenu() {
|
||||
if (header instanceof MenuHeader) {
|
||||
((MenuHeader)header).btnMenu.trigger();
|
||||
}
|
||||
else { //just so settings screen if no menu header
|
||||
SettingsScreen.show(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void doLayout(float width, float height) {
|
||||
if ((GuiBase.isAndroid() && Forge.isLandscapeMode())||(width > height)) {
|
||||
doLandscapeLayout(width, height); //handle landscape layout special
|
||||
} else if (header != null) {
|
||||
header.setBounds(0, 0, width, header.getPreferredHeight());
|
||||
doLayout(header.getHeight(), width, height);
|
||||
} else {
|
||||
doLayout(0, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void doLayout(float startY, float width, float height);
|
||||
|
||||
//do layout for landscape mode and return width for any screen hosted on top of this screen
|
||||
protected float doLandscapeLayout(float width, float height) {
|
||||
//just use normal doLayout function by default after making room for header menu
|
||||
float startY = 0;
|
||||
if (header != null) {
|
||||
float headerWidth = header.doLandscapeLayout(width, height);
|
||||
if (headerWidth == 0) { //if header doesn't support landscape layout, make room for it at top
|
||||
header.setBounds(0, 0, width, header.getPreferredHeight());
|
||||
startY += header.getHeight();
|
||||
}
|
||||
else { //otherwise make room for it on right
|
||||
width -= headerWidth;
|
||||
}
|
||||
}
|
||||
doLayout(startY, width, height);
|
||||
return width;
|
||||
}
|
||||
|
||||
//get screen to serve as the backdrop for this screen when in landscape mode
|
||||
public FScreen getLandscapeBackdropScreen() {
|
||||
return null; //use home screen as backdrop when in landscape mode by default
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSize(float width, float height) {
|
||||
if (Forge.isLandscapeMode()) {
|
||||
//adjust size if in landscape mode and has a backdrop
|
||||
FScreen backdrop = getLandscapeBackdropScreen();
|
||||
if (backdrop != null) {
|
||||
width = backdrop.doLandscapeLayout(width, height);
|
||||
}
|
||||
}
|
||||
if (getWidth() == width && getHeight() == height) {
|
||||
if (header != null) {
|
||||
header.onScreenActivate(); //let header handle when screen activated
|
||||
}
|
||||
return;
|
||||
}
|
||||
super.setSize(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildTouchListeners(float screenX, float screenY, List<FDisplayObject> listeners) {
|
||||
if (Forge.isLandscapeMode()) {
|
||||
//allow touch events on backdrop screen if any
|
||||
FScreen backdrop = getLandscapeBackdropScreen();
|
||||
if (backdrop != null) {
|
||||
backdrop.buildTouchListeners(screenX, screenY, listeners);
|
||||
}
|
||||
}
|
||||
super.buildTouchListeners(screenX, screenY, listeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g) {
|
||||
if (Forge.isLandscapeMode() && getLeft() == 0) { //check that left is 0 to avoid infinite loop
|
||||
//draw landscape backdrop first if needed
|
||||
FScreen backdrop = getLandscapeBackdropScreen();
|
||||
if (backdrop != null) {
|
||||
g.draw(backdrop);
|
||||
//temporarily shift into position for drawing in front of backdrop
|
||||
setLeft(Forge.getScreenWidth() - getWidth());
|
||||
g.draw(this);
|
||||
setLeft(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.draw(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackground(Graphics g) {
|
||||
if (Forge.isLandscapeMode() && getLandscapeBackdropScreen() != null) {
|
||||
return; //don't draw background if this screen has a backdrop
|
||||
}
|
||||
float w = getWidth();
|
||||
float h = getHeight();
|
||||
g.drawImage(FSkinTexture.BG_TEXTURE, 0, 0, w, h);
|
||||
g.fillRect(TEXTURE_OVERLAY_COLOR, 0, 0, w, h);
|
||||
}
|
||||
|
||||
public static abstract class Header extends FContainer {
|
||||
public static final FSkinColor BTN_PRESSED_COLOR = TEXTURE_OVERLAY_COLOR.alphaColor(1f);
|
||||
public static final FSkinColor LINE_COLOR = BTN_PRESSED_COLOR.stepColor(-40);
|
||||
public static final FSkinColor BACK_COLOR = BTN_PRESSED_COLOR.stepColor(-80);
|
||||
public static final float LINE_THICKNESS = Utils.scale(1);
|
||||
|
||||
public abstract float getPreferredHeight();
|
||||
|
||||
//handle when screen activated
|
||||
protected void onScreenActivate() {
|
||||
}
|
||||
|
||||
//do layout for landscape mode and return needed width
|
||||
public abstract float doLandscapeLayout(float screenWidth, float screenHeight);
|
||||
}
|
||||
private static class DefaultHeader extends Header {
|
||||
protected static final float HEIGHT = Math.round(Utils.AVG_FINGER_HEIGHT * 0.8f);
|
||||
protected static final FSkinFont FONT = FSkinFont.get(16);
|
||||
|
||||
protected final FLabel btnBack, lblCaption;
|
||||
|
||||
public DefaultHeader(String headerCaption) {
|
||||
btnBack = add(new FLabel.Builder().icon(new BackIcon(HEIGHT, HEIGHT)).pressedColor(BTN_PRESSED_COLOR).align(Align.center).command(new FEvent.FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
Forge.back();
|
||||
}
|
||||
}).build());
|
||||
lblCaption = add(new FLabel.Builder().text(headerCaption).font(FONT).align(Align.center).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPreferredHeight() {
|
||||
return HEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float doLandscapeLayout(float screenWidth, float screenHeight) {
|
||||
return 0; //default header doesn't need to display for landscape mode
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawBackground(Graphics g) {
|
||||
g.fillRect(BACK_COLOR, 0, 0, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOverlay(Graphics g) {
|
||||
if (Forge.isLandscapeMode() && getWidth() < Forge.getCurrentScreen().getWidth()) {
|
||||
//in landscape mode, draw left border for sidebar if needed
|
||||
g.drawLine(LINE_THICKNESS, LINE_COLOR, 0, 0, 0, getHeight());
|
||||
return;
|
||||
}
|
||||
float y = HEIGHT - LINE_THICKNESS / 2;
|
||||
g.drawLine(LINE_THICKNESS, LINE_COLOR, 0, y, getWidth(), y);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
btnBack.setBounds(0, 0, height, height);
|
||||
lblCaption.setBounds(height, 0, width - 2 * height, height);
|
||||
}
|
||||
}
|
||||
protected static class MenuHeader extends DefaultHeader {
|
||||
private final FLabel btnMenu;
|
||||
private final FPopupMenu menu;
|
||||
|
||||
public MenuHeader(String headerCaption, FPopupMenu menu0) {
|
||||
super(headerCaption);
|
||||
menu = menu0;
|
||||
btnMenu = add(new FLabel.Builder().icon(new MenuIcon(HEIGHT, HEIGHT)).pressedColor(BTN_PRESSED_COLOR).align(Align.center).command(new FEvent.FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
menu.show(btnMenu, 0, HEIGHT);
|
||||
}
|
||||
}).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOverlay(Graphics g) {
|
||||
if (Forge.isLandscapeMode() && displaySidebarForLandscapeMode()) {
|
||||
//in landscape mode, draw left border for header
|
||||
g.drawLine(LINE_THICKNESS, LINE_COLOR, 0, 0, 0, getHeight());
|
||||
return;
|
||||
}
|
||||
super.drawOverlay(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
super.doLayout(width, height);
|
||||
|
||||
menu.hide(); //ensure menu hidden when screen resized
|
||||
|
||||
if (Forge.isLandscapeMode() && displaySidebarForLandscapeMode()) {
|
||||
//for landscape mode, hide menu button and display menu as sidebar
|
||||
btnBack.setBounds(0, 0, 0, 0);
|
||||
lblCaption.setBounds(0, 0, 0, 0);
|
||||
btnMenu.setBounds(0, 0, 0, 0);
|
||||
menu.show(getLeft(), 0, width, height);
|
||||
return;
|
||||
}
|
||||
|
||||
btnMenu.setBounds(width - height, 0, height, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onScreenActivate() {
|
||||
//ensure menu layout refreshed for sidebar when screen activated
|
||||
if (Forge.isLandscapeMode() && displaySidebarForLandscapeMode()) {
|
||||
menu.hide();
|
||||
menu.show(getLeft(), 0, getWidth(), getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean displaySidebarForLandscapeMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float doLandscapeLayout(float screenWidth, float screenHeight) {
|
||||
if (displaySidebarForLandscapeMode()) {
|
||||
float width = screenHeight * 0.8f;
|
||||
setBounds(screenWidth - width, 0, width, screenHeight);
|
||||
return width;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class BackIcon implements FImage {
|
||||
private static final float THICKNESS = Utils.scale(3);
|
||||
private static final FSkinColor COLOR = FSkinColor.get(FSkinColor.Colors.CLR_TEXT);
|
||||
|
||||
private final float width, height;
|
||||
public BackIcon(float width0, float height0) {
|
||||
width = width0;
|
||||
height = height0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
float xMid = x + w * 0.4f;
|
||||
float yMid = y + h / 2;
|
||||
float offsetX = h / 8;
|
||||
float offsetY = w / 4;
|
||||
|
||||
g.drawLine(THICKNESS, COLOR, xMid + offsetX, yMid - offsetY, xMid - offsetX, yMid + 1);
|
||||
g.drawLine(THICKNESS, COLOR, xMid - offsetX, yMid - 1, xMid + offsetX, yMid + offsetY);
|
||||
}
|
||||
}
|
||||
|
||||
protected static class MenuIcon implements FImage {
|
||||
private static final FSkinColor COLOR = FSkinColor.get(FSkinColor.Colors.CLR_TEXT);
|
||||
|
||||
private final float width, height;
|
||||
public MenuIcon(float width0, float height0) {
|
||||
width = width0;
|
||||
height = height0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||
float thickness = Math.round(h / 5);
|
||||
float delta = Math.round(thickness * 1.75f);
|
||||
y += (h - 2 * delta - thickness) / 2;
|
||||
|
||||
g.fillRect(COLOR, x, y, thickness, thickness);
|
||||
y += delta;
|
||||
g.fillRect(COLOR, x, y, thickness, thickness);
|
||||
y += delta;
|
||||
g.fillRect(COLOR, x, y, thickness, thickness);
|
||||
x += delta;
|
||||
y -= 2 * delta;
|
||||
w -= delta;
|
||||
g.fillRect(COLOR, x, y, w, thickness);
|
||||
y += delta;
|
||||
g.fillRect(COLOR, x, y, w, thickness);
|
||||
y += delta;
|
||||
g.fillRect(COLOR, x, y, w, thickness);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean allowBackInLandscapeMode() {
|
||||
return false; //don't allow going back if home screen is backdrop by default
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyDown(int keyCode) {
|
||||
if (keyCode == Keys.ESCAPE || keyCode == Keys.BACK) {
|
||||
if (Forge.endKeyInput()) { return true; }
|
||||
|
||||
if (Forge.isLandscapeMode() && !allowBackInLandscapeMode()) {
|
||||
Forge.exit(false); //prompt to exit if attempting to go back from screen that doesn't allow back in landscape mode
|
||||
return true;
|
||||
}
|
||||
Forge.back(); //go back on escape by default
|
||||
return true;
|
||||
}
|
||||
if (keyCode == Keys.F5) { //allow revalidating current screen when running desktop app
|
||||
revalidate();
|
||||
}
|
||||
return super.keyDown(keyCode);
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package forge.adventure.libgdxgui.screens;
|
||||
|
||||
import com.badlogic.gdx.Input.Keys;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinImage;
|
||||
import forge.adventure.libgdxgui.menu.FPopupMenu;
|
||||
import forge.adventure.libgdxgui.toolbox.FDisplayObject;
|
||||
import forge.adventure.libgdxgui.toolbox.FOptionPane;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
|
||||
public abstract class LaunchScreen extends FScreen {
|
||||
private static final float MAX_START_BUTTON_HEIGHT = 1.75f * Utils.AVG_FINGER_HEIGHT;
|
||||
private float START_BUTTON_RATIO = 0.f;
|
||||
private static final float PADDING = FOptionPane.PADDING;
|
||||
|
||||
protected final StartButton btnStart = add(new StartButton());
|
||||
|
||||
public LaunchScreen(String headerCaption) {
|
||||
super(headerCaption);
|
||||
}
|
||||
public LaunchScreen(String headerCaption, FPopupMenu menu) {
|
||||
super(headerCaption, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void doLayout(float startY, float width, float height) {
|
||||
if (Forge.hdstart)
|
||||
START_BUTTON_RATIO = FSkinImage.HDBTN_START_UP.getWidth() / FSkinImage.HDBTN_START_UP.getHeight();
|
||||
else
|
||||
START_BUTTON_RATIO = FSkinImage.BTN_START_UP.getWidth() / FSkinImage.BTN_START_UP.getHeight();
|
||||
|
||||
float buttonWidth = width - 2 * PADDING;
|
||||
float buttonHeight = buttonWidth / START_BUTTON_RATIO;
|
||||
if (buttonHeight > MAX_START_BUTTON_HEIGHT) {
|
||||
buttonHeight = MAX_START_BUTTON_HEIGHT;
|
||||
buttonWidth = buttonHeight * START_BUTTON_RATIO;
|
||||
}
|
||||
btnStart.setBounds((width - buttonWidth) / 2, height - buttonHeight - PADDING, buttonWidth, buttonHeight);
|
||||
|
||||
doLayoutAboveBtnStart(startY, width, height - buttonHeight - 2 * PADDING);
|
||||
}
|
||||
|
||||
protected abstract void doLayoutAboveBtnStart(float startY, float width, float height);
|
||||
protected abstract void startMatch();
|
||||
|
||||
protected class StartButton extends FDisplayObject {
|
||||
private boolean pressed;
|
||||
|
||||
/**
|
||||
* Instantiates a new FButton.
|
||||
*/
|
||||
public StartButton() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean press(float x, float y) {
|
||||
pressed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean release(float x, float y) {
|
||||
pressed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean tap(float x, float y, int count) {
|
||||
if (count == 1) {
|
||||
btnStart.setEnabled(false);
|
||||
startMatch();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g) {
|
||||
if (Forge.hdstart)
|
||||
g.drawImage(pressed ? FSkinImage.HDBTN_START_DOWN : FSkinImage.HDBTN_START_UP,
|
||||
0, 0, getWidth(), getHeight());
|
||||
else
|
||||
g.drawImage(pressed ? FSkinImage.BTN_START_DOWN : FSkinImage.BTN_START_UP,
|
||||
0, 0, getWidth(), getHeight());
|
||||
//its must be enabled or you can't start any game modes
|
||||
if (!Forge.isLoadingaMatch()) {
|
||||
if(!btnStart.isEnabled())
|
||||
btnStart.setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyDown(int keyCode) {
|
||||
switch (keyCode) {
|
||||
case Keys.ENTER:
|
||||
case Keys.SPACE:
|
||||
startMatch(); //start match on Enter or Space
|
||||
return true;
|
||||
}
|
||||
return super.keyDown(keyCode);
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
package forge.adventure.libgdxgui.screens;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkin;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.assets.FSkinImage;
|
||||
import forge.adventure.libgdxgui.toolbox.FOverlay;
|
||||
import forge.adventure.libgdxgui.util.Utils;
|
||||
import forge.gui.FThreads;
|
||||
import forge.util.ThreadUtil;
|
||||
|
||||
public class LoadingOverlay extends FOverlay {
|
||||
private static final float INSETS = Utils.scale(10);
|
||||
private static final float LOGO_SIZE_FACTOR = 0.7f;
|
||||
private static final float INSETS_FACTOR = 0.025f;
|
||||
private static final FSkinFont FONT = FSkinFont.get(22);
|
||||
private static final FSkinColor BACK_COLOR = FSkinColor.get(FSkinColor.Colors.CLR_ACTIVE).alphaColor(0.75f);
|
||||
private static final FSkinColor FORE_COLOR = FSkinColor.get(FSkinColor.Colors.CLR_TEXT);
|
||||
|
||||
public static void show(String caption0, final Runnable runnable) {
|
||||
final LoadingOverlay loader = new LoadingOverlay(caption0);
|
||||
loader.show(); //show loading overlay then delay running remaining logic so UI can respond
|
||||
ThreadUtil.invokeInGameThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
FThreads.invokeInEdtLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
runnable.run();
|
||||
loader.hide();
|
||||
loader.finishedloading(); //setLoadingaMatch to false
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void runBackgroundTask(String caption0, final Runnable task) {
|
||||
final LoadingOverlay loader = new LoadingOverlay(caption0);
|
||||
loader.show();
|
||||
FThreads.invokeInBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
task.run();
|
||||
FThreads.invokeInEdtLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
loader.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String caption;
|
||||
|
||||
public LoadingOverlay(String caption0) {
|
||||
caption = caption0;
|
||||
}
|
||||
|
||||
public void setCaption(String caption0) {
|
||||
caption = caption0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisibleOnScreen(FScreen screen) {
|
||||
return true; //allow LoadingOverlay to remain visible while transitioning between screens
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOverlay(Graphics g) {
|
||||
float x = INSETS;
|
||||
float panelWidth = getWidth() - 2 * INSETS;
|
||||
|
||||
if (Forge.isLandscapeMode()) {
|
||||
panelWidth = getHeight() - 2 * INSETS;
|
||||
x = (getWidth() - panelWidth) / 2;
|
||||
}
|
||||
|
||||
float padding = panelWidth * INSETS_FACTOR;
|
||||
float logoSize = panelWidth * LOGO_SIZE_FACTOR;
|
||||
float fontHeight = FONT.getCapHeight();
|
||||
float panelHeight = logoSize + fontHeight + 4 * padding;
|
||||
|
||||
float y = (getHeight() - panelHeight) / 2;
|
||||
float oldAlpha = g.getfloatAlphaComposite();
|
||||
//dark translucent back..
|
||||
g.setAlphaComposite(0.6f);
|
||||
g.fillRect(Color.BLACK, 0, 0, getWidth(), getHeight());
|
||||
g.setAlphaComposite(oldAlpha);
|
||||
//overlay
|
||||
g.fillRect(BACK_COLOR, x, y, panelWidth, panelHeight);
|
||||
g.drawRect(Utils.scale(2), FORE_COLOR, x, y, panelWidth, panelHeight);
|
||||
y += padding;
|
||||
if (FSkin.hdLogo == null)
|
||||
g.drawImage(FSkinImage.LOGO, (getWidth() - logoSize) / 2f, y, logoSize, logoSize);
|
||||
else
|
||||
g.drawImage(FSkin.hdLogo, (getWidth() - logoSize) / 2f, y, logoSize, logoSize);
|
||||
y += logoSize + padding;
|
||||
g.drawText(caption, FONT, FORE_COLOR, x, y, panelWidth, getHeight(), false, Align.center, false);
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
package forge.adventure.libgdxgui.screens;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import forge.adventure.libgdxgui.Forge;
|
||||
import forge.adventure.libgdxgui.Graphics;
|
||||
import forge.adventure.libgdxgui.assets.FSkinColor;
|
||||
import forge.adventure.libgdxgui.assets.FSkinFont;
|
||||
import forge.adventure.libgdxgui.assets.FSkinTexture;
|
||||
import forge.adventure.libgdxgui.toolbox.FContainer;
|
||||
import forge.adventure.libgdxgui.toolbox.FProgressBar;
|
||||
|
||||
public class SplashScreen extends FContainer {
|
||||
private TextureRegion background;
|
||||
private final FProgressBar progressBar;
|
||||
private FSkinFont disclaimerFont;
|
||||
private boolean preparedForDialogs;
|
||||
|
||||
public SplashScreen() {
|
||||
progressBar = new FProgressBar();
|
||||
progressBar.setDescription("Welcome to Forge");
|
||||
}
|
||||
|
||||
public FProgressBar getProgressBar() {
|
||||
return progressBar;
|
||||
}
|
||||
|
||||
public void setBackground(TextureRegion background0) {
|
||||
background = background0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
}
|
||||
|
||||
//prepare for showing dialogs on top of splash screen if needed
|
||||
public void prepareForDialogs() {
|
||||
if (preparedForDialogs) { return; }
|
||||
|
||||
//establish fallback colors for before actual colors are loaded
|
||||
Color defaultColor = new Color(0, 0, 0, 0);
|
||||
for (final FSkinColor.Colors c : FSkinColor.Colors.values()) {
|
||||
switch (c) {
|
||||
case CLR_BORDERS:
|
||||
case CLR_TEXT:
|
||||
c.setColor(FProgressBar.SEL_FORE_COLOR);
|
||||
break;
|
||||
case CLR_ACTIVE:
|
||||
case CLR_THEME2:
|
||||
c.setColor(FProgressBar.SEL_BACK_COLOR);
|
||||
break;
|
||||
case CLR_INACTIVE:
|
||||
c.setColor(FSkinColor.stepColor(FProgressBar.SEL_BACK_COLOR, -80));
|
||||
break;
|
||||
default:
|
||||
c.setColor(defaultColor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
FSkinColor.updateAll();
|
||||
preparedForDialogs = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackground(Graphics g) {
|
||||
if (background == null) { return; }
|
||||
|
||||
g.drawImage(FSkinTexture.BG_TEXTURE, 0, 0, getWidth(), getHeight());
|
||||
|
||||
float x, y, w, h;
|
||||
float backgroundRatio = background.getRegionWidth() / background.getRegionHeight();
|
||||
float screenRatio = getWidth() / getHeight();
|
||||
if (backgroundRatio > screenRatio) {
|
||||
x = 0;
|
||||
w = getWidth();
|
||||
h = getWidth() * backgroundRatio;
|
||||
y = (getHeight() - h) / 2;
|
||||
}
|
||||
else {
|
||||
y = 0;
|
||||
h = getHeight();
|
||||
w = getHeight() / backgroundRatio;
|
||||
x = (getWidth() - w) / 2;
|
||||
}
|
||||
g.drawImage(background, x, y, w, h);
|
||||
|
||||
y += h * 295f / 450f;
|
||||
if (disclaimerFont == null) {
|
||||
disclaimerFont = FSkinFont.get(9);
|
||||
}
|
||||
float disclaimerHeight = 30f / 450f * h;
|
||||
String disclaimer = "Forge is not affiliated in any way with Wizards of the Coast.\n"
|
||||
+ "Forge is open source software, released under the GNU General Public License.";
|
||||
g.drawText(disclaimer, disclaimerFont, FProgressBar.SEL_FORE_COLOR,
|
||||
x, y, w, disclaimerHeight, true, Align.center, true);
|
||||
|
||||
float padding = 20f / 450f * w;
|
||||
float pbHeight = 57f / 450f * h;
|
||||
y += 78f / 450f * h;
|
||||
progressBar.setBounds(x + padding, y, w - 2 * padding, pbHeight);
|
||||
g.draw(progressBar);
|
||||
|
||||
String version = "v. " + Forge.CURRENT_VERSION + " (Alpha)";
|
||||
g.drawText(version, disclaimerFont, FProgressBar.SEL_FORE_COLOR, x, getHeight() - disclaimerHeight, w, disclaimerHeight, false, Align.center, true);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user