- 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:
Grimm
2021-10-18 20:11:06 +02:00
parent 2966bdfc6a
commit 035976d165
182 changed files with 307 additions and 37329 deletions

View File

@@ -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>

View 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);
}

View 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;
}

View 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);
}

View 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;
}

View 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);
}

View 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);
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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;
}
}
}

View File

@@ -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();
}
}

View File

@@ -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");
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}
}

View File

@@ -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) {
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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(&quot;fonts/output.fnt&quot;), new FontInfo(&quot;Arial&quot;, 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);
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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; }
}

View File

@@ -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
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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
}
}

View File

@@ -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);
}
});
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}
}

View File

@@ -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;
}
};
}
}

View File

@@ -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;
}
};
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
};
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
};
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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());
}
};
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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
}
}
}

View File

@@ -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
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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) {
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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