mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 20:58:03 +00:00
Merge remote-tracking branch 'origin/master' into code-cleanup
# Conflicts: # forge-ai/src/main/java/forge/ai/AiAttackController.java # forge-ai/src/main/java/forge/ai/AiCardMemory.java # forge-ai/src/main/java/forge/ai/AiController.java # forge-core/src/main/java/forge/card/ICardDatabase.java # forge-core/src/main/java/forge/item/generation/BoosterGenerator.java # forge-core/src/main/java/forge/util/FileSection.java # forge-core/src/main/java/forge/util/collect/FCollection.java # forge-game/src/main/java/forge/game/card/CardProperty.java # forge-game/src/main/java/forge/game/combat/Combat.java # forge-game/src/main/java/forge/game/spellability/SpellAbility.java # forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java # forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/ACEditorBase.java # forge-gui-mobile/src/forge/itemmanager/ItemManager.java # forge-gui/src/main/java/forge/deck/DeckgenUtil.java # forge-gui/src/main/java/forge/gamemodes/limited/CardThemedDeckBuilder.java
This commit is contained in:
@@ -159,6 +159,9 @@ public class Forge implements ApplicationListener {
|
||||
public void create() {
|
||||
//install our error handler
|
||||
ExceptionHandler.registerErrorHandling();
|
||||
// closeSplashScreen() is called early on non-Windows OS so it will not crash, LWJGL3 bug on AWT Splash.
|
||||
if (OperatingSystem.isWindows())
|
||||
getDeviceAdapter().closeSplashScreen();
|
||||
|
||||
GuiBase.setIsAndroid(Gdx.app.getType() == Application.ApplicationType.Android);
|
||||
|
||||
@@ -257,8 +260,6 @@ public class Forge implements ApplicationListener {
|
||||
/* call preloadExtendedArt here, if we put it above we will *
|
||||
* get error: No OpenGL context found in the current thread. */
|
||||
preloadExtendedArt();
|
||||
// should be after create method but try to close this at a later time.
|
||||
getDeviceAdapter().closeSplashScreen();
|
||||
});
|
||||
};
|
||||
//see if app or assets need updating
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
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.GlyphLayout;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
@@ -33,7 +34,7 @@ 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 SpriteBatch batch = new SpriteBatch();
|
||||
private final Batch batch = new SpriteBatch();
|
||||
private final ShapeRenderer shapeRenderer = new ShapeRenderer();
|
||||
private final Deque<Matrix4> Dtransforms = new ArrayDeque<>();
|
||||
private final Vector3 tmp = new Vector3();
|
||||
@@ -114,7 +115,7 @@ public class Graphics {
|
||||
if (dummyTexture != null) dummyTexture.dispose();
|
||||
}
|
||||
|
||||
public SpriteBatch getBatch() {
|
||||
public Batch getBatch() {
|
||||
return batch;
|
||||
}
|
||||
|
||||
@@ -317,24 +318,14 @@ public class Graphics {
|
||||
}
|
||||
|
||||
public void drawLineArrow(float arrowThickness, FSkinColor skinColor, float x1, float y1, float x2, float y2) {
|
||||
fillCircle(skinColor.getColor(), x2, y2, arrowThickness);
|
||||
drawLineArrow(arrowThickness, skinColor.getColor(), x1, y1, x2, y2);
|
||||
fillCircle(Color.WHITE, x2, y2, arrowThickness / 2);
|
||||
drawLineArrow(arrowThickness / 3, Color.WHITE, x1, y1, x2, y2);
|
||||
//drawLine(arrowThickness / 3, Color.WHITE, x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
public void drawLineArrow(float thickness, Color color, float x1, float y1, float x2, float y2) {
|
||||
batch.end(); //must pause batch while rendering shapes
|
||||
float ct = thickness / 2;
|
||||
float lt = thickness / 3;
|
||||
|
||||
/*float angle = new Vector2(x1 - x2, y1 - y2).angleRad();
|
||||
float arrowHeadRotation = (float) (Math.PI * 0.8f);
|
||||
Vector2 arrowCorner3 = new Vector2(x2 + (thickness / 3) * (float) Math.cos(angle + arrowHeadRotation), y2 + (thickness / 3) * (float) Math.sin(angle + arrowHeadRotation));
|
||||
Vector2 arrowCorner4 = new Vector2(x2 + (thickness / 3) * (float) Math.cos(angle - arrowHeadRotation), y2 + (thickness / 3) * (float) Math.sin(angle - arrowHeadRotation));*/
|
||||
|
||||
if (thickness > 1) {
|
||||
Gdx.gl.glLineWidth(thickness);
|
||||
}
|
||||
if (alphaComposite < 1) {
|
||||
color = FSkinColor.alphaColor(color, color.a * alphaComposite);
|
||||
}
|
||||
@@ -345,12 +336,29 @@ public class Graphics {
|
||||
if (needSmoothing) {
|
||||
Gdx.gl.glEnable(GL_LINE_SMOOTH);
|
||||
}
|
||||
startShape(ShapeType.Filled);
|
||||
shapeRenderer.setColor(color);
|
||||
shapeRenderer.circle(adjustX(x2), adjustY(y2, 0), thickness);
|
||||
shapeRenderer.setColor(Color.WHITE);
|
||||
shapeRenderer.circle(adjustX(x2), adjustY(y2, 0), ct);
|
||||
endShape();
|
||||
|
||||
if (thickness > 1) {
|
||||
Gdx.gl.glLineWidth(thickness);
|
||||
}
|
||||
startShape(ShapeType.Line);
|
||||
shapeRenderer.setColor(color);
|
||||
shapeRenderer.line(adjustX(x1), adjustY(y1, 0), adjustX(x2), adjustY(y2, 0));
|
||||
endShape();
|
||||
|
||||
if (lt > 1) {
|
||||
Gdx.gl.glLineWidth(lt);
|
||||
}
|
||||
startShape(ShapeType.Line);
|
||||
shapeRenderer.setColor(Color.WHITE);
|
||||
shapeRenderer.line(adjustX(x1), adjustY(y1, 0), adjustX(x2), adjustY(y2, 0));
|
||||
endShape();
|
||||
|
||||
if (needSmoothing) {
|
||||
Gdx.gl.glDisable(GL_LINE_SMOOTH);
|
||||
}
|
||||
|
||||
@@ -277,11 +277,8 @@ public class World implements Disposable, SaveFileContent {
|
||||
for (int xclear = -size; xclear < size; xclear++)
|
||||
for (int yclear = -size; yclear < size; yclear++) {
|
||||
try {
|
||||
|
||||
terrainMap[x + xclear][height - 1 - (y + yclear)] = 0;
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,6 +341,9 @@ public class World implements Disposable, SaveFileContent {
|
||||
structure.initialize();
|
||||
structureDataMap.put(data, structure);
|
||||
return measureGenerationTime("wavefunctioncollapse " + data.sourcePath, threadStartTime);
|
||||
}).exceptionally(ex -> {
|
||||
ex.printStackTrace();
|
||||
return 0L;
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -648,7 +648,10 @@ public class World implements Disposable, SaveFileContent {
|
||||
startY = startY + sy;
|
||||
}
|
||||
}
|
||||
return 0l;
|
||||
return 0L;
|
||||
}).exceptionally(ex -> {
|
||||
ex.printStackTrace();
|
||||
return 0L;
|
||||
}));
|
||||
}
|
||||
futuresArray = futures.toArray(new CompletableFuture<?>[0]);
|
||||
@@ -689,7 +692,10 @@ public class World implements Disposable, SaveFileContent {
|
||||
startY = startY + sy;
|
||||
}
|
||||
}
|
||||
return 0l;
|
||||
return 0L;
|
||||
}).exceptionally(ex -> {
|
||||
ex.printStackTrace();
|
||||
return 0L;
|
||||
}));
|
||||
}
|
||||
futuresArray = futures.toArray(new CompletableFuture<?>[0]);
|
||||
@@ -931,7 +937,7 @@ public class World implements Disposable, SaveFileContent {
|
||||
}
|
||||
|
||||
public int getChunkSize() {
|
||||
return (Scene.getIntendedWidth() > Scene.getIntendedHeight() ? Scene.getIntendedWidth() : Scene.getIntendedHeight()) / data.tileSize;
|
||||
return (Math.max(Scene.getIntendedWidth(), Scene.getIntendedHeight())) / data.tileSize;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
|
||||
@@ -11,12 +11,9 @@ 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.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.*;
|
||||
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.SpriteBatch;
|
||||
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;
|
||||
@@ -323,7 +320,7 @@ public class FSkinFont {
|
||||
return font.getLineHeight();
|
||||
}
|
||||
|
||||
public void draw(SpriteBatch batch, String text, Color color, float x, float y, float w, boolean wrap, int horzAlignment) {
|
||||
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);
|
||||
|
||||
@@ -25,6 +25,8 @@ import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.EvictingQueue;
|
||||
import com.google.common.collect.Queues;
|
||||
import com.google.common.collect.Sets;
|
||||
@@ -70,20 +72,7 @@ import forge.util.ImageUtil;
|
||||
*/
|
||||
public class ImageCache {
|
||||
private static ImageCache imageCache;
|
||||
private HashSet<String> _missingIconKeys;
|
||||
private HashSet<String> missingIconKeys() {
|
||||
HashSet<String> result = _missingIconKeys;
|
||||
if (result == null) {
|
||||
synchronized (this) {
|
||||
result = _missingIconKeys;
|
||||
if (result == null) {
|
||||
result = new HashSet<>();
|
||||
_missingIconKeys = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _missingIconKeys;
|
||||
}
|
||||
private Supplier<HashSet<String>> missingIconKeys = Suppliers.memoize(HashSet::new);
|
||||
private final List<String> borderlessCardlistKey = FileUtil.readFile(ForgeConstants.BORDERLESS_CARD_LIST_FILE);
|
||||
public int counter = 0;
|
||||
private int maxCardCapacity = 300; //default card capacity
|
||||
@@ -133,20 +122,7 @@ public class ImageCache {
|
||||
return Forge.getAssets().getDefaultImage();
|
||||
}
|
||||
|
||||
private HashMap<String, ImageRecord> _imageRecord;
|
||||
private HashMap<String, ImageRecord> imageRecord() {
|
||||
HashMap<String, ImageRecord> result = _imageRecord;
|
||||
if (result == null) {
|
||||
synchronized (this) {
|
||||
result = _imageRecord;
|
||||
if (result == null) {
|
||||
result = new HashMap<>(maxCardCapacity + (maxCardCapacity / 3));
|
||||
_imageRecord = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _imageRecord;
|
||||
}
|
||||
private Supplier<HashMap<String, ImageRecord>> imageRecord = Suppliers.memoize(() -> new HashMap<>(maxCardCapacity + (maxCardCapacity / 3)));
|
||||
private boolean imageLoaded, delayLoadRequested;
|
||||
|
||||
public void allowSingleLoad() {
|
||||
@@ -155,7 +131,7 @@ public class ImageCache {
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
missingIconKeys().clear();
|
||||
missingIconKeys.get().clear();
|
||||
ImageKeys.clearMissingCards();
|
||||
}
|
||||
|
||||
@@ -201,8 +177,8 @@ public class ImageCache {
|
||||
public 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);
|
||||
if (missingIconKeys.get().contains(imageKey) || (icon = getImage(ihi.getIconImageKey(), false, true)) == null) {
|
||||
missingIconKeys.get().add(imageKey);
|
||||
return FSkinImage.UNKNOWN;
|
||||
}
|
||||
return new FTextureImage(icon);
|
||||
@@ -317,8 +293,8 @@ public class ImageCache {
|
||||
/*fix not loading image file since we intentionally not to update the cache in order for the
|
||||
image fetcher to update automatically after the card image/s are downloaded*/
|
||||
imageLoaded = false;
|
||||
if (image != null && imageRecord().get(image.toString()) == null)
|
||||
imageRecord().put(image.toString(), new ImageRecord(Color.valueOf("#171717").toString(), false, getRadius(image))); //black border
|
||||
if (image != null && imageRecord.get().get(image.toString()) == null)
|
||||
imageRecord.get().put(image.toString(), new ImageRecord(Color.valueOf("#171717").toString(), false, getRadius(image))); //black border
|
||||
}
|
||||
}
|
||||
return image;
|
||||
@@ -450,7 +426,7 @@ public class ImageCache {
|
||||
if (t == null)
|
||||
return Color.valueOf("#171717");
|
||||
try {
|
||||
return Color.valueOf(imageRecord().get(t.toString()).colorValue);
|
||||
return Color.valueOf(imageRecord.get().get(t.toString()).colorValue);
|
||||
} catch (Exception e) {
|
||||
return Color.valueOf("#171717");
|
||||
}
|
||||
@@ -468,13 +444,13 @@ public class ImageCache {
|
||||
return 0;
|
||||
}
|
||||
public void updateImageRecord(String textureString, String colorValue, Boolean isClosertoWhite, int radius) {
|
||||
imageRecord().put(textureString, new ImageRecord(colorValue, isClosertoWhite, radius));
|
||||
imageRecord.get().put(textureString, new ImageRecord(colorValue, isClosertoWhite, radius));
|
||||
}
|
||||
|
||||
public int getRadius(Texture t) {
|
||||
if (t == null)
|
||||
return 20;
|
||||
ImageRecord record = imageRecord().get(t.toString());
|
||||
ImageRecord record = imageRecord.get().get(t.toString());
|
||||
if (record == null)
|
||||
return 20;
|
||||
Integer i = record.cardRadius;
|
||||
@@ -484,7 +460,7 @@ public class ImageCache {
|
||||
}
|
||||
|
||||
public FImage getBorder(String textureString) {
|
||||
ImageRecord record = imageRecord().get(textureString);
|
||||
ImageRecord record = imageRecord.get().get(textureString);
|
||||
if (record == null)
|
||||
return FSkinImage.IMG_BORDER_BLACK;
|
||||
Boolean border = record.isCloserToWhite;
|
||||
|
||||
@@ -177,7 +177,7 @@ public class TextRenderer {
|
||||
needClip = true;
|
||||
}
|
||||
}
|
||||
addPiece(new SymbolPiece(symbol, inReminderTextCount > 0), lineNum, x, y - font.getAscent() + (lineHeight - pieceWidth) / 2, pieceWidth, pieceWidth);
|
||||
addPiece(new SymbolPiece(symbol, inReminderTextCount > 0), lineNum, x, y - lineHeight / 4, pieceWidth, pieceWidth);
|
||||
x += pieceWidth;
|
||||
pieceWidth = 0;
|
||||
text.setLength(0);
|
||||
|
||||
@@ -377,9 +377,11 @@ public class CardZoom extends FOverlay {
|
||||
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);
|
||||
if (currentCard != null)
|
||||
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 (currentCard != null)
|
||||
CardImageRenderer.drawDetails(g, currentCard, gameView, showBackSide ? showBackSide : showAltState, x, y, cardWidth, cardHeight);
|
||||
}
|
||||
|
||||
if (!showMerged) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import forge.Forge.KeyInputAdapter;
|
||||
import forge.Graphics;
|
||||
import forge.assets.*;
|
||||
import forge.card.CardEdition;
|
||||
import forge.card.MagicColor;
|
||||
import forge.deck.io.DeckPreferences;
|
||||
import forge.gamemodes.limited.BoosterDraft;
|
||||
import forge.gamemodes.planarconquest.ConquestUtil;
|
||||
@@ -1798,6 +1799,8 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
CardManagerPage cardSourceSection;
|
||||
DeckSection destination = DeckSection.matchingSection(card);
|
||||
final DeckSectionPage destinationPage = parentScreen.getPageForSection(destination);
|
||||
// val for colorID setup
|
||||
int val;
|
||||
switch (deckSection) {
|
||||
default:
|
||||
case Main:
|
||||
@@ -1840,6 +1843,19 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
}
|
||||
}
|
||||
addCommanderItems(menu, card);
|
||||
if ((val = card.getRules().getSetColorID()) > 0) {
|
||||
menu.addItem(new FMenuItem(Forge.getLocalizer().getMessage("lblColorIdentity"), Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS, e -> {
|
||||
//sort options so current option is on top and selected by default
|
||||
Set<String> colorChoices = new HashSet<>(MagicColor.Constant.ONLY_COLORS);
|
||||
GuiChoose.getChoices(Forge.getLocalizer().getMessage("lblChooseAColor", Lang.getNumeral(val)), val, val, colorChoices, new Callback<>() {
|
||||
@Override
|
||||
public void run(List<String> result) {
|
||||
addCard(card.getColorIDVersion(new HashSet<>(result)));
|
||||
removeCard(card);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
break;
|
||||
case Sideboard:
|
||||
cardSourceSection = parentScreen.isLimitedEditor() ? parentScreen.getMainDeckPage() : parentScreen.getCatalogPage();
|
||||
@@ -1879,6 +1895,19 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
}
|
||||
}
|
||||
addCommanderItems(menu, card);
|
||||
if ((val = card.getRules().getSetColorID()) > 0) {
|
||||
menu.addItem(new FMenuItem(Forge.getLocalizer().getMessage("lblColorIdentity"), Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS, e -> {
|
||||
//sort options so current option is on top and selected by default
|
||||
Set<String> colorChoices = new HashSet<>(MagicColor.Constant.ONLY_COLORS);
|
||||
GuiChoose.getChoices(Forge.getLocalizer().getMessage("lblChooseAColor", Lang.getNumeral(val)), val, val, colorChoices, new Callback<>() {
|
||||
@Override
|
||||
public void run(List<String> result) {
|
||||
addCard(card.getColorIDVersion(new HashSet<>(result)));
|
||||
removeCard(card);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
break;
|
||||
case Commander:
|
||||
if (parentScreen.editorType != EditorType.PlanarConquest || isPartnerCommander(card)) {
|
||||
|
||||
@@ -26,6 +26,8 @@ import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import forge.Forge;
|
||||
import forge.Graphics;
|
||||
import forge.assets.FSkinColor;
|
||||
@@ -64,22 +66,7 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
protected final ItemManagerModel<T> model;
|
||||
private Predicate<? super T> filterPredicate = null;
|
||||
private AdvancedSearchFilter<? extends T> advancedSearchFilter;
|
||||
private List<ItemFilter<? extends T>> _filters;
|
||||
|
||||
private List<ItemFilter<? extends T>> filters() {
|
||||
List<ItemFilter<? extends T>> result = _filters;
|
||||
if (result == null) {
|
||||
synchronized (this) {
|
||||
result = _filters;
|
||||
if (result == null) {
|
||||
result = new ArrayList<>();
|
||||
_filters = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _filters;
|
||||
}
|
||||
|
||||
private Supplier<List<ItemFilter<? extends T>>> filters = Suppliers.memoize(ArrayList::new);
|
||||
private boolean hideFilters = false;
|
||||
private boolean wantUnique = false;
|
||||
private boolean showRanking = false;
|
||||
@@ -92,22 +79,7 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
private ItemManagerConfig config;
|
||||
private Function<Entry<? extends InventoryItem, Integer>, Object> fnNewGet;
|
||||
private boolean viewUpdating, needSecondUpdate;
|
||||
private List<ItemColumn> _sortCols;
|
||||
|
||||
private List<ItemColumn> sortCols() {
|
||||
List<ItemColumn> result = _sortCols;
|
||||
if (result == null) {
|
||||
synchronized (this) {
|
||||
result = _sortCols;
|
||||
if (result == null) {
|
||||
result = new ArrayList<>();
|
||||
_sortCols = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _sortCols;
|
||||
}
|
||||
|
||||
private Supplier<List<ItemColumn>> sortCols = Suppliers.memoize(ArrayList::new);
|
||||
private final TextSearchFilter<? extends T> searchFilter;
|
||||
private CardFormatFilter cardFormatFilter;
|
||||
|
||||
@@ -146,16 +118,9 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
listView = new ItemListView<>(this, model);
|
||||
imageView = createImageView(model);
|
||||
|
||||
if (Forge.isMobileAdventureMode) {
|
||||
// reversed default
|
||||
views.add(imageView);
|
||||
views.add(listView);
|
||||
currentView = imageView;
|
||||
} else {
|
||||
views.add(listView);
|
||||
views.add(imageView);
|
||||
currentView = listView;
|
||||
}
|
||||
views.add(listView);
|
||||
views.add(imageView);
|
||||
currentView = listView;
|
||||
btnView.setIcon(currentView.getIcon());
|
||||
|
||||
//build display
|
||||
@@ -248,7 +213,7 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
}
|
||||
cols.sort(Comparator.comparingInt(arg0 -> arg0.getConfig().getIndex()));
|
||||
|
||||
sortCols().clear();
|
||||
sortCols.get().clear();
|
||||
if (cbxSortOptions != null) {
|
||||
cbxSortOptions.setDropDownItemTap(null);
|
||||
cbxSortOptions.removeAllItems();
|
||||
@@ -258,14 +223,14 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
for (final ItemColumn col : cols) {
|
||||
col.setIndex(modelIndex++);
|
||||
if (col.isVisible()) {
|
||||
sortCols().add(col);
|
||||
sortCols.get().add(col);
|
||||
}
|
||||
}
|
||||
|
||||
final ItemColumn[] sortcols = new ItemColumn[sortCols().size()];
|
||||
final ItemColumn[] sortcols = new ItemColumn[sortCols.get().size()];
|
||||
|
||||
// Assemble priority sort.
|
||||
for (ItemColumn col : sortCols()) {
|
||||
for (ItemColumn col : sortCols.get()) {
|
||||
if (cbxSortOptions != null) {
|
||||
cbxSortOptions.addItem(col);
|
||||
}
|
||||
@@ -382,7 +347,7 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
helper.offset(0, ItemFilter.PADDING);
|
||||
// for Adventure Mode Store, Sideboard and Deck Event previews layout
|
||||
if (ItemManagerConfig.ADVENTURE_STORE_POOL.equals(config) || ItemManagerConfig.ADVENTURE_SIDEBOARD.equals(config)) {
|
||||
for (ItemFilter<? extends T> filter : filters()) {
|
||||
for (ItemFilter<? extends T> filter : filters.get()) {
|
||||
if (filter instanceof CardColorFilter) {
|
||||
filter.getWidget().setVisible(true);
|
||||
helper.include(filter.getWidget(), (viewButtonWidth + helper.getGapX()) * 7, fieldHeight);
|
||||
@@ -405,7 +370,7 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
helper.fillLine(advancedSearchFilter.getWidget(), fieldHeight);
|
||||
}
|
||||
if (!hideFilters) {
|
||||
for (ItemFilter<? extends T> filter : filters()) {
|
||||
for (ItemFilter<? extends T> filter : filters.get()) {
|
||||
helper.include(filter.getWidget(), filter.getPreferredWidth(helper.getRemainingLineWidth(), fieldHeight), fieldHeight);
|
||||
}
|
||||
if (allowSortChange()) {
|
||||
@@ -695,7 +660,7 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
protected abstract AdvancedSearchFilter<? extends T> createAdvancedSearchFilter();
|
||||
|
||||
public void addFilter(final ItemFilter<? extends T> filter) {
|
||||
filters().add(filter);
|
||||
filters.get().add(filter);
|
||||
add(filter.getWidget());
|
||||
if (filter instanceof CardFormatFilter)
|
||||
cardFormatFilter = (CardFormatFilter) filter;
|
||||
@@ -729,10 +694,10 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
|
||||
public void restoreDefaultFilters() {
|
||||
lockFiltering = true;
|
||||
for (ItemFilter<? extends T> filter : filters()) {
|
||||
for (ItemFilter<? extends T> filter : filters.get()) {
|
||||
remove(filter.getWidget());
|
||||
}
|
||||
filters().clear();
|
||||
filters.get().clear();
|
||||
addDefaultFilters();
|
||||
lockFiltering = false;
|
||||
revalidate();
|
||||
@@ -741,7 +706,7 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
|
||||
public void resetFilters() {
|
||||
lockFiltering = true; //prevent updating filtering from this change until all filters reset
|
||||
for (final ItemFilter<? extends T> filter : filters()) {
|
||||
for (final ItemFilter<? extends T> filter : filters.get()) {
|
||||
filter.reset();
|
||||
}
|
||||
searchFilter.reset();
|
||||
@@ -759,7 +724,7 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
}
|
||||
|
||||
public void removeFilter(ItemFilter<? extends T> filter) {
|
||||
filters().remove(filter);
|
||||
filters.get().remove(filter);
|
||||
remove(filter.getWidget());
|
||||
revalidate();
|
||||
applyFilters();
|
||||
@@ -771,7 +736,7 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
}
|
||||
|
||||
List<Predicate<? super T>> predicates = new ArrayList<>();
|
||||
for (ItemFilter<? extends T> filter : filters()) {
|
||||
for (ItemFilter<? extends T> filter : filters.get()) {
|
||||
if (!filter.isEmpty()) {
|
||||
predicates.add(filter.buildPredicate(genericType));
|
||||
}
|
||||
@@ -822,7 +787,7 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
hideFilters = hideFilters0;
|
||||
|
||||
boolean visible = !hideFilters0;
|
||||
for (ItemFilter<? extends T> filter : filters()) {
|
||||
for (ItemFilter<? extends T> filter : filters.get()) {
|
||||
filter.getWidget().setVisible(visible);
|
||||
}
|
||||
if (allowSortChange()) {
|
||||
@@ -857,7 +822,7 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
ItemManager.this.add(advancedSearchFilter.getWidget());
|
||||
}
|
||||
lockFiltering = true;
|
||||
for (final ItemFilter<? extends T> filter : filters()) {
|
||||
for (final ItemFilter<? extends T> filter : filters.get()) {
|
||||
filter.reset();
|
||||
}
|
||||
searchFilter.reset();
|
||||
@@ -1132,9 +1097,9 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
|
||||
if (cbxSortOptions != null) {
|
||||
return cbxSortOptions.getWidth();
|
||||
}
|
||||
if (filters().isEmpty()) {
|
||||
if (filters.get().isEmpty()) {
|
||||
return 0f;
|
||||
}
|
||||
return filters().get(filters().size() - 1).getWidget().getWidth();
|
||||
return filters.get().get(filters.get().size() - 1).getWidget().getWidth();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import forge.Forge;
|
||||
import forge.Forge.KeyInputAdapter;
|
||||
import forge.Graphics;
|
||||
@@ -36,6 +38,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static forge.assets.FSkin.getDefaultSkinFile;
|
||||
@@ -44,6 +47,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
private static final float PADDING = Utils.scale(5);
|
||||
private static final float PILE_SPACING_Y = 0.1f;
|
||||
private static final FSkinFont LABEL_FONT = FSkinFont.get(12);
|
||||
private TextRenderer textRenderer = new TextRenderer(true);
|
||||
|
||||
private static FSkinColor getGroupHeaderForeColor() {
|
||||
if (Forge.isMobileAdventureMode)
|
||||
@@ -63,20 +67,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
private static final int MIN_COLUMN_COUNT = Forge.isLandscapeMode() ? 2 : 1;
|
||||
private static final int MAX_COLUMN_COUNT = 10;
|
||||
|
||||
private List<Integer> _selectedIndices;
|
||||
private List<Integer> selectedIndices() {
|
||||
List<Integer> result = _selectedIndices;
|
||||
if (result == null) {
|
||||
synchronized (this) {
|
||||
result = _selectedIndices;
|
||||
if (result == null) {
|
||||
result = new ArrayList<>();
|
||||
_selectedIndices = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _selectedIndices;
|
||||
}
|
||||
private Supplier<List<Integer>> selectedIndices = Suppliers.memoize(ArrayList::new);
|
||||
private int columnCount = 4;
|
||||
private float scrollHeight = 0;
|
||||
private ColumnDef pileBy = null;
|
||||
@@ -84,34 +75,8 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
private ItemInfo focalItem;
|
||||
private boolean updatingLayout;
|
||||
private float totalZoomAmount;
|
||||
private List<ItemInfo> _orderedItems;
|
||||
private List<ItemInfo> orderedItems() {
|
||||
List<ItemInfo> result = _orderedItems;
|
||||
if (result == null) {
|
||||
synchronized (this) {
|
||||
result = _orderedItems;
|
||||
if (result == null) {
|
||||
result = new ArrayList<>();
|
||||
_orderedItems = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _orderedItems;
|
||||
}
|
||||
private List<Group> _groups;
|
||||
private List<Group> groups() {
|
||||
List<Group> result = _groups;
|
||||
if (result == null) {
|
||||
synchronized (this) {
|
||||
result = _groups;
|
||||
if (result == null) {
|
||||
result = new ArrayList<>();
|
||||
_groups = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _groups;
|
||||
}
|
||||
private Supplier<List<ItemInfo>> orderedItems = Suppliers.memoize(ArrayList::new);
|
||||
private Supplier<List<Group>> groups = Suppliers.memoize(ArrayList::new);
|
||||
|
||||
private class ExpandCollapseButton extends FLabel {
|
||||
private boolean isAllCollapsed;
|
||||
@@ -124,7 +89,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
}
|
||||
|
||||
boolean collapsed = !isAllCollapsed;
|
||||
for (Group group : groups()) {
|
||||
for (Group group : groups.get()) {
|
||||
group.isCollapsed = collapsed;
|
||||
}
|
||||
|
||||
@@ -136,7 +101,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
|
||||
private void updateIsAllCollapsed() {
|
||||
boolean isAllCollapsed0 = true;
|
||||
for (Group group : groups()) {
|
||||
for (Group group : groups.get()) {
|
||||
if (!group.isCollapsed) {
|
||||
isAllCollapsed0 = false;
|
||||
break;
|
||||
@@ -211,7 +176,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
getPnlOptions().add(cbPileByOptions);
|
||||
|
||||
Group group = new Group(""); //add default group
|
||||
groups().add(group);
|
||||
groups.get().add(group);
|
||||
getScroller().add(group);
|
||||
}
|
||||
|
||||
@@ -242,26 +207,26 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
cbGroupByOptions.setSelectedItem(groupBy);
|
||||
}
|
||||
|
||||
groups().clear();
|
||||
groups.get().clear();
|
||||
|
||||
if (groupBy == null) {
|
||||
groups().add(new Group(""));
|
||||
groups.get().add(new Group(""));
|
||||
btnExpandCollapseAll.updateIsAllCollapsed();
|
||||
} else {
|
||||
for (String groupName : groupBy.getGroups()) {
|
||||
groups().add(new Group(groupName));
|
||||
groups.get().add(new Group(groupName));
|
||||
}
|
||||
|
||||
//collapse all groups by default if all previous groups were collapsed
|
||||
if (btnExpandCollapseAll.isAllCollapsed) {
|
||||
for (Group group : groups()) {
|
||||
for (Group group : groups.get()) {
|
||||
group.isCollapsed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getScroller().clear();
|
||||
for (Group group : groups()) {
|
||||
for (Group group : groups.get()) {
|
||||
getScroller().add(group);
|
||||
}
|
||||
|
||||
@@ -352,7 +317,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
|
||||
//if not item hovered, use first fully visible item as focal point
|
||||
final float visibleTop = getScrollValue();
|
||||
for (Group group : groups()) {
|
||||
for (Group group : groups.get()) {
|
||||
if (group.getBottom() < visibleTop) {
|
||||
continue;
|
||||
}
|
||||
@@ -367,10 +332,10 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (orderedItems().isEmpty()) {
|
||||
if (orderedItems.get().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return orderedItems().get(0);
|
||||
return orderedItems.get().get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -380,9 +345,9 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
|
||||
@Override
|
||||
protected void onRefresh() {
|
||||
Group otherItems = groupBy == null ? groups().get(0) : null;
|
||||
Group otherItems = groupBy == null ? groups.get().get(0) : null;
|
||||
|
||||
for (Group group : groups()) {
|
||||
for (Group group : groups.get()) {
|
||||
group.items.clear();
|
||||
}
|
||||
clearSelection();
|
||||
@@ -395,19 +360,19 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
|
||||
Group group;
|
||||
if (groupIndex >= 0) {
|
||||
if (groupIndex >= groups().size())
|
||||
group = groups().get(groups().size() - 1);
|
||||
if (groupIndex >= groups.get().size())
|
||||
group = groups.get().get(groups.get().size() - 1);
|
||||
else
|
||||
group = groups().get(groupIndex);
|
||||
group = groups.get().get(groupIndex);
|
||||
} else {
|
||||
if (otherItems == null) {
|
||||
//reuse existing Other group if possible
|
||||
if (groups().size() > groupBy.getGroups().length) {
|
||||
otherItems = groups().get(groups().size() - 1);
|
||||
if (groups.get().size() > groupBy.getGroups().length) {
|
||||
otherItems = groups.get().get(groups.get().size() - 1);
|
||||
} else {
|
||||
otherItems = new Group(Forge.getLocalizer().getMessage("lblOther"));
|
||||
otherItems.isCollapsed = btnExpandCollapseAll.isAllCollapsed;
|
||||
groups().add(otherItems);
|
||||
groups.get().add(otherItems);
|
||||
}
|
||||
}
|
||||
group = otherItems;
|
||||
@@ -419,10 +384,10 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
}
|
||||
}
|
||||
|
||||
if (otherItems == null && groups().size() > groupBy.getGroups().length) {
|
||||
int index = groups().size() - 1;
|
||||
if (index < groups().size() && index >= 0)
|
||||
groups().remove(index); //remove Other group if empty
|
||||
if (otherItems == null && groups.get().size() > groupBy.getGroups().length) {
|
||||
int index = groups.get().size() - 1;
|
||||
if (index < groups.get().size() && index >= 0)
|
||||
groups.get().remove(index); //remove Other group if empty
|
||||
btnExpandCollapseAll.updateIsAllCollapsed();
|
||||
}
|
||||
|
||||
@@ -470,8 +435,8 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
float dx = itemWidth + gap;
|
||||
float dy = pileBy == null ? itemHeight + gap : itemHeight * PILE_SPACING_Y;
|
||||
|
||||
for (int i = 0; i < groups().size(); i++) {
|
||||
Group group = groups().get(i);
|
||||
for (int i = 0; i < groups.get().size(); i++) {
|
||||
Group group = groups.get().get(i);
|
||||
|
||||
if (forRefresh && pileBy != null) { //refresh piles if needed
|
||||
//use TreeMap to build pile set so iterating below sorts on key
|
||||
@@ -564,8 +529,8 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
|
||||
if (forRefresh) { //refresh ordered items if needed
|
||||
int index = 0;
|
||||
orderedItems().clear();
|
||||
for (Group group : groups()) {
|
||||
orderedItems.get().clear();
|
||||
for (Group group : groups.get()) {
|
||||
if (group.isCollapsed || group.items.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
@@ -573,7 +538,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
for (Pile pile : group.piles) {
|
||||
for (ItemInfo itemInfo : pile.items) {
|
||||
itemInfo.index = index++;
|
||||
orderedItems().add(itemInfo);
|
||||
orderedItems.get().add(itemInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -623,11 +588,11 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
|
||||
private ItemInfo getItemAtPoint(float x, float y) {
|
||||
//check selected items first since they appear on top
|
||||
for (int i = selectedIndices().size() - 1; i >= 0; i--) {
|
||||
int currentIndex = selectedIndices().get(i);
|
||||
if (currentIndex < 0 || orderedItems().size() <= currentIndex)
|
||||
for (int i = selectedIndices.get().size() - 1; i >= 0; i--) {
|
||||
int currentIndex = selectedIndices.get().get(i);
|
||||
if (currentIndex < 0 || orderedItems.get().size() <= currentIndex)
|
||||
continue;
|
||||
ItemInfo item = orderedItems().get(currentIndex);
|
||||
ItemInfo item = orderedItems.get().get(currentIndex);
|
||||
float relX = x + item.group.getScrollLeft() - item.group.getLeft();
|
||||
float relY = y + getScrollValue();
|
||||
if (item.contains(relX, relY)) {
|
||||
@@ -635,8 +600,8 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = groups().size() - 1; i >= 0; i--) {
|
||||
Group group = groups().get(i);
|
||||
for (int i = groups.get().size() - 1; i >= 0; i--) {
|
||||
Group group = groups.get().get(i);
|
||||
if (!group.isCollapsed) {
|
||||
for (int j = group.piles.size() - 1; j >= 0; j--) {
|
||||
float relX = x + group.getScrollLeft() - group.getLeft();
|
||||
@@ -659,14 +624,14 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
@Override
|
||||
public T getItemAtIndex(int index) {
|
||||
if (index >= 0 && index < getCount()) {
|
||||
return orderedItems().get(index).item;
|
||||
return orderedItems.get().get(index).item;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexOfItem(T item) {
|
||||
for (Group group : groups()) {
|
||||
for (Group group : groups.get()) {
|
||||
for (ItemInfo itemInfo : group.items) {
|
||||
if (itemInfo.item == item) {
|
||||
//if group containing item is collapsed, expand it so the item can be selected and has a valid index
|
||||
@@ -685,22 +650,22 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
|
||||
@Override
|
||||
public int getSelectedIndex() {
|
||||
return selectedIndices().isEmpty() ? -1 : selectedIndices().get(0);
|
||||
return selectedIndices.get().isEmpty() ? -1 : selectedIndices.get().get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Integer> getSelectedIndices() {
|
||||
return selectedIndices();
|
||||
return selectedIndices.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return orderedItems().size();
|
||||
return orderedItems.get().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSelectionCount() {
|
||||
return selectedIndices().size();
|
||||
return selectedIndices.get().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -728,7 +693,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
@Override
|
||||
public void selectAll() {
|
||||
clearSelection();
|
||||
IntStream.range(0, getCount()).forEach(selectedIndices()::add);
|
||||
IntStream.range(0, getCount()).forEach(selectedIndices.get()::add);
|
||||
updateSelection();
|
||||
onSelectionChange();
|
||||
}
|
||||
@@ -736,7 +701,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
@Override
|
||||
protected void onSetSelectedIndex(int index) {
|
||||
clearSelection();
|
||||
selectedIndices().add(index);
|
||||
selectedIndices.get().add(index);
|
||||
updateSelection();
|
||||
}
|
||||
|
||||
@@ -744,24 +709,24 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
protected void onSetSelectedIndices(Iterable<Integer> indices) {
|
||||
clearSelection();
|
||||
for (Integer index : indices) {
|
||||
selectedIndices().add(index);
|
||||
selectedIndices.get().add(index);
|
||||
}
|
||||
updateSelection();
|
||||
}
|
||||
|
||||
private void clearSelection() {
|
||||
int count = getCount();
|
||||
for (Integer i : selectedIndices()) {
|
||||
for (Integer i : selectedIndices.get()) {
|
||||
if (i < count) {
|
||||
orderedItems().get(i).selected = false;
|
||||
orderedItems.get().get(i).selected = false;
|
||||
}
|
||||
}
|
||||
selectedIndices().clear();
|
||||
selectedIndices.get().clear();
|
||||
}
|
||||
|
||||
private void updateSelection() {
|
||||
for (Integer i : selectedIndices()) {
|
||||
orderedItems().get(i).selected = true;
|
||||
for (Integer i : selectedIndices.get()) {
|
||||
orderedItems.get().get(i).selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -777,9 +742,9 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
}
|
||||
|
||||
if (item.selected) { //unselect item if already selected
|
||||
if (selectedIndices().size() > minSelections) {
|
||||
if (selectedIndices.get().size() > minSelections) {
|
||||
item.selected = false;
|
||||
selectedIndices().remove((Object) item.index);
|
||||
selectedIndices.get().remove((Object) item.index);
|
||||
onSelectionChange();
|
||||
item.group.scrollIntoView(item);
|
||||
}
|
||||
@@ -788,8 +753,8 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
if (maxSelections <= 1 || (!KeyInputAdapter.isCtrlKeyDown() && !KeyInputAdapter.isShiftKeyDown())) {
|
||||
clearSelection();
|
||||
}
|
||||
if (selectedIndices().size() < maxSelections) {
|
||||
selectedIndices().add(0, item.index);
|
||||
if (selectedIndices.get().size() < maxSelections) {
|
||||
selectedIndices.get().add(0, item.index);
|
||||
item.selected = true;
|
||||
onSelectionChange();
|
||||
item.group.scrollIntoView(item);
|
||||
@@ -800,29 +765,29 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
|
||||
@Override
|
||||
public void scrollSelectionIntoView() {
|
||||
if (selectedIndices().isEmpty()) {
|
||||
if (selectedIndices.get().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int index = selectedIndices().get(0);
|
||||
if (index < 0 || orderedItems().size() <= index) {
|
||||
int index = selectedIndices.get().get(0);
|
||||
if (index < 0 || orderedItems.get().size() <= index) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemInfo itemInfo = orderedItems().get(index);
|
||||
ItemInfo itemInfo = orderedItems.get().get(index);
|
||||
getScroller().scrollIntoView(itemInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getSelectionBounds() {
|
||||
if (selectedIndices().isEmpty()) {
|
||||
if (selectedIndices.get().isEmpty()) {
|
||||
return new Rectangle();
|
||||
}
|
||||
|
||||
int index = selectedIndices().get(0);
|
||||
if (index < 0 || orderedItems().size() <= index) {
|
||||
int index = selectedIndices.get().get(0);
|
||||
if (index < 0 || orderedItems.get().size() <= index) {
|
||||
return new Rectangle();
|
||||
}
|
||||
ItemInfo itemInfo = orderedItems().get(index);
|
||||
ItemInfo itemInfo = orderedItems.get().get(index);
|
||||
Vector2 relPos = itemInfo.group.getChildRelativePosition(itemInfo);
|
||||
return new Rectangle(itemInfo.group.screenPos.x + relPos.x - SEL_BORDER_SIZE + itemInfo.group.getLeft(),
|
||||
itemInfo.group.screenPos.y + relPos.y - SEL_BORDER_SIZE,
|
||||
@@ -831,21 +796,21 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
|
||||
@Override
|
||||
public void zoomSelected() {
|
||||
if (selectedIndices().isEmpty()) {
|
||||
if (selectedIndices.get().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int index = selectedIndices().get(0);
|
||||
if (index < 0 || orderedItems().size() <= index) {
|
||||
int index = selectedIndices.get().get(0);
|
||||
if (index < 0 || orderedItems.get().size() <= index) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemInfo itemInfo = orderedItems().get(index);
|
||||
ItemInfo itemInfo = orderedItems.get().get(index);
|
||||
if (itemInfo != null) {
|
||||
if (itemInfo.getKey() instanceof CardThemedDeckGenerator || itemInfo.getKey() instanceof CommanderDeckGenerator
|
||||
|| itemInfo.getKey() instanceof ArchetypeDeckGenerator || itemInfo.getKey() instanceof DeckProxy) {
|
||||
FDeckViewer.show(((DeckProxy) itemInfo.getKey()).getDeck());
|
||||
}
|
||||
CardZoom.show(orderedItems(), orderedItems().indexOf(itemInfo), itemManager);
|
||||
CardZoom.show(orderedItems.get(), orderedItems.get().indexOf(itemInfo), itemManager);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -975,7 +940,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
FDeckViewer.show(((DeckProxy) item.getKey()).getDeck());
|
||||
return true;
|
||||
}
|
||||
CardZoom.show(orderedItems(), orderedItems().indexOf(item), itemManager);
|
||||
CardZoom.show(orderedItems.get(), orderedItems.get().indexOf(item), itemManager);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1029,6 +994,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
private boolean selected, deckSelectMode, showRanking;
|
||||
private final float IMAGE_SIZE = CardRenderer.MANA_SYMBOL_SIZE;
|
||||
private DeckProxy deckProxy = null;
|
||||
private String colorID = null;
|
||||
private FImageComplex deckCover = null;
|
||||
private Texture dpImg = null;
|
||||
//private TextureRegion tr;
|
||||
@@ -1055,6 +1021,9 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
draftRankImage = FSkinImage.DRAFTRANK_C;
|
||||
}
|
||||
}
|
||||
if (((PaperCard) item).getColorID() != null) {
|
||||
colorID = ((PaperCard) item).getColorID().stream().map(MagicColor::toSymbol).collect(Collectors.joining());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1136,6 +1105,10 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
// spire colors
|
||||
if (colorID != null && !colorID.isEmpty()) {
|
||||
textRenderer.drawText(g, colorID, FSkinFont.forHeight(w / 5), Color.WHITE, x, y + h / 4, w, h, y, h, false, Align.center, true);
|
||||
}
|
||||
} else if (item instanceof ConquestCommander) {
|
||||
CardRenderer.drawCard(g, ((ConquestCommander) item).getCard(), x, y, w, h, pos);
|
||||
} else if (deckSelectMode) {
|
||||
|
||||
@@ -32,7 +32,6 @@ import forge.assets.FSkinColor.Colors;
|
||||
import forge.assets.FSkinTexture;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.combat.CombatView;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.zone.ZoneType;
|
||||
@@ -91,6 +90,11 @@ public class MatchScreen extends FScreen {
|
||||
private static List<FDisplayObject> potentialListener;
|
||||
private int selectedPlayer;
|
||||
|
||||
|
||||
private final Map<Integer, Vector2> endpoints;
|
||||
private final Set<CardView> cardsonBattlefield;
|
||||
private final Set<PlayerView> playerViewSet;
|
||||
|
||||
public MatchScreen(List<VPlayerPanel> playerPanels0) {
|
||||
super(new FMenuBar());
|
||||
|
||||
@@ -164,6 +168,9 @@ public class MatchScreen extends FScreen {
|
||||
log.setMenuTab(new HiddenMenuTab(log));
|
||||
devMenu.setMenuTab(new HiddenMenuTab(devMenu));
|
||||
}
|
||||
endpoints = new HashMap<>();
|
||||
cardsonBattlefield = new HashSet<>();
|
||||
playerViewSet = new HashSet<>();
|
||||
}
|
||||
|
||||
private boolean is4Player() {
|
||||
@@ -392,8 +399,7 @@ public class MatchScreen extends FScreen {
|
||||
if (Forge.isLandscapeMode() && (!GuiBase.isAndroid() || Forge.hasGamepad()) && !CardZoom.isOpen() && potentialListener != null) {
|
||||
for (FDisplayObject object : potentialListener) {
|
||||
if (object != null) {
|
||||
if (object instanceof FCardPanel) {
|
||||
FCardPanel cardPanel = (FCardPanel) object;
|
||||
if (object instanceof FCardPanel cardPanel) {
|
||||
try {
|
||||
if (cardPanel.isHovered()) {
|
||||
VPlayerPanel vPlayerPanel = getPlayerPanel(cardPanel.getCard().getController());
|
||||
@@ -431,9 +437,9 @@ public class MatchScreen extends FScreen {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else if (object instanceof VStack.StackInstanceDisplay) {
|
||||
} else if (object instanceof VStack.StackInstanceDisplay vstackDisplay) {
|
||||
try {
|
||||
CardView cardView = ((VStack.StackInstanceDisplay) object).stackInstance.getSourceCard();
|
||||
CardView cardView = vstackDisplay.stackInstance.getSourceCard();
|
||||
if (object.isHovered() && cardView != null && getStack().isVisible()) {
|
||||
float cardW = getHeight() * 0.45f;
|
||||
float cardH = FCardPanel.ASPECT_RATIO * cardW;
|
||||
@@ -459,30 +465,40 @@ public class MatchScreen extends FScreen {
|
||||
}
|
||||
|
||||
void drawArcs(Graphics g) {
|
||||
//get all card targeting arrow origins on the battlefield
|
||||
final Map<Integer, Vector2> endpoints = new HashMap<>();
|
||||
final Set<CardView> cardsonBattlefield = new HashSet<>();
|
||||
final Set<PlayerView> playerViewSet = new HashSet<>();
|
||||
final GameView game = MatchController.instance.getGameView();
|
||||
if (game == null)
|
||||
return;
|
||||
//get all card targeting arrow origins on the battlefield
|
||||
endpoints.clear();
|
||||
cardsonBattlefield.clear();
|
||||
playerViewSet.clear();
|
||||
try {
|
||||
for (PlayerView p : game.getPlayers()) {
|
||||
if (p != null && playerPanelsList.contains(getPlayerPanel(p))) {
|
||||
if (p == null)
|
||||
continue;
|
||||
VPlayerPanel playerPanel = getPlayerPanel(p);
|
||||
if (playerPanel != null && playerPanelsList.contains(playerPanel)) {
|
||||
playerViewSet.add(p);
|
||||
if (p.getBattlefield() != null) {
|
||||
for (CardView c : p.getBattlefield()) {
|
||||
endpoints.put(c.getId(), CardAreaPanel.get(c).getTargetingArrowOrigin());
|
||||
CardAreaPanel panel = CardAreaPanel.get(c);
|
||||
Vector2 origin = panel.getTargetingArrowOrigin();
|
||||
//outside left bounds
|
||||
if (origin.x < playerPanel.getField().getLeft())
|
||||
continue;
|
||||
//outside right bounds
|
||||
if (origin.x > playerPanel.getField().getRight())
|
||||
continue;
|
||||
endpoints.put(c.getId(), origin);
|
||||
cardsonBattlefield.add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//draw arrows for combat
|
||||
final CombatView combat = game.getCombat();
|
||||
for (CardView c : cardsonBattlefield) {
|
||||
TargetingOverlay.assembleArrows(g, c, endpoints, combat, playerViewSet);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
if (endpoints.isEmpty())
|
||||
return;
|
||||
TargetingOverlay.assembleArrows(g, cardsonBattlefield, endpoints, game.getCombat(), playerViewSet);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -511,7 +527,7 @@ public class MatchScreen extends FScreen {
|
||||
}
|
||||
}
|
||||
revalidate(true);
|
||||
} catch (Exception e) {
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -525,7 +541,7 @@ public class MatchScreen extends FScreen {
|
||||
selectedPlayerPanel().getSelectedRow().setNextSelected(1);
|
||||
}
|
||||
revalidate(true);
|
||||
} catch (Exception e) {
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -549,7 +565,7 @@ public class MatchScreen extends FScreen {
|
||||
}
|
||||
}
|
||||
revalidate(true);
|
||||
} catch (Exception e) {
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -563,7 +579,7 @@ public class MatchScreen extends FScreen {
|
||||
selectedPlayerPanel().getSelectedRow().setPreviousSelected(1);
|
||||
}
|
||||
revalidate(true);
|
||||
} catch (Exception e) {
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -576,7 +592,7 @@ public class MatchScreen extends FScreen {
|
||||
} else {
|
||||
selectedPlayerPanel().getSelectedRow().showZoom();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -591,7 +607,7 @@ public class MatchScreen extends FScreen {
|
||||
//nullPotentialListener();
|
||||
selectedPlayerPanel().getSelectedRow().tapChild();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -615,7 +631,7 @@ public class MatchScreen extends FScreen {
|
||||
return getActivePrompt().getBtnCancel().trigger(); //trigger Cancel if can't trigger OK
|
||||
case Keys.ESCAPE:
|
||||
if (!FModel.getPreferences().getPrefBoolean(FPref.UI_ALLOW_ESC_TO_END_TURN) && !Forge.hasGamepad()) {//bypass check
|
||||
if (getActivePrompt().getBtnCancel().getText().equals(Forge.getLocalizer().getInstance().getMessage("lblEndTurn"))) {
|
||||
if (getActivePrompt().getBtnCancel().getText().equals(Forge.getLocalizer().getMessage("lblEndTurn"))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -796,12 +812,11 @@ public class MatchScreen extends FScreen {
|
||||
}
|
||||
|
||||
public void updateSingleCard(final CardView card) {
|
||||
final CardAreaPanel pnl = CardAreaPanel.get(card);
|
||||
if (pnl == null) {
|
||||
if (card == null)
|
||||
return;
|
||||
}
|
||||
final CardAreaPanel pnl = CardAreaPanel.get(card);
|
||||
final ZoneType zone = card.getZone();
|
||||
if (zone != null && zone == ZoneType.Battlefield) {
|
||||
if (zone == ZoneType.Battlefield) {
|
||||
pnl.updateCard(card);
|
||||
} else { //ensure card not on battlefield is reset such that it no longer thinks it's on the battlefield
|
||||
pnl.setTapped(false);
|
||||
@@ -818,28 +833,18 @@ public class MatchScreen extends FScreen {
|
||||
|
||||
FSkinTexture getBG() {
|
||||
if (Forge.isMobileAdventureMode) {
|
||||
switch (GameScene.instance().getAdventurePlayerLocation(false, true)) {
|
||||
case "green":
|
||||
return FSkinTexture.ADV_BG_FOREST;
|
||||
case "black":
|
||||
return FSkinTexture.ADV_BG_SWAMP;
|
||||
case "red":
|
||||
return FSkinTexture.ADV_BG_MOUNTAIN;
|
||||
case "blue":
|
||||
return FSkinTexture.ADV_BG_ISLAND;
|
||||
case "white":
|
||||
return FSkinTexture.ADV_BG_PLAINS;
|
||||
case "waste":
|
||||
return FSkinTexture.ADV_BG_WASTE;
|
||||
case "cave":
|
||||
return FSkinTexture.ADV_BG_CAVE;
|
||||
case "dungeon":
|
||||
return FSkinTexture.ADV_BG_DUNGEON;
|
||||
case "castle":
|
||||
return FSkinTexture.ADV_BG_CASTLE;
|
||||
default:
|
||||
return FSkinTexture.ADV_BG_COMMON;
|
||||
}
|
||||
return switch (GameScene.instance().getAdventurePlayerLocation(false, true)) {
|
||||
case "green" -> FSkinTexture.ADV_BG_FOREST;
|
||||
case "black" -> FSkinTexture.ADV_BG_SWAMP;
|
||||
case "red" -> FSkinTexture.ADV_BG_MOUNTAIN;
|
||||
case "blue" -> FSkinTexture.ADV_BG_ISLAND;
|
||||
case "white" -> FSkinTexture.ADV_BG_PLAINS;
|
||||
case "waste" -> FSkinTexture.ADV_BG_WASTE;
|
||||
case "cave" -> FSkinTexture.ADV_BG_CAVE;
|
||||
case "dungeon" -> FSkinTexture.ADV_BG_DUNGEON;
|
||||
case "castle" -> FSkinTexture.ADV_BG_CASTLE;
|
||||
default -> FSkinTexture.ADV_BG_COMMON;
|
||||
};
|
||||
}
|
||||
return FSkinTexture.BG_MATCH;
|
||||
}
|
||||
@@ -952,7 +957,7 @@ public class MatchScreen extends FScreen {
|
||||
if (!hasActivePlane())
|
||||
return;
|
||||
}
|
||||
boolean isGameFast = MatchController.instance.isGameFast();
|
||||
//boolean isGameFast = MatchController.instance.isGameFast(); //this used to control animation speed
|
||||
float midField = topPlayerPanel.getBottom();
|
||||
float promptHeight = !Forge.isLandscapeMode() || bottomPlayerPrompt == null ? 0f : bottomPlayerPrompt.getHeight() / 1.3f;
|
||||
float x = topPlayerPanel.getField().getLeft();
|
||||
|
||||
@@ -68,50 +68,54 @@ public class TargetingOverlay {
|
||||
|
||||
private TargetingOverlay() {
|
||||
}
|
||||
public static void assembleArrows(final Graphics g, final CardView c, final Map<Integer, Vector2> endpoints, final CombatView combat, final Set<PlayerView> playerViewSet) {
|
||||
final CardView attachedTo = c.getAttachedTo();
|
||||
final Iterable<CardView> attachedCards = c.getAttachedCards();
|
||||
final CardView paired = c.getPairedWith();
|
||||
if (null != attachedTo) {
|
||||
if (attachedTo.getController() != null && !attachedTo.getController().equals(c.getController())) {
|
||||
public static void assembleArrows(final Graphics g, final Set<CardView> cardsonBattlefield, final Map<Integer, Vector2> endpoints, final CombatView combat, final Set<PlayerView> playerViewSet) {
|
||||
if (cardsonBattlefield.isEmpty())
|
||||
return;
|
||||
for (CardView c : cardsonBattlefield) {
|
||||
final CardView attachedTo = c.getAttachedTo();
|
||||
final Iterable<CardView> attachedCards = c.getAttachedCards();
|
||||
final CardView paired = c.getPairedWith();
|
||||
if (null != attachedTo) {
|
||||
if (attachedTo.getController() != null && !attachedTo.getController().equals(c.getController())) {
|
||||
drawArrow(g, endpoints.get(attachedTo.getId()), endpoints.get(c.getId()), ArcConnection.Friends);
|
||||
}
|
||||
}
|
||||
if (null != attachedTo && c == attachedTo.getAttachedTo()) {
|
||||
drawArrow(g, endpoints.get(attachedTo.getId()), endpoints.get(c.getId()), ArcConnection.Friends);
|
||||
}
|
||||
}
|
||||
if (null != attachedTo && c == attachedTo.getAttachedTo()) {
|
||||
drawArrow(g, endpoints.get(attachedTo.getId()), endpoints.get(c.getId()), ArcConnection.Friends);
|
||||
}
|
||||
if (null != attachedCards) {
|
||||
for (final CardView enc : attachedCards) {
|
||||
if (enc.getController() != null && !enc.getController().equals(c.getController())) {
|
||||
drawArrow(g, endpoints.get(c.getId()), endpoints.get(enc.getId()), ArcConnection.Friends);
|
||||
if (null != attachedCards) {
|
||||
for (final CardView enc : attachedCards) {
|
||||
if (enc.getController() != null && !enc.getController().equals(c.getController())) {
|
||||
drawArrow(g, endpoints.get(c.getId()), endpoints.get(enc.getId()), ArcConnection.Friends);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (null != paired) {
|
||||
drawArrow(g, endpoints.get(paired.getId()), endpoints.get(c.getId()), ArcConnection.Friends);
|
||||
}
|
||||
if (null != combat) {
|
||||
final GameEntityView defender = combat.getDefender(c);
|
||||
// if c is attacking a planeswalker or battle
|
||||
if (defender instanceof CardView) {
|
||||
drawArrow(g, endpoints.get(defender.getId()), endpoints.get(c.getId()), ArcConnection.FoesAttacking);
|
||||
if (null != paired) {
|
||||
drawArrow(g, endpoints.get(paired.getId()), endpoints.get(c.getId()), ArcConnection.Friends);
|
||||
}
|
||||
// if c is a planeswalker that's being attacked
|
||||
for (final CardView pwAttacker : combat.getAttackersOf(c)) {
|
||||
drawArrow(g, endpoints.get(c.getId()), endpoints.get(pwAttacker.getId()), ArcConnection.FoesAttacking);
|
||||
}
|
||||
for (final CardView attackingCard : combat.getAttackers()) {
|
||||
final Iterable<CardView> cards = combat.getPlannedBlockers(attackingCard);
|
||||
if (cards == null) continue;
|
||||
for (final CardView blockingCard : cards) {
|
||||
if (!attackingCard.equals(c) && !blockingCard.equals(c)) { continue; }
|
||||
drawArrow(g, endpoints.get(attackingCard.getId()), endpoints.get(blockingCard.getId()), ArcConnection.FoesBlocking);
|
||||
if (null != combat) {
|
||||
final GameEntityView defender = combat.getDefender(c);
|
||||
// if c is attacking a planeswalker or battle
|
||||
if (defender instanceof CardView) {
|
||||
drawArrow(g, endpoints.get(defender.getId()), endpoints.get(c.getId()), ArcConnection.FoesAttacking);
|
||||
}
|
||||
if (playerViewSet != null) {
|
||||
for (final PlayerView p : playerViewSet) {
|
||||
if (combat.getAttackersOf(p).contains(attackingCard)) {
|
||||
final Vector2 vPlayer = MatchController.getView().getPlayerPanel(p).getAvatar().getTargetingArrowOrigin();
|
||||
drawArrow(g, endpoints.get(attackingCard.getId()), vPlayer, TargetingOverlay.ArcConnection.FoesAttacking);
|
||||
// if c is a planeswalker that's being attacked
|
||||
for (final CardView pwAttacker : combat.getAttackersOf(c)) {
|
||||
drawArrow(g, endpoints.get(c.getId()), endpoints.get(pwAttacker.getId()), ArcConnection.FoesAttacking);
|
||||
}
|
||||
for (final CardView attackingCard : combat.getAttackers()) {
|
||||
final Iterable<CardView> cards = combat.getPlannedBlockers(attackingCard);
|
||||
if (cards == null) continue;
|
||||
for (final CardView blockingCard : cards) {
|
||||
if (!attackingCard.equals(c) && !blockingCard.equals(c)) { continue; }
|
||||
drawArrow(g, endpoints.get(attackingCard.getId()), endpoints.get(blockingCard.getId()), ArcConnection.FoesBlocking);
|
||||
}
|
||||
if (playerViewSet != null) {
|
||||
for (final PlayerView p : playerViewSet) {
|
||||
if (combat.getAttackersOf(p).contains(attackingCard)) {
|
||||
final Vector2 vPlayer = MatchScreen.getPlayerPanel(p).getAvatar().getTargetingArrowOrigin();
|
||||
drawArrow(g, endpoints.get(attackingCard.getId()), vPlayer, TargetingOverlay.ArcConnection.FoesAttacking);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,6 @@ public class VAssignGenericAmount extends FDialog {
|
||||
|
||||
/** Constructor.
|
||||
*
|
||||
* @param attacker0 {@link forge.game.card.Card}
|
||||
* @param targets Map<GameEntity, Integer>, map of GameEntity and its maximum assignable amount
|
||||
* @param amount Total amount to be assigned
|
||||
* @param atLeastOne Must assign at least one amount to each target
|
||||
@@ -168,7 +167,7 @@ public class VAssignGenericAmount extends FDialog {
|
||||
obj = add(new EffectSourcePanel((CardView)entity));
|
||||
} else if (entity instanceof PlayerView) {
|
||||
PlayerView player = (PlayerView)entity;
|
||||
obj = add(new MiscTargetPanel(player.getName(), MatchController.getPlayerAvatar(player)));
|
||||
obj = add(new MiscTargetPanel(player.getName(), MatchController.getPlayerAvatar(player), null));
|
||||
} else if (entity instanceof Byte) {
|
||||
FSkinImageInterface manaSymbol;
|
||||
byte color = (Byte) entity;
|
||||
@@ -185,9 +184,9 @@ public class VAssignGenericAmount extends FDialog {
|
||||
} else { // Should never come here, but add this to avoid compile error
|
||||
manaSymbol = Forge.getAssets().images().get(FSkinProp.IMG_MANA_COLORLESS);
|
||||
}
|
||||
obj = add(new MiscTargetPanel("", manaSymbol));
|
||||
obj = add(new MiscTargetPanel("", manaSymbol, entity));
|
||||
} else {
|
||||
obj = add(new MiscTargetPanel(entity.toString(), FSkinImage.UNKNOWN));
|
||||
obj = add(new MiscTargetPanel(entity.toString(), FSkinImage.UNKNOWN, null));
|
||||
}
|
||||
label = add(new FLabel.Builder().text("0").font(FSkinFont.get(18)).align(Align.center).build());
|
||||
btnSubtract = add(new FLabel.ButtonBuilder().icon(FSkinImage.MINUS).command(e -> assignAmountTo(entity, false)).build());
|
||||
@@ -232,19 +231,21 @@ public class VAssignGenericAmount extends FDialog {
|
||||
}
|
||||
}
|
||||
|
||||
private static class MiscTargetPanel extends FDisplayObject {
|
||||
private static final FSkinFont FONT = FSkinFont.get(18);
|
||||
private static FSkinColor getForeColor() {
|
||||
private class MiscTargetPanel extends FDisplayObject {
|
||||
private final FSkinFont FONT = FSkinFont.get(18);
|
||||
private FSkinColor getForeColor() {
|
||||
if (Forge.isMobileAdventureMode)
|
||||
return FSkinColor.get(Colors.ADV_CLR_TEXT);
|
||||
return FSkinColor.get(Colors.CLR_TEXT);
|
||||
}
|
||||
private final String name;
|
||||
private final FImage image;
|
||||
private final Object entity;
|
||||
|
||||
private MiscTargetPanel(String name0, FImage image0) {
|
||||
private MiscTargetPanel(String name0, FImage image0, Object entity0) {
|
||||
name = name0;
|
||||
image = image0;
|
||||
entity = entity0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -254,6 +255,24 @@ public class VAssignGenericAmount extends FDialog {
|
||||
g.drawImage(image, 0, 0, w, w);
|
||||
g.drawText(name, FONT, getForeColor(), 0, w, w, h - w, false, Align.center, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
if (count > 1 && entity != null) {
|
||||
AssignTarget at = targetsMap.get(entity);
|
||||
int assigned = at.amount;
|
||||
int leftToAssign = Math.max(0, at.max - assigned);
|
||||
int amountToAdd = Math.min(getRemainingAmount(), leftToAssign);
|
||||
|
||||
if (0 == amountToAdd || amountToAdd + assigned < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
addAssignedAmount(at, amountToAdd);
|
||||
updateLabels();
|
||||
}
|
||||
return super.tap(x, y, count);
|
||||
}
|
||||
}
|
||||
|
||||
private void assignAmountTo(Object source, boolean isAdding) {
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import forge.Forge;
|
||||
import forge.Graphics;
|
||||
import forge.card.CardRenderer.CardStackPosition;
|
||||
@@ -28,47 +30,21 @@ import io.sentry.Sentry;
|
||||
public abstract class VCardDisplayArea extends VDisplayArea implements ActivateHandler {
|
||||
private static final float CARD_STACK_OFFSET = 0.2f;
|
||||
|
||||
protected List<CardView> _orderedCards;
|
||||
protected List<CardView> orderedCards() {
|
||||
List<CardView> result = _orderedCards;
|
||||
if (result == null) {
|
||||
synchronized (this) {
|
||||
result = _orderedCards;
|
||||
if (result == null) {
|
||||
result = new ArrayList<>();
|
||||
_orderedCards = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _orderedCards;
|
||||
}
|
||||
protected List<CardAreaPanel> _cardPanels;
|
||||
protected List<CardAreaPanel> cardPanels() {
|
||||
List<CardAreaPanel> result = _cardPanels;
|
||||
if (result == null) {
|
||||
synchronized (this) {
|
||||
result = _cardPanels;
|
||||
if (result == null) {
|
||||
result = new ArrayList<>();
|
||||
_cardPanels = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _cardPanels;
|
||||
}
|
||||
protected Supplier<List<CardView>> orderedCards = Suppliers.memoize(ArrayList::new);
|
||||
protected Supplier<List<CardAreaPanel>> cardPanels = Suppliers.memoize(ArrayList::new);
|
||||
private boolean rotateCards180;
|
||||
|
||||
public Iterable<CardView> getOrderedCards() {
|
||||
return orderedCards();
|
||||
return orderedCards.get();
|
||||
}
|
||||
|
||||
public Iterable<CardAreaPanel> getCardPanels() {
|
||||
return cardPanels();
|
||||
return cardPanels.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return cardPanels().size();
|
||||
return cardPanels.get().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,15 +61,15 @@ public abstract class VCardDisplayArea extends VDisplayArea implements ActivateH
|
||||
for (CardView card : model) {
|
||||
CardAreaPanel cardPanel = CardAreaPanel.get(card);
|
||||
addCardPanelToDisplayArea(cardPanel);
|
||||
cardPanels().add(cardPanel);
|
||||
if (newCardPanel == null && !orderedCards().contains(card)) {
|
||||
cardPanels.get().add(cardPanel);
|
||||
if (newCardPanel == null && !orderedCards.get().contains(card)) {
|
||||
newCardPanel = cardPanel;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isVisible()) { //only revalidate if currently visible
|
||||
revalidate();
|
||||
|
||||
|
||||
if (newCardPanel != null) { //if new cards added, ensure first new card is scrolled into view
|
||||
scrollIntoView(newCardPanel);
|
||||
}
|
||||
@@ -105,7 +81,7 @@ public abstract class VCardDisplayArea extends VDisplayArea implements ActivateH
|
||||
if (isVisible() == b0) { return; }
|
||||
super.setVisible(b0);
|
||||
if (b0) { //when zone becomes visible, ensure display area of panels is updated and panels layed out
|
||||
for (CardAreaPanel pnl : cardPanels()) {
|
||||
for (CardAreaPanel pnl : cardPanels.get()) {
|
||||
pnl.displayArea = this;
|
||||
}
|
||||
revalidate();
|
||||
@@ -140,7 +116,7 @@ public abstract class VCardDisplayArea extends VDisplayArea implements ActivateH
|
||||
CardPanelContainer.this.remove(CardPanel.getDragAnimationPanel());
|
||||
CardPanelContainer.this.setMouseDragPanel(null);
|
||||
}*/
|
||||
cardPanels().remove(fromPanel);
|
||||
cardPanels.get().remove(fromPanel);
|
||||
remove(fromPanel);
|
||||
}
|
||||
|
||||
@@ -151,14 +127,14 @@ public abstract class VCardDisplayArea extends VDisplayArea implements ActivateH
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
if (!cardPanels().isEmpty()) {
|
||||
for (CardAreaPanel panel : cardPanels()) {
|
||||
if (!cardPanels.get().isEmpty()) {
|
||||
for (CardAreaPanel panel : cardPanels.get()) {
|
||||
if (panel.displayArea == null || panel.displayArea == this ||
|
||||
!panel.displayArea.cardPanels().contains(panel)) { //don't reset if panel's displayed in another area already
|
||||
!panel.displayArea.cardPanels.get().contains(panel)) { //don't reset if panel's displayed in another area already
|
||||
panel.reset();
|
||||
}
|
||||
}
|
||||
cardPanels().clear();
|
||||
cardPanels.get().clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +152,7 @@ public abstract class VCardDisplayArea extends VDisplayArea implements ActivateH
|
||||
}
|
||||
}
|
||||
|
||||
orderedCards().add(cardPanel.getCard());
|
||||
orderedCards.get().add(cardPanel.getCard());
|
||||
cardPanel.setBounds(x, y, cardWidth, cardHeight);
|
||||
|
||||
if (cardPanel.getNextPanelInStack() != null) { //add next panel in stack if needed
|
||||
@@ -195,14 +171,14 @@ public abstract class VCardDisplayArea extends VDisplayArea implements ActivateH
|
||||
|
||||
@Override
|
||||
protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) {
|
||||
orderedCards().clear();
|
||||
orderedCards.get().clear();
|
||||
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float cardHeight = visibleHeight;
|
||||
float cardWidth = getCardWidth(cardHeight);
|
||||
|
||||
for (CardAreaPanel cardPanel : new ArrayList<>(cardPanels())) {
|
||||
for (CardAreaPanel cardPanel : new ArrayList<>(cardPanels.get())) {
|
||||
if (cardPanel != null) {
|
||||
int count = addCards(cardPanel, x, y, cardWidth, cardHeight);
|
||||
x += cardWidth + (count - 1) * cardWidth * CARD_STACK_OFFSET;
|
||||
@@ -223,8 +199,8 @@ public abstract class VCardDisplayArea extends VDisplayArea implements ActivateH
|
||||
public String getActivateAction(int index) {
|
||||
if(!GuiBase.isNetworkplay()) {
|
||||
//causes lag on netplay client side, also index shouldn't be out of bounds
|
||||
if (index >= 0 && index < orderedCards().size())
|
||||
return MatchController.instance.getGameController().getActivateDescription(orderedCards().get(index));
|
||||
if (index >= 0 && index < orderedCards.get().size())
|
||||
return MatchController.instance.getGameController().getActivateDescription(orderedCards.get().get(index));
|
||||
}
|
||||
|
||||
return Forge.getLocalizer().getMessage("lblActivateAction"); //simple text on card zoom swipe up
|
||||
@@ -233,15 +209,15 @@ public abstract class VCardDisplayArea extends VDisplayArea implements ActivateH
|
||||
@Override
|
||||
public void setSelectedIndex(int index) {
|
||||
//just scroll card into view
|
||||
if (index < orderedCards().size()) {
|
||||
final CardAreaPanel cardPanel = CardAreaPanel.get(orderedCards().get(index));
|
||||
if (index < orderedCards.get().size()) {
|
||||
final CardAreaPanel cardPanel = CardAreaPanel.get(orderedCards.get().get(index));
|
||||
scrollIntoView(cardPanel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate(int index) {
|
||||
final CardAreaPanel cardPanel = CardAreaPanel.get(orderedCards().get(index));
|
||||
final CardAreaPanel cardPanel = CardAreaPanel.get(orderedCards.get().get(index));
|
||||
//must invoke in game thread in case a dialog needs to be shown
|
||||
ThreadUtil.invokeInGameThread(() -> cardPanel.selectCard(false));
|
||||
}
|
||||
@@ -449,7 +425,7 @@ public abstract class VCardDisplayArea extends VDisplayArea implements ActivateH
|
||||
public void showZoom() {
|
||||
if (displayArea == null) { return; }
|
||||
|
||||
final List<CardView> cards = displayArea.orderedCards();
|
||||
final List<CardView> cards = displayArea.orderedCards.get();
|
||||
CardZoom.show(cards, cards.indexOf(getCard()), displayArea);
|
||||
}
|
||||
|
||||
|
||||
@@ -615,7 +615,13 @@ public class VPlayerPanel extends FContainer {
|
||||
private final VDisplayArea displayArea;
|
||||
|
||||
private InfoTab(FSkinImageInterface icon0, VDisplayArea displayArea0) {
|
||||
icon = icon0;
|
||||
// missing or invalid player infotab icon probably old theme or custom theme.
|
||||
if (icon0 == null) {
|
||||
System.err.println("Missing/Invalid VPlayerPanel icon for: " + displayArea0 + " , defaulting to blank icon. Check your theme/skin layout.");
|
||||
icon = FSkinImage.BLANK;
|
||||
} else {
|
||||
icon = icon0;
|
||||
}
|
||||
displayArea = displayArea0;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import forge.menu.FMenuTab;
|
||||
import forge.menu.FPopupMenu;
|
||||
import forge.player.PlayerZoneUpdates;
|
||||
import forge.screens.match.MatchController;
|
||||
import forge.screens.match.MatchScreen;
|
||||
import forge.screens.match.TargetingOverlay;
|
||||
import forge.toolbox.FCardPanel;
|
||||
import forge.toolbox.FDisplayObject;
|
||||
@@ -179,7 +180,8 @@ public class VStack extends FDropDown {
|
||||
activeItem = display;
|
||||
}
|
||||
else {
|
||||
activeItem.setHeight(display.preferredHeight); //increase active item height to preferred height if needed
|
||||
if (display != null)
|
||||
activeItem.setHeight(display.preferredHeight); //increase active item height to preferred height if needed
|
||||
if (activeItem.getBottom() > y) {
|
||||
y = activeItem.getBottom(); //ensure stack height increases if needed
|
||||
}
|
||||
@@ -233,7 +235,7 @@ public class VStack extends FDropDown {
|
||||
}
|
||||
for (PlayerView p : instance.getTargetPlayers()) {
|
||||
TargetingOverlay.ArcConnection conn = activator.isOpponentOf(p) ? TargetingOverlay.ArcConnection.FoesStackTargeting : TargetingOverlay.ArcConnection.FriendsStackTargeting;
|
||||
TargetingOverlay.drawArrow(g, arrowOrigin, MatchController.getView().getPlayerPanel(p).getAvatar().getTargetingArrowOrigin(), conn);
|
||||
TargetingOverlay.drawArrow(g, arrowOrigin, MatchScreen.getPlayerPanel(p).getAvatar().getTargetingArrowOrigin(), conn);
|
||||
}
|
||||
instance = instance.getSubInstance();
|
||||
}
|
||||
|
||||
@@ -37,11 +37,11 @@ public class VZoneDisplay extends VCardDisplayArea {
|
||||
float y = screenToLocalY(screenY);
|
||||
if (revealedPanel.contains(x, y)) { return; }
|
||||
|
||||
int idx = cardPanels().size() - 1;
|
||||
int idx = cardPanels.get().size() - 1;
|
||||
for (int i = getChildCount() - 2; i >= 0; i--) {
|
||||
final FDisplayObject cardPanel = getChildAt(i);
|
||||
if (cardPanel.contains(x, y)) {
|
||||
idx = cardPanels().indexOf(cardPanel);
|
||||
idx = cardPanels.get().indexOf(cardPanel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -54,9 +54,9 @@ public class VZoneDisplay extends VCardDisplayArea {
|
||||
if (revealedPanel == null) { //if no overlapping panels, just pan scroll as normal
|
||||
return super.pan(x, y, deltaX, deltaY, moreVertical);
|
||||
}
|
||||
int idx = cardPanels().size() - 1;
|
||||
int idx = cardPanels.get().size() - 1;
|
||||
for (int i = idx - 1; i >= 0; i--) {
|
||||
if (cardPanels().get(i).contains(x, y)) {
|
||||
if (cardPanels.get().get(i).contains(x, y)) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
@@ -66,15 +66,15 @@ public class VZoneDisplay extends VCardDisplayArea {
|
||||
}
|
||||
|
||||
private void setRevealedPanel(int idx) {
|
||||
if (idx >= 0 && idx < cardPanels().size())
|
||||
revealedPanel = cardPanels().get(idx);
|
||||
if (idx >= 0 && idx < cardPanels.get().size())
|
||||
revealedPanel = cardPanels.get().get(idx);
|
||||
else
|
||||
return;
|
||||
|
||||
clearChildren();
|
||||
if (Forge.isLandscapeMode()) {
|
||||
//for landscape mode, just show revealed card on top
|
||||
for (CardAreaPanel cardPanel : cardPanels()) {
|
||||
for (CardAreaPanel cardPanel : cardPanels.get()) {
|
||||
if (cardPanel != revealedPanel) {
|
||||
add(cardPanel);
|
||||
}
|
||||
@@ -82,16 +82,16 @@ public class VZoneDisplay extends VCardDisplayArea {
|
||||
}
|
||||
else {
|
||||
//for portrait mode, cascade cards back from revealed panel
|
||||
int maxIdx = cardPanels().size() - 1;
|
||||
int maxIdx = cardPanels.get().size() - 1;
|
||||
int offset = Math.max(idx, maxIdx - idx);
|
||||
for (int i = offset; i > 0; i--) {
|
||||
int idx1 = idx - i;
|
||||
int idx2 = idx + i;
|
||||
if (idx1 >= 0) {
|
||||
add(cardPanels().get(idx1));
|
||||
add(cardPanels.get().get(idx1));
|
||||
}
|
||||
if (idx2 <= maxIdx) {
|
||||
add(cardPanels().get(idx2));
|
||||
add(cardPanels.get().get(idx2));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,7 @@ public class VZoneDisplay extends VCardDisplayArea {
|
||||
return new ScrollBounds(visibleWidth, visibleHeight);
|
||||
}
|
||||
|
||||
orderedCards().clear();
|
||||
orderedCards.get().clear();
|
||||
|
||||
if (Forge.isLandscapeMode() && layoutVerticallyForLandscapeMode()) {
|
||||
return layoutAndGetScrollBoundsLandscape(visibleWidth, visibleHeight);
|
||||
@@ -134,22 +134,22 @@ public class VZoneDisplay extends VCardDisplayArea {
|
||||
float cardWidth = getCardWidth(cardHeight);
|
||||
float dx = cardWidth;
|
||||
|
||||
float totalWidth = cardWidth * cardPanels().size();
|
||||
float totalWidth = cardWidth * cardPanels.get().size();
|
||||
if (totalWidth > visibleWidth && totalWidth <= visibleWidth * 2) {
|
||||
//allow overlapping cards up to one half of the card,
|
||||
//otherwise don't overlap and allow scrolling horizontally
|
||||
dx *= (visibleWidth - cardWidth) / (totalWidth - cardWidth);
|
||||
dx += FCardPanel.PADDING / cardPanels().size(); //make final card go right up to right edge of screen
|
||||
dx += FCardPanel.PADDING / cardPanels.get().size(); //make final card go right up to right edge of screen
|
||||
if (revealedPanel == null) {
|
||||
revealedPanel = cardPanels().get(cardPanels().size() - 1);
|
||||
revealedPanel = cardPanels.get().get(cardPanels.get().size() - 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
revealedPanel = null;
|
||||
}
|
||||
|
||||
for (CardAreaPanel cardPanel : cardPanels()) {
|
||||
orderedCards().add(cardPanel.getCard());
|
||||
for (CardAreaPanel cardPanel : cardPanels.get()) {
|
||||
orderedCards.get().add(cardPanel.getCard());
|
||||
cardPanel.setBounds(x, y, cardWidth, cardHeight);
|
||||
x += dx;
|
||||
}
|
||||
@@ -165,7 +165,7 @@ public class VZoneDisplay extends VCardDisplayArea {
|
||||
float dy = cardHeight;
|
||||
float scrollHeight;
|
||||
|
||||
int rowCount = (int)Math.ceil((float)cardPanels().size() / 2f);
|
||||
int rowCount = (int)Math.ceil((float)cardPanels.get().size() / 2f);
|
||||
float totalHeight = cardHeight * rowCount;
|
||||
if (totalHeight > visibleHeight && totalHeight <= visibleHeight * 3) {
|
||||
//allow overlapping cards up to one third of the card,
|
||||
@@ -173,7 +173,7 @@ public class VZoneDisplay extends VCardDisplayArea {
|
||||
dy *= (visibleHeight - cardHeight) / (totalHeight - cardHeight);
|
||||
dy += FCardPanel.PADDING / rowCount; //make final card go right up to right edge of screen
|
||||
if (revealedPanel == null) {
|
||||
revealedPanel = cardPanels().get(cardPanels().size() - 1);
|
||||
revealedPanel = cardPanels.get().get(cardPanels.get().size() - 1);
|
||||
}
|
||||
scrollHeight = visibleHeight;
|
||||
}
|
||||
@@ -182,10 +182,10 @@ public class VZoneDisplay extends VCardDisplayArea {
|
||||
scrollHeight = rowCount * dy;
|
||||
}
|
||||
|
||||
for (CardAreaPanel cardPanel : cardPanels()) {
|
||||
orderedCards().add(cardPanel.getCard());
|
||||
for (CardAreaPanel cardPanel : cardPanels.get()) {
|
||||
orderedCards.get().add(cardPanel.getCard());
|
||||
cardPanel.setBounds(x, y, cardWidth, cardHeight);
|
||||
if (orderedCards().size() % 2 == 0) {
|
||||
if (orderedCards.get().size() % 2 == 0) {
|
||||
x = 0;
|
||||
y += dy;
|
||||
}
|
||||
|
||||
@@ -244,6 +244,10 @@ public class SettingsPage extends TabPage<SettingsScreen> {
|
||||
Forge.getLocalizer().getMessage("cbExperimentalRestore"),
|
||||
Forge.getLocalizer().getMessage("nlExperimentalRestore")),
|
||||
1);
|
||||
lstSettings.addItem(new CustomSelectSetting(FPref.MATCH_AI_TIMEOUT, Forge.getLocalizer().getMessage("cbAITimeout"),
|
||||
Forge.getLocalizer().getMessage("nlAITimeout"),
|
||||
Lists.newArrayList("5", "10", "60", "120", "240", "300", "600")),
|
||||
1);
|
||||
lstSettings.addItem(new BooleanSetting(FPref.FILTERED_HANDS,
|
||||
Forge.getLocalizer().getMessage("cbFilteredHands"),
|
||||
Forge.getLocalizer().getMessage("nlFilteredHands")),
|
||||
|
||||
Reference in New Issue
Block a user