Add reveal button to mobile-gui

- currently it gets all cards that was revealed by via reveal(...)
- update menutab to show scroll indicator as default
This commit is contained in:
Anthony Calosa
2022-12-10 09:20:41 +08:00
parent d15a505081
commit ccc985654c
19 changed files with 841 additions and 367 deletions

View File

@@ -18,6 +18,7 @@ import forge.game.player.PlayerView;
import forge.game.player.RegisteredPlayer; import forge.game.player.RegisteredPlayer;
import forge.game.spellability.StackItemView; import forge.game.spellability.StackItemView;
import forge.game.zone.MagicStack; import forge.game.zone.MagicStack;
import forge.trackable.TrackableCollection;
import forge.trackable.TrackableObject; import forge.trackable.TrackableObject;
import forge.trackable.TrackableProperty; import forge.trackable.TrackableProperty;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
@@ -64,15 +65,19 @@ public class GameView extends TrackableObject {
public String getTitle() { public String getTitle() {
return get(TrackableProperty.Title); return get(TrackableProperty.Title);
} }
public boolean isCommander() { public boolean isCommander() {
return get(TrackableProperty.IsCommander); return get(TrackableProperty.IsCommander);
} }
public GameType getGameType() { public GameType getGameType() {
return get(TrackableProperty.GameType); return get(TrackableProperty.GameType);
} }
public int getPoisonCountersToLose() { public int getPoisonCountersToLose() {
return get(TrackableProperty.PoisonCountersToLose); return get(TrackableProperty.PoisonCountersToLose);
} }
public int getNumGamesInMatch() { public int getNumGamesInMatch() {
return get(TrackableProperty.NumGamesInMatch); return get(TrackableProperty.NumGamesInMatch);
} }
@@ -80,31 +85,39 @@ public class GameView extends TrackableObject {
public int getTurn() { public int getTurn() {
return get(TrackableProperty.Turn); return get(TrackableProperty.Turn);
} }
void updateTurn(PhaseHandler phaseHandler) { void updateTurn(PhaseHandler phaseHandler) {
set(TrackableProperty.Turn, phaseHandler.getTurn()); set(TrackableProperty.Turn, phaseHandler.getTurn());
} }
public PhaseType getPhase() { public PhaseType getPhase() {
return get(TrackableProperty.Phase); return get(TrackableProperty.Phase);
} }
void updatePhase(PhaseHandler phaseHandler) { void updatePhase(PhaseHandler phaseHandler) {
set(TrackableProperty.Phase, phaseHandler.getPhase()); set(TrackableProperty.Phase, phaseHandler.getPhase());
} }
public PlayerView getPlayerTurn() { public PlayerView getPlayerTurn() {
return get(TrackableProperty.PlayerTurn); return get(TrackableProperty.PlayerTurn);
} }
void updatePlayerTurn(PhaseHandler phaseHandler) { void updatePlayerTurn(PhaseHandler phaseHandler) {
set(TrackableProperty.PlayerTurn, PlayerView.get(phaseHandler.getPlayerTurn())); set(TrackableProperty.PlayerTurn, PlayerView.get(phaseHandler.getPlayerTurn()));
} }
public void updateNeedsPhaseRedrawn(PlayerView p, PhaseType ph) { public void updateNeedsPhaseRedrawn(PlayerView p, PhaseType ph) {
set(TrackableProperty.PlayerTurn, p); set(TrackableProperty.PlayerTurn, p);
set(TrackableProperty.Phase, ph); set(TrackableProperty.Phase, ph);
set(TrackableProperty.NeedsPhaseRedrawn, true); set(TrackableProperty.NeedsPhaseRedrawn, true);
} }
public boolean getNeedsPhaseRedrawn() { public boolean getNeedsPhaseRedrawn() {
if (get(TrackableProperty.NeedsPhaseRedrawn) == null) if (get(TrackableProperty.NeedsPhaseRedrawn) == null)
return false; return false;
return get(TrackableProperty.NeedsPhaseRedrawn); return get(TrackableProperty.NeedsPhaseRedrawn);
} }
public void clearNeedsPhaseRedrawn() { public void clearNeedsPhaseRedrawn() {
set(TrackableProperty.NeedsPhaseRedrawn, false); set(TrackableProperty.NeedsPhaseRedrawn, false);
} }
@@ -112,18 +125,23 @@ public class GameView extends TrackableObject {
public void updatePlanarPlayer(PlayerView p) { public void updatePlanarPlayer(PlayerView p) {
set(TrackableProperty.PlanarPlayer, p); set(TrackableProperty.PlanarPlayer, p);
} }
public PlayerView getPlanarPlayer() { public PlayerView getPlanarPlayer() {
return get(TrackableProperty.PlanarPlayer); return get(TrackableProperty.PlanarPlayer);
} }
public FCollectionView<StackItemView> getStack() { public FCollectionView<StackItemView> getStack() {
return get(TrackableProperty.Stack); return get(TrackableProperty.Stack);
} }
public StackItemView peekStack() { public StackItemView peekStack() {
return Iterables.getFirst(getStack(), null); return Iterables.getFirst(getStack(), null);
} }
public int getStormCount() { public int getStormCount() {
return get(TrackableProperty.StormCount); return get(TrackableProperty.StormCount);
} }
void updateStack(final MagicStack stack) { void updateStack(final MagicStack stack) {
set(TrackableProperty.Stack, StackItemView.getCollection(stack)); set(TrackableProperty.Stack, StackItemView.getCollection(stack));
set(TrackableProperty.StormCount, stack.getSpellsCastThisTurn().size()); set(TrackableProperty.StormCount, stack.getSpellsCastThisTurn().size());
@@ -132,6 +150,7 @@ public class GameView extends TrackableObject {
public boolean isFirstGameInMatch() { public boolean isFirstGameInMatch() {
return getNumPlayedGamesInMatch() == 0; return getNumPlayedGamesInMatch() == 0;
} }
public int getNumPlayedGamesInMatch() { public int getNumPlayedGamesInMatch() {
return get(TrackableProperty.NumPlayedGamesInMatch); return get(TrackableProperty.NumPlayedGamesInMatch);
} }
@@ -139,23 +158,29 @@ public class GameView extends TrackableObject {
public boolean isGameOver() { public boolean isGameOver() {
return get(TrackableProperty.GameOver); return get(TrackableProperty.GameOver);
} }
public boolean isMatchOver() { public boolean isMatchOver() {
return get(TrackableProperty.MatchOver); return get(TrackableProperty.MatchOver);
} }
public boolean isMulligan() { public boolean isMulligan() {
if (get(TrackableProperty.Mulligan) == null) if (get(TrackableProperty.Mulligan) == null)
return false; return false;
return get(TrackableProperty.Mulligan); return get(TrackableProperty.Mulligan);
} }
public void updateIsMulligan(boolean value) { public void updateIsMulligan(boolean value) {
set(TrackableProperty.Mulligan, value); set(TrackableProperty.Mulligan, value);
} }
public String getWinningPlayerName() { public String getWinningPlayerName() {
return get(TrackableProperty.WinningPlayerName); return get(TrackableProperty.WinningPlayerName);
} }
public int getWinningTeam() { public int getWinningTeam() {
return get(TrackableProperty.WinningTeam); return get(TrackableProperty.WinningTeam);
} }
void updateGameOver(final Game game) { void updateGameOver(final Game game) {
set(TrackableProperty.GameOver, game.isGameOver()); set(TrackableProperty.GameOver, game.isGameOver());
set(TrackableProperty.MatchOver, game.getMatch().isMatchOver()); set(TrackableProperty.MatchOver, game.getMatch().isMatchOver());
@@ -168,16 +193,27 @@ public class GameView extends TrackableObject {
public GameLog getGameLog() { public GameLog getGameLog() {
return get(TrackableProperty.GameLog); return get(TrackableProperty.GameLog);
} }
void updateGameLog(GameLog gameLog) { void updateGameLog(GameLog gameLog) {
flagAsChanged(TrackableProperty.GameLog); //don't need to set the property since it won't change flagAsChanged(TrackableProperty.GameLog); //don't need to set the property since it won't change
} }
public TrackableCollection<CardView> getRevealedCollection() {
return get(TrackableProperty.RevealedCardsCollection);
}
public void updateRevealedCards(TrackableCollection<CardView> collection) {
set(TrackableProperty.RevealedCardsCollection, collection);
}
public CombatView getCombat() { public CombatView getCombat() {
return get(TrackableProperty.CombatView); return get(TrackableProperty.CombatView);
} }
public void updateCombatView(CombatView combatView) { public void updateCombatView(CombatView combatView) {
set(TrackableProperty.CombatView, combatView); set(TrackableProperty.CombatView, combatView);
} }
void updateCombat(Combat combat) { void updateCombat(Combat combat) {
if (combat == null) { if (combat == null) {
set(TrackableProperty.CombatView, null); set(TrackableProperty.CombatView, null);

View File

@@ -43,6 +43,7 @@ public enum TrackableProperty {
SplitCard(TrackableTypes.BooleanType), SplitCard(TrackableTypes.BooleanType),
MergedCards(TrackableTypes.StringType), MergedCards(TrackableTypes.StringType),
MergedCardsCollection(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze), MergedCardsCollection(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
RevealedCardsCollection(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
PaperCardBackup(TrackableTypes.IPaperCardType), PaperCardBackup(TrackableTypes.IPaperCardType),
Attacking(TrackableTypes.BooleanType), Attacking(TrackableTypes.BooleanType),
@@ -278,6 +279,7 @@ public enum TrackableProperty {
TrackableProperty(TrackableType<?> type0) { TrackableProperty(TrackableType<?> type0) {
this(type0, FreezeMode.RespectsFreeze); this(type0, FreezeMode.RespectsFreeze);
} }
TrackableProperty(TrackableType<?> type0, FreezeMode freezeMode0) { TrackableProperty(TrackableType<?> type0, FreezeMode freezeMode0) {
type = type0; type = type0;
freezeMode = freezeMode0; freezeMode = freezeMode0;
@@ -304,10 +306,12 @@ public enum TrackableProperty {
public <T> T getDefaultValue() { public <T> T getDefaultValue() {
return ((TrackableType<T>) type).getDefaultValue(); return ((TrackableType<T>) type).getDefaultValue();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T deserialize(TrackableDeserializer td, T oldValue) { public <T> T deserialize(TrackableDeserializer td, T oldValue) {
return ((TrackableType<T>) type).deserialize(td, oldValue); return ((TrackableType<T>) type).deserialize(td, oldValue);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> void serialize(TrackableSerializer ts, T value) { public <T> void serialize(TrackableSerializer ts, T value) {
((TrackableType<T>) type).serialize(ts, value); ((TrackableType<T>) type).serialize(ts, value);
@@ -318,9 +322,11 @@ public enum TrackableProperty {
//we don't need to worry about the values changing since we will ensure //we don't need to worry about the values changing since we will ensure
//both players are on the same version of Forge before allowing them to connect //both players are on the same version of Forge before allowing them to connect
private static TrackableProperty[] props = values(); private static TrackableProperty[] props = values();
public static int serialize(TrackableProperty prop) { public static int serialize(TrackableProperty prop) {
return prop.ordinal(); return prop.ordinal();
} }
public static TrackableProperty deserialize(int ordinal) { public static TrackableProperty deserialize(int ordinal) {
return props[ordinal]; return props[ordinal];
} }

View File

@@ -1132,7 +1132,8 @@ public class Forge implements ApplicationListener {
return false; return false;
} }
} }
public static float mouseMovedX = 0;
public static float mouseMovedY = 0;
private static class MainInputProcessor extends FGestureAdapter { private static class MainInputProcessor extends FGestureAdapter {
private static final List<FDisplayObject> potentialListeners = new ArrayList<>(); private static final List<FDisplayObject> potentialListeners = new ArrayList<>();
private static char lastKeyTyped; private static char lastKeyTyped;
@@ -1216,7 +1217,7 @@ public class Forge implements ApplicationListener {
return false; return false;
} }
private void updatePotentialListeners(int x, int y) { private void updatePotentialListeners(float x, float y) {
potentialListeners.clear(); potentialListeners.clear();
//base potential listeners on object containing touch down point //base potential listeners on object containing touch down point
@@ -1391,8 +1392,6 @@ public class Forge implements ApplicationListener {
} }
//mouseMoved and scrolled events for desktop version //mouseMoved and scrolled events for desktop version
private int mouseMovedX, mouseMovedY;
@Override @Override
public boolean mouseMoved(int screenX, int screenY) { public boolean mouseMoved(int screenX, int screenY) {
magnify = true; magnify = true;

View File

@@ -338,6 +338,9 @@ public enum FSkinImage implements FImage {
FAVICON (FSkinProp.ICO_FAVICON, SourceFile.ICONS), FAVICON (FSkinProp.ICO_FAVICON, SourceFile.ICONS),
LOCK (FSkinProp.ICO_LOCK, SourceFile.ICONS), LOCK (FSkinProp.ICO_LOCK, SourceFile.ICONS),
//reveal icons
SEE (FSkinProp.ICO_SEE, SourceFile.ICONS),
UNSEE (FSkinProp.ICO_UNSEE, SourceFile.ICONS),
//Layout images //Layout images
HANDLE (FSkinProp.IMG_HANDLE, SourceFile.ICONS), HANDLE (FSkinProp.IMG_HANDLE, SourceFile.ICONS),

View File

@@ -774,9 +774,7 @@ public class CardRenderer {
} }
//Darken unselectable cards //Darken unselectable cards
if (unselectable) { if (unselectable) {
g.setAlphaComposite(0.6f); g.fillRect(FSkinColor.getStandardColor(Color.BLACK).alphaColor(0.6f), cx, cy, cw, ch);
g.fillRect(Color.BLACK, cx, cy, cw, ch);
g.setAlphaComposite(oldAlpha);
} }
//Magenta outline when card is chosen //Magenta outline when card is chosen
if (MatchController.instance.isUsedToPay(card)) { if (MatchController.instance.isUsedToPay(card)) {

View File

@@ -7,8 +7,13 @@ import forge.Graphics;
import forge.assets.FSkinColor; import forge.assets.FSkinColor;
import forge.assets.FSkinColor.Colors; import forge.assets.FSkinColor.Colors;
import forge.assets.FSkinTexture; import forge.assets.FSkinTexture;
import forge.gui.GuiBase;
import forge.screens.FScreen; import forge.screens.FScreen;
import forge.screens.match.views.VDevMenu;
import forge.screens.match.views.VGameMenu;
import forge.screens.match.views.VLog;
import forge.screens.match.views.VPlayers;
import forge.screens.match.views.VReveal;
import forge.screens.match.views.VStack;
import forge.toolbox.FContainer; import forge.toolbox.FContainer;
import forge.toolbox.FDisplayObject; import forge.toolbox.FDisplayObject;
import forge.toolbox.FOverlay; import forge.toolbox.FOverlay;
@@ -34,6 +39,7 @@ public abstract class FDropDown extends FScrollPane {
public FMenuTab getMenuTab() { public FMenuTab getMenuTab() {
return menuTab; return menuTab;
} }
public void setMenuTab(FMenuTab menuTab0) { public void setMenuTab(FMenuTab menuTab0) {
menuTab = menuTab0; menuTab = menuTab0;
} }
@@ -41,6 +47,7 @@ public abstract class FDropDown extends FScrollPane {
public FContainer getDropDownContainer() { public FContainer getDropDownContainer() {
return dropDownContainer; return dropDownContainer;
} }
public void setDropDownContainer(FContainer dropDownContainer0) { public void setDropDownContainer(FContainer dropDownContainer0) {
dropDownContainer = dropDownContainer0; dropDownContainer = dropDownContainer0;
} }
@@ -69,9 +76,11 @@ public abstract class FDropDown extends FScrollPane {
public void hide() { public void hide() {
setVisible(false); setVisible(false);
} }
public void setNextSelected() { public void setNextSelected() {
scrollToHoveredChild(true); scrollToHoveredChild(true);
} }
public void setPreviousSelected() { public void setPreviousSelected() {
scrollToHoveredChild(false); scrollToHoveredChild(false);
} }
@@ -101,7 +110,9 @@ public abstract class FDropDown extends FScrollPane {
@Override @Override
public void setVisible(boolean visible0) { public void setVisible(boolean visible0) {
if (isVisible() == visible0) { return; } if (isVisible() == visible0) {
return;
}
//add/remove drop down from its container, current screen, or top overlay when its visibility changes //add/remove drop down from its container, current screen, or top overlay when its visibility changes
FContainer container = getContainer(); FContainer container = getContainer();
@@ -114,8 +125,7 @@ public abstract class FDropDown extends FScrollPane {
container.add(backdrop); container.add(backdrop);
} }
container.add(this); container.add(this);
} } else {
else {
container.remove(this); container.remove(this);
if (backdrop != null) { if (backdrop != null) {
backdrop.setVisible(false); backdrop.setVisible(false);
@@ -131,10 +141,13 @@ public abstract class FDropDown extends FScrollPane {
} }
protected abstract boolean autoHide(); protected abstract boolean autoHide();
protected abstract ScrollBounds updateAndGetPaneSize(float maxWidth, float maxVisibleHeight); protected abstract ScrollBounds updateAndGetPaneSize(float maxWidth, float maxVisibleHeight);
protected void updateSizeAndPosition() { protected void updateSizeAndPosition() {
if (menuTab == null) { return; } if (menuTab == null) {
return;
}
Rectangle boundary = Forge.getCurrentScreen().getDropDownBoundary(); Rectangle boundary = Forge.getCurrentScreen().getDropDownBoundary();
@@ -145,8 +158,7 @@ public abstract class FDropDown extends FScrollPane {
if (y < boundary.y + boundary.height / 2) { if (y < boundary.y + boundary.height / 2) {
showAbove = false; showAbove = false;
maxVisibleHeight = boundary.y + boundary.height - y; //prevent covering prompt maxVisibleHeight = boundary.y + boundary.height - y; //prevent covering prompt
} } else { //handle drop downs at near bottom of screen
else { //handle drop downs at near bottom of screen
showAbove = true; showAbove = true;
y = menuTab.screenPos.y; y = menuTab.screenPos.y;
maxVisibleHeight = y - boundary.y; maxVisibleHeight = y - boundary.y;
@@ -191,6 +203,31 @@ public abstract class FDropDown extends FScrollPane {
float w = getWidth(); float w = getWidth();
float h = getHeight(); float h = getHeight();
g.drawRect(2, getBorderColor(), 0, 0, w, h); //ensure border shows up on all sides g.drawRect(2, getBorderColor(), 0, 0, w, h); //ensure border shows up on all sides
if (getDropDownOwner() instanceof FMenuTab) {
try {
if (getScrollLeft() > 0) {
float x = getIndicatorMargin();
float y = getHeight() / 2;
g.fillTriangle(getIndicatorColor(), x, y, x + getIndicatorSize(), y - getIndicatorSize(), x + getIndicatorSize(), y + getIndicatorSize());
}
if (getScrollLeft() < getMaxScrollLeft()) {
float x = getWidth() - getIndicatorMargin();
float y = getHeight() / 2;
g.fillTriangle(getIndicatorColor(), x, y, x - getIndicatorSize(), y - getIndicatorSize(), x - getIndicatorSize(), y + getIndicatorSize());
}
if (getScrollTop() > 0) {
float x = getWidth() / 2;
float y = getIndicatorMargin();
g.fillTriangle(getIndicatorColor(), x, y, x - getIndicatorSize(), y + getIndicatorSize(), x + getIndicatorSize(), y + getIndicatorSize());
}
if (getScrollTop() < getMaxScrollTop()) {
float x = getWidth() / 2;
float y = getHeight() - getIndicatorSize();
g.fillTriangle(getIndicatorColor(), x, y, x - getIndicatorSize(), y - getIndicatorSize(), x + getIndicatorSize(), y - getIndicatorSize());
}
} catch (Exception e) {
}
}
} }
protected FDisplayObject getDropDownOwner() { protected FDisplayObject getDropDownOwner() {
@@ -201,6 +238,7 @@ public abstract class FDropDown extends FScrollPane {
FDisplayObject owner = getDropDownOwner(); FDisplayObject owner = getDropDownOwner();
return owner == null || !owner.screenPos.contains(x, y); //auto-hide when backdrop pressed unless over owner return owner == null || !owner.screenPos.contains(x, y); //auto-hide when backdrop pressed unless over owner
} }
public void tapChild() { public void tapChild() {
if (selectedChild != null) { if (selectedChild != null) {
selectedChild.tap(0, 0, 1); selectedChild.tap(0, 0, 1);
@@ -210,11 +248,13 @@ public abstract class FDropDown extends FScrollPane {
hide(); hide();
} }
} }
public void cancel() { public void cancel() {
if (getMenuTab() != null) if (getMenuTab() != null)
getMenuTab().clearSelected(); getMenuTab().clearSelected();
hide(); hide();
} }
public void scrollToHoveredChild(boolean down) { public void scrollToHoveredChild(boolean down) {
selectedChild = null; selectedChild = null;
for (FDisplayObject fDisplayObject : getChildren()) { for (FDisplayObject fDisplayObject : getChildren()) {
@@ -252,7 +292,9 @@ public abstract class FDropDown extends FScrollPane {
@Override @Override
public boolean tap(float x, float y, int count) { public boolean tap(float x, float y, int count) {
if (!isVisible()) { return false; } if (!isVisible()) {
return false;
}
hide(); //always hide if tapped hide(); //always hide if tapped
return preventOwnerHandlingBackupTap(x, y, count); return preventOwnerHandlingBackupTap(x, y, count);
@@ -260,21 +302,21 @@ public abstract class FDropDown extends FScrollPane {
@Override @Override
public boolean pan(float x, float y, float deltaX, float deltaY, boolean moreVertical) { public boolean pan(float x, float y, float deltaX, float deltaY, boolean moreVertical) {
if (!GuiBase.isAndroid()) if (!isMatchHeader())
hide(); //always hide if backdrop panned hide(); //always hide if backdrop panned
return false; //allow pan to pass through to object behind backdrop return false; //allow pan to pass through to object behind backdrop
} }
@Override @Override
public boolean fling(float velocityX, float velocityY) { public boolean fling(float velocityX, float velocityY) {
if (!GuiBase.isAndroid()) if (!isMatchHeader())
hide(); //always hide if backdrop flung hide(); //always hide if backdrop flung
return false; //allow fling to pass through to object behind backdrop return false; //allow fling to pass through to object behind backdrop
} }
@Override @Override
public boolean zoom(float x, float y, float amount) { public boolean zoom(float x, float y, float amount) {
if (!GuiBase.isAndroid()) if (!isMatchHeader())
hide(); //always hide if backdrop zoomed hide(); //always hide if backdrop zoomed
return false; //allow zoom to pass through to object behind backdrop return false; //allow zoom to pass through to object behind backdrop
} }
@@ -284,4 +326,20 @@ public abstract class FDropDown extends FScrollPane {
//draw nothing for backdrop //draw nothing for backdrop
} }
} }
private boolean isMatchHeader() {
if (this instanceof VGameMenu)
return true;
if (this instanceof VPlayers)
return true;
if (this instanceof VReveal)
return true;
if (this instanceof VLog)
return true;
if (this instanceof VDevMenu)
return true;
if (this instanceof VStack)
return true;
return false;
}
} }

View File

@@ -4,15 +4,21 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.badlogic.gdx.Input; import com.badlogic.gdx.Input;
import forge.Forge;
import forge.Graphics; import forge.Graphics;
import forge.screens.FScreen.Header; import forge.screens.FScreen.Header;
import forge.screens.match.MatchController;
public class FMenuBar extends Header { public class FMenuBar extends Header {
private final List<FMenuTab> tabs = new ArrayList<>(); private final List<FMenuTab> tabs = new ArrayList<>();
private int selected = -1; private int selected = -1;
public void addTab(String text0, FDropDown dropDown0) { public void addTab(String text0, FDropDown dropDown0) {
FMenuTab tab = new FMenuTab(text0, this, dropDown0, tabs.size()); addTab(text0, dropDown0, false);
}
public void addTab(String text0, FDropDown dropDown0, boolean iconOnly) {
FMenuTab tab = new FMenuTab(text0, this, dropDown0, tabs.size(), iconOnly);
dropDown0.setMenuTab(tab); dropDown0.setMenuTab(tab);
tabs.add(add(tab)); tabs.add(add(tab));
} }
@@ -29,10 +35,22 @@ public class FMenuBar extends Header {
protected void doLayout(float width, float height) { protected void doLayout(float width, float height) {
int visibleTabCount = 0; int visibleTabCount = 0;
float minWidth = 0; float minWidth = 0;
int iconOnlyTabCount = 0;
float iconMinWidth = 0;
for (FMenuTab tab : tabs) { for (FMenuTab tab : tabs) {
if (tab.isVisible()) { if (tab.isVisible()) {
if (Forge.isLandscapeMode()) {
if (!tab.iconOnly) {
minWidth += tab.getMinWidth(); minWidth += tab.getMinWidth();
visibleTabCount++; visibleTabCount++;
} else {
iconMinWidth += tab.getMinWidth();
iconOnlyTabCount++;
}
} else {
minWidth += tab.getMinWidth();
visibleTabCount++;
}
} }
} }
int tabWidth; int tabWidth;
@@ -40,12 +58,15 @@ public class FMenuBar extends Header {
float dx = (width - minWidth) / visibleTabCount; float dx = (width - minWidth) / visibleTabCount;
for (FMenuTab tab : tabs) { for (FMenuTab tab : tabs) {
if (tab.isVisible()) { if (tab.isVisible()) {
if (tab.iconOnly) {
tab.setActiveIcon(MatchController.instance.getGameView().getRevealedCollection() != null);
}
tabWidth = Math.round(tab.getMinWidth() + dx); tabWidth = Math.round(tab.getMinWidth() + dx);
if (x + tabWidth > width) { if (x + tabWidth > width) {
tabWidth = Math.round(width - x); //prevent final tab extending off screen tabWidth = Math.round(width - x); //prevent final tab extending off screen
} }
tab.setBounds(x, 0, tabWidth, height); tab.setBounds(tab.iconOnly ? 0 : x, 0, tab.iconOnly ? tab.getMinWidth() + FMenuTab.PADDING * 2 : tabWidth, height);
x += tabWidth; x += tab.iconOnly ? tab.getMinWidth() + FMenuTab.PADDING * 2 : tabWidth;
} }
} }
} }
@@ -61,6 +82,7 @@ public class FMenuBar extends Header {
public float doLandscapeLayout(float screenWidth, float screenHeight) { public float doLandscapeLayout(float screenWidth, float screenHeight) {
return 0; return 0;
} }
public void setNextSelected() { public void setNextSelected() {
selected++; selected++;
closeAll(); closeAll();
@@ -68,13 +90,15 @@ public class FMenuBar extends Header {
selected = 0; selected = 0;
try { try {
tabs.get(selected).showDropDown(); tabs.get(selected).showDropDown();
} catch (Exception e) {} } catch (Exception e) {
}
if (selected > tabs.size()) { if (selected > tabs.size()) {
closeAll(); closeAll();
selected = tabs.size(); selected = tabs.size();
return; return;
} }
} }
public void setPreviousSelected() { public void setPreviousSelected() {
selected--; selected--;
closeAll(); closeAll();
@@ -82,21 +106,25 @@ public class FMenuBar extends Header {
selected = tabs.size(); selected = tabs.size();
try { try {
tabs.get(selected).showDropDown(); tabs.get(selected).showDropDown();
} catch (Exception e) {} } catch (Exception e) {
}
if (selected < 0) { if (selected < 0) {
closeAll(); closeAll();
selected = -1; selected = -1;
return; return;
} }
} }
public void closeAll() { public void closeAll() {
for (FMenuTab fMenuTab : tabs) { for (FMenuTab fMenuTab : tabs) {
fMenuTab.hideDropDown(); fMenuTab.hideDropDown();
} }
} }
public boolean isShowingMenu(boolean anyDropdown) { public boolean isShowingMenu(boolean anyDropdown) {
return tabs.stream().anyMatch(tab -> tab.isShowingDropdownMenu(anyDropdown)); return tabs.stream().anyMatch(tab -> tab.isShowingDropdownMenu(anyDropdown));
} }
public void clearSelected() { public void clearSelected() {
selected--; selected--;
if (selected < -1) if (selected < -1)

View File

@@ -5,14 +5,18 @@ import com.badlogic.gdx.utils.Align;
import forge.Forge; import forge.Forge;
import forge.Graphics; import forge.Graphics;
import forge.assets.FImage;
import forge.assets.FSkinColor; import forge.assets.FSkinColor;
import forge.assets.FSkinColor.Colors; import forge.assets.FSkinColor.Colors;
import forge.assets.FSkinFont; import forge.assets.FSkinFont;
import forge.assets.FSkinImage;
import forge.toolbox.FDisplayObject; import forge.toolbox.FDisplayObject;
import forge.util.Utils; import forge.util.Utils;
public class FMenuTab extends FDisplayObject { public class FMenuTab extends FDisplayObject {
public static final FSkinFont FONT = FSkinFont.get(12); public static final FSkinFont FONT = FSkinFont.get(12);
boolean iconOnly = false;
boolean active = false;
private static FSkinColor getSelBackColor() { private static FSkinColor getSelBackColor() {
if (Forge.isMobileAdventureMode) if (Forge.isMobileAdventureMode)
return FSkinColor.get(Colors.ADV_CLR_ACTIVE); return FSkinColor.get(Colors.ADV_CLR_ACTIVE);
@@ -42,10 +46,11 @@ public class FMenuTab extends FDisplayObject {
private float minWidth; private float minWidth;
private int index; private int index;
public FMenuTab(String text0, FMenuBar menuBar0, FDropDown dropDown0, int index0) { public FMenuTab(String text0, FMenuBar menuBar0, FDropDown dropDown0, int index0, boolean iconOnly0) {
menuBar = menuBar0; menuBar = menuBar0;
dropDown = dropDown0; dropDown = dropDown0;
index = index0; index = index0;
iconOnly = iconOnly0;
setText(text0); setText(text0);
} }
@@ -89,6 +94,10 @@ public class FMenuTab extends FDisplayObject {
menuBar.revalidate(); menuBar.revalidate();
} }
public void setActiveIcon(boolean value) {
active = value;
}
@Override @Override
public void setVisible(boolean visible0) { public void setVisible(boolean visible0) {
if (isVisible() == visible0) { return; } if (isVisible() == visible0) { return; }
@@ -102,6 +111,10 @@ public class FMenuTab extends FDisplayObject {
} }
public float getMinWidth() { public float getMinWidth() {
if (iconOnly) {
float multiplier = Forge.isLandscapeMode() ? 2.5f : 1.8f;
return FONT.getLineHeight() * multiplier;
}
return minWidth; return minWidth;
} }
@@ -140,6 +153,13 @@ public class FMenuTab extends FDisplayObject {
h = getHeight() - 2 * PADDING; h = getHeight() - 2 * PADDING;
if (isHovered()) if (isHovered())
g.fillRect(getSelBackColor().brighter(), x, y, w, h); g.fillRect(getSelBackColor().brighter(), x, y, w, h);
if (iconOnly) {
float mod = w * 0.75f;
FImage icon = active ? FSkinImage.SEE : FSkinImage.UNSEE;
float scaleW = icon.getWidth() * 0.8f;
float scaleH = icon.getHeight() * 0.8f;
g.drawImage(icon, x + w/2 - scaleW/2, y + h/2 - scaleH/2, scaleW, scaleH);
} else
g.drawText(text, FONT, foreColor, x, y, w, h, false, Align.center, true); g.drawText(text, FONT, foreColor, x, y, w, h, false, Align.center, true);
} }
public boolean isShowingDropdownMenu(boolean any) { public boolean isShowingDropdownMenu(boolean any) {

View File

@@ -123,9 +123,7 @@ public class LoadingOverlay extends FOverlay {
float y = (getHeight() - panelHeight) / 2; float y = (getHeight() - panelHeight) / 2;
float oldAlpha = g.getfloatAlphaComposite(); float oldAlpha = g.getfloatAlphaComposite();
//dark translucent back.. //dark translucent back..
g.setAlphaComposite(0.6f); g.fillRect(FSkinColor.getStandardColor(Color.BLACK).alphaColor(0.6f), 0, 0, getWidth(), getHeight());
g.fillRect(Color.BLACK, 0, 0, getWidth(), getHeight());
g.setAlphaComposite(oldAlpha);
//overlay //overlay
g.fillRect(getOverlayColor(), x, y, panelWidth, panelHeight); g.fillRect(getOverlayColor(), x, y, panelWidth, panelHeight);
g.drawRect(Utils.scale(2), getForeColor(), x, y, panelWidth, panelHeight); g.drawRect(Utils.scale(2), getForeColor(), x, y, panelWidth, panelHeight);

View File

@@ -13,6 +13,7 @@ import forge.card.CardZoom;
import forge.game.spellability.StackItemView; import forge.game.spellability.StackItemView;
import forge.gui.interfaces.IGuiGame; import forge.gui.interfaces.IGuiGame;
import forge.screens.match.views.VField; import forge.screens.match.views.VField;
import forge.screens.match.views.VReveal;
import forge.toolbox.FDisplayObject; import forge.toolbox.FDisplayObject;
import forge.util.Utils; import forge.util.Utils;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
@@ -77,6 +78,7 @@ public class MatchScreen extends FScreen {
private List<VPlayerPanel> playerPanelsList; private List<VPlayerPanel> playerPanelsList;
private final VGameMenu gameMenu; private final VGameMenu gameMenu;
private final VPlayers players; private final VPlayers players;
private final VReveal revealed;
private final VLog log; private final VLog log;
private final VStack stack; private final VStack stack;
private final VDevMenu devMenu; private final VDevMenu devMenu;
@@ -133,6 +135,8 @@ public class MatchScreen extends FScreen {
gameMenu.setDropDownContainer(this); gameMenu.setDropDownContainer(this);
players = new VPlayers(); players = new VPlayers();
players.setDropDownContainer(this); players.setDropDownContainer(this);
revealed = new VReveal();
revealed.setDropDownContainer(this);
log = new VLog(); log = new VLog();
log.setDropDownContainer(this); log.setDropDownContainer(this);
devMenu = new VDevMenu(); devMenu = new VDevMenu();
@@ -142,13 +146,13 @@ public class MatchScreen extends FScreen {
FMenuBar menuBar = (FMenuBar) getHeader(); FMenuBar menuBar = (FMenuBar) getHeader();
if (topPlayerPrompt == null) { if (topPlayerPrompt == null) {
menuBar.addTab("", revealed, true);
menuBar.addTab(Forge.getLocalizer().getMessage("lblGame"), gameMenu); menuBar.addTab(Forge.getLocalizer().getMessage("lblGame"), gameMenu);
menuBar.addTab(Forge.getLocalizer().getMessage("lblPlayers") + " (" + playerPanels.size() + ")", players); menuBar.addTab(Forge.getLocalizer().getMessage("lblPlayers") + " (" + playerPanels.size() + ")", players);
menuBar.addTab(Forge.getLocalizer().getMessage("lblLog"), log); menuBar.addTab(Forge.getLocalizer().getMessage("lblLog"), log);
menuBar.addTab(Forge.getLocalizer().getMessage("lblDev"), devMenu); menuBar.addTab(Forge.getLocalizer().getMessage("lblDev"), devMenu);
menuBar.addTab(Forge.getLocalizer().getMessage("lblStack") + " (0)", stack); menuBar.addTab(Forge.getLocalizer().getMessage("lblStack") + " (0)", stack);
} } else {
else {
menuBar.addTab("\u2022 \u2022 \u2022", new PlayerSpecificMenu(true)); menuBar.addTab("\u2022 \u2022 \u2022", new PlayerSpecificMenu(true));
stack.setRotate90(true); stack.setRotate90(true);
menuBar.addTab(Forge.getLocalizer().getMessage("lblStack") + " (0)", stack); menuBar.addTab(Forge.getLocalizer().getMessage("lblStack") + " (0)", stack);
@@ -176,9 +180,10 @@ public class MatchScreen extends FScreen {
private class HiddenMenuTab extends FMenuTab { private class HiddenMenuTab extends FMenuTab {
private HiddenMenuTab(FDropDown dropDown0) { private HiddenMenuTab(FDropDown dropDown0) {
super(null, null, dropDown0, -1); super(null, null, dropDown0, -1, false);
setVisible(false); setVisible(false);
} }
@Override @Override
public void setText(String text0) { public void setText(String text0) {
//avoid trying to set text for this tab //avoid trying to set text for this tab
@@ -214,8 +219,7 @@ public class MatchScreen extends FScreen {
Rectangle menuScreenPos = PlayerSpecificMenu.this.screenPos; Rectangle menuScreenPos = PlayerSpecificMenu.this.screenPos;
if (dropDown.getRotate180()) { if (dropDown.getRotate180()) {
dropDown.getMenuTab().screenPos.setPosition(menuScreenPos.x + menuScreenPos.width, menuScreenPos.y); dropDown.getMenuTab().screenPos.setPosition(menuScreenPos.x + menuScreenPos.width, menuScreenPos.y);
} } else {
else {
dropDown.getMenuTab().screenPos.setPosition(menuScreenPos.x + menuScreenPos.width, menuScreenPos.y + menuScreenPos.height); dropDown.getMenuTab().screenPos.setPosition(menuScreenPos.x + menuScreenPos.width, menuScreenPos.y + menuScreenPos.height);
} }
dropDown.show(); dropDown.show();
@@ -233,8 +237,7 @@ public class MatchScreen extends FScreen {
if (ForgePreferences.DEV_MODE) { if (ForgePreferences.DEV_MODE) {
addItem(new MenuItem(Forge.getLocalizer().getMessage("lblDev"), devMenu)); addItem(new MenuItem(Forge.getLocalizer().getMessage("lblDev"), devMenu));
} }
} } else { //TODO: Support using menu when player doesn't have priority
else { //TODO: Support using menu when player doesn't have priority
FMenuItem item = new FMenuItem(Forge.getLocalizer().getMessage("lblMustWaitPriority"), null); FMenuItem item = new FMenuItem(Forge.getLocalizer().getMessage("lblMustWaitPriority"), null);
item.setEnabled(false); item.setEnabled(false);
addItem(item); addItem(item);
@@ -338,7 +341,9 @@ public class MatchScreen extends FScreen {
@Override @Override
protected void drawOverlay(Graphics g) { protected void drawOverlay(Graphics g) {
final GameView game = MatchController.instance.getGameView(); final GameView game = MatchController.instance.getGameView();
if (game == null) { return; } if (game == null) {
return;
}
if (gameMenu != null) { if (gameMenu != null) {
if (gameMenu.getChildCount() > 1) { if (gameMenu.getChildCount() > 1) {
@@ -412,8 +417,7 @@ public class MatchScreen extends FScreen {
float cardY = (cardPanel.screenPos.y - cardH) + cardPanel.getHeight(); float cardY = (cardPanel.screenPos.y - cardH) + cardPanel.getHeight();
if (vPlayerPanel.getPlayer() == bottomPlayerPanel.getPlayer()) { if (vPlayerPanel.getPlayer() == bottomPlayerPanel.getPlayer()) {
cardY = bottomPlayerPrompt.screenPos.y - cardH; cardY = bottomPlayerPrompt.screenPos.y - cardH;
} } else if (cardY < vPlayerPanel.getField().screenPos.y && vPlayerPanel.getPlayer() != bottomPlayerPanel.getPlayer()) {
else if (cardY < vPlayerPanel.getField().screenPos.y && vPlayerPanel.getPlayer() != bottomPlayerPanel.getPlayer()) {
cardY = vPlayerPanel.getField().screenPos.y; cardY = vPlayerPanel.getField().screenPos.y;
if ((cardY + cardH) > bottomPlayerPrompt.screenPos.y) if ((cardY + cardH) > bottomPlayerPrompt.screenPos.y)
cardY = bottomPlayerPrompt.screenPos.y - cardH; cardY = bottomPlayerPrompt.screenPos.y - cardH;
@@ -453,6 +457,7 @@ public class MatchScreen extends FScreen {
} }
} }
} }
void drawArcs(Graphics g) { void drawArcs(Graphics g) {
//get all card targeting arrow origins on the battlefield //get all card targeting arrow origins on the battlefield
final Map<Integer, Vector2> endpoints = new HashMap<>(); final Map<Integer, Vector2> endpoints = new HashMap<>();
@@ -506,7 +511,8 @@ public class MatchScreen extends FScreen {
} }
} }
revalidate(true); revalidate(true);
} catch (Exception e) {} } catch (Exception e) {
}
} }
break; break;
case Keys.DPAD_RIGHT: case Keys.DPAD_RIGHT:
@@ -519,7 +525,8 @@ public class MatchScreen extends FScreen {
selectedPlayerPanel().getSelectedRow().setNextSelected(1); selectedPlayerPanel().getSelectedRow().setNextSelected(1);
} }
revalidate(true); revalidate(true);
} catch (Exception e) {} } catch (Exception e) {
}
} }
break; break;
case Keys.DPAD_UP: case Keys.DPAD_UP:
@@ -542,7 +549,8 @@ public class MatchScreen extends FScreen {
} }
} }
revalidate(true); revalidate(true);
} catch (Exception e) {} } catch (Exception e) {
}
} }
break; break;
case Keys.DPAD_LEFT: case Keys.DPAD_LEFT:
@@ -555,7 +563,8 @@ public class MatchScreen extends FScreen {
selectedPlayerPanel().getSelectedRow().setPreviousSelected(1); selectedPlayerPanel().getSelectedRow().setPreviousSelected(1);
} }
revalidate(true); revalidate(true);
} catch (Exception e) {} } catch (Exception e) {
}
} }
break; break;
case Keys.BUTTON_Y: case Keys.BUTTON_Y:
@@ -567,7 +576,8 @@ public class MatchScreen extends FScreen {
} else { } else {
selectedPlayerPanel().getSelectedRow().showZoom(); selectedPlayerPanel().getSelectedRow().showZoom();
} }
} catch (Exception e) {} } catch (Exception e) {
}
} }
break; break;
case Keys.BUTTON_A: case Keys.BUTTON_A:
@@ -581,7 +591,8 @@ public class MatchScreen extends FScreen {
//nullPotentialListener(); //nullPotentialListener();
selectedPlayerPanel().getSelectedRow().tapChild(); selectedPlayerPanel().getSelectedRow().tapChild();
} }
} catch (Exception e) {} } catch (Exception e) {
}
} }
break; break;
case Keys.BUTTON_L1: //switch selected panels case Keys.BUTTON_L1: //switch selected panels
@@ -652,8 +663,7 @@ public class MatchScreen extends FScreen {
if (gui.shouldAlwaysAcceptTrigger(triggerID)) { if (gui.shouldAlwaysAcceptTrigger(triggerID)) {
gui.setShouldAlwaysAskTrigger(triggerID); gui.setShouldAlwaysAskTrigger(triggerID);
} } else {
else {
gui.setShouldAlwaysAcceptTrigger(triggerID); gui.setShouldAlwaysAcceptTrigger(triggerID);
if (stackInstance.equals(gameView.peekStack())) { if (stackInstance.equals(gameView.peekStack())) {
//auto-yes if ability is on top of stack //auto-yes if ability is on top of stack
@@ -686,8 +696,7 @@ public class MatchScreen extends FScreen {
if (gui.shouldAlwaysDeclineTrigger(triggerID)) { if (gui.shouldAlwaysDeclineTrigger(triggerID)) {
gui.setShouldAlwaysAskTrigger(triggerID); gui.setShouldAlwaysAskTrigger(triggerID);
} } else {
else {
gui.setShouldAlwaysDeclineTrigger(triggerID); gui.setShouldAlwaysDeclineTrigger(triggerID);
if (stackInstance.equals(gameView.peekStack())) { if (stackInstance.equals(gameView.peekStack())) {
//auto-no if ability is on top of stack //auto-no if ability is on top of stack
@@ -788,12 +797,13 @@ public class MatchScreen extends FScreen {
public void updateSingleCard(final CardView card) { public void updateSingleCard(final CardView card) {
final CardAreaPanel pnl = CardAreaPanel.get(card); final CardAreaPanel pnl = CardAreaPanel.get(card);
if (pnl == null) { return; } if (pnl == null) {
return;
}
final ZoneType zone = card.getZone(); final ZoneType zone = card.getZone();
if (zone != null && zone == ZoneType.Battlefield) { if (zone != null && zone == ZoneType.Battlefield) {
pnl.updateCard(card); pnl.updateCard(card);
} } else { //ensure card not on battlefield is reset such that it no longer thinks it's on the battlefield
else { //ensure card not on battlefield is reset such that it no longer thinks it's on the battlefield
pnl.setTapped(false); pnl.setTapped(false);
pnl.getAttachedPanels().clear(); pnl.getAttachedPanels().clear();
pnl.setAttachedToPanel(null); pnl.setAttachedToPanel(null);
@@ -801,9 +811,11 @@ public class MatchScreen extends FScreen {
pnl.setNextPanelInStack(null); pnl.setNextPanelInStack(null);
} }
} }
private String daytime = null; private String daytime = null;
private Float time = null; private Float time = null;
FSkinTexture currentBG = getBG(); FSkinTexture currentBG = getBG();
FSkinTexture getBG() { FSkinTexture getBG() {
if (Forge.isMobileAdventureMode) { if (Forge.isMobileAdventureMode) {
switch (GameScene.instance().getAdventurePlayerLocation(false)) { switch (GameScene.instance().getAdventurePlayerLocation(false)) {
@@ -831,6 +843,7 @@ public class MatchScreen extends FScreen {
} }
return FSkinTexture.BG_MATCH; return FSkinTexture.BG_MATCH;
} }
private class BGAnimation extends ForgeAnimation { private class BGAnimation extends ForgeAnimation {
private static final float DURATION = 1.4f; private static final float DURATION = 1.4f;
private float progress = 0; private float progress = 0;
@@ -925,6 +938,7 @@ public class MatchScreen extends FScreen {
} }
} }
private class FieldScroller extends FScrollPane { private class FieldScroller extends FScrollPane {
private float extraHeight = 0; private float extraHeight = 0;
private String plane = ""; private String plane = "";
@@ -998,8 +1012,10 @@ public class MatchScreen extends FScreen {
} }
} }
} }
//auto adjust zoom for local multiplayer landscape mode //auto adjust zoom for local multiplayer landscape mode
List<VPlayerPanel> losers = new ArrayList<>(); List<VPlayerPanel> losers = new ArrayList<>();
@Override @Override
public void drawOverlay(Graphics g) { public void drawOverlay(Graphics g) {
if (Forge.isLandscapeMode()) { if (Forge.isLandscapeMode()) {
@@ -1154,11 +1170,16 @@ public class MatchScreen extends FScreen {
} }
backupHorzScrollPane(playerPanel.getCommandZone(), x, horzScrollPanes); backupHorzScrollPane(playerPanel.getCommandZone(), x, horzScrollPanes);
} }
private void backupHorzScrollPane(FScrollPane scrollPane, float x, Map<FScrollPane, Pair<Float, Float>> horzScrollPanes) { private void backupHorzScrollPane(FScrollPane scrollPane, float x, Map<FScrollPane, Pair<Float, Float>> horzScrollPanes) {
horzScrollPanes.put(scrollPane, Pair.of(scrollPane.getScrollLeft(), scrollPane.getScrollWidth())); horzScrollPanes.put(scrollPane, Pair.of(scrollPane.getScrollLeft(), scrollPane.getScrollWidth()));
} }
} }
private String getPlaneName(){ return MatchController.instance.getGameView().getPlanarPlayer().getCurrentPlaneName(); }
private String getPlaneName() {
return MatchController.instance.getGameView().getPlanarPlayer().getCurrentPlaneName();
}
private boolean hasActivePlane() { private boolean hasActivePlane() {
if (MatchController.instance.getGameView() != null) if (MatchController.instance.getGameView() != null)
if (MatchController.instance.getGameView().getPlanarPlayer() != null) { if (MatchController.instance.getGameView().getPlanarPlayer() != null) {
@@ -1172,6 +1193,7 @@ public class MatchScreen extends FScreen {
setPotentialListener(listeners); setPotentialListener(listeners);
super.buildTouchListeners(screenX, screenY, listeners); super.buildTouchListeners(screenX, screenY, listeners);
} }
public VPlayerPanel selectedPlayerPanel() { public VPlayerPanel selectedPlayerPanel() {
if (selectedPlayer >= playerPanelsList.size()) if (selectedPlayer >= playerPanelsList.size())
selectedPlayer = playerPanelsList.size() - 1; selectedPlayer = playerPanelsList.size() - 1;
@@ -1179,12 +1201,14 @@ public class MatchScreen extends FScreen {
return null; return null;
return playerPanelsList.get(selectedPlayer); return playerPanelsList.get(selectedPlayer);
} }
public static void setPotentialListener(List<FDisplayObject> listener) { public static void setPotentialListener(List<FDisplayObject> listener) {
if (potentialListener != null) if (potentialListener != null)
for (FDisplayObject f : potentialListener) for (FDisplayObject f : potentialListener)
f.setHovered(false); f.setHovered(false);
potentialListener = listener; potentialListener = listener;
} }
public static void nullPotentialListener() { public static void nullPotentialListener() {
if (potentialListener != null) if (potentialListener != null)
for (FDisplayObject f : potentialListener) for (FDisplayObject f : potentialListener)

View File

@@ -11,6 +11,7 @@ import forge.Graphics;
import forge.animation.ForgeAnimation; import forge.animation.ForgeAnimation;
import forge.assets.FImage; import forge.assets.FImage;
import forge.assets.FSkin; import forge.assets.FSkin;
import forge.assets.FSkinColor;
import forge.assets.FSkinFont; import forge.assets.FSkinFont;
import forge.game.card.CounterEnumType; import forge.game.card.CounterEnumType;
import forge.game.player.PlayerView; import forge.game.player.PlayerView;
@@ -153,15 +154,11 @@ public class VAvatar extends FDisplayObject {
float alpha = displayPriority ? 1f : 0.8f; float alpha = displayPriority ? 1f : 0.8f;
if (alphaModifier < 1) if (alphaModifier < 1)
alpha = alphaModifier; alpha = alphaModifier;
g.setAlphaComposite(alpha); g.drawRect(w / 16f, FSkinColor.getStandardColor(Color.CYAN).alphaColor(alpha), 0, 0, w, h);
g.drawRect(w / 16f, Color.CYAN, 0, 0, w, h);
g.setAlphaComposite(oldAlpha);
} }
//priority indicator //priority indicator
if (displayPriority && player.getHasPriority() && alphaModifier == 1) { if (displayPriority && player.getHasPriority() && alphaModifier == 1) {
g.setAlphaComposite(0.6f); g.drawRect(w / 16f, FSkinColor.getStandardColor(Color.LIME).alphaColor(0.6f), 0, 0, w, h);
g.drawRect(w / 16f, Color.LIME, 0, 0, w, h);
g.setAlphaComposite(oldAlpha);
} }
//highlighted //highlighted
if (MatchController.instance.isHighlighted(player)) { if (MatchController.instance.isHighlighted(player)) {

View File

@@ -0,0 +1,159 @@
package forge.screens.match.views;
import com.badlogic.gdx.utils.Align;
import forge.Forge;
import forge.Graphics;
import forge.assets.FImage;
import forge.assets.FSkinColor;
import forge.assets.FSkinFont;
import forge.assets.TextRenderer;
import forge.card.CardRenderer;
import forge.card.CardZoom;
import forge.game.card.CardView;
import forge.gui.card.CardDetailUtil;
import forge.menu.FDropDown;
import forge.screens.match.MatchController;
import forge.toolbox.FDisplayObject;
import forge.toolbox.FLabel;
import forge.trackable.TrackableCollection;
import forge.util.CardTranslation;
import forge.util.Utils;
import java.util.ArrayList;
import java.util.List;
public class VReveal extends FDropDown {
public static final float MARGINS = Utils.scale(4);
private static final FSkinFont FONT = FSkinFont.get(11);
public static final float PADDING = Utils.scale(3);
private TrackableCollection<CardView> revealed;
private static FSkinColor getAltRowColor() {
if (Forge.isMobileAdventureMode)
return FSkinColor.get(FSkinColor.Colors.ADV_CLR_ZEBRA);
return FSkinColor.get(FSkinColor.Colors.CLR_ZEBRA);
}
private static FSkinColor getRowColor() {
return getAltRowColor().darker();
}
private static FSkinColor getForeColor() {
if (Forge.isMobileAdventureMode)
return FSkinColor.get(FSkinColor.Colors.ADV_CLR_TEXT);
return FSkinColor.get(FSkinColor.Colors.CLR_TEXT);
}
private final TextRenderer renderer = new TextRenderer(false);
@Override
protected boolean autoHide() {
return true;
}
@Override
protected void drawBackground(Graphics g) {
float w = getWidth();
float h = getHeight();
g.fillRect(getRowColor(), 0, 0, w, h); //can fill background with main row color since drop down will never be taller than number of rows
}
@Override
protected ScrollBounds updateAndGetPaneSize(float maxWidth, float maxVisibleHeight) {
float x = MARGINS;
float y = MARGINS;
float totalWidth = Forge.getScreenWidth();
float width = totalWidth - 2 * MARGINS;
float entryHeight;
float entryWidth = totalWidth;
float minWidth = 4 * Utils.AVG_FINGER_WIDTH;
if (entryWidth < minWidth) {
entryWidth = minWidth;
}
revealed = MatchController.instance.getGameView().getRevealedCollection();
if (revealed == null || revealed.isEmpty()) {
FLabel label = add(new FLabel.Builder().text("[" + Forge.getLocalizer().getMessage("lblEmpty") + "]").font(FSkinFont.get(11)).align(Align.center).build());
float height = Math.round(label.getAutoSizeBounds().height) + 2 * PADDING;
label.setBounds(x, y, width, height);
return new ScrollBounds(totalWidth, y + height + MARGINS);
} else {
clear();
boolean isAltRow = false;
RevealEntryDisplay revealEntryDisplay;
x = getMenuTab().screenPos.x;
y = 1;
for (CardView c : revealed) {
revealEntryDisplay = add(new RevealEntryDisplay(c, isAltRow));
isAltRow = !isAltRow;
entryHeight = revealEntryDisplay.getMinHeight(entryWidth) + MARGINS;
revealEntryDisplay.setBounds(0, y, entryWidth, entryHeight);
y += entryHeight;
}
}
return new ScrollBounds(totalWidth, y + MARGINS);
}
private class RevealEntryDisplay extends FDisplayObject {
CardView card;
boolean altRow;
String text;
FImage cardArt;
private RevealEntryDisplay(CardView cardView, boolean isAltRow) {
card = cardView;
altRow = isAltRow;
text = CardTranslation.getTranslatedName(card.getCurrentState().getName()) + "\n" + formatType();
cardArt = CardRenderer.getCardArt(cardView);
}
private float getMinHeight(float width) {
width -= 2 * PADDING; //account for left and right insets
float height = renderer.getWrappedBounds("\n", FONT, width).height;
height += 2 * PADDING;
return Math.round(height);
}
@Override
public boolean tap(float x, float y, int count) {
try {
List<CardView> cardViewList = new ArrayList<>(revealed);
int index = cardViewList.indexOf(card);
CardZoom.show(cardViewList, index, null);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
@Override
public void draw(Graphics g) {
float w = getWidth();
float h = getHeight();
float cardArtWidth = h * 1.302f;
if (altRow) {
g.fillRect(getAltRowColor(), 0, 0, w, h);
}
if (isHovered()) {
g.fillRect(getForeColor().brighter().alphaColor(0.3f), 0, 0, w, h);
}
g.drawImage(cardArt, 0, 0, cardArtWidth, h);
//use full height without padding so text not scaled down
renderer.drawText(g, text, FONT, getForeColor(), cardArtWidth + PADDING, PADDING, w - (2 * PADDING + cardArtWidth), h, 0, h, false, Align.left, false);
}
private String formatType() {
String type = CardDetailUtil.formatCardType(card.getCurrentState(), true);
if (card.getCurrentState().isCreature()) { //include P/T or Loyalty at end of type
type += " (" + card.getCurrentState().getPower() + " / " + card.getCurrentState().getToughness() + ")";
} else if (card.getCurrentState().isPlaneswalker()) {
type += " (" + card.getCurrentState().getLoyalty() + ")";
} else if (card.getCurrentState().getType().hasSubtype("Vehicle")) {
type += String.format(" [%s / %s]", card.getCurrentState().getPower(), card.getCurrentState().getToughness());
}
return type;
}
}
}

View File

@@ -427,9 +427,7 @@ public class FLabel extends FDisplayObject implements IButton {
else if (!text.isEmpty()) { else if (!text.isEmpty()) {
float oldAlpha = g.getfloatAlphaComposite(); float oldAlpha = g.getfloatAlphaComposite();
if (isHovered() && selectable) { if (isHovered() && selectable) {
g.setAlphaComposite(0.4f); g.fillRect(FSkinColor.getStandardColor(Color.GRAY).alphaColor(0.4f), x, y, w, h);
g.fillRect(Color.GRAY, x, y, w, h);
g.setAlphaComposite(oldAlpha);
} }
drawText(g, x, y, w, h, alignment); drawText(g, x, y, w, h, alignment);
} }

View File

@@ -15,7 +15,7 @@ import forge.util.Utils;
public abstract class FScrollPane extends FContainer { public abstract class FScrollPane extends FContainer {
private static final float FLING_DECEL = 750f; private static final float FLING_DECEL = 750f;
private static FSkinColor getIndicatorColor() { public static FSkinColor getIndicatorColor() {
if (Forge.isMobileAdventureMode) if (Forge.isMobileAdventureMode)
return FSkinColor.get(FSkinColor.Colors.ADV_CLR_TEXT).alphaColor(0.7f); return FSkinColor.get(FSkinColor.Colors.ADV_CLR_TEXT).alphaColor(0.7f);
return FSkinColor.get(FSkinColor.Colors.CLR_TEXT).alphaColor(0.7f); return FSkinColor.get(FSkinColor.Colors.CLR_TEXT).alphaColor(0.7f);
@@ -30,6 +30,14 @@ public abstract class FScrollPane extends FContainer {
scrollBounds = new ScrollBounds(); scrollBounds = new ScrollBounds();
} }
public float getIndicatorMargin() {
return INDICATOR_MARGIN;
}
public float getIndicatorSize() {
return INDICATOR_SIZE;
}
public float getScrollLeft() { public float getScrollLeft() {
return scrollLeft; return scrollLeft;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@@ -9,6 +9,7 @@ import java.util.Set;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import forge.trackable.TrackableCollection;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@@ -50,12 +51,15 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
public final boolean hasLocalPlayers() { public final boolean hasLocalPlayers() {
return !gameControllers.isEmpty(); return !gameControllers.isEmpty();
} }
public final Set<PlayerView> getLocalPlayers() { public final Set<PlayerView> getLocalPlayers() {
return gameControllers.keySet(); return gameControllers.keySet();
} }
public final int getLocalPlayerCount() { public final int getLocalPlayerCount() {
return gameControllers.size(); return gameControllers.size();
} }
public final boolean isLocalPlayer(final PlayerView player) { public final boolean isLocalPlayer(final PlayerView player) {
return gameControllers.containsKey(player); return gameControllers.containsKey(player);
} }
@@ -94,12 +98,15 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
currentPlayer = player; currentPlayer = player;
updateCurrentPlayer(player); updateCurrentPlayer(player);
} }
protected abstract void updateCurrentPlayer(PlayerView player); protected abstract void updateCurrentPlayer(PlayerView player);
private GameView gameView = null; private GameView gameView = null;
public final GameView getGameView() { public final GameView getGameView() {
return gameView; return gameView;
} }
@Override @Override
public void setGameView(final GameView gameView0) { public void setGameView(final GameView gameView0) {
if (gameView == null || gameView0 == null) { if (gameView == null || gameView0 == null) {
@@ -118,6 +125,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
public final IGameController getGameController() { public final IGameController getGameController() {
return getGameController(getCurrentPlayer()); return getGameController(getCurrentPlayer());
} }
public final IGameController getGameController(final PlayerView player) { public final IGameController getGameController(final PlayerView player) {
if (player == null) { if (player == null) {
return spectator; return spectator;
@@ -180,6 +188,16 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
updateCards(Collections.singleton(card)); updateCards(Collections.singleton(card));
} }
@Override
public void updateRevealedCards(TrackableCollection<CardView> collection) {
if (gameView != null) {
TrackableCollection<CardView> existing = gameView.getRevealedCollection();
if (existing != null)
collection.addAll(existing);
gameView.updateRevealedCards(collection);
}
}
@Override @Override
public void refreshCardDetails(final Iterable<CardView> cards) { public void refreshCardDetails(final Iterable<CardView> cards) {
//not needed for base game implementation //not needed for base game implementation
@@ -225,10 +243,14 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
@Override @Override
public boolean mayFlip(final CardView cv) { public boolean mayFlip(final CardView cv) {
if (cv == null) { return false; } if (cv == null) {
return false;
}
final CardStateView altState = cv.getAlternateState(); final CardStateView altState = cv.getAlternateState();
if (altState == null) { return false; } if (altState == null) {
return false;
}
switch (altState.getState()) { switch (altState.getState()) {
case Original: case Original:
@@ -252,6 +274,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
} }
private final Set<PlayerView> highlightedPlayers = Sets.newHashSet(); private final Set<PlayerView> highlightedPlayers = Sets.newHashSet();
@Override @Override
public void setHighlighted(final PlayerView pv, final boolean b) { public void setHighlighted(final PlayerView pv, final boolean b) {
final boolean hasChanged = b ? highlightedPlayers.add(pv) : highlightedPlayers.remove(pv); final boolean hasChanged = b ? highlightedPlayers.add(pv) : highlightedPlayers.remove(pv);
@@ -265,6 +288,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
} }
private final Set<CardView> highlightedCards = Sets.newHashSet(); private final Set<CardView> highlightedCards = Sets.newHashSet();
// used to highlight cards in UI // used to highlight cards in UI
@Override @Override
public void setUsedToPay(final CardView card, final boolean value) { public void setUsedToPay(final CardView card, final boolean value) {
@@ -279,34 +303,56 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
} }
private final Set<CardView> selectableCards = Sets.newHashSet(); private final Set<CardView> selectableCards = Sets.newHashSet();
public void setSelectables(final Iterable<CardView> cards) { public void setSelectables(final Iterable<CardView> cards) {
for (CardView cv : cards) { selectableCards.add(cv); } for (CardView cv : cards) {
selectableCards.add(cv);
} }
}
public void clearSelectables() { public void clearSelectables() {
selectableCards.clear(); selectableCards.clear();
} }
public boolean isSelectable(final CardView card) { public boolean isSelectable(final CardView card) {
return selectableCards.contains(card); return selectableCards.contains(card);
} }
public boolean isSelecting() { public boolean isSelecting() {
return !selectableCards.isEmpty(); return !selectableCards.isEmpty();
} }
public boolean isGamePaused() { return gamePause; }
public boolean isGameFast() { return gameSpeed; } public boolean isGamePaused() {
public void setgamePause(boolean pause) { gamePause = pause; } return gamePause;
public void setGameSpeed(boolean isFast) { gameSpeed = isFast; } }
public boolean isGameFast() {
return gameSpeed;
}
public void setgamePause(boolean pause) {
gamePause = pause;
}
public void setGameSpeed(boolean isFast) {
gameSpeed = isFast;
}
public void pauseMatch() { public void pauseMatch() {
IGameController controller = spectator; IGameController controller = spectator;
if (controller != null && !isGamePaused()) if (controller != null && !isGamePaused())
controller.selectButtonOk(); controller.selectButtonOk();
} }
public void resumeMatch() { public void resumeMatch() {
IGameController controller = spectator; IGameController controller = spectator;
if (controller != null && isGamePaused()) if (controller != null && isGamePaused())
controller.selectButtonOk(); controller.selectButtonOk();
} }
/** Concede game, bring up WinLose UI. */ /**
* Concede game, bring up WinLose UI.
*/
public boolean concede() { public boolean concede() {
if (gameView.isGameOver()) { if (gameView.isGameOver()) {
return true; return true;
@@ -346,11 +392,9 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
} }
ignoreConcedeChain = false; ignoreConcedeChain = false;
return false; return false;
} } else if (spectator == null) {
else if (spectator == null) {
return true; //if no local players or spectator, just quit return true; //if no local players or spectator, just quit
} } else {
else {
if (showConfirmDialog(Localizer.getInstance().getMessage("lblCloseGameSpectator"), Localizer.getInstance().getMessage("lblCloseGame"), Localizer.getInstance().getMessage("lblClose"), Localizer.getInstance().getMessage("lblCancel"))) { if (showConfirmDialog(Localizer.getInstance().getMessage("lblCloseGameSpectator"), Localizer.getInstance().getMessage("lblCloseGame"), Localizer.getInstance().getMessage("lblClose"), Localizer.getInstance().getMessage("lblCancel"))) {
IGameController controller = spectator; IGameController controller = spectator;
spectator = null; //ensure we don't prompt again, including when calling nextGameDecision below spectator = null; //ensure we don't prompt again, including when calling nextGameDecision below
@@ -421,16 +465,13 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
awaitNextInputTask = new TimerTask() { awaitNextInputTask = new TimerTask() {
@Override @Override
public void run() { public void run() {
FThreads.invokeInEdtLater(new Runnable() { FThreads.invokeInEdtLater(() -> {
@Override
public void run() {
synchronized (awaitNextInputTimer) { synchronized (awaitNextInputTimer) {
if (awaitNextInputTask != null) { if (awaitNextInputTask != null) {
updatePromptForAwait(getCurrentPlayer()); updatePromptForAwait(getCurrentPlayer());
awaitNextInputTask = null; awaitNextInputTask = null;
} }
} }
}
}); });
} }
}; };
@@ -451,7 +492,8 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
if (awaitNextInputTask != null) { if (awaitNextInputTask != null) {
try { try {
awaitNextInputTask.cancel(); //cancel timer once next input shown if needed awaitNextInputTask.cancel(); //cancel timer once next input shown if needed
} catch (final Exception ex) {} //suppress any exception thrown by cancel() } catch (final Exception ex) {
} //suppress any exception thrown by cancel()
awaitNextInputTask = null; awaitNextInputTask = null;
} }
} }
@@ -470,9 +512,11 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
// Abilities to auto-yield to // Abilities to auto-yield to
private final Set<String> autoYields = Sets.newHashSet(); private final Set<String> autoYields = Sets.newHashSet();
public final Iterable<String> getAutoYields() { public final Iterable<String> getAutoYields() {
return autoYields; return autoYields;
} }
@Override @Override
public final boolean shouldAutoYield(final String key) { public final boolean shouldAutoYield(final String key) {
String abilityKey = key.indexOf("): ") != -1 ? key.substring(key.indexOf("): ") + 3) : key; String abilityKey = key.indexOf("): ") != -1 ? key.substring(key.indexOf("): ") + 3) : key;
@@ -480,6 +524,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
return !getDisableAutoYields() && autoYields.contains(yieldPerAbility ? abilityKey : key); return !getDisableAutoYields() && autoYields.contains(yieldPerAbility ? abilityKey : key);
} }
@Override @Override
public final void setShouldAutoYield(final String key, final boolean autoYield) { public final void setShouldAutoYield(final String key, final boolean autoYield) {
String abilityKey = key.indexOf("): ") != -1 ? key.substring(key.indexOf("): ") + 3) : key; String abilityKey = key.indexOf("): ") != -1 ? key.substring(key.indexOf("): ") + 3) : key;
@@ -487,16 +532,17 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
if (autoYield) { if (autoYield) {
autoYields.add(yieldPerAbility ? abilityKey : key); autoYields.add(yieldPerAbility ? abilityKey : key);
} } else {
else {
autoYields.remove(yieldPerAbility ? abilityKey : key); autoYields.remove(yieldPerAbility ? abilityKey : key);
} }
} }
private boolean disableAutoYields; private boolean disableAutoYields;
public final boolean getDisableAutoYields() { public final boolean getDisableAutoYields() {
return disableAutoYields; return disableAutoYields;
} }
public final void setDisableAutoYields(final boolean b0) { public final void setDisableAutoYields(final boolean b0) {
disableAutoYields = b0; disableAutoYields = b0;
} }
@@ -511,16 +557,29 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
private final Map<Integer, Boolean> triggersAlwaysAccept = Maps.newTreeMap(); private final Map<Integer, Boolean> triggersAlwaysAccept = Maps.newTreeMap();
@Override @Override
public final boolean shouldAlwaysAcceptTrigger(final int trigger) { return Boolean.TRUE.equals(triggersAlwaysAccept.get(Integer.valueOf(trigger))); } public final boolean shouldAlwaysAcceptTrigger(final int trigger) {
@Override return Boolean.TRUE.equals(triggersAlwaysAccept.get(Integer.valueOf(trigger)));
public final boolean shouldAlwaysDeclineTrigger(final int trigger) { return Boolean.FALSE.equals(triggersAlwaysAccept.get(Integer.valueOf(trigger))); } }
@Override @Override
public final void setShouldAlwaysAcceptTrigger(final int trigger) { triggersAlwaysAccept.put(Integer.valueOf(trigger), Boolean.TRUE); } public final boolean shouldAlwaysDeclineTrigger(final int trigger) {
return Boolean.FALSE.equals(triggersAlwaysAccept.get(Integer.valueOf(trigger)));
}
@Override @Override
public final void setShouldAlwaysDeclineTrigger(final int trigger) { triggersAlwaysAccept.put(Integer.valueOf(trigger), Boolean.FALSE); } public final void setShouldAlwaysAcceptTrigger(final int trigger) {
triggersAlwaysAccept.put(Integer.valueOf(trigger), Boolean.TRUE);
}
@Override @Override
public final void setShouldAlwaysAskTrigger(final int trigger) { triggersAlwaysAccept.remove(Integer.valueOf(trigger)); } public final void setShouldAlwaysDeclineTrigger(final int trigger) {
triggersAlwaysAccept.put(Integer.valueOf(trigger), Boolean.FALSE);
}
@Override
public final void setShouldAlwaysAskTrigger(final int trigger) {
triggersAlwaysAccept.remove(Integer.valueOf(trigger));
}
// End of Triggers preliminary choice // End of Triggers preliminary choice
@@ -529,12 +588,9 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
/** /**
* Convenience for getChoices(message, 0, 1, choices). * Convenience for getChoices(message, 0, 1, choices).
* *
* @param <T> * @param <T> is automatically inferred.
* is automatically inferred. * @param message a {@link java.lang.String} object.
* @param message * @param choices a T object.
* a {@link java.lang.String} object.
* @param choices
* a T object.
* @return null if choices is missing, empty, or if the users' choices are * @return null if choices is missing, empty, or if the users' choices are
* empty; otherwise, returns the first item in the List returned by * empty; otherwise, returns the first item in the List returned by
* getChoices. * getChoices.
@@ -550,17 +606,15 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
} }
// returned Object will never be null // returned Object will never be null
/** /**
* <p> * <p>
* getChoice. * getChoice.
* </p> * </p>
* *
* @param <T> * @param <T> a T object.
* a T object. * @param message a {@link java.lang.String} object.
* @param message * @param choices a T object.
* a {@link java.lang.String} object.
* @param choices
* a T object.
* @return a T object. * @return a T object.
*/ */
@Override @Override
@@ -588,13 +642,17 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
public Integer getInteger(final String message, final int min) { public Integer getInteger(final String message, final int min) {
return getInteger(message, min, Integer.MAX_VALUE, false); return getInteger(message, min, Integer.MAX_VALUE, false);
} }
@Override @Override
public Integer getInteger(final String message, final int min, final int max) { public Integer getInteger(final String message, final int min, final int max) {
return getInteger(message, min, max, false); return getInteger(message, min, max, false);
} }
@Override @Override
public Integer getInteger(final String message, final int min, final int max, final boolean sortDesc) { public Integer getInteger(final String message, final int min, final int max, final boolean sortDesc) {
if (max <= min) { return min; } //just return min if max <= min if (max <= min) {
return min;
} //just return min if max <= min
//force cutting off after 100 numbers at most //force cutting off after 100 numbers at most
if (max == Integer.MAX_VALUE) { if (max == Integer.MAX_VALUE) {
@@ -654,7 +712,9 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
while (true) { while (true) {
final String str = showInputDialog(prompt, message); final String str = showInputDialog(prompt, message);
if (str == null) { return null; } // that is 'cancel' if (str == null) {
return null;
} // that is 'cancel'
if (StringUtils.isNumeric(str)) { if (StringUtils.isNumeric(str)) {
final Integer val = Integer.valueOf(str); final Integer val = Integer.valueOf(str);

View File

@@ -31,87 +31,139 @@ import forge.util.ITriggerEvent;
public interface IGuiGame { public interface IGuiGame {
void setGameView(GameView gameView); void setGameView(GameView gameView);
GameView getGameView(); GameView getGameView();
void setOriginalGameController(PlayerView view, IGameController gameController); void setOriginalGameController(PlayerView view, IGameController gameController);
void setGameController(PlayerView player, IGameController gameController); void setGameController(PlayerView player, IGameController gameController);
void setSpectator(IGameController spectator); void setSpectator(IGameController spectator);
void openView(TrackableCollection<PlayerView> myPlayers); void openView(TrackableCollection<PlayerView> myPlayers);
void afterGameEnd(); void afterGameEnd();
void showCombat(); void showCombat();
void showPromptMessage(PlayerView playerView, String message); void showPromptMessage(PlayerView playerView, String message);
void showCardPromptMessage(PlayerView playerView, String message, CardView card); void showCardPromptMessage(PlayerView playerView, String message, CardView card);
void updateButtons(PlayerView owner, boolean okEnabled, boolean cancelEnabled, boolean focusOk); void updateButtons(PlayerView owner, boolean okEnabled, boolean cancelEnabled, boolean focusOk);
void updateButtons(PlayerView owner, String label1, String label2, boolean enable1, boolean enable2, boolean focus1); void updateButtons(PlayerView owner, String label1, String label2, boolean enable1, boolean enable2, boolean focus1);
void flashIncorrectAction(); void flashIncorrectAction();
void alertUser(); void alertUser();
void updatePhase(boolean saveState); void updatePhase(boolean saveState);
void updateTurn(PlayerView player); void updateTurn(PlayerView player);
void updatePlayerControl(); void updatePlayerControl();
void enableOverlay(); void enableOverlay();
void disableOverlay(); void disableOverlay();
void finishGame(); void finishGame();
void showManaPool(PlayerView player); void showManaPool(PlayerView player);
void hideManaPool(PlayerView player); void hideManaPool(PlayerView player);
void updateStack(); void updateStack();
void notifyStackAddition(final GameEventSpellAbilityCast event); void notifyStackAddition(final GameEventSpellAbilityCast event);
void notifyStackRemoval(final GameEventSpellRemovedFromStack event); void notifyStackRemoval(final GameEventSpellRemovedFromStack event);
void handleLandPlayed(Card land); void handleLandPlayed(Card land);
Iterable<PlayerZoneUpdate> tempShowZones(PlayerView controller, Iterable<PlayerZoneUpdate> zonesToUpdate); Iterable<PlayerZoneUpdate> tempShowZones(PlayerView controller, Iterable<PlayerZoneUpdate> zonesToUpdate);
void hideZones(PlayerView controller, Iterable<PlayerZoneUpdate> zonesToUpdate); void hideZones(PlayerView controller, Iterable<PlayerZoneUpdate> zonesToUpdate);
void updateZones(Iterable<PlayerZoneUpdate> zonesToUpdate); void updateZones(Iterable<PlayerZoneUpdate> zonesToUpdate);
void updateSingleCard(CardView card); void updateSingleCard(CardView card);
void updateCards(Iterable<CardView> cards); void updateCards(Iterable<CardView> cards);
void updateRevealedCards(TrackableCollection<CardView> collection);
void refreshCardDetails(Iterable<CardView> cards); void refreshCardDetails(Iterable<CardView> cards);
void refreshField(); void refreshField();
GameState getGamestate(); GameState getGamestate();
void updateManaPool(Iterable<PlayerView> manaPoolUpdate); void updateManaPool(Iterable<PlayerView> manaPoolUpdate);
void updateLives(Iterable<PlayerView> livesUpdate); void updateLives(Iterable<PlayerView> livesUpdate);
void setPanelSelection(CardView hostCard); void setPanelSelection(CardView hostCard);
SpellAbilityView getAbilityToPlay(CardView hostCard, List<SpellAbilityView> abilities, ITriggerEvent triggerEvent); SpellAbilityView getAbilityToPlay(CardView hostCard, List<SpellAbilityView> abilities, ITriggerEvent triggerEvent);
Map<CardView, Integer> assignCombatDamage(CardView attacker, List<CardView> blockers, int damage, GameEntityView defender, boolean overrideOrder, boolean maySkip); Map<CardView, Integer> assignCombatDamage(CardView attacker, List<CardView> blockers, int damage, GameEntityView defender, boolean overrideOrder, boolean maySkip);
// The Object passed should be GameEntityView for most case. Can be Byte for "generate mana of any combination" effect // The Object passed should be GameEntityView for most case. Can be Byte for "generate mana of any combination" effect
Map<Object, Integer> assignGenericAmount(CardView effectSource, Map<Object, Integer> target, int amount, final boolean atLeastOne, final String amountLabel); Map<Object, Integer> assignGenericAmount(CardView effectSource, Map<Object, Integer> target, int amount, final boolean atLeastOne, final String amountLabel);
void message(String message); void message(String message);
void message(String message, String title); void message(String message, String title);
void showErrorDialog(String message); void showErrorDialog(String message);
void showErrorDialog(String message, String title); void showErrorDialog(String message, String title);
boolean showConfirmDialog(String message, String title); boolean showConfirmDialog(String message, String title);
boolean showConfirmDialog(String message, String title, boolean defaultYes); boolean showConfirmDialog(String message, String title, boolean defaultYes);
boolean showConfirmDialog(String message, String title, String yesButtonText, String noButtonText); boolean showConfirmDialog(String message, String title, String yesButtonText, String noButtonText);
boolean showConfirmDialog(String message, String title, String yesButtonText, String noButtonText, boolean defaultYes); boolean showConfirmDialog(String message, String title, String yesButtonText, String noButtonText, boolean defaultYes);
int showOptionDialog(String message, String title, FSkinProp icon, List<String> options, int defaultOption); int showOptionDialog(String message, String title, FSkinProp icon, List<String> options, int defaultOption);
String showInputDialog(String message, String title); String showInputDialog(String message, String title);
String showInputDialog(String message, String title, FSkinProp icon); String showInputDialog(String message, String title, FSkinProp icon);
String showInputDialog(String message, String title, FSkinProp icon, String initialInput); String showInputDialog(String message, String title, FSkinProp icon, String initialInput);
String showInputDialog(String message, String title, FSkinProp icon, String initialInput, List<String> inputOptions); String showInputDialog(String message, String title, FSkinProp icon, String initialInput, List<String> inputOptions);
boolean confirm(CardView c, String question); boolean confirm(CardView c, String question);
boolean confirm(CardView c, String question, List<String> options); boolean confirm(CardView c, String question, List<String> options);
boolean confirm(CardView c, String question, boolean defaultIsYes, List<String> options); boolean confirm(CardView c, String question, boolean defaultIsYes, List<String> options);
<T> List<T> getChoices(String message, int min, int max, List<T> choices); <T> List<T> getChoices(String message, int min, int max, List<T> choices);
<T> List<T> getChoices(String message, int min, int max, List<T> choices, T selected, Function<T, String> display); <T> List<T> getChoices(String message, int min, int max, List<T> choices, T selected, Function<T, String> display);
// Get Integer in range // Get Integer in range
Integer getInteger(String message, int min); Integer getInteger(String message, int min);
Integer getInteger(String message, int min, int max); Integer getInteger(String message, int min, int max);
Integer getInteger(String message, int min, int max, boolean sortDesc); Integer getInteger(String message, int min, int max, boolean sortDesc);
Integer getInteger(String message, int min, int max, int cutoff); Integer getInteger(String message, int min, int max, int cutoff);
/** /**
* Convenience for getChoices(message, 0, 1, choices). * Convenience for getChoices(message, 0, 1, choices).
* *
* @param <T> * @param <T> is automatically inferred.
* is automatically inferred. * @param message a {@link java.lang.String} object.
* @param message * @param choices a T object.
* a {@link java.lang.String} object.
* @param choices
* a T object.
* @return null if choices is missing, empty, or if the users' choices are * @return null if choices is missing, empty, or if the users' choices are
* empty; otherwise, returns the first item in the List returned by * empty; otherwise, returns the first item in the List returned by
* getChoices. * getChoices.
@@ -123,12 +175,9 @@ public interface IGuiGame {
* getChoice. * getChoice.
* </p> * </p>
* *
* @param <T> * @param <T> a T object.
* a T object. * @param message a {@link java.lang.String} object.
* @param message * @param choices a T object.
* a {@link java.lang.String} object.
* @param choices
* a T object.
* @return One of {@code choices}. Can only be {@code null} if {@code choices} is empty. * @return One of {@code choices}. Can only be {@code null} if {@code choices} is empty.
*/ */
<T> T one(String message, List<T> choices); <T> T one(String message, List<T> choices);
@@ -136,9 +185,11 @@ public interface IGuiGame {
<T> void reveal(String message, List<T> items); <T> void reveal(String message, List<T> items);
<T> List<T> many(String title, String topCaption, int cnt, List<T> sourceChoices, CardView c); <T> List<T> many(String title, String topCaption, int cnt, List<T> sourceChoices, CardView c);
<T> List<T> many(String title, String topCaption, int min, int max, List<T> sourceChoices, CardView c); <T> List<T> many(String title, String topCaption, int min, int max, List<T> sourceChoices, CardView c);
<T> List<T> order(String title, String top, List<T> sourceChoices, CardView c); <T> List<T> order(String title, String top, List<T> sourceChoices, CardView c);
<T> List<T> order(String title, String top, int remainingObjectsMin, int remainingObjectsMax, List<T> sourceChoices, List<T> destChoices, CardView referenceCard, boolean sideboardingMode); <T> List<T> order(String title, String top, int remainingObjectsMin, int remainingObjectsMax, List<T> sourceChoices, List<T> destChoices, CardView referenceCard, boolean sideboardingMode);
/** /**
@@ -146,53 +197,78 @@ public interface IGuiGame {
* current implementation requires the user to cancel in order to get the * current implementation requires the user to cancel in order to get the
* new item to be the first item in the resulting list. * new item to be the first item in the resulting list.
* *
* @param title * @param title the dialog title.
* the dialog title. * @param newItem the object to insert.
* @param newItem * @param oldItems the list of objects.
* the object to insert.
* @param oldItems
* the list of objects.
* @return A shallow copy of the list of objects, with newItem inserted. * @return A shallow copy of the list of objects, with newItem inserted.
*/ */
<T> List<T> insertInList(String title, T newItem, List<T> oldItems); <T> List<T> insertInList(String title, T newItem, List<T> oldItems);
List<PaperCard> sideboard(CardPool sideboard, CardPool main, String message); List<PaperCard> sideboard(CardPool sideboard, CardPool main, String message);
GameEntityView chooseSingleEntityForEffect(String title, List<? extends GameEntityView> optionList, DelayedReveal delayedReveal, boolean isOptional); GameEntityView chooseSingleEntityForEffect(String title, List<? extends GameEntityView> optionList, DelayedReveal delayedReveal, boolean isOptional);
List<GameEntityView> chooseEntitiesForEffect(String title, List<? extends GameEntityView> optionList, int min, int max, DelayedReveal delayedReveal); List<GameEntityView> chooseEntitiesForEffect(String title, List<? extends GameEntityView> optionList, int min, int max, DelayedReveal delayedReveal);
// show a list of cards and allow some of them to be moved around and return new list // show a list of cards and allow some of them to be moved around and return new list
List<CardView> manipulateCardList(String title, final Iterable<CardView> cards, final Iterable<CardView> manipulable, boolean toTop, boolean toBottom, boolean toAnywhere); List<CardView> manipulateCardList(String title, final Iterable<CardView> cards, final Iterable<CardView> manipulable, boolean toTop, boolean toBottom, boolean toAnywhere);
void setCard(CardView card); void setCard(CardView card);
void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi); void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi);
PlayerZoneUpdates openZones(PlayerView controller, Collection<ZoneType> zones, Map<PlayerView, Object> players, boolean backupLastZones); PlayerZoneUpdates openZones(PlayerView controller, Collection<ZoneType> zones, Map<PlayerView, Object> players, boolean backupLastZones);
void restoreOldZones(PlayerView playerView, PlayerZoneUpdates playerZoneUpdates); void restoreOldZones(PlayerView playerView, PlayerZoneUpdates playerZoneUpdates);
void setHighlighted(PlayerView pv, boolean b); void setHighlighted(PlayerView pv, boolean b);
void setUsedToPay(CardView card, boolean value); void setUsedToPay(CardView card, boolean value);
void setSelectables(final Iterable<CardView> cards); void setSelectables(final Iterable<CardView> cards);
void clearSelectables(); void clearSelectables();
boolean isSelecting(); boolean isSelecting();
boolean isGamePaused(); boolean isGamePaused();
void setgamePause(boolean pause); void setgamePause(boolean pause);
void setGameSpeed(boolean gameSpeed); void setGameSpeed(boolean gameSpeed);
String getDayTime(); String getDayTime();
void updateDayTime(String daytime); void updateDayTime(String daytime);
void awaitNextInput(); void awaitNextInput();
void cancelAwaitNextInput(); void cancelAwaitNextInput();
boolean isUiSetToSkipPhase(PlayerView playerTurn, PhaseType phase); boolean isUiSetToSkipPhase(PlayerView playerTurn, PhaseType phase);
void autoPassUntilEndOfTurn(PlayerView player); void autoPassUntilEndOfTurn(PlayerView player);
boolean mayAutoPass(PlayerView player); boolean mayAutoPass(PlayerView player);
void autoPassCancel(PlayerView player); void autoPassCancel(PlayerView player);
void updateAutoPassPrompt(); void updateAutoPassPrompt();
boolean shouldAutoYield(String key); boolean shouldAutoYield(String key);
void setShouldAutoYield(String key, boolean autoYield); void setShouldAutoYield(String key, boolean autoYield);
boolean shouldAlwaysAcceptTrigger(int trigger); boolean shouldAlwaysAcceptTrigger(int trigger);
boolean shouldAlwaysDeclineTrigger(int trigger); boolean shouldAlwaysDeclineTrigger(int trigger);
void setShouldAlwaysAcceptTrigger(int trigger); void setShouldAlwaysAcceptTrigger(int trigger);
void setShouldAlwaysDeclineTrigger(int trigger); void setShouldAlwaysDeclineTrigger(int trigger);
void setShouldAlwaysAskTrigger(int trigger); void setShouldAlwaysAskTrigger(int trigger);
void clearAutoYields(); void clearAutoYields();
void setCurrentPlayer(PlayerView player); void setCurrentPlayer(PlayerView player);

View File

@@ -328,6 +328,9 @@ public enum FSkinProp {
ICO_FAVICON (new int[] {0, 640, 80, 80}, PropType.ICON), ICO_FAVICON (new int[] {0, 640, 80, 80}, PropType.ICON),
ICO_LOCK (new int[] {620, 800, 48, 48}, PropType.ICON), ICO_LOCK (new int[] {620, 800, 48, 48}, PropType.ICON),
//reveal icons
ICO_SEE (new int[] {568, 1520, 60, 40}, PropType.ICON),
ICO_UNSEE (new int[] {568, 1560, 60, 40}, PropType.ICON),
//layout images //layout images
IMG_HANDLE (new int[] {320, 450, 80, 20}, PropType.IMAGE), IMG_HANDLE (new int[] {320, 450, 80, 20}, PropType.IMAGE),

View File

@@ -19,6 +19,7 @@ import java.util.Map.Entry;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.TreeSet; import java.util.TreeSet;
import forge.trackable.TrackableCollection;
import forge.util.ImageUtil; import forge.util.ImageUtil;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.Range; import org.apache.commons.lang3.Range;
@@ -148,7 +149,7 @@ import io.sentry.Sentry;
/** /**
* A prototype for player controller class * A prototype for player controller class
* * <p>
* Handles phase skips for now. * Handles phase skips for now.
*/ */
public class PlayerControllerHuman extends PlayerController implements IGameController { public class PlayerControllerHuman extends PlayerController implements IGameController {
@@ -258,8 +259,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
* Set this to {@code true} to enable this player to see all cards any other * Set this to {@code true} to enable this player to see all cards any other
* player can see. * player can see.
* *
* @param mayLookAtAllCards * @param mayLookAtAllCards the mayLookAtAllCards to set
* the mayLookAtAllCards to set
*/ */
public void setMayLookAtAllCards(final boolean mayLookAtAllCards) { public void setMayLookAtAllCards(final boolean mayLookAtAllCards) {
this.mayLookAtAllCards = mayLookAtAllCards; this.mayLookAtAllCards = mayLookAtAllCards;
@@ -516,7 +516,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
private boolean useSelectCardsInput(final FCollectionView<? extends GameEntity> sourceList) { private boolean useSelectCardsInput(final FCollectionView<? extends GameEntity> sourceList) {
// can't use InputSelect from GUI thread (e.g., DevMode Tutor) // can't use InputSelect from GUI thread (e.g., DevMode Tutor)
if (FThreads.isGuiThread()) { return false; } if (FThreads.isGuiThread()) {
return false;
}
// if UI_SELECT_FROM_CARD_DISPLAYS not set use InputSelect only for battlefield and player hand // if UI_SELECT_FROM_CARD_DISPLAYS not set use InputSelect only for battlefield and player hand
// if UI_SELECT_FROM_CARD_DISPLAYS set and using desktop GUI use InputSelect for any zone that can be shown // if UI_SELECT_FROM_CARD_DISPLAYS set and using desktop GUI use InputSelect for any zone that can be shown
@@ -919,7 +921,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
final String fm = MessageUtil.formatMessage(message, getLocalPlayerView(), owner); final String fm = MessageUtil.formatMessage(message, getLocalPlayerView(), owner);
if (!cards.isEmpty()) { if (!cards.isEmpty()) {
tempShowCards(cards); tempShowCards(cards);
getGui().reveal(fm, CardView.getCollection(cards)); TrackableCollection<CardView> collection = CardView.getCollection(cards);
getGui().reveal(fm, collection);
getGui().updateRevealedCards(collection);
endTempShowCards(); endTempShowCards();
} else { } else {
getGui().message(MessageUtil.formatMessage(localizer.getMessage("lblThereNoCardInPlayerZone", "{player's}", zone.getTranslatedName().toLowerCase()), getGui().message(MessageUtil.formatMessage(localizer.getMessage("lblThereNoCardInPlayerZone", "{player's}", zone.getTranslatedName().toLowerCase()),
@@ -1522,8 +1526,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
return choices; return choices;
} }
@SuppressWarnings("serial") @SuppressWarnings("serial") final InputSelectCardsFromList inp = new InputSelectCardsFromList(this, nDiscard, nDiscard,
final InputSelectCardsFromList inp = new InputSelectCardsFromList(this, nDiscard, nDiscard,
player.getZone(ZoneType.Hand).getCards()) { player.getZone(ZoneType.Hand).getCards()) {
@Override @Override
protected final boolean allowAwaitNextInput() { protected final boolean allowAwaitNextInput() {