From f8a1b327b4749d22d0c26bd2210300e674ff2cc2 Mon Sep 17 00:00:00 2001 From: magenoxx Date: Fri, 11 Jul 2014 10:49:00 +0400 Subject: [PATCH] [UI] Order of cards in hand is changable --- .../src/main/java/mage/client/cards/Card.java | 59 +--- .../main/java/mage/client/cards/Cards.java | 91 +++--- .../main/java/mage/client/game/HandPanel.java | 10 +- .../plugins/adapters/MageActionCallback.java | 291 ++++++++++-------- .../mage/client/util/gui/ArrowBuilder.java | 1 + .../java/mage/client/util/gui/ArrowUtil.java | 116 +++++++ .../java/org/mage/card/arcane/CardPanel.java | 56 +++- Mage.Common/src/mage/cards/MageCard.java | 8 +- .../src/mage/cards/action/ActionCallback.java | 1 + .../mage/cards/action/impl/EmptyCallback.java | 5 + 10 files changed, 399 insertions(+), 239 deletions(-) create mode 100644 Mage.Client/src/main/java/mage/client/util/gui/ArrowUtil.java diff --git a/Mage.Client/src/main/java/mage/client/cards/Card.java b/Mage.Client/src/main/java/mage/client/cards/Card.java index 24bade0d9df..0057f63b9c7 100644 --- a/Mage.Client/src/main/java/mage/client/cards/Card.java +++ b/Mage.Client/src/main/java/mage/client/cards/Card.java @@ -34,50 +34,12 @@ package mage.client.cards; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.event.ComponentEvent; -import java.awt.event.ComponentListener; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; -import java.awt.image.BufferedImage; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import javax.swing.JScrollPane; -import javax.swing.Popup; -import javax.swing.PopupFactory; -import javax.swing.text.BadLocationException; -import javax.swing.text.Style; -import javax.swing.text.StyleConstants; -import javax.swing.text.StyleContext; -import javax.swing.text.StyledDocument; import mage.cards.CardDimensions; import mage.cards.MagePermanent; import mage.cards.Sets; import mage.cards.TextPopup; import mage.cards.action.ActionCallback; import mage.client.MageFrame; -import static mage.client.constants.Constants.CONTENT_MAX_XOFFSET; -import static mage.client.constants.Constants.FRAME_MAX_HEIGHT; -import static mage.client.constants.Constants.FRAME_MAX_WIDTH; -import static mage.client.constants.Constants.NAME_FONT_MAX_SIZE; -import static mage.client.constants.Constants.NAME_MAX_YOFFSET; -import static mage.client.constants.Constants.POWBOX_TEXT_MAX_LEFT; -import static mage.client.constants.Constants.POWBOX_TEXT_MAX_TOP; -import static mage.client.constants.Constants.SYMBOL_MAX_XOFFSET; -import static mage.client.constants.Constants.SYMBOL_MAX_YOFFSET; -import static mage.client.constants.Constants.TYPE_MAX_YOFFSET; import mage.client.game.PlayAreaPanel; import mage.client.util.Config; import mage.client.util.DefaultActionCallback; @@ -86,11 +48,18 @@ import mage.client.util.gui.ArrowBuilder; import mage.constants.CardType; import mage.constants.EnlargeMode; import mage.remote.Session; -import mage.view.AbilityView; -import mage.view.CardView; -import mage.view.CounterView; -import mage.view.PermanentView; -import mage.view.StackAbilityView; +import mage.view.*; + +import javax.swing.*; +import javax.swing.text.*; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static mage.client.constants.Constants.*; /** * @@ -557,4 +526,8 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis @Override public void setSelected(boolean selected) { } + + @Override + public void setCardAreaRef(JPanel cardArea) { + } } diff --git a/Mage.Client/src/main/java/mage/client/cards/Cards.java b/Mage.Client/src/main/java/mage/client/cards/Cards.java index 69491e22978..8387066fe39 100644 --- a/Mage.Client/src/main/java/mage/client/cards/Cards.java +++ b/Mage.Client/src/main/java/mage/client/cards/Cards.java @@ -39,14 +39,14 @@ import mage.client.plugins.impl.Plugins; import mage.client.util.CardsViewUtil; import mage.client.util.Config; import mage.view.*; +import org.apache.log4j.Logger; +import org.mage.card.arcane.CardPanel; import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; import java.awt.*; import java.util.*; import java.util.Map.Entry; -import mage.cards.action.ActionCallback; -import mage.client.plugins.adapters.MageActionCallback; -import org.apache.log4j.Logger; /** * @@ -61,6 +61,8 @@ public class Cards extends javax.swing.JPanel { private static final int GAP_X = 5; private String zone; + private static final Border emptyBorder = new EmptyBorder(0,0,0,0); + /** * Defines whether component should be visible whenever there is no objects within. * True by default. @@ -82,18 +84,15 @@ public class Cards extends javax.swing.JPanel { if (!skipAddingScrollPane) { jScrollPane1.setOpaque(false); jScrollPane1.getViewport().setOpaque(false); + jScrollPane1.setBorder(emptyBorder); } if (Plugins.getInstance().isCardPluginLoaded()) { cardArea.setLayout(null); } + cardArea.setBorder(emptyBorder); } - public void cleanUp() { -// ActionCallback actionCallback = Plugins.getInstance().getActionCallback(); -// if (actionCallback instanceof MageActionCallback) { -// ((MageActionCallback) actionCallback).setCardPreviewComponent(null); -// } - } + public void cleanUp() {} /** * Sets components background color @@ -182,12 +181,13 @@ public class Cards extends javax.swing.JPanel { } if (changed) { - layoutCards(getCardDimension(), cards, order); + layoutCards(); } if (!isVisibleIfEmpty) { cardArea.setVisible(cards.size() > 0); } + sizeCards(getCardDimension()); this.revalidate(); this.repaint(); @@ -196,13 +196,13 @@ public class Cards extends javax.swing.JPanel { } public void sizeCards(Dimension cardDimension) { - cardArea.setPreferredSize(new Dimension((int)(cards.size() * (cardDimension.getWidth() + GAP_X)) + 5, (int)(cardDimension.getHeight()) + 20)); + cardArea.setPreferredSize(new Dimension((int)((cards.size()) * (cardDimension.getWidth() + GAP_X)) + 20, (int)(cardDimension.getHeight()) + 20)); cardArea.revalidate(); cardArea.repaint(); } private Dimension getCardDimension() { - if (cardDimension == null) { + if (cardDimension == null) { cardDimension = new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight); } return cardDimension; @@ -215,6 +215,19 @@ public class Cards extends javax.swing.JPanel { } cards.put(card.getId(), cardImg); cardArea.add(cardImg); + definePosition(cardImg); + cardImg.setCardAreaRef(cardArea); + } + + private void definePosition(MageCard card) { + int dx = 0; + for (Component comp: cardArea.getComponents()) { + if (!comp.equals(card)) { + dx = Math.max(dx, (int)comp.getLocation().getX()); + } + } + dx += ((CardPanel)card).getCardWidth() + GAP_X; + card.setLocation(dx, (int)card.getLocation().getY()); } private void removeCard(UUID cardId) { @@ -232,35 +245,7 @@ public class Cards extends javax.swing.JPanel { } private int countCards() { - int count = 0; - for (Component comp: cardArea.getComponents()) { - count++; - } - return count; - } - - private void layoutCards(Dimension dimension, Map cards, java.util.List order) { - if (Plugins.getInstance().isCardPluginLoaded()) { - int dx = GAP_X; - if (order != null) { - for (UUID cardId : order) { - MageCard card = cards.get(cardId); - if (card != null) { - card.setLocation(dx, 0); - card.setCardBounds(dx, 0, dimension.width, dimension.height); - dx += dimension.width + GAP_X; - } else { - System.err.println("[ERROR] Cards.java: couldn't find a card from ordered list!"); - } - } - } else { - for (MageCard card: cards.values()) { - card.setLocation(dx, 0); - card.setCardBounds(dx, 0, dimension.width, dimension.height); - dx += dimension.width + GAP_X; - } - } - } + return cardArea.getComponentCount(); } /** This method is called from within the constructor to @@ -311,7 +296,29 @@ public class Cards extends javax.swing.JPanel { public void setCardDimension(Dimension dimension) { this.cardDimension = dimension; - layoutCards(cardDimension, cards, null); + layoutCards(); + } + + private void layoutCards() { + java.util.List cards = new ArrayList(); + + for (Component component : cardArea.getComponents()) { + if (component instanceof CardPanel) { + cards.add((CardPanel)component); + } + } + Collections.sort(cards, new Comparator() { + @Override + public int compare(CardPanel cp1, CardPanel cp2) { + return Integer.valueOf(cp1.getLocation().x).compareTo(Integer.valueOf(cp2.getLocation().x)); + } + }); + + int dx = 0; + for (Component component : cards) { + component.setLocation(dx, component.getLocation().y); + dx += ((CardPanel) component).getCardWidth() + GAP_X; + } } public void setZone(String zone) { diff --git a/Mage.Client/src/main/java/mage/client/game/HandPanel.java b/Mage.Client/src/main/java/mage/client/game/HandPanel.java index 5cbf9803f39..756c4fa5e78 100644 --- a/Mage.Client/src/main/java/mage/client/game/HandPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/HandPanel.java @@ -5,13 +5,13 @@ import mage.client.cards.BigCard; import mage.client.dialog.PreferencesDialog; import mage.client.util.Config; import mage.constants.Zone; +import mage.view.CardsView; import javax.swing.*; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import java.awt.*; import java.util.UUID; -import mage.view.CardsView; public class HandPanel extends JPanel { @@ -31,12 +31,13 @@ public class HandPanel extends JPanel { public void initComponents() { hand = new mage.client.cards.Cards(true); hand.setCardDimension(getHandCardDimension()); + jPanel = new JPanel(); jScrollPane1 = new JScrollPane(jPanel); jScrollPane1.getViewport().setBackground(new Color(0,0,0,0)); jPanel.setLayout(new GridBagLayout()); // centers hand - jPanel.setBackground(new Color(0,0,0,0)); + jPanel.setBackground(new Color(0, 0, 0, 0)); jPanel.add(hand); setOpaque(false); @@ -47,12 +48,13 @@ public class HandPanel extends JPanel { jScrollPane1.setBorder(emptyBorder); jScrollPane1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); jScrollPane1.getHorizontalScrollBar().setUnitIncrement(8); + jScrollPane1.setViewportBorder(emptyBorder); setLayout(new BorderLayout()); add(jScrollPane1, BorderLayout.CENTER); hand.setHScrollSpeed(8); - hand.setBackgroundColor(new Color(0, 0, 0, 100)); + hand.setBackgroundColor(new Color(0, 0, 0, 0)); hand.setVisibleIfEmpty(false); hand.setBorder(emptyBorder); hand.setZone(Zone.HAND.toString()); @@ -87,7 +89,7 @@ public class HandPanel extends JPanel { private JPanel jPanel; private JScrollPane jScrollPane1; - private Border emptyBorder = new EmptyBorder(0,0,0,0); + private static final Border emptyBorder = new EmptyBorder(0,0,0,0); private mage.client.cards.Cards hand; } diff --git a/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java b/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java index fc148a0636b..8920ba7028b 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java +++ b/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java @@ -1,19 +1,17 @@ package mage.client.plugins.adapters; import mage.cards.MageCard; -import mage.cards.MagePermanent; import mage.cards.action.ActionCallback; import mage.cards.action.TransferData; import mage.client.MageFrame; import mage.client.cards.BigCard; import mage.client.components.MageComponents; import mage.client.dialog.PreferencesDialog; -import mage.client.game.PlayAreaPanel; -import mage.client.game.PlayerPanelExt; import mage.client.plugins.impl.Plugins; import mage.client.util.DefaultActionCallback; import mage.client.util.ImageHelper; import mage.client.util.gui.ArrowBuilder; +import mage.client.util.gui.ArrowUtil; import mage.client.util.gui.GuiDisplayUtil; import mage.components.CardInfoPane; import mage.constants.EnlargeMode; @@ -21,10 +19,9 @@ import mage.remote.Session; import mage.utils.ThreadUtils; import mage.view.CardView; import mage.view.PermanentView; -import mage.view.PlayerView; -import mage.view.SimpleCardsView; import org.apache.log4j.Logger; import org.jdesktop.swingx.JXPanel; +import org.mage.card.arcane.CardPanel; import org.mage.plugins.card.images.ImageCache; import javax.swing.*; @@ -32,8 +29,8 @@ import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.image.BufferedImage; +import java.util.*; import java.util.List; -import java.util.UUID; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -43,11 +40,15 @@ import java.util.concurrent.TimeUnit; * Class that handles the callbacks from the card panels to mage to display big card * images from the cards the mouse hovers on. Also handles tooltip text window. * - * @author Nantuko + * @author Nantuko, noxx */ public class MageActionCallback implements ActionCallback { private static final Logger logger = Logger.getLogger(ActionCallback.class); + public static final int GAP_X = 5; + public static final double COMPARE_GAP_X = 30; + public static final int GO_DOWN_ON_DRAG_Y_OFFSET = 0; + public static final int MIN_X_OFFSET_REQUIRED = 25; private Popup popup; private JPopupMenu jPopupMenu; @@ -69,6 +70,12 @@ public class MageActionCallback implements ActionCallback { private static final ScheduledExecutorService timeoutExecutor = Executors.newScheduledThreadPool(1); private ScheduledFuture hideTimeout; + private CardView currentCard; + private boolean isDragging; + private Point initialCardPos; + private Point initialMousePos; + private Set cardPanels = new HashSet(); + public MageActionCallback() { enlargeMode = EnlargeMode.NORMAL; } @@ -90,21 +97,6 @@ public class MageActionCallback implements ActionCallback { public void mouseClicked(MouseEvent e, TransferData data) { } - @Override - public void mousePressed(MouseEvent e, TransferData data) { - data.component.requestFocusInWindow(); - // Closes popup & enlarged view if a card/Permanent is selected - hidePopup(); - } - - @Override - public void mouseReleased(MouseEvent e, TransferData data) { - data.component.requestFocusInWindow(); - defaultCallback.mouseClicked(e, data.gameId, session, data.card); - // Closes popup & enlarged view if a card/Permanent is selected - hidePopup(); - } - @Override public void mouseEntered(MouseEvent e, final TransferData data) { hidePopup(); @@ -116,109 +108,18 @@ public class MageActionCallback implements ActionCallback { Component parentComponent = SwingUtilities.getRoot(data.component); Point parentPoint = parentComponent.getLocationOnScreen(); - drawArrowsForTargets(data, parentPoint); - drawArrowsForSource(data, parentPoint); - drawArrowsForPairedCards(data, parentPoint); - drawArrowsForEnchantPlayers(data, parentPoint); + if (data.locationOnScreen == null) { + data.locationOnScreen = data.component.getLocationOnScreen(); + } + + ArrowUtil.drawArrowsForTargets(data, parentPoint); + ArrowUtil.drawArrowsForSource(data, parentPoint); + ArrowUtil.drawArrowsForPairedCards(data, parentPoint); + ArrowUtil.drawArrowsForEnchantPlayers(data, parentPoint); showPopup(data, parentComponent, parentPoint); } - private void drawArrowsForPairedCards(TransferData data, Point parentPoint) { - if (data.card.getPairedCard() != null) { - Point me = new Point(data.locationOnScreen); - me.translate(-parentPoint.x, -parentPoint.y); - UUID uuid = data.card.getPairedCard(); - for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) { - MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid); - if (permanent != null) { - Point target = permanent.getLocationOnScreen(); - target.translate(-parentPoint.x, -parentPoint.y); - ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() + 10, Color.green, ArrowBuilder.Type.PAIRED); - } - } - } - } - - private void drawArrowsForEnchantPlayers(TransferData data, Point parentPoint) { - if (data.gameId != null && MageFrame.getGame(data.gameId) != null) { - for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) { - PlayerPanelExt playAreaPanel = pa.getPlayerPanel(); - if (playAreaPanel != null && playAreaPanel.getPlayer() != null && playAreaPanel.getPlayer().hasAttachments()) { - Point me = new Point(data.locationOnScreen); - me.translate(-parentPoint.x, -parentPoint.y); - for (UUID attachmentId : playAreaPanel.getPlayer().getAttachments()) { - if (attachmentId.equals(data.card.getId())) { - Point player = pa.getLocationOnScreen(); - player.translate(-parentPoint.x, -parentPoint.y); - ArrowBuilder.getBuilder().addArrow(data.gameId,(int) me.getX() + 35, (int) me.getY(), (int) player.getX() + 40, (int) player.getY() - 40, Color.magenta, ArrowBuilder.Type.ENCHANT_PLAYERS); - } - } - } - } - } - } - - private void drawArrowsForSource(TransferData data, Point parentPoint) { - if (data.card.isAbility()) { - Point me = new Point(data.locationOnScreen); - me.translate(-parentPoint.x, -parentPoint.y); - UUID uuid = data.card.getParentId(); - for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) { - MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid); - if (permanent != null) { - Point source = permanent.getLocationOnScreen(); - source.translate(-parentPoint.x, -parentPoint.y); - ArrowBuilder.getBuilder().addArrow(data.gameId, (int) source.getX() + 40, (int) source.getY() + 10, (int) me.getX() + 35, (int) me.getY() + 20, Color.blue, ArrowBuilder.Type.SOURCE); - } - } - } - } - - private void drawArrowsForTargets(TransferData data, Point parentPoint) { - List targets = data.card.getTargets(); - if (targets == null) { - return; - } - - Point me = new Point(data.locationOnScreen); - me.translate(-parentPoint.x, -parentPoint.y); - for (UUID uuid : targets) { - - PlayAreaPanel p = MageFrame.getGame(data.gameId).getPlayers().get(uuid); - if (p != null) { - Point target = p.getLocationOnScreen(); - target.translate(-parentPoint.x, -parentPoint.y); - ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() - 40, Color.red, ArrowBuilder.Type.TARGET); - continue; - } - - for (PlayAreaPanel panel : MageFrame.getGame(data.gameId).getPlayers().values()) { - MagePermanent permanent = panel.getBattlefieldPanel().getPermanents().get(uuid); - if (permanent != null) { - Point target = permanent.getLocationOnScreen(); - target.translate(-parentPoint.x, -parentPoint.y); - ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() + 10, Color.red, ArrowBuilder.Type.TARGET); - continue; - } - - PlayerView view = panel.getPlayerPanel().getPlayer(); - if (view != null) { - SimpleCardsView graveyard = view.getGraveyard(); - if (graveyard.containsKey(uuid)) { - p = MageFrame.getGame(data.gameId).getPlayers().get(view.getPlayerId()); - if (p != null) { - Point target = p.getLocationOnScreen(); - target.translate(-parentPoint.x, -parentPoint.y); - int yOffset = p.isSmallMode() ? (PlayAreaPanel.PANEL_HEIGHT - PlayAreaPanel.PANEL_HEIGHT_SMALL) : 0; - ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 15, (int) target.getY() + 145 - yOffset, Color.red, ArrowBuilder.Type.TARGET); - } - } - } - } - } - } - private void showPopup(final TransferData data, final Component parentComponent, final Point parentPoint) { if (data.component != null) { String showTooltips = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_TOOLTIPS_ANY_ZONE, "true"); @@ -229,6 +130,12 @@ public class MageActionCallback implements ActionCallback { if (cardInfoPane == null) { PopupFactory factory = PopupFactory.getSharedInstance(); + if (data.locationOnScreen == null) { + if (data.component == null) { + return; + } + data.locationOnScreen = data.component.getLocationOnScreen(); + } popup = factory.getPopup(data.component, data.popupText, (int) data.locationOnScreen.getX() + data.popupOffsetX, (int) data.locationOnScreen.getY() + data.popupOffsetY + 40); popup.show(); // hack to get popup to resize to fit text @@ -256,6 +163,10 @@ public class MageActionCallback implements ActionCallback { ((CardInfoPane) popup2).setCard(data.card, popupContainer); + if (data.locationOnScreen == null) { + data.locationOnScreen = data.component.getLocationOnScreen(); + } + Point location = new Point((int) data.locationOnScreen.getX() + data.popupOffsetX - 40, (int) data.locationOnScreen.getY() + data.popupOffsetY - 40); location = GuiDisplayUtil.keepComponentInsideParent(location, parentPoint, popup2, parentComponent); location.translate(-parentPoint.x, -parentPoint.y); @@ -265,15 +176,15 @@ public class MageActionCallback implements ActionCallback { final Component c = MageFrame.getUI().getComponent(MageComponents.DESKTOP_PANE); SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if (!popupTextWindowOpen || !enlargedWindowState.equals(EnlargedWindowState.CLOSED)) { - return; - } - popupContainer.setVisible(true); - c.repaint(); - } - } + @Override + public void run() { + if (!popupTextWindowOpen || !enlargedWindowState.equals(EnlargedWindowState.CLOSED)) { + return; + } + popupContainer.setVisible(true); + c.repaint(); + } + } ); } catch (InterruptedException e) { @@ -283,8 +194,127 @@ public class MageActionCallback implements ActionCallback { }); } + @Override + public void mousePressed(MouseEvent e, TransferData data) { + data.component.requestFocusInWindow(); + currentCard = data.card; + isDragging = false; + cardPanels.clear(); + Point mouse = new Point(e.getX(), e.getY()); + SwingUtilities.convertPointToScreen(mouse, data.component); + initialMousePos = new Point((int)mouse.getX(), (int)mouse.getY()); + initialCardPos = data.component.getLocation(); + // Closes popup & enlarged view if a card/Permanent is selected + hidePopup(); + } + + @Override + public void mouseReleased(MouseEvent e, TransferData transferData) { + int maxXOffset = 0; + if (isDragging) { + CardPanel card = ((CardPanel)transferData.component); + Point mouse = new Point(e.getX(), e.getY()); + SwingUtilities.convertPointToScreen(mouse, transferData.component); + int xOffset = card.getXOffset(card.getCardWidth()); + maxXOffset = Math.abs((int) (mouse.getX() - initialMousePos.x) - xOffset); + + } + if (maxXOffset > MIN_X_OFFSET_REQUIRED) { // we need this for protection from small card movements + CardPanel card = ((CardPanel)transferData.component); + for (Component component : card.getCardArea().getComponents()) { + if (component instanceof CardPanel) { + if (cardPanels.contains(component)) { + component.setLocation(component.getLocation().x, component.getLocation().y - GO_DOWN_ON_DRAG_Y_OFFSET); + } + } + } + sort(card, card.getCardArea(), true); + cardPanels.clear(); + } else { + transferData.component.requestFocusInWindow(); + defaultCallback.mouseClicked(e, transferData.gameId, session, transferData.card); + // Closes popup & enlarged view if a card/Permanent is selected + hidePopup(); + } + } + @Override public void mouseMoved(MouseEvent e, TransferData transferData) { + handlePopup(transferData); + } + + @Override + public void mouseDragged(MouseEvent e, TransferData transferData) { + CardPanel card = ((CardPanel)transferData.component); + if (card.getZone() == null || !card.getZone().equalsIgnoreCase("hand")) { + // drag'n'drop is allowed for HAND zone only + return; + } + currentCard = null; + isDragging = true; + Point p = card.getCardLocation(); + Point mouse = new Point(e.getX(), e.getY()); + SwingUtilities.convertPointToScreen(mouse, transferData.component); + int xOffset = card.getXOffset(card.getCardWidth()); + int newX = Math.max(initialCardPos.x + (int)(mouse.getX() - initialMousePos.x) - xOffset, 0); + card.setCardBounds( + newX, + p.y, + card.getCardWidth(), + card.getCardHeight()); + card.getCardArea().setComponentZOrder(card, 0); + sort(card, card.getCardArea(), false); + } + + private void sort(CardPanel card, JPanel container, boolean sortSource) { + java.util.List cards = new ArrayList(); + for (Component component : container.getComponents()) { + if (component instanceof CardPanel) { + if (!component.equals(card)) { + if (!cardPanels.contains(component)) { + component.setLocation(component.getLocation().x, component.getLocation().y + GO_DOWN_ON_DRAG_Y_OFFSET); + } + cardPanels.add((CardPanel)component); + } + cards.add((CardPanel)component); + } + } + sortLayout(cards, card, sortSource); + } + + private void sortLayout(List cards, CardPanel source, boolean includeSource) { + source.getLocation().x -= COMPARE_GAP_X; // this creates nice effect + + Collections.sort(cards, new Comparator() { + @Override + public int compare(CardPanel cp1, CardPanel cp2) { + return Integer.valueOf(cp1.getLocation().x).compareTo(cp2.getLocation().x); + } + }); + + int dx = 0; + boolean createdGapForSource = false; + for (Component component : cards) { + if (!includeSource) { + if (!component.equals(source)) { + component.setLocation(dx, component.getLocation().y); + dx += ((CardPanel) component).getCardWidth() + GAP_X; + // once dx is bigger than source's x position + // we need to create a gap for the source card + // but only once + if (!createdGapForSource && (dx + COMPARE_GAP_X) > source.getLocation().x) { + createdGapForSource = true; + dx += ((CardPanel) component).getCardWidth() + GAP_X; + } + } + } else { + component.setLocation(dx, component.getLocation().y); + dx += ((CardPanel) component).getCardWidth() + GAP_X; + } + } + } + + private void handlePopup(TransferData transferData) { if (!Plugins.getInstance().isCardPluginLoaded()) { return; } @@ -469,6 +499,7 @@ public class MageActionCallback implements ActionCallback { final Component popupContainer = MageFrame.getUI().getComponent(mageComponentCardPreviewContainer); Component cardPreviewPane = MageFrame.getUI().getComponent(mageComponentCardPreviewPane); if (cardPreviewPane != null) { + transferData.locationOnScreen = transferData.component.getLocationOnScreen(); Point location = new Point((int) transferData.locationOnScreen.getX() + transferData.popupOffsetX - 40, (int) transferData.locationOnScreen.getY() + transferData.popupOffsetY - 40); location = GuiDisplayUtil.keepComponentInsideParent(location, parentPoint, cardPreviewPane, parentComponent); location.translate(-parentPoint.x, -parentPoint.y); diff --git a/Mage.Client/src/main/java/mage/client/util/gui/ArrowBuilder.java b/Mage.Client/src/main/java/mage/client/util/gui/ArrowBuilder.java index 3e68d2b6d27..62c256105bb 100644 --- a/Mage.Client/src/main/java/mage/client/util/gui/ArrowBuilder.java +++ b/Mage.Client/src/main/java/mage/client/util/gui/ArrowBuilder.java @@ -180,4 +180,5 @@ public class ArrowBuilder { arrowPanels.get(gameId).setVisible(true); } } + } diff --git a/Mage.Client/src/main/java/mage/client/util/gui/ArrowUtil.java b/Mage.Client/src/main/java/mage/client/util/gui/ArrowUtil.java new file mode 100644 index 00000000000..cafc0bc7c08 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/util/gui/ArrowUtil.java @@ -0,0 +1,116 @@ +package mage.client.util.gui; + +import mage.cards.MagePermanent; +import mage.cards.action.TransferData; +import mage.client.MageFrame; +import mage.client.game.PlayAreaPanel; +import mage.client.game.PlayerPanelExt; +import mage.view.PlayerView; +import mage.view.SimpleCardsView; + +import java.awt.*; +import java.util.*; + +/** + * @author noxx + */ +public class ArrowUtil { + + private ArrowUtil() {} + + public static void drawArrowsForPairedCards(TransferData data, Point parentPoint) { + if (data.card.getPairedCard() != null) { + Point me = new Point(data.locationOnScreen); + me.translate(-parentPoint.x, -parentPoint.y); + UUID uuid = data.card.getPairedCard(); + for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) { + MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid); + if (permanent != null) { + Point target = permanent.getLocationOnScreen(); + target.translate(-parentPoint.x, -parentPoint.y); + ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() + 10, Color.green, ArrowBuilder.Type.PAIRED); + } + } + } + } + + public static void drawArrowsForEnchantPlayers(TransferData data, Point parentPoint) { + if (data.gameId != null && MageFrame.getGame(data.gameId) != null) { + for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) { + PlayerPanelExt playAreaPanel = pa.getPlayerPanel(); + if (playAreaPanel != null && playAreaPanel.getPlayer() != null && playAreaPanel.getPlayer().hasAttachments()) { + Point me = new Point(data.locationOnScreen); + me.translate(-parentPoint.x, -parentPoint.y); + for (UUID attachmentId : playAreaPanel.getPlayer().getAttachments()) { + if (attachmentId.equals(data.card.getId())) { + Point player = pa.getLocationOnScreen(); + player.translate(-parentPoint.x, -parentPoint.y); + ArrowBuilder.getBuilder().addArrow(data.gameId,(int) me.getX() + 35, (int) me.getY(), (int) player.getX() + 40, (int) player.getY() - 40, Color.magenta, ArrowBuilder.Type.ENCHANT_PLAYERS); + } + } + } + } + } + } + + public static void drawArrowsForSource(TransferData data, Point parentPoint) { + if (data.card.isAbility()) { + Point me = new Point(data.locationOnScreen); + me.translate(-parentPoint.x, -parentPoint.y); + UUID uuid = data.card.getParentId(); + for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) { + MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid); + if (permanent != null) { + Point source = permanent.getLocationOnScreen(); + source.translate(-parentPoint.x, -parentPoint.y); + ArrowBuilder.getBuilder().addArrow(data.gameId, (int) source.getX() + 40, (int) source.getY() + 10, (int) me.getX() + 35, (int) me.getY() + 20, Color.blue, ArrowBuilder.Type.SOURCE); + } + } + } + } + + public static void drawArrowsForTargets(TransferData data, Point parentPoint) { + java.util.List targets = data.card.getTargets(); + if (targets == null) { + return; + } + + Point me = new Point(data.locationOnScreen); + me.translate(-parentPoint.x, -parentPoint.y); + for (UUID uuid : targets) { + + PlayAreaPanel p = MageFrame.getGame(data.gameId).getPlayers().get(uuid); + if (p != null) { + Point target = p.getLocationOnScreen(); + target.translate(-parentPoint.x, -parentPoint.y); + ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() - 40, Color.red, ArrowBuilder.Type.TARGET); + continue; + } + + for (PlayAreaPanel panel : MageFrame.getGame(data.gameId).getPlayers().values()) { + MagePermanent permanent = panel.getBattlefieldPanel().getPermanents().get(uuid); + if (permanent != null) { + Point target = permanent.getLocationOnScreen(); + target.translate(-parentPoint.x, -parentPoint.y); + ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() + 10, Color.red, ArrowBuilder.Type.TARGET); + continue; + } + + PlayerView view = panel.getPlayerPanel().getPlayer(); + if (view != null) { + SimpleCardsView graveyard = view.getGraveyard(); + if (graveyard.containsKey(uuid)) { + p = MageFrame.getGame(data.gameId).getPlayers().get(view.getPlayerId()); + if (p != null) { + Point target = p.getLocationOnScreen(); + target.translate(-parentPoint.x, -parentPoint.y); + int yOffset = p.isSmallMode() ? (PlayAreaPanel.PANEL_HEIGHT - PlayAreaPanel.PANEL_HEIGHT_SMALL) : 0; + ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 15, (int) target.getY() + 145 - yOffset, Color.red, ArrowBuilder.Type.TARGET); + } + } + } + } + } + } + +} diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java index 7d145f27d4e..64885273866 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java @@ -106,6 +106,8 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti private boolean displayTitleAnyway; + private JPanel cardArea; + public CardPanel(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback, final boolean foil, Dimension dimension) { this.gameCard = newGameCard; this.callback = callback; @@ -152,7 +154,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti } if (this.gameCard.isToken()) { - // token icon + // token icon iconPanel = new JPanel(); iconPanel.setLayout(null); iconPanel.setOpaque(false); @@ -354,6 +356,11 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti repaint(); } + @Override + public void setCardAreaRef(JPanel cardArea) { + this.cardArea = cardArea; + } + public boolean getSelected() { return this.isSelected; } @@ -516,22 +523,37 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti } @Override - public final void setCardBounds(int x, int y, int width, int height) { - cardWidth = width; - cardHeight = height; - int rotCenterX = Math.round(width / 2f); - int rotCenterY = height - rotCenterX; - int rotCenterToTopCorner = Math.round(width * CardPanel.ROT_CENTER_TO_TOP_CORNER); - int rotCenterToBottomCorner = Math.round(width * CardPanel.ROT_CENTER_TO_BOTTOM_CORNER); - int xOffset = rotCenterX - rotCenterToBottomCorner; - int yOffset = rotCenterY - rotCenterToTopCorner; + public final void setCardBounds(int x, int y, int cardWidth, int cardHeight) { + this.cardWidth = cardWidth; + this.cardHeight = cardHeight; + int rotCenterX = Math.round(cardWidth / 2f); + int rotCenterY = cardHeight - rotCenterX; + int rotCenterToTopCorner = Math.round(cardWidth * CardPanel.ROT_CENTER_TO_TOP_CORNER); + int rotCenterToBottomCorner = Math.round(cardWidth * CardPanel.ROT_CENTER_TO_BOTTOM_CORNER); + int xOffset = getXOffset(cardWidth); + int yOffset = getYOffset(cardWidth, cardHeight); cardXOffset = -xOffset; cardYOffset = -yOffset; - width = -xOffset + rotCenterX + rotCenterToTopCorner; - height = -yOffset + rotCenterY + rotCenterToBottomCorner; + int width = -xOffset + rotCenterX + rotCenterToTopCorner; + int height = -yOffset + rotCenterY + rotCenterToBottomCorner; setBounds(x + xOffset, y + yOffset, width, height); } + public int getXOffset(int cardWidth) { + int rotCenterX = Math.round(cardWidth / 2f); + int rotCenterToBottomCorner = Math.round(cardWidth * CardPanel.ROT_CENTER_TO_BOTTOM_CORNER); + int xOffset = rotCenterX - rotCenterToBottomCorner; + return xOffset; + } + + public int getYOffset(int cardWidth, int cardHeight) { + int rotCenterX = Math.round(cardWidth / 2f); + int rotCenterY = cardHeight - rotCenterX; + int rotCenterToTopCorner = Math.round(cardWidth * CardPanel.ROT_CENTER_TO_TOP_CORNER); + int yOffset = rotCenterY - rotCenterToTopCorner; + return yOffset; + } + public int getCardX() { return getX() + cardXOffset; } @@ -777,6 +799,8 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti @Override public void mouseDragged(MouseEvent e) { + data.component = this; + callback.mouseDragged(e, data); } @Override @@ -834,11 +858,6 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti data.gameId = this.gameId; data.popupOffsetX = isTapped() ? cardHeight + cardXOffset + POPUP_X_GAP : cardWidth + cardXOffset + POPUP_X_GAP; data.popupOffsetY = 40; - if (this.isShowing()) { - data.locationOnScreen = this.getLocationOnScreen(); - } else { - - } return data; } @@ -965,4 +984,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti callback.mouseWheelMoved(e, data); } + public JPanel getCardArea() { + return cardArea; + } } diff --git a/Mage.Common/src/mage/cards/MageCard.java b/Mage.Common/src/mage/cards/MageCard.java index 9712a30f53a..5d72b153813 100644 --- a/Mage.Common/src/mage/cards/MageCard.java +++ b/Mage.Common/src/mage/cards/MageCard.java @@ -1,11 +1,12 @@ package mage.cards; -import java.awt.Image; -import java.util.UUID; -import javax.swing.JPanel; import mage.cards.action.ActionCallback; import mage.view.CardView; +import javax.swing.*; +import java.awt.*; +import java.util.UUID; + public abstract class MageCard extends JPanel { private static final long serialVersionUID = 6089945326434301879L; @@ -27,4 +28,5 @@ public abstract class MageCard extends JPanel { public abstract boolean isTransformed(); public abstract void showCardTitle(); public abstract void setSelected(boolean selected); + public abstract void setCardAreaRef(JPanel cardArea); } diff --git a/Mage.Common/src/mage/cards/action/ActionCallback.java b/Mage.Common/src/mage/cards/action/ActionCallback.java index 0e412fbedaa..c355ff4faeb 100644 --- a/Mage.Common/src/mage/cards/action/ActionCallback.java +++ b/Mage.Common/src/mage/cards/action/ActionCallback.java @@ -8,6 +8,7 @@ public interface ActionCallback { void mousePressed(MouseEvent e, TransferData data); void mouseReleased(MouseEvent e, TransferData data); void mouseMoved(MouseEvent e, TransferData data); + void mouseDragged(MouseEvent e, TransferData data); void mouseEntered(MouseEvent e, TransferData data); void mouseExited(MouseEvent e, TransferData data); void mouseWheelMoved(MouseWheelEvent e, TransferData data); diff --git a/Mage.Common/src/mage/cards/action/impl/EmptyCallback.java b/Mage.Common/src/mage/cards/action/impl/EmptyCallback.java index b20d7e098d7..425225a573a 100644 --- a/Mage.Common/src/mage/cards/action/impl/EmptyCallback.java +++ b/Mage.Common/src/mage/cards/action/impl/EmptyCallback.java @@ -17,6 +17,11 @@ public class EmptyCallback implements ActionCallback { public void mouseMoved(MouseEvent e, TransferData data) { } + @Override + public void mouseDragged(MouseEvent e, TransferData data) { + + } + @Override public void mouseEntered(MouseEvent e, TransferData data) { }