diff --git a/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java b/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java index 2d3d2b1e553..15b14abf1f0 100644 --- a/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java @@ -33,6 +33,25 @@ */ package mage.client.game; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; +import javax.swing.JComponent; +import javax.swing.JLayeredPane; +import javax.swing.JScrollPane; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; import mage.cards.MagePermanent; import mage.client.cards.BigCard; import mage.client.cards.Permanent; @@ -45,16 +64,6 @@ import mage.client.util.layout.impl.OldCardLayoutStrategy; import mage.view.CounterView; import mage.view.PermanentView; -import javax.swing.*; -import javax.swing.border.Border; -import javax.swing.border.EmptyBorder; -import java.awt.*; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; -import java.util.*; -import java.util.List; -import java.util.Map.Entry; - /** * * @author BetaSteward_at_googlemail.com @@ -155,12 +164,13 @@ public class BattlefieldPanel extends javax.swing.JLayeredPane { } else { if (!changed) { changed = oldMagePermanent.getOriginalPermanent().isCreature() != permanent.isCreature(); + // Check if there was a chnage in the permanets that are the permanent attached to if (!changed) { - int s1 = permanent.getAttachments() == null ? 0 : permanent.getAttachments().size(); - int s2 = oldMagePermanent.getLinks().size(); - if (s1 != s2) { + int attachments = permanent.getAttachments() == null ? 0 : permanent.getAttachments().size(); + int attachmentsBefore = oldMagePermanent.getLinks().size(); + if (attachments != attachmentsBefore) { changed = true; - } else if (s1 > 0) { + } else if (attachments > 0) { Set attachmentIds = new HashSet<>(permanent.getAttachments()); for (MagePermanent magePermanent : oldMagePermanent.getLinks()) { if (!attachmentIds.contains(magePermanent.getOriginalPermanent().getId())) { @@ -174,14 +184,16 @@ public class BattlefieldPanel extends javax.swing.JLayeredPane { } } } + // Check if permanents it now attached to another or no permanent if (!changed) { - UUID u1 = oldMagePermanent.getOriginalPermanent().getAttachedTo(); - UUID u2 = permanent.getAttachedTo(); - if (u1 == null && u2 != null || u2 == null && u1 != null - || (u1 != null && !u1.equals(u2))) { + UUID attachedToIdBefore = oldMagePermanent.getOriginalPermanent().getAttachedTo(); + UUID attachedToId = permanent.getAttachedTo(); + if (attachedToIdBefore == null && attachedToId != null || attachedToId == null && attachedToIdBefore != null + || (attachedToIdBefore != null && !attachedToIdBefore.equals(attachedToId))) { changed = true; } } + // Check for changes in the counters of the permanent if (!changed) { List counters1 = oldMagePermanent.getOriginalPermanent().getCounters(); List counters2 = permanent.getCounters(); diff --git a/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java b/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java index 4790245038e..5574f1c8c38 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java +++ b/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java @@ -2,7 +2,6 @@ package mage.client.plugins; import java.awt.*; import java.awt.image.BufferedImage; -import java.util.Collection; import java.util.Map; import java.util.UUID; import javax.swing.*; @@ -33,7 +32,7 @@ public interface MagePlugins { boolean isCounterPluginLoaded(); - int sortPermanents(Map ui, Collection permanents, boolean topRow); + int sortPermanents(Map ui, Map permanents, boolean topRow); void downloadSymbols(); diff --git a/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java b/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java index 3696f8e9b2d..d9f1fef14ff 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java +++ b/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java @@ -3,12 +3,10 @@ package mage.client.plugins.impl; import java.awt.Dimension; import java.awt.image.BufferedImage; import java.io.File; -import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.UUID; import javax.swing.JComponent; - import mage.cards.MageCard; import mage.cards.MagePermanent; import mage.cards.action.ActionCallback; @@ -30,9 +28,8 @@ import net.xeoh.plugins.base.PluginManager; import net.xeoh.plugins.base.impl.PluginManagerFactory; import org.apache.log4j.Logger; import org.mage.plugins.card.CardPluginImpl; -import org.mage.plugins.theme.ThemePluginImpl; - import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir; +import org.mage.plugins.theme.ThemePluginImpl; public enum Plugins implements MagePlugins { instance; @@ -47,7 +44,6 @@ public enum Plugins implements MagePlugins { private static final MageActionCallback mageActionCallback = new MageActionCallback(); private final Map sortingOptions = new HashMap<>(); - @Override public void loadPlugins() { @@ -125,7 +121,7 @@ public enum Plugins implements MagePlugins { } @Override - public int sortPermanents(Map ui, Collection permanents, boolean topRow) { + public int sortPermanents(Map ui, Map permanents, boolean topRow) { if (this.cardPlugin != null) { return this.cardPlugin.sortPermanents(ui, permanents, PreferencesDialog.getCachedValue("nonLandPermanentsInOnePile", "false").equals("true"), topRow); } diff --git a/Mage.Client/src/main/java/mage/client/util/layout/impl/OldCardLayoutStrategy.java b/Mage.Client/src/main/java/mage/client/util/layout/impl/OldCardLayoutStrategy.java index 13890e801ad..af9547c15c7 100644 --- a/Mage.Client/src/main/java/mage/client/util/layout/impl/OldCardLayoutStrategy.java +++ b/Mage.Client/src/main/java/mage/client/util/layout/impl/OldCardLayoutStrategy.java @@ -1,6 +1,7 @@ package mage.client.util.layout.impl; import java.awt.Dimension; +import java.awt.Point; import java.awt.Rectangle; import java.util.Map; import java.util.UUID; @@ -30,72 +31,167 @@ public class OldCardLayoutStrategy implements CardLayoutStrategy { */ private static final int ATTACHMENT_MIN_DY_OFFSET = 12; + final class AttachmentLayoutInfos { + + private int columns; + private int attachments; + + public AttachmentLayoutInfos(int columns, int attachments) { + this.columns = columns; + this.attachments = attachments; + } + + public int getColumns() { + return columns; + } + + public int getAttachments() { + return attachments; + } + + public void increaseAttachments() { + attachments++; + } + + public void increaseColumns() { + columns++; + } + } + @Override public void doLayout(BattlefieldPanel battlefieldPanel, int width) { Map permanents = battlefieldPanel.getPermanents(); - JLayeredPane jPanel = battlefieldPanel.getMainPanel(); + JLayeredPane mainPanel = battlefieldPanel.getMainPanel(); - int height = Plugins.instance.sortPermanents(battlefieldPanel.getUiComponentsList(), permanents.values(), battlefieldPanel.isTopPanelBattlefield()); - jPanel.setPreferredSize(new Dimension(width - 30, height)); + // does the basic layout of rows and colums + int height = Plugins.instance.sortPermanents(battlefieldPanel.getUiComponentsList(), permanents, battlefieldPanel.isTopPanelBattlefield()); + + mainPanel.setPreferredSize(new Dimension(width - 30, height)); for (PermanentView permanent : battlefieldPanel.getBattlefield().values()) { - if (permanent.getAttachments() != null) { - groupAttachments(battlefieldPanel, jPanel, permanents, permanent); + if (permanent.getAttachments() != null && !permanent.isAttachedTo()) { // Layout only permanents that are not attached to other permanents itself + groupAttachments(battlefieldPanel, mainPanel, permanents, permanent); } } } - private void groupAttachments(JLayeredPane jLayeredPane, JLayeredPane jPanel, Map permanents, PermanentView permanent) { - MagePermanent perm = permanents.get(permanent.getId()); - if (perm == null) { + private void groupAttachments(BattlefieldPanel battlefieldPanel, JLayeredPane mainPanel, Map permanents, PermanentView permanentWithAttachmentsView) { + MagePermanent permWithAttachments = permanents.get(permanentWithAttachmentsView.getId()); + if (permWithAttachments == null) { return; } - int position = jLayeredPane.getPosition(perm); - perm.getLinks().clear(); - Rectangle rectangleBaseCard = perm.getBounds(); + // Calculate how many vertical columns are needed and number of attachements + AttachmentLayoutInfos attachmentLayoutInfos = calculateNeededNumberOfVerticalColumns(0, battlefieldPanel, permanents, permanentWithAttachmentsView); + int position = battlefieldPanel.getPosition(permWithAttachments); // relative position within the layer + // permWithAttachments.getLinks().clear(); + Rectangle rectangleBaseCard = permWithAttachments.getBounds(); if (!Plugins.instance.isCardPluginLoaded()) { - for (UUID attachmentId : permanent.getAttachments()) { + permWithAttachments.getLinks().clear(); + for (UUID attachmentId : permanentWithAttachmentsView.getAttachments()) { MagePermanent link = permanents.get(attachmentId); if (link != null) { - perm.getLinks().add(link); + permWithAttachments.getLinks().add(link); rectangleBaseCard.translate(20, 20); link.setBounds(rectangleBaseCard); - jLayeredPane.setPosition(link, ++position); + battlefieldPanel.setPosition(link, ++position); } } } else { - int index = permanent.getAttachments().size(); - for (UUID attachmentId : permanent.getAttachments()) { - MagePermanent link = permanents.get(attachmentId); - if (link != null) { - link.setBounds(rectangleBaseCard); - perm.getLinks().add(link); - int dyOffset = Math.max(perm.getHeight() / 10, ATTACHMENT_MIN_DY_OFFSET); - if (index == 1) { - rectangleBaseCard.translate(Math.max(perm.getWidth() / 10, ATTACHMENTS_MIN_DX_OFFSET), dyOffset); // do it once - } else { - rectangleBaseCard.translate(0, dyOffset); - } - perm.setBounds(rectangleBaseCard); - jLayeredPane.moveToFront(link); - jLayeredPane.moveToFront(perm); - jPanel.setComponentZOrder(link, index); - index--; - } - } - jPanel.setComponentZOrder(perm, index); + layoutAttachements(rectangleBaseCard.getX(), attachmentLayoutInfos.getColumns(), + attachmentLayoutInfos.getAttachments(), permanentWithAttachmentsView, permanents, battlefieldPanel, mainPanel, rectangleBaseCard); + mainPanel.setComponentZOrder(permWithAttachments, 0); } } + private void layoutAttachements(double baseX, // basic x position + int maxCul, // number of attachments levels + int ZOrder, + PermanentView permanentWithAttachmentsView, + Map permanents, + BattlefieldPanel battlefieldPanel, + JLayeredPane mainPanel, + Rectangle rectangleBaseCard) { + + MagePermanent permWithAttachments = permanents.get(permanentWithAttachmentsView.getId()); + if (permWithAttachments == null) { + return; + } + int col = getVerticalCul(permanentWithAttachmentsView, battlefieldPanel); // from right to left [2][1][0] + int currentAttachmentCol = col + 1; + permWithAttachments.getLinks().clear(); + int VerticalIndex = permanentWithAttachmentsView.getAttachments().size(); + for (UUID attachmentId : permanentWithAttachmentsView.getAttachments()) { + PermanentView attachedPermanentView = battlefieldPanel.getBattlefield().get(attachmentId); + if (attachedPermanentView != null && attachedPermanentView.getAttachments() != null && !attachedPermanentView.getAttachments().isEmpty()) { + layoutAttachements(baseX, maxCul, ZOrder, attachedPermanentView, permanents, battlefieldPanel, mainPanel, rectangleBaseCard); + } + + MagePermanent attachedPermanent = permanents.get(attachmentId); + if (attachedPermanent != null) { + // reset x position + Point point = new Point(); + point.setLocation(baseX + (maxCul - currentAttachmentCol) * Math.max(permWithAttachments.getWidth() / 10, ATTACHMENTS_MIN_DX_OFFSET), rectangleBaseCard.getY()); + rectangleBaseCard.setLocation(point); + + attachedPermanent.setBounds(rectangleBaseCard); // set position first to the same as of the permanent it is attached to + permWithAttachments.getLinks().add(attachedPermanent); + int dyOffset = Math.max(permWithAttachments.getHeight() / 10, ATTACHMENT_MIN_DY_OFFSET); // calculate y offset + if (VerticalIndex == 1) { + rectangleBaseCard.translate(Math.max(permWithAttachments.getWidth() / 10, ATTACHMENTS_MIN_DX_OFFSET), dyOffset); // do it once + } else { + rectangleBaseCard.translate(0, dyOffset); + } + permWithAttachments.setBounds(rectangleBaseCard); + battlefieldPanel.moveToFront(attachedPermanent); + battlefieldPanel.moveToFront(permWithAttachments); + mainPanel.setComponentZOrder(attachedPermanent, ZOrder--); + VerticalIndex--; + } + } + } + + private AttachmentLayoutInfos calculateNeededNumberOfVerticalColumns(int currentCol, BattlefieldPanel battlefieldPanel, Map permanents, PermanentView permanentWithAttachmentsView) { + int maxCol = ++currentCol; + int attachments = 0; + for (UUID attachmentId : permanentWithAttachmentsView.getAttachments()) { + PermanentView attachedPermanent = battlefieldPanel.getBattlefield().get(attachmentId); + if (attachedPermanent != null) { + attachments++; + if (attachedPermanent.getAttachments() != null && !attachedPermanent.getAttachments().isEmpty()) { + AttachmentLayoutInfos attachmentLayoutInfos = calculateNeededNumberOfVerticalColumns(currentCol, battlefieldPanel, permanents, attachedPermanent); + if (attachmentLayoutInfos.getColumns() > maxCol) { + maxCol = attachmentLayoutInfos.getColumns(); + attachments += attachmentLayoutInfos.getAttachments(); + } + } + } + } + return new AttachmentLayoutInfos(maxCol, attachments); + } + + // The root permanent is col 0. An attachment attached to the root is col 1. And an attachement attached to the first attachment is col 2. etc. + private int getVerticalCul(PermanentView permanentView, BattlefieldPanel battlefieldPanel) { + int cul = 0; + if (permanentView.isAttachedTo()) { + PermanentView attachedToPermanent = battlefieldPanel.getBattlefield().get(permanentView.getAttachedTo()); + if (attachedToPermanent != null) { + cul = getVerticalCul(attachedToPermanent, battlefieldPanel); + } + cul++; + } + return cul; + } + @Override public int getDefaultZOrder() { throw new UnsupportedOperationException("Not supported yet."); } @Override - public void onAdd(BattlefieldPanel jLayeredPane) { + public void onAdd(BattlefieldPanel jLayeredPane + ) { throw new UnsupportedOperationException("Not supported yet."); } } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java b/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java index 8ef8279f8ac..6f55636670f 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java @@ -1,5 +1,21 @@ package org.mage.plugins.card; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Rectangle; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JLayeredPane; import mage.cards.MagePermanent; import mage.cards.action.ActionCallback; import mage.client.dialog.PreferencesDialog; @@ -25,15 +41,6 @@ import org.mage.plugins.card.dl.sources.ScryfallSymbolsSource; import org.mage.plugins.card.images.ImageCache; import org.mage.plugins.card.info.CardInfoPaneImpl; -import javax.swing.*; -import java.awt.*; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.awt.image.BufferedImage; -import java.util.*; -import java.util.List; -import java.util.concurrent.TimeUnit; - /** * {@link CardPlugin} implementation. * @@ -128,7 +135,7 @@ public class CardPluginImpl implements CardPlugin { } @Override - public int sortPermanents(Map ui, Collection permanents, boolean nonPermanentsOwnRow, boolean topPanel) { + public int sortPermanents(Map ui, Map permanents, boolean nonPermanentsOwnRow, boolean topPanel) { //TODO: add caching //requires to find out is position have been changed that includes: //adding/removing permanents, type change @@ -149,7 +156,7 @@ public class CardPluginImpl implements CardPlugin { outerLoop: // - for (MagePermanent permanent : permanents) { + for (MagePermanent permanent : permanents.values()) { if (!permanent.isLand() || permanent.isCreature()) { continue; } @@ -196,8 +203,13 @@ public class CardPluginImpl implements CardPlugin { Stack stack = new Stack(); - if (permanent.getOriginalPermanent().getAttachments() != null) { - stack.setMaxAttachedCount(permanent.getOriginalPermanent().getAttachments().size()); + if (permanent.getOriginalPermanent().getAttachments() != null + && !permanent.getOriginalPermanent().getAttachments().isEmpty() + && !permanent.getOriginalPermanent().isAttachedTo()) { + // get the number of all attachements and sub attachments + AttachmentLayoutInfos ali = calculateNeededNumberOfVerticalColumns(0, permanents, permanent); + stack.setMaxAttachedCount(ali.getAttachments()); + stack.setAttachmentColumns(ali.getColumns()); } stack.add(permanent); @@ -411,6 +423,25 @@ public class CardPluginImpl implements CardPlugin { return height - cardSpacingY + GUTTER_Y * 2; } + private AttachmentLayoutInfos calculateNeededNumberOfVerticalColumns(int currentCol, Map permanents, MagePermanent permanentWithAttachments) { + int maxCol = ++currentCol; + int attachments = 0; + for (UUID attachmentId : permanentWithAttachments.getOriginalPermanent().getAttachments()) { + MagePermanent attachedPermanent = permanents.get(attachmentId); + if (attachedPermanent != null) { + attachments++; + if (attachedPermanent.getOriginalPermanent().getAttachments() != null && !attachedPermanent.getOriginalPermanent().getAttachments().isEmpty()) { + AttachmentLayoutInfos attachmentLayoutInfos = calculateNeededNumberOfVerticalColumns(currentCol, permanents, attachedPermanent); + if (attachmentLayoutInfos.getColumns() > maxCol) { + maxCol = attachmentLayoutInfos.getColumns(); + attachments += attachmentLayoutInfos.getAttachments(); + } + } + } + } + return new AttachmentLayoutInfos(maxCol, attachments); + } + private enum RowType { land, creature, other, attached; @@ -438,13 +469,13 @@ public class CardPluginImpl implements CardPlugin { super(16); } - public Row(Collection permanents, RowType type) { + public Row(Map permanents, RowType type) { this(); addAll(permanents, type); } - private void addAll(Collection permanents, RowType type) { - for (MagePermanent permanent : permanents) { + private void addAll(Map permanents, RowType type) { + for (MagePermanent permanent : permanents.values()) { if (!type.isType(permanent)) { continue; } @@ -455,7 +486,9 @@ public class CardPluginImpl implements CardPlugin { Stack stack = new Stack(); stack.add(permanent); if (permanent.getOriginalPermanent().getAttachments() != null) { - stack.setMaxAttachedCount(permanent.getOriginalPermanent().getAttachments().size()); + AttachmentLayoutInfos ali = calculateNeededNumberOfVerticalColumns(0, permanents, permanent); + stack.setMaxAttachedCount(ali.getAttachments()); + stack.setAttachmentColumns(ali.getColumns()); } add(stack); } @@ -499,13 +532,14 @@ public class CardPluginImpl implements CardPlugin { * Max attached object count attached to single permanent in the stack. */ private int maxAttachedCount = 0; + private int attachmentColumns = 0; public Stack() { super(8); } private int getWidth() { - return cardWidth + (size() - 1) * stackSpacingX + cardSpacingX; + return cardWidth + (size() - 1) * stackSpacingX + cardSpacingX + (12 * attachmentColumns); } private int getHeight() { @@ -519,6 +553,37 @@ public class CardPluginImpl implements CardPlugin { public void setMaxAttachedCount(int maxAttachedCount) { this.maxAttachedCount = maxAttachedCount; } + + public void setAttachmentColumns(int attachmentColumns) { + this.attachmentColumns = attachmentColumns; + } + } + + private final class AttachmentLayoutInfos { + + private int columns; + private int attachments; + + public AttachmentLayoutInfos(int columns, int attachments) { + this.columns = columns; + this.attachments = attachments; + } + + public int getColumns() { + return columns; + } + + public int getAttachments() { + return attachments; + } + + public void increaseAttachments() { + attachments++; + } + + public void increaseColumns() { + columns++; + } } /** @@ -552,8 +617,7 @@ public class CardPluginImpl implements CardPlugin { for (DownloadJob job : it) { g.getDownloader().add(job); } - */ - + */ it = new DirectLinksForDownload(); for (DownloadJob job : it) { g.getDownloader().add(job); diff --git a/Mage.Common/src/main/java/mage/interfaces/plugin/CardPlugin.java b/Mage.Common/src/main/java/mage/interfaces/plugin/CardPlugin.java index ac3c739f07b..7aab71f8b5f 100644 --- a/Mage.Common/src/main/java/mage/interfaces/plugin/CardPlugin.java +++ b/Mage.Common/src/main/java/mage/interfaces/plugin/CardPlugin.java @@ -2,7 +2,6 @@ package mage.interfaces.plugin; import java.awt.*; import java.awt.image.BufferedImage; -import java.util.Collection; import java.util.Map; import java.util.UUID; import javax.swing.*; @@ -27,7 +26,7 @@ public interface CardPlugin extends Plugin { MagePermanent getMageCard(CardView permanent, Dimension dimension, UUID gameId, ActionCallback callback, boolean canBeFoil, boolean loadImage); - int sortPermanents(Map ui, Collection cards, boolean nonPermanentsOwnRow, boolean topPanel); + int sortPermanents(Map ui, Map cards, boolean nonPermanentsOwnRow, boolean topPanel); /** * Download various symbols (mana, tap, set).