From 234304f9ec5c109728c74bc0f34f6e2e59c1691c Mon Sep 17 00:00:00 2001 From: "Peter F. Patel-Schneider" Date: Sun, 6 Jan 2019 10:47:20 -0500 Subject: [PATCH 1/4] Add option to select cards from any Zone that can be shown (implemented in desktop GUI only for now) --- .../java/forge/screens/match/CMatchUI.java | 56 +++++++++++++- .../forge/view/arcane/FloatingCardArea.java | 9 +++ .../forge/screens/match/MatchController.java | 10 +++ .../src/forge/screens/match/MatchScreen.java | 9 +++ .../main/java/forge/interfaces/IGuiGame.java | 2 + .../input/InputSelectEntitiesFromList.java | 22 ++++++ .../main/java/forge/net/ProtocolMethod.java | 4 +- .../java/forge/net/server/NetGuiGame.java | 12 +++ .../forge/player/PlayerControllerHuman.java | 77 ++++++++----------- .../forge/properties/ForgePreferences.java | 2 +- 10 files changed, 156 insertions(+), 47 deletions(-) diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java index 0e13b5c3add..1cb0220a907 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java @@ -101,6 +101,7 @@ import forge.util.gui.SOptionPane; import forge.view.FView; import forge.view.arcane.CardPanel; import forge.view.arcane.FloatingCardArea; +import forge.match.input.*; /** * Constructs instance of match UI controller, used as a single point of @@ -395,7 +396,8 @@ public final class CMatchUI break; case Hand: updateHand = true; - //$FALL-THROUGH$ + updateZones = true; + break; default: updateZones = true; FloatingCardArea.refresh(owner, zone); @@ -424,6 +426,57 @@ public final class CMatchUI } } + @Override + public Iterable tempShowZones(final PlayerView controller, final Iterable zonesToUpdate) { + for (final PlayerZoneUpdate update : zonesToUpdate) { + final PlayerView player = update.getPlayer(); + for (final ZoneType zone : update.getZones()) { + switch (zone) { + case Battlefield: // always shown + break; + case Hand: // controller hand always shown + if (controller != player) { + FloatingCardArea.show(this,player,zone); + } + break; + case Library: + case Graveyard: + case Exile: + case Flashback: + case Command: + FloatingCardArea.show(this,player,zone); + break; + default: + break; + } + } + } + return zonesToUpdate; //pfps should return only the newly shown zones + } + + @Override + public void hideZones(final PlayerView controller, final Iterable zonesToUpdate) { + for (final PlayerZoneUpdate update : zonesToUpdate) { + final PlayerView player = update.getPlayer(); + for (final ZoneType zone : update.getZones()) { + switch (zone) { + case Battlefield: // always shown + break; + case Hand: // the controller's hand should never be temporarily shown, but ... + case Library: + case Graveyard: + case Exile: + case Flashback: + case Command: + FloatingCardArea.hide(this,player,zone); + break; + default: + break; + } + } + } + } + // Player's mana pool changes @Override public void updateManaPool(final Iterable manaPoolUpdate) { @@ -465,6 +518,7 @@ public final class CMatchUI } break; default: + FloatingCardArea.refresh(c.getController(),zone); // in case the card is visible in the zone break; } } diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/FloatingCardArea.java b/forge-gui-desktop/src/main/java/forge/view/arcane/FloatingCardArea.java index fc1365798bb..66b3428e906 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/FloatingCardArea.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/FloatingCardArea.java @@ -69,6 +69,10 @@ public class FloatingCardArea extends CardArea { final FloatingCardArea cardArea = _init(matchUI, player, zone); cardArea.showWindow(); } + public static void hide(final CMatchUI matchUI, final PlayerView player, final ZoneType zone) { + final FloatingCardArea cardArea = _init(matchUI, player, zone); + cardArea.hideWindow(); + } private static FloatingCardArea _init(final CMatchUI matchUI, final PlayerView player, final ZoneType zone) { final int key = getKey(player, zone); FloatingCardArea cardArea = floatingAreas.get(key); @@ -205,6 +209,11 @@ public class FloatingCardArea extends CardArea { window.setFocusableWindowState(false); // should probably do this earlier window.setVisible(true); } + private void hideWindow() { + onShow(); + window.setFocusableWindowState(false); // should probably do this earlier + window.setVisible(false); + } private void showOrHideWindow() { onShow(); window.setFocusableWindowState(false); // should probably do this earlier diff --git a/forge-gui-mobile/src/forge/screens/match/MatchController.java b/forge-gui-mobile/src/forge/screens/match/MatchController.java index 4e7fb644f00..8ded7b6ff33 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchController.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchController.java @@ -343,6 +343,16 @@ public class MatchController extends AbstractGuiGame { view.updateZones(zonesToUpdate); } + @Override + public Iterable tempShowZones(final PlayerView controller, final Iterable zonesToUpdate) { + return view.tempShowZones(controller, zonesToUpdate); + } + + @Override + public void hideZones(final PlayerView controller, final Iterable zonesToUpdate) { + view.hideZones(controller, zonesToUpdate); + } + @Override public void updateCards(final Iterable cards) { for (final CardView card : cards) { diff --git a/forge-gui-mobile/src/forge/screens/match/MatchScreen.java b/forge-gui-mobile/src/forge/screens/match/MatchScreen.java index 774d8c34355..9b710575c4a 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchScreen.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchScreen.java @@ -468,6 +468,15 @@ public class MatchScreen extends FScreen { } } + public Iterable tempShowZones(final PlayerView controller, final Iterable zonesToUpdate) { + // pfps needs to actually do something + return zonesToUpdate; // pfps should return only those zones newly shown + } + + public void hideZones(final PlayerView controller, final Iterable zonesToUpdate) { + // pfps needs to actually do something + } + public void updateSingleCard(final CardView card) { final CardAreaPanel pnl = CardAreaPanel.get(card); if (pnl == null) { return; } diff --git a/forge-gui/src/main/java/forge/interfaces/IGuiGame.java b/forge-gui/src/main/java/forge/interfaces/IGuiGame.java index 1abfe662f54..039b132e988 100644 --- a/forge-gui/src/main/java/forge/interfaces/IGuiGame.java +++ b/forge-gui/src/main/java/forge/interfaces/IGuiGame.java @@ -47,6 +47,8 @@ public interface IGuiGame { void showManaPool(PlayerView player); void hideManaPool(PlayerView player); void updateStack(); + Iterable tempShowZones(PlayerView controller, Iterable zonesToUpdate); + void hideZones(PlayerView controller, Iterable zonesToUpdate); void updateZones(Iterable zonesToUpdate); void updateSingleCard(CardView card); void updateCards(Iterable cards); diff --git a/forge-gui/src/main/java/forge/match/input/InputSelectEntitiesFromList.java b/forge-gui/src/main/java/forge/match/input/InputSelectEntitiesFromList.java index 6448cafae29..f9e082a3624 100644 --- a/forge-gui/src/main/java/forge/match/input/InputSelectEntitiesFromList.java +++ b/forge-gui/src/main/java/forge/match/input/InputSelectEntitiesFromList.java @@ -11,12 +11,17 @@ import forge.player.PlayerControllerHuman; import forge.util.collect.FCollection; import forge.util.collect.FCollectionView; import forge.util.ITriggerEvent; +import forge.player.PlayerZoneUpdate; +import forge.player.PlayerZoneUpdates; +import forge.game.zone.Zone; +import forge.FThreads; public class InputSelectEntitiesFromList extends InputSelectManyBase { private static final long serialVersionUID = -6609493252672573139L; private final FCollectionView validChoices; protected final FCollection selected = new FCollection(); + protected Iterable zonesShown; // want to hide these zones when input done public InputSelectEntitiesFromList(final PlayerControllerHuman controller, final int min, final int max, final FCollectionView validChoices0) { this(controller, min, max, validChoices0, null); @@ -28,6 +33,17 @@ public class InputSelectEntitiesFromList extends InputSele if (min > validChoices.size()) { System.out.println(String.format("Trying to choose at least %d things from a list with only %d things!", min, validChoices.size())); } + PlayerZoneUpdates zonesToUpdate = new PlayerZoneUpdates(); + for (final GameEntity c : validChoices) { + final Zone cz = (c instanceof Card) ? ((Card) c).getZone() : null ; + zonesToUpdate.add(new PlayerZoneUpdate(cz.getPlayer().getView(),cz.getZoneType())); + } + FThreads.invokeInEdtNowOrLater(new Runnable() { + @Override public void run() { + controller.getGui().updateZones(zonesToUpdate); + zonesShown = controller.getGui().tempShowZones(controller.getPlayer().getView(),zonesToUpdate); + } + }); } @Override @@ -93,4 +109,10 @@ public class InputSelectEntitiesFromList extends InputSele ? String.format(message, selected.size()) : String.format(message, max - selected.size()); } + + @Override + protected void onStop() { + getController().getGui().hideZones(getController().getPlayer().getView(),zonesShown); + super.onStop(); + } } diff --git a/forge-gui/src/main/java/forge/net/ProtocolMethod.java b/forge-gui/src/main/java/forge/net/ProtocolMethod.java index 11ff02380d9..85101da9108 100644 --- a/forge-gui/src/main/java/forge/net/ProtocolMethod.java +++ b/forge-gui/src/main/java/forge/net/ProtocolMethod.java @@ -49,6 +49,8 @@ public enum ProtocolMethod { hideManaPool (Mode.SERVER, Void.TYPE, PlayerView.class), updateStack (Mode.SERVER), updateZones (Mode.SERVER, Void.TYPE, Iterable/*PlayerZoneUpdate*/.class), + tempShowZones (Mode.SERVER, Iterable/*PlayerZoneUpdate*/.class, PlayerView.class, Iterable/*PlayerZoneUpdate*/.class), + hideZones (Mode.SERVER, Void.TYPE, PlayerView.class, Iterable/*PlayerZoneUpdate*/.class), updateCards (Mode.SERVER, Void.TYPE, Iterable/*CardView*/.class), updateManaPool (Mode.SERVER, Void.TYPE, Iterable/*PlayerView*/.class), updateLives (Mode.SERVER, Void.TYPE, Iterable/*PlayerView*/.class), @@ -184,4 +186,4 @@ public enum ProtocolMethod { throw new IllegalStateException(String.format("Protocol method %s: illegal return object type %s returned by client, expected %s", name(), value.getClass().getName(), getReturnType().getName())); } } -} \ No newline at end of file +} diff --git a/forge-gui/src/main/java/forge/net/server/NetGuiGame.java b/forge-gui/src/main/java/forge/net/server/NetGuiGame.java index eb479e9352a..5635608fbd0 100644 --- a/forge-gui/src/main/java/forge/net/server/NetGuiGame.java +++ b/forge-gui/src/main/java/forge/net/server/NetGuiGame.java @@ -147,6 +147,18 @@ public class NetGuiGame extends AbstractGuiGame { send(ProtocolMethod.updateZones, zonesToUpdate); } + @Override + public Iterable tempShowZones(final PlayerView controller, final Iterable zonesToUpdate) { + updateGameView(); + return sendAndWait(ProtocolMethod.tempShowZones, controller, zonesToUpdate); + } + + @Override + public void hideZones(final PlayerView controller, final Iterable zonesToUpdate) { + updateGameView(); + send(ProtocolMethod.hideZones, controller, zonesToUpdate); + } + @Override public void updateCards(final Iterable cards) { updateGameView(); diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index b26a3954f65..a745f973e6d 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -348,6 +348,30 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont return new CardCollection(inp.getSelected()); } + private boolean useSelectCardsInput(final FCollectionView sourceList) { + // if UI_SELECT_FROM_ZONES not set use InputSelect only for battlefield and player hand + // if UI_SELECT_FROM_ZONES set use InputSelect for any zone that can be shown + for (final GameEntity c : sourceList) { + if (c instanceof Player) { + continue; + } + if (!(c instanceof Card)) { + return false; + } + final Zone cz = ((Card) c).getZone(); + final boolean useUiPointAtCard = + cz != null && + FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_ZONES) ? + (cz.is(ZoneType.Battlefield) || cz.is(ZoneType.Hand) || cz.is(ZoneType.Library) || + cz.is(ZoneType.Graveyard) || cz.is(ZoneType.Exile) || cz.is(ZoneType.Flashback) || cz.is(ZoneType.Command)) : + (cz.is(ZoneType.Hand) && cz.getPlayer() == player || cz.is(ZoneType.Battlefield)); + if (!useUiPointAtCard) { + return false; + } + } + return true; + } + @Override public CardCollectionView chooseCardsForEffect(final CardCollectionView sourceList, final SpellAbility sa, final String title, final int min, final int max, final boolean isOptional) { @@ -362,22 +386,13 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont getGui().setPanelSelection(CardView.get(sa.getHostCard())); - // try to use InputSelectCardsFromList when possible - boolean cardsAreInMyHandOrBattlefield = true; - for (final Card c : sourceList) { - final Zone z = c.getZone(); - if (z != null && (z.is(ZoneType.Battlefield) || z.is(ZoneType.Hand, player))) { - continue; - } - cardsAreInMyHandOrBattlefield = false; - break; - } - - if (cardsAreInMyHandOrBattlefield) { + if (useSelectCardsInput(sourceList)) { + tempShowCards(sourceList); final InputSelectCardsFromList sc = new InputSelectCardsFromList(this, min, max, sourceList, sa); sc.setMessage(title); sc.setCancelAllowed(isOptional); sc.showAndWait(); + endTempShowCards(); return new CardCollection(sc.getSelected()); } @@ -411,31 +426,18 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont return Iterables.getFirst(optionList, null); } - boolean canUseSelectCardsInput = true; - for (final GameEntity c : optionList) { - if (c instanceof Player) { - continue; - } - final Zone cz = ((Card) c).getZone(); - // can point at cards in own hand and anyone's battlefield - final boolean canUiPointAtCards = cz != null - && (cz.is(ZoneType.Hand) && cz.getPlayer() == player || cz.is(ZoneType.Battlefield)); - if (!canUiPointAtCards) { - canUseSelectCardsInput = false; - break; - } - } - - if (canUseSelectCardsInput) { + if (useSelectCardsInput(optionList)) { if (delayedReveal != null) { reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix()); } + tempShow(optionList); final InputSelectEntitiesFromList input = new InputSelectEntitiesFromList(this, isOptional ? 0 : 1, 1, optionList, sa); input.setCancelAllowed(isOptional); input.setMessage(MessageUtil.formatMessage(title, player, targetedPlayer)); input.showAndWait(); + endTempShowCards(); return Iterables.getFirst(input.getSelected(), null); } @@ -475,31 +477,18 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont return null; } - boolean canUseSelectCardsInput = true; - for (final GameEntity c : optionList) { - if (c instanceof Player) { - continue; - } - final Zone cz = ((Card) c).getZone(); - // can point at cards in own hand and anyone's battlefield - final boolean canUiPointAtCards = cz != null - && (cz.is(ZoneType.Hand) && cz.getPlayer() == player || cz.is(ZoneType.Battlefield)); - if (!canUiPointAtCards) { - canUseSelectCardsInput = false; - break; - } - } - - if (canUseSelectCardsInput) { + if (useSelectCardsInput(optionList)) { if (delayedReveal != null) { reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix()); } + tempShow(optionList); final InputSelectEntitiesFromList input = new InputSelectEntitiesFromList(this, 0, optionList.size(), optionList, sa); input.setCancelAllowed(true); input.setMessage(MessageUtil.formatMessage(title, player, targetedPlayer)); input.showAndWait(); + endTempShowCards(); return (List) input.getSelected(); } diff --git a/forge-gui/src/main/java/forge/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/properties/ForgePreferences.java index 2d6af689171..b96037d9fca 100644 --- a/forge-gui/src/main/java/forge/properties/ForgePreferences.java +++ b/forge-gui/src/main/java/forge/properties/ForgePreferences.java @@ -125,7 +125,7 @@ public class ForgePreferences extends PreferencesStore { UI_DISABLE_IMAGES_EFFECT_CARDS("false"), UI_ALLOW_ORDER_GRAVEYARD_WHEN_NEEDED ("Never"), UI_DEFAULT_FONT_SIZE("12"), - + UI_SELECT_FROM_ZONES("true"), UI_FOR_TOUCHSCREN("false"), UI_VIBRATE_ON_LIFE_LOSS("true"), From 69502dd97b8bcc4c7c3bed50136965b7208ca7cd Mon Sep 17 00:00:00 2001 From: "Peter F. Patel-Schneider" Date: Sun, 6 Jan 2019 12:07:19 -0500 Subject: [PATCH 2/4] Pass min/max through choice code so that user can't choose too many cards --- .../src/main/java/forge/ai/PlayerControllerAi.java | 4 ++-- .../forge/game/ability/effects/ChangeZoneEffect.java | 2 +- .../main/java/forge/game/player/PlayerController.java | 4 ++-- .../src/main/java/forge/screens/match/CMatchUI.java | 4 ++-- .../util/PlayerControllerForTests.java | 4 ++-- .../src/forge/screens/match/MatchController.java | 4 ++-- forge-gui/src/main/java/forge/interfaces/IGuiGame.java | 2 +- forge-gui/src/main/java/forge/net/ProtocolMethod.java | 2 +- .../src/main/java/forge/net/server/NetGuiGame.java | 4 ++-- .../main/java/forge/player/PlayerControllerHuman.java | 10 +++++----- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index 83ebcbdae44..bc002769539 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -162,7 +162,7 @@ public class PlayerControllerAi extends PlayerController { @Override public List chooseEntitiesForEffect( - FCollectionView optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, + FCollectionView optionList, int min, int max, DelayedReveal delayedReveal, SpellAbility sa, String title, Player targetedPlayer) { // this isn't used return null; @@ -1090,7 +1090,7 @@ public class PlayerControllerAi extends PlayerController { @Override public List chooseCardsForZoneChange( - ZoneType destination, List origin, SpellAbility sa, CardCollection fetchList, + ZoneType destination, List origin, SpellAbility sa, CardCollection fetchList, int min, int max, DelayedReveal delayedReveal, String selectPrompt, Player decider) { // this isn't used return null; diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java index b0ef097496b..dbf654df439 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java @@ -852,7 +852,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { } // ensure that selection is within maximum allowed changeNum do { - selectedCards = decider.getController().chooseCardsForZoneChange(destination, origin, sa, fetchList, delayedReveal, selectPrompt, decider); + selectedCards = decider.getController().chooseCardsForZoneChange(destination, origin, sa, fetchList, 0, changeNum, delayedReveal, selectPrompt, decider); } while (selectedCards != null && selectedCards.size() > changeNum); if (selectedCards != null) { for (Card card : selectedCards) { diff --git a/forge-game/src/main/java/forge/game/player/PlayerController.java b/forge-game/src/main/java/forge/game/player/PlayerController.java index f603e7656e4..3e09e7c3f1c 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerController.java +++ b/forge-game/src/main/java/forge/game/player/PlayerController.java @@ -111,7 +111,7 @@ public abstract class PlayerController { public abstract SpellAbility chooseSingleSpellForEffect(List spells, SpellAbility sa, String title, Map params); - public abstract List chooseEntitiesForEffect(FCollectionView optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, Player relatedPlayer); + public abstract List chooseEntitiesForEffect(FCollectionView optionList, int min, int max, DelayedReveal delayedReveal, SpellAbility sa, String title, Player relatedPlayer); public abstract boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message); public abstract boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode bidlife, String string, int bid, Player winner); @@ -239,7 +239,7 @@ public abstract class PlayerController { // better to have this odd method than those if playerType comparison in ChangeZone public abstract Card chooseSingleCardForZoneChange(ZoneType destination, List origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal, String selectPrompt, boolean isOptional, Player decider); - public abstract List chooseCardsForZoneChange(ZoneType destination, List origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal, String selectPrompt, Player decider); + public abstract List chooseCardsForZoneChange(ZoneType destination, List origin, SpellAbility sa, CardCollection fetchList, int min, int max, DelayedReveal delayedReveal, String selectPrompt, Player decider); public abstract void autoPassCancel(); diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java index 1cb0220a907..5da67c046f3 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java @@ -996,11 +996,11 @@ public final class CMatchUI } @Override - public List chooseEntitiesForEffect(final String title, final List optionList, final DelayedReveal delayedReveal) { + public List chooseEntitiesForEffect(final String title, final List optionList, final int min, final int max, final DelayedReveal delayedReveal) { if (delayedReveal != null) { reveal(delayedReveal.getMessagePrefix(), delayedReveal.getCards()); //TODO: Merge this into search dialog } - return (List) order(title,"Selected", 0, optionList.size(), optionList, null, null, false); + return (List) order(title,"Selected", min, max, optionList, null, null, false); } @Override diff --git a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java index 80e3e033579..4a2c07f63c6 100644 --- a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java +++ b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java @@ -174,7 +174,7 @@ public class PlayerControllerForTests extends PlayerController { } @Override - public List chooseEntitiesForEffect(FCollectionView optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, Player relatedPlayer) { + public List chooseEntitiesForEffect(FCollectionView optionList, int min, int max, DelayedReveal delayedReveal, SpellAbility sa, String title, Player relatedPlayer) { // this isn't used return null; } @@ -624,7 +624,7 @@ public class PlayerControllerForTests extends PlayerController { } @Override - public List chooseCardsForZoneChange(ZoneType destination, List origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal, String selectPrompt, Player decider) { + public List chooseCardsForZoneChange(ZoneType destination, List origin, SpellAbility sa, CardCollection fetchList, int min, int max, DelayedReveal delayedReveal, String selectPrompt, Player decider) { // this isn't used return null; } diff --git a/forge-gui-mobile/src/forge/screens/match/MatchController.java b/forge-gui-mobile/src/forge/screens/match/MatchController.java index 8ded7b6ff33..f0ab65ff144 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchController.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchController.java @@ -516,8 +516,8 @@ public class MatchController extends AbstractGuiGame { } @Override - public List chooseEntitiesForEffect(String title, List optionList, DelayedReveal delayedReveal) { - return SGuiChoose.order(title, "Selected", 0, -1, (List) optionList, null); + public List chooseEntitiesForEffect(String title, List optionList, int min, int max, DelayedReveal delayedReveal) { + return SGuiChoose.order(title, "Selected", min, max, (List) optionList, null); } @Override diff --git a/forge-gui/src/main/java/forge/interfaces/IGuiGame.java b/forge-gui/src/main/java/forge/interfaces/IGuiGame.java index 039b132e988..de67ed2ef38 100644 --- a/forge-gui/src/main/java/forge/interfaces/IGuiGame.java +++ b/forge-gui/src/main/java/forge/interfaces/IGuiGame.java @@ -146,7 +146,7 @@ public interface IGuiGame { List sideboard(CardPool sideboard, CardPool main); GameEntityView chooseSingleEntityForEffect(String title, List optionList, DelayedReveal delayedReveal, boolean isOptional); - List chooseEntitiesForEffect(String title, List optionList, DelayedReveal delayedReveal); + List chooseEntitiesForEffect(String title, List optionList, int min, int max, DelayedReveal delayedReveal); void setCard(CardView card); void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi); boolean openZones(Collection zones, Map players); diff --git a/forge-gui/src/main/java/forge/net/ProtocolMethod.java b/forge-gui/src/main/java/forge/net/ProtocolMethod.java index 85101da9108..a5c3851c1cc 100644 --- a/forge-gui/src/main/java/forge/net/ProtocolMethod.java +++ b/forge-gui/src/main/java/forge/net/ProtocolMethod.java @@ -67,7 +67,7 @@ public enum ProtocolMethod { order (Mode.SERVER, List.class, String.class, String.class, Integer.TYPE, Integer.TYPE, List.class, List.class, CardView.class, Boolean.TYPE), sideboard (Mode.SERVER, List.class, CardPool.class, CardPool.class), chooseSingleEntityForEffect(Mode.SERVER, GameEntityView.class, String.class, List.class, DelayedReveal.class, Boolean.TYPE), - chooseEntitiesForEffect(Mode.SERVER, GameEntityView.class, String.class, List.class, DelayedReveal.class), + chooseEntitiesForEffect(Mode.SERVER, GameEntityView.class, String.class, List.class, Integer.TYPE, Integer.TYPE, DelayedReveal.class), setCard (Mode.SERVER, Void.TYPE, CardView.class), // TODO case "setPlayerAvatar": openZones (Mode.SERVER, Boolean.TYPE, Collection/*ZoneType*/.class, Map/*PlayerView,Object*/.class), diff --git a/forge-gui/src/main/java/forge/net/server/NetGuiGame.java b/forge-gui/src/main/java/forge/net/server/NetGuiGame.java index 5635608fbd0..7578bb067f5 100644 --- a/forge-gui/src/main/java/forge/net/server/NetGuiGame.java +++ b/forge-gui/src/main/java/forge/net/server/NetGuiGame.java @@ -244,8 +244,8 @@ public class NetGuiGame extends AbstractGuiGame { } @Override - public List chooseEntitiesForEffect(final String title, final List optionList, final DelayedReveal delayedReveal) { - return sendAndWait(ProtocolMethod.chooseEntitiesForEffect, title, optionList, delayedReveal); + public List chooseEntitiesForEffect(final String title, final List optionList, final int min, final int max, final DelayedReveal delayedReveal) { + return sendAndWait(ProtocolMethod.chooseEntitiesForEffect, title, optionList, min, max, delayedReveal); } @Override diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index a745f973e6d..bad4aa8d8e0 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -460,7 +460,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont @SuppressWarnings("unchecked") @Override - public List chooseEntitiesForEffect(final FCollectionView optionList, + public List chooseEntitiesForEffect(final FCollectionView optionList, final int min, final int max, final DelayedReveal delayedReveal, final SpellAbility sa, final String title, final Player targetedPlayer) { // useful details for debugging problems with the mass select logic @@ -483,7 +483,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont delayedReveal.getMessagePrefix()); } tempShow(optionList); - final InputSelectEntitiesFromList input = new InputSelectEntitiesFromList(this, 0, optionList.size(), + final InputSelectEntitiesFromList input = new InputSelectEntitiesFromList(this, min, max, optionList, sa); input.setCancelAllowed(true); input.setMessage(MessageUtil.formatMessage(title, player, targetedPlayer)); @@ -497,7 +497,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont tempShow(delayedReveal.getCards()); } final List chosen = getGui().chooseEntitiesForEffect(title, - GameEntityView.getEntityCollection(optionList), delayedReveal); + GameEntityView.getEntityCollection(optionList), min, max, delayedReveal); endTempShowCards(); List results = new ArrayList<>(); @@ -1780,9 +1780,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont } public List chooseCardsForZoneChange(final ZoneType destination, final List origin, - final SpellAbility sa, final CardCollection fetchList, final DelayedReveal delayedReveal, + final SpellAbility sa, final CardCollection fetchList, final int min, final int max, final DelayedReveal delayedReveal, final String selectPrompt, final Player decider) { - return chooseEntitiesForEffect(fetchList, delayedReveal, sa, selectPrompt, decider); + return chooseEntitiesForEffect(fetchList, min, max, delayedReveal, sa, selectPrompt, decider); } @Override From 09fc3ae60c28b57d35c970ad112dc03f290a639a Mon Sep 17 00:00:00 2001 From: "Peter F. Patel-Schneider" Date: Wed, 9 Jan 2019 21:13:09 -0500 Subject: [PATCH 3/4] add new GUI interface allowing cards to be moved around in a list and use for arrangeForScry if preference UI_SELECT_FROM_CARD_DISPLAYS is set --- .../src/main/java/forge/util/Localizer.java | 2 +- .../src/main/java/forge/gui/GuiChoose.java | 28 +- .../java/forge/screens/match/CMatchUI.java | 6 + .../main/java/forge/view/arcane/CardArea.java | 4 +- .../forge/view/arcane/CardPanelContainer.java | 35 +- .../java/forge/view/arcane/ListCardArea.java | 317 ++++++++++++++++++ .../forge/screens/match/MatchController.java | 6 + .../main/java/forge/interfaces/IGuiGame.java | 5 + .../main/java/forge/net/ProtocolMethod.java | 1 + .../java/forge/net/server/NetGuiGame.java | 6 + .../forge/player/PlayerControllerHuman.java | 72 ++-- .../forge/properties/ForgePreferences.java | 2 +- 12 files changed, 443 insertions(+), 41 deletions(-) create mode 100644 forge-gui-desktop/src/main/java/forge/view/arcane/ListCardArea.java diff --git a/forge-core/src/main/java/forge/util/Localizer.java b/forge-core/src/main/java/forge/util/Localizer.java index 6463a9716c1..cc31a7f1af3 100644 --- a/forge-core/src/main/java/forge/util/Localizer.java +++ b/forge-core/src/main/java/forge/util/Localizer.java @@ -86,7 +86,7 @@ public class Localizer { resourceBundle = ResourceBundle.getBundle(languageRegionID, new Locale(splitLocale[0], splitLocale[1]), loader); } catch (NullPointerException | MissingResourceException e) { //If the language can't be loaded, default to US English - resourceBundle = ResourceBundle.getBundle("en-GB", new Locale("en", "GB"), loader); + resourceBundle = ResourceBundle.getBundle("en-US", new Locale("en", "US"), loader); e.printStackTrace(); } diff --git a/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java b/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java index ea177273bda..61a919fd59e 100644 --- a/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java +++ b/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java @@ -29,7 +29,7 @@ import forge.item.PaperCard; import forge.model.FModel; import forge.screens.match.CMatchUI; import forge.toolbox.FOptionPane; - +import forge.view.arcane.ListCardArea; public class GuiChoose { @@ -285,5 +285,31 @@ public class GuiChoose { return null; } + public static List manipulateCardList(final CMatchUI gui, final String title, final List cards, final List manipulable, + final boolean toTop, final boolean toBottom, final boolean toAnywhere) { + final Callable> callable = new Callable>() { + @Override + public List call() throws Exception { + ListCardArea tempArea = new ListCardArea(gui,title,cards,manipulable,toTop,toBottom,toAnywhere); + // tempArea.pack(); + // window? tempArea.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + tempArea.show(); + // tempArea.dispose(); + //try { Thread.sleep(1000); } catch(InterruptedException ex) { } + final List cardList = tempArea.getCardList(); + return cardList; + } + }; + final FutureTask> ft = new FutureTask>(callable); + FThreads.invokeInEdtAndWait(ft); + try { + List result = ft.get(); + return result; + } catch (final Exception e) { // we have waited enough + e.printStackTrace(); + } + return null; + } + } diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java index 5da67c046f3..a338000744f 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java @@ -51,6 +51,7 @@ import forge.deck.Deck; import forge.deckchooser.FDeckViewer; import forge.game.GameEntityView; import forge.game.GameView; +import forge.game.card.Card; import forge.game.card.CardView; import forge.game.combat.CombatView; import forge.game.phase.PhaseType; @@ -1003,6 +1004,11 @@ public final class CMatchUI return (List) order(title,"Selected", min, max, optionList, null, null, false); } + @Override + public List manipulateCardList(final String title, final List cards, final List manipulable, final boolean toTop, final boolean toBottom, final boolean toAnywhere) { + return GuiChoose.manipulateCardList(this, title, cards, manipulable, toTop, toBottom, toAnywhere); + } + @Override public void setPlayerAvatar(final LobbyPlayer player, final IHasIcon ihi) { avatarImages.put(player.getName(), ihi.getIconImageKey()); diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/CardArea.java b/forge-gui-desktop/src/main/java/forge/view/arcane/CardArea.java index 46132c094e5..7c148bc3062 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/CardArea.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/CardArea.java @@ -246,8 +246,8 @@ public class CardArea extends CardPanelContainer implements CardPanelMouseListen dragPanel.setDisplayEnabled(false); CardPanel.setDragAnimationPanel(new CardPanel(dragPanel.getMatchUI(), dragPanel.getCard())); - final JFrame frame = (JFrame) SwingUtilities.windowForComponent(this); - final JLayeredPane layeredPane = frame.getLayeredPane(); + final RootPaneContainer frame = (RootPaneContainer) SwingUtilities.windowForComponent(this); + final JLayeredPane layeredPane = frame.getLayeredPane(); layeredPane.add(CardPanel.getDragAnimationPanel()); layeredPane.moveToFront(CardPanel.getDragAnimationPanel()); final Point p = SwingUtilities.convertPoint(this, this.mouseDragStartX, this.mouseDragStartY, layeredPane); diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanelContainer.java b/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanelContainer.java index de07aafc508..45c9c1780fd 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanelContainer.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanelContainer.java @@ -182,6 +182,10 @@ public abstract class CardPanelContainer extends SkinnedPanel { }); } + protected boolean cardPanelDraggable(final CardPanel panel) { + return true; + } + private MouseMotionListener setupMotionMouseListener() { final MouseMotionListener mml = new MouseMotionListener() { @Override @@ -207,20 +211,23 @@ public abstract class CardPanelContainer extends SkinnedPanel { if (panel != mouseDownPanel) { return; } - if (intialMouseDragX == -1) { - intialMouseDragX = x; - intialMouseDragY = y; - return; - } - if ((Math.abs(x - intialMouseDragX) < CardPanelContainer.DRAG_SMUDGE) + + if (cardPanelDraggable(panel)) { // allow for non-draggable cards + if (intialMouseDragX == -1) { + intialMouseDragX = x; + intialMouseDragY = y; + return; + } + if ((Math.abs(x - intialMouseDragX) < CardPanelContainer.DRAG_SMUDGE) && (Math.abs(y - intialMouseDragY) < CardPanelContainer.DRAG_SMUDGE)) { - return; - } - mouseDownPanel = null; - setMouseDragPanel(panel); - mouseDragOffsetX = panel.getX() - intialMouseDragX; - mouseDragOffsetY = panel.getY() - intialMouseDragY; - mouseDragStart(getMouseDragPanel(), evt); + return; + } + mouseDownPanel = null; + setMouseDragPanel(panel); + mouseDragOffsetX = panel.getX() - intialMouseDragX; + mouseDragOffsetY = panel.getY() - intialMouseDragY; + mouseDragStart(getMouseDragPanel(), evt); + } } @Override @@ -453,4 +460,4 @@ public abstract class CardPanelContainer extends SkinnedPanel { this.layoutListeners.add(listener); } -} \ No newline at end of file +} diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/ListCardArea.java b/forge-gui-desktop/src/main/java/forge/view/arcane/ListCardArea.java new file mode 100644 index 00000000000..2ab3358a9f0 --- /dev/null +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/ListCardArea.java @@ -0,0 +1,317 @@ +/* + * Forge: Play Magic: the Gathering. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package forge.view.arcane; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.ScrollPaneConstants; +import javax.swing.Timer; + +import forge.Singletons; +import forge.game.card.Card; +import forge.game.card.CardView; +import forge.gui.framework.SDisplayUtil; +import forge.model.FModel; +import forge.properties.ForgePreferences; +import forge.properties.ForgePreferences.FPref; +import forge.screens.match.CMatchUI; +import forge.view.arcane.util.CardPanelMouseAdapter; +import forge.toolbox.FScrollPane; +import forge.toolbox.MouseTriggerEvent; +import forge.view.FFrame; +import forge.view.FDialog; + +import forge.toolbox.FButton; + +public class ListCardArea extends CardArea { + + private static final String COORD_DELIM = ","; + private static final ForgePreferences prefs = FModel.getPreferences(); + + public void show() { + this.showWindow(); + } + public void hide() { + this.hideWindow(); + } + + private ArrayList cardList; + private ArrayList moveableCards; + private boolean toTop, toBottom, toAnywhere; + private String title; + private FPref locPref; + private boolean hasBeenShown = false, locLoaded; + private static ListCardArea storedArea; + + private final FButton doneButton; + + public ListCardArea(final CMatchUI matchUI, final String title0, final List cardList0, final List moveableCards0, final boolean toTop0, final boolean toBottom0, final boolean toAnywhere0) { + super(matchUI, new FScrollPane(false, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)); + window.add(getScrollPane(),"grow, push"); + try { Thread.sleep(1000); } catch(InterruptedException ex) { } + getScrollPane().setViewportView(this); + setOpaque(false); + doneButton = new FButton("Done"); + doneButton.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { window.setVisible(false); } + }); + window.add(doneButton,BorderLayout.SOUTH); + cardList = new ArrayList(cardList0); // this is modified - pfps - is there a better way? + moveableCards = new ArrayList(moveableCards0); + title = title0; + toTop = toTop0; + toBottom = toBottom0; + toAnywhere = toAnywhere0; + this.setDragEnabled(true); + this.setVertical(true); + storedArea = this; + } + + public List getCardList() { + return cardList; + } + + @SuppressWarnings("serial") + // private SkinnedFrame window = new SkinnedFrame() { + private final FDialog window = new FDialog(true, true, "0") { + @Override + public void setLocationRelativeTo(Component c) { + super.setLocationRelativeTo(c); + } + + @Override + public void setVisible(boolean b0) { + if (isVisible() == b0) { return; } + if (b0) { + refresh(); + } + super.setVisible(b0); + } + }; + + private void showWindow() { + onShow(); + window.setFocusableWindowState(true); + window.setVisible(true); + } + private void hideWindow() { + onShow(); + window.setFocusableWindowState(false); // should probably do this earlier + window.setVisible(false); + } + private void onShow() { + if (!hasBeenShown) { + loadLocation(); + this.addCardPanelMouseListener(new CardPanelMouseAdapter() { + @Override + public void mouseDragEnd(final CardPanel dragPanel, final MouseEvent evt) { + dragEnd(dragPanel); + } + }); + this.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(final KeyEvent e) { + switch (e.getKeyCode()) { + case KeyEvent.VK_ENTER: + doneButton.doClick(); + break; + default: + break; + } + } + }); + } + + } + + // is this a valid place to move the card? + private boolean validIndex(final Card card, final int index) { + if (toAnywhere) { return true; } + int oldIndex = cardList.indexOf(card); + boolean topMove = true; + for(int i=0; iindex?1:0); i 0) { + String[] coords = value.split(COORD_DELIM); + if (coords.length == 4) { + try { + int x = Integer.parseInt(coords[0]); + int y = Integer.parseInt(coords[1]); + int w = Integer.parseInt(coords[2]); + int h = Integer.parseInt(coords[3]); + + //ensure the window is accessible + int centerX = x + w / 2; + int centerY = y + h / 2; + Rectangle screenBounds = SDisplayUtil.getScreenBoundsForPoint(new Point(centerX, centerY)); + if (centerX < screenBounds.x) { + x = screenBounds.x; + } + else if (centerX > screenBounds.x + screenBounds.width) { + x = screenBounds.x + screenBounds.width - w; + if (x < screenBounds.x) { + x = screenBounds.x; + } + } + if (centerY < screenBounds.y) { + y = screenBounds.y; + } + else if (centerY > screenBounds.y + screenBounds.height) { + y = screenBounds.y + screenBounds.height - h; + if (y < screenBounds.y) { + y = screenBounds.y; + } + } + window.setBounds(x, y, w, h); + locLoaded = true; + return; + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + prefs.setPref(locPref, ""); //clear value if invalid + prefs.save(); + } + } + //fallback default size + FFrame mainFrame = Singletons.getView().getFrame(); + window.setSize(mainFrame.getWidth() / 5, mainFrame.getHeight() / 2); + } + + public void refresh() { + List cardPanels = new ArrayList(); + // FCollectionView cards = new FCollection(cardList); + if (cardList != null) { + for (final Card card : cardList) { + CardPanel cardPanel = getCardPanel(card.getId()); + if (cardPanel == null) { + cardPanel = new CardPanel(getMatchUI(), card.getView()); + cardPanel.setDisplayEnabled(true); + } + else { + cardPanel.setCard(card.getView()); //ensure card view updated + } + cardPanels.add(cardPanel); + } + } + + boolean hadCardPanels = getCardPanels().size() > 0; + setCardPanels(cardPanels); + window.setTitle(String.format(title, cardPanels.size())); + + //if window had cards and now doesn't, hide window + //(e.g. cast final card from Flashback zone) + if (hadCardPanels && cardPanels.size() == 0) { + window.setVisible(false); + } + } + + @Override + public void doLayout() { + // if (window.isResizing()) { + // //delay layout slightly to reduce flicker during window resize + // layoutTimer.restart(); + // } + //else { + finishDoLayout(); + //} + } + + private final Timer layoutTimer = new Timer(250, new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + layoutTimer.stop(); + finishDoLayout(); + } + }); + + private void finishDoLayout() { + super.doLayout(); + } + + @Override + public final void mouseOver(final CardPanel panel, final MouseEvent evt) { + getMatchUI().setCard(panel.getCard(), evt.isShiftDown()); + super.mouseOver(panel, evt); + } + @Override + public final void mouseLeftClicked(final CardPanel panel, final MouseEvent evt) { + getMatchUI().getGameController().selectCard(panel.getCard(), null, new MouseTriggerEvent(evt)); + super.mouseLeftClicked(panel, evt); + } + @Override + public final void mouseRightClicked(final CardPanel panel, final MouseEvent evt) { + getMatchUI().getGameController().selectCard(panel.getCard(), null, new MouseTriggerEvent(evt)); + super.mouseRightClicked(panel, evt); + } + +} diff --git a/forge-gui-mobile/src/forge/screens/match/MatchController.java b/forge-gui-mobile/src/forge/screens/match/MatchController.java index f0ab65ff144..5a361c87e49 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchController.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchController.java @@ -29,6 +29,7 @@ import forge.deck.CardPool; import forge.deck.FSideboardDialog; import forge.game.GameEntityView; import forge.game.GameView; +import forge.game.card.Card; import forge.game.card.CardView; import forge.game.phase.PhaseType; import forge.game.player.DelayedReveal; @@ -520,6 +521,11 @@ public class MatchController extends AbstractGuiGame { return SGuiChoose.order(title, "Selected", min, max, (List) optionList, null); } + @Override + public List manipulateCardList(final String title, final List cards, final List manipulable, final boolean toTop, final boolean toBottom, final boolean toAnywhere) { + return null; // pfps not implemented yet + } + @Override public void setCard(final CardView card) { // doesn't need to do anything diff --git a/forge-gui/src/main/java/forge/interfaces/IGuiGame.java b/forge-gui/src/main/java/forge/interfaces/IGuiGame.java index de67ed2ef38..5e60457fb8d 100644 --- a/forge-gui/src/main/java/forge/interfaces/IGuiGame.java +++ b/forge-gui/src/main/java/forge/interfaces/IGuiGame.java @@ -11,6 +11,7 @@ import forge.assets.FSkinProp; import forge.deck.CardPool; import forge.game.GameEntityView; import forge.game.GameView; +import forge.game.card.Card; import forge.game.card.CardView; import forge.game.phase.PhaseType; import forge.game.player.DelayedReveal; @@ -147,6 +148,10 @@ public interface IGuiGame { List sideboard(CardPool sideboard, CardPool main); GameEntityView chooseSingleEntityForEffect(String title, List optionList, DelayedReveal delayedReveal, boolean isOptional); List chooseEntitiesForEffect(String title, List 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 + List manipulateCardList(String title, final List cards, final List manipulable, boolean toTop, boolean toBottom, boolean toAnywhere); + void setCard(CardView card); void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi); boolean openZones(Collection zones, Map players); diff --git a/forge-gui/src/main/java/forge/net/ProtocolMethod.java b/forge-gui/src/main/java/forge/net/ProtocolMethod.java index a5c3851c1cc..4642efd5101 100644 --- a/forge-gui/src/main/java/forge/net/ProtocolMethod.java +++ b/forge-gui/src/main/java/forge/net/ProtocolMethod.java @@ -68,6 +68,7 @@ public enum ProtocolMethod { sideboard (Mode.SERVER, List.class, CardPool.class, CardPool.class), chooseSingleEntityForEffect(Mode.SERVER, GameEntityView.class, String.class, List.class, DelayedReveal.class, Boolean.TYPE), chooseEntitiesForEffect(Mode.SERVER, GameEntityView.class, String.class, List.class, Integer.TYPE, Integer.TYPE, DelayedReveal.class), + manipulateCardList (Mode.SERVER, List.class, String.class, List.class, List.class, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE), setCard (Mode.SERVER, Void.TYPE, CardView.class), // TODO case "setPlayerAvatar": openZones (Mode.SERVER, Boolean.TYPE, Collection/*ZoneType*/.class, Map/*PlayerView,Object*/.class), diff --git a/forge-gui/src/main/java/forge/net/server/NetGuiGame.java b/forge-gui/src/main/java/forge/net/server/NetGuiGame.java index 7578bb067f5..069f3302d4c 100644 --- a/forge-gui/src/main/java/forge/net/server/NetGuiGame.java +++ b/forge-gui/src/main/java/forge/net/server/NetGuiGame.java @@ -11,6 +11,7 @@ import forge.assets.FSkinProp; import forge.deck.CardPool; import forge.game.GameEntityView; import forge.game.GameView; +import forge.game.card.Card; import forge.game.card.CardView; import forge.game.phase.PhaseType; import forge.game.player.DelayedReveal; @@ -248,6 +249,11 @@ public class NetGuiGame extends AbstractGuiGame { return sendAndWait(ProtocolMethod.chooseEntitiesForEffect, title, optionList, min, max, delayedReveal); } + @Override + public List manipulateCardList(final String title, final List cards, final List manipulable, final boolean toTop, final boolean toBottom, final boolean toAnywhere) { + return sendAndWait(ProtocolMethod.manipulateCardList, title, cards, manipulable, toTop, toBottom, toAnywhere); + } + @Override public void setCard(final CardView card) { updateGameView(); diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index bad4aa8d8e0..8874ca43c9a 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -349,8 +349,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont } private boolean useSelectCardsInput(final FCollectionView sourceList) { - // if UI_SELECT_FROM_ZONES not set use InputSelect only for battlefield and player hand - // if UI_SELECT_FROM_ZONES set use InputSelect for any zone that can be shown + // if UI_SELECT_FROM_CARD_DISPLAYS not set use InputSelect only for battlefield and player hand + // if UI_SELECT_FROM_CARD_DISPLAYS set use InputSelect for any zone that can be shown + if ( FThreads.isGuiThread() ) { return false; } // also can't use InputSelect from GUI thread (e.g., DevMode Tutor) for (final GameEntity c : sourceList) { if (c instanceof Player) { continue; @@ -361,7 +362,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont final Zone cz = ((Card) c).getZone(); final boolean useUiPointAtCard = cz != null && - FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_ZONES) ? + FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_CARD_DISPLAYS) ? (cz.is(ZoneType.Battlefield) || cz.is(ZoneType.Hand) || cz.is(ZoneType.Library) || cz.is(ZoneType.Graveyard) || cz.is(ZoneType.Exile) || cz.is(ZoneType.Flashback) || cz.is(ZoneType.Command)) : (cz.is(ZoneType.Hand) && cz.getPlayer() == player || cz.is(ZoneType.Battlefield)); @@ -736,31 +737,58 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont } } + public ImmutablePair arrangeForMove(final String title, final List cards, final List manipulable, final boolean topOK, final boolean bottomOK) { + List result = getGui().manipulateCardList("Move cards to top or bottom of library", cards, manipulable, topOK, bottomOK, false); + CardCollection toBottom = new CardCollection(); + CardCollection toTop = new CardCollection(); + for (int i = 0; manipulable.contains(result.get(i)) && i arrangeForScry(final CardCollection topN) { CardCollection toBottom = null; CardCollection toTop = null; tempShowCards(topN); - if (topN.size() == 1) { - if (willPutCardOnTop(topN.get(0))) { - toTop = topN; - } else { - toBottom = topN; - } - } else { - toBottom = game.getCardList(getGui().many("Select cards to be put on the bottom of your library", - "Cards to put on the bottom", -1, CardView.getCollection(topN), null)); - topN.removeAll((Collection) toBottom); - if (topN.isEmpty()) { - toTop = null; - } else if (topN.size() == 1) { - toTop = topN; - } else { - toTop = game.getCardList(getGui().order("Arrange cards to be put on top of your library", - "Top of Library", CardView.getCollection(topN), null)); - } - } + if ( FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_CARD_DISPLAYS) ) { + ArrayList cardList = new ArrayList(); // pfps there must be a better way + for (final Card card : player.getCardsIn(ZoneType.Library)) { + cardList.add(card); + } + ImmutablePair result = + arrangeForMove("Move cards to top or bottom of library", cardList, topN, true, true); + System.out.print("Arrange "); System.out.println(result); + toTop = result.getLeft(); + toBottom = result.getRight(); + } else { + if (topN.size() == 1) { + if (willPutCardOnTop(topN.get(0))) { + toTop = topN; + } else { + toBottom = topN; + } + } else { + toBottom = game.getCardList(getGui().many("Select cards to be put on the bottom of your library", + "Cards to put on the bottom", -1, CardView.getCollection(topN), null)); + topN.removeAll((Collection) toBottom); + if (topN.isEmpty()) { + toTop = null; + } else if (topN.size() == 1) { + toTop = topN; + } else { + toTop = game.getCardList(getGui().order("Arrange cards to be put on top of your library", + "Top of Library", CardView.getCollection(topN), null)); + } + } + } endTempShowCards(); return ImmutablePair.of(toTop, toBottom); } diff --git a/forge-gui/src/main/java/forge/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/properties/ForgePreferences.java index b96037d9fca..6059254787d 100644 --- a/forge-gui/src/main/java/forge/properties/ForgePreferences.java +++ b/forge-gui/src/main/java/forge/properties/ForgePreferences.java @@ -125,7 +125,7 @@ public class ForgePreferences extends PreferencesStore { UI_DISABLE_IMAGES_EFFECT_CARDS("false"), UI_ALLOW_ORDER_GRAVEYARD_WHEN_NEEDED ("Never"), UI_DEFAULT_FONT_SIZE("12"), - UI_SELECT_FROM_ZONES("true"), + UI_SELECT_FROM_CARD_DISPLAYS("true"), UI_FOR_TOUCHSCREN("false"), UI_VIBRATE_ON_LIFE_LOSS("true"), From 3609ff9eff31c5ea1044be0308358f9f6bb60ddc Mon Sep 17 00:00:00 2001 From: "Peter F. Patel-Schneider" Date: Fri, 11 Jan 2019 03:48:42 -0500 Subject: [PATCH 4/4] only use new input methods if in desktop GUI; remove debugging prints --- .../src/main/java/forge/view/arcane/ListCardArea.java | 3 --- .../src/forge/screens/match/MatchController.java | 3 ++- .../main/java/forge/player/PlayerControllerHuman.java | 10 +++++----- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/ListCardArea.java b/forge-gui-desktop/src/main/java/forge/view/arcane/ListCardArea.java index 2ab3358a9f0..3a601829df9 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/ListCardArea.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/ListCardArea.java @@ -184,7 +184,6 @@ public class ListCardArea extends CardArea { //update index of dragged card in hand zone to match new index within hand area final int index = getCardPanels().indexOf(dragPanel); if (validIndex(dragCard,index)) { - System.out.print("Really move card to index "); System.out.println(index); synchronized (cardList) { cardList.remove(dragCard); cardList.add(index, dragCard); @@ -195,10 +194,8 @@ public class ListCardArea extends CardArea { } private void loadLocation() { - System.out.println("loadlocation"); if (locPref != null) { String value = prefs.getPref(locPref); - System.out.print(locPref); System.out.println(value); if (value.length() > 0) { String[] coords = value.split(COORD_DELIM); if (coords.length == 4) { diff --git a/forge-gui-mobile/src/forge/screens/match/MatchController.java b/forge-gui-mobile/src/forge/screens/match/MatchController.java index 5a361c87e49..789fa67d32c 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchController.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchController.java @@ -523,7 +523,8 @@ public class MatchController extends AbstractGuiGame { @Override public List manipulateCardList(final String title, final List cards, final List manipulable, final boolean toTop, final boolean toBottom, final boolean toAnywhere) { - return null; // pfps not implemented yet + System.err.println("Not implemented yet - should never be called"); + return null; } @Override diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 8874ca43c9a..8526c486a62 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -349,9 +349,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont } private boolean useSelectCardsInput(final FCollectionView sourceList) { + if ( FThreads.isGuiThread() ) { return false; } // can't use InputSelect from GUI thread (e.g., DevMode Tutor) // if UI_SELECT_FROM_CARD_DISPLAYS not set use InputSelect only for battlefield and player hand - // if UI_SELECT_FROM_CARD_DISPLAYS set use InputSelect for any zone that can be shown - if ( FThreads.isGuiThread() ) { return false; } // also can't use InputSelect from GUI thread (e.g., DevMode Tutor) + // if UI_SELECT_FROM_CARD_DISPLAYS set and using desktop GUI use InputSelect for any zone that can be shown for (final GameEntity c : sourceList) { if (c instanceof Player) { continue; @@ -362,7 +362,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont final Zone cz = ((Card) c).getZone(); final boolean useUiPointAtCard = cz != null && - FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_CARD_DISPLAYS) ? + (FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_CARD_DISPLAYS) && (!GuiBase.getInterface().isLibgdxPort()) ) ? (cz.is(ZoneType.Battlefield) || cz.is(ZoneType.Hand) || cz.is(ZoneType.Library) || cz.is(ZoneType.Graveyard) || cz.is(ZoneType.Exile) || cz.is(ZoneType.Flashback) || cz.is(ZoneType.Command)) : (cz.is(ZoneType.Hand) && cz.getPlayer() == player || cz.is(ZoneType.Battlefield)); @@ -758,14 +758,14 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont CardCollection toTop = null; tempShowCards(topN); - if ( FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_CARD_DISPLAYS) ) { + if ( FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_CARD_DISPLAYS) && + (!GuiBase.getInterface().isLibgdxPort()) ) { ArrayList cardList = new ArrayList(); // pfps there must be a better way for (final Card card : player.getCardsIn(ZoneType.Library)) { cardList.add(card); } ImmutablePair result = arrangeForMove("Move cards to top or bottom of library", cardList, topN, true, true); - System.out.print("Arrange "); System.out.println(result); toTop = result.getLeft(); toBottom = result.getRight(); } else {