forked from External/mage
* GUI: new reworked GUI and card render engine, card icons and dozens of other fixes (see full list in related PR);
This commit is contained in:
parent
df98cc3e62
commit
a1da5ef437
304 changed files with 7266 additions and 5093 deletions
|
|
@ -1,10 +1,11 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import mage.cards.MageCard;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import javax.swing.*;
|
||||
import mage.cards.MagePermanent;
|
||||
|
||||
public abstract class Animation {
|
||||
|
||||
|
|
@ -18,7 +19,7 @@ public abstract class Animation {
|
|||
private static CardPanel enlargedAnimationPanel;
|
||||
private static final Object enlargeLock = new Object();
|
||||
|
||||
private TimerTask timerTask;
|
||||
private final TimerTask timerTask;
|
||||
private FrameTimer frameTimer;
|
||||
private long elapsed;
|
||||
|
||||
|
|
@ -115,53 +116,59 @@ public abstract class Animation {
|
|||
}
|
||||
}
|
||||
|
||||
public static void tapCardToggle(final CardPanel panel, final MagePermanent parent, final boolean tapped, final boolean flipped) {
|
||||
public static void tapCardToggle(final CardPanel source, final boolean tapped, final boolean flipped) {
|
||||
CardPanel mainPanel = source;
|
||||
MageCard parentPanel = mainPanel.getTopPanelRef();
|
||||
|
||||
new Animation(300) {
|
||||
@Override
|
||||
protected void start() {
|
||||
parent.onBeginAnimation();
|
||||
parentPanel.onBeginAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void update(float percentage) {
|
||||
if (tapped) {
|
||||
panel.setTappedAngle(CardPanel.TAPPED_ANGLE * percentage);
|
||||
mainPanel.setTappedAngle(CardPanel.TAPPED_ANGLE * percentage);
|
||||
// reverse movement if untapping
|
||||
if (!panel.isTapped()) {
|
||||
panel.setTappedAngle(CardPanel.TAPPED_ANGLE - panel.getTappedAngle());
|
||||
if (!mainPanel.isTapped()) {
|
||||
mainPanel.setTappedAngle(CardPanel.TAPPED_ANGLE - mainPanel.getTappedAngle());
|
||||
}
|
||||
}
|
||||
if (flipped) {
|
||||
panel.setFlippedAngle(CardPanel.FLIPPED_ANGLE * percentage);
|
||||
if (!panel.isFlipped()) {
|
||||
panel.setFlippedAngle(CardPanel.FLIPPED_ANGLE - panel.getFlippedAngle());
|
||||
mainPanel.setFlippedAngle(CardPanel.FLIPPED_ANGLE * percentage);
|
||||
if (!mainPanel.isFlipped()) {
|
||||
mainPanel.setFlippedAngle(CardPanel.FLIPPED_ANGLE - mainPanel.getFlippedAngle());
|
||||
}
|
||||
}
|
||||
panel.repaint();
|
||||
parentPanel.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void end() {
|
||||
if (tapped) {
|
||||
panel.setTappedAngle(panel.isTapped() ? CardPanel.TAPPED_ANGLE : 0);
|
||||
mainPanel.setTappedAngle(mainPanel.isTapped() ? CardPanel.TAPPED_ANGLE : 0);
|
||||
}
|
||||
if (flipped) {
|
||||
panel.setFlippedAngle(panel.isFlipped() ? CardPanel.FLIPPED_ANGLE : 0);
|
||||
mainPanel.setFlippedAngle(mainPanel.isFlipped() ? CardPanel.FLIPPED_ANGLE : 0);
|
||||
}
|
||||
parent.onEndAnimation();
|
||||
parent.repaint();
|
||||
parentPanel.onEndAnimation();
|
||||
parentPanel.repaint();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void transformCard(final CardPanel panel, final MagePermanent parent, final boolean transformed) {
|
||||
public static void transformCard(final CardPanel source) {
|
||||
|
||||
CardPanel mainPanel = source;
|
||||
MageCard parentPanel = mainPanel.getTopPanelRef();
|
||||
|
||||
new Animation(600) {
|
||||
private boolean state = false;
|
||||
|
||||
@Override
|
||||
protected void start() {
|
||||
parent.onBeginAnimation();
|
||||
parentPanel.onBeginAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -169,48 +176,51 @@ public abstract class Animation {
|
|||
double p = percentage * 2;
|
||||
if (percentage > 0.5) {
|
||||
if (!state) {
|
||||
parent.toggleTransformed();
|
||||
parentPanel.toggleTransformed();
|
||||
}
|
||||
state = true;
|
||||
p = (p - 0.5) * 2;
|
||||
}
|
||||
if (!state) {
|
||||
panel.transformAngle = Math.max(0.01, 1 - p);
|
||||
mainPanel.transformAngle = Math.max(0.01, 1 - p);
|
||||
} else {
|
||||
panel.transformAngle = Math.max(0.01, p - 1);
|
||||
mainPanel.transformAngle = Math.max(0.01, p - 1);
|
||||
}
|
||||
panel.repaint();
|
||||
parentPanel.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void end() {
|
||||
if (!state) {
|
||||
parent.toggleTransformed();
|
||||
parentPanel.toggleTransformed();
|
||||
}
|
||||
state = true;
|
||||
panel.transformAngle = 1;
|
||||
mainPanel.transformAngle = 1;
|
||||
|
||||
parent.onEndAnimation();
|
||||
parent.repaint();
|
||||
parentPanel.onEndAnimation();
|
||||
parentPanel.repaint();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void moveCardToPlay(final int startX, final int startY, final int startWidth, final int endX, final int endY,
|
||||
final int endWidth, final CardPanel animationPanel, final CardPanel placeholder, final JLayeredPane layeredPane,
|
||||
final int speed) {
|
||||
final int endWidth, final CardPanel cardToAnimate, final CardPanel placeholder, final JLayeredPane layeredPane,
|
||||
final int speed) {
|
||||
CardPanel cardPanel = (CardPanel) cardToAnimate.getMainPanel();
|
||||
MageCard mainPanel = cardToAnimate.getTopPanelRef();
|
||||
|
||||
UI.invokeLater(() -> {
|
||||
final int startHeight = Math.round(startWidth * CardPanel.ASPECT_RATIO);
|
||||
final int endHeight = Math.round(endWidth * CardPanel.ASPECT_RATIO);
|
||||
final float a = 2f;
|
||||
final float sqrta = (float) Math.sqrt(1 / a);
|
||||
|
||||
animationPanel.setCardBounds(startX, startY, startWidth, startHeight);
|
||||
animationPanel.setAnimationPanel(true);
|
||||
Container parent = animationPanel.getParent();
|
||||
mainPanel.setCardBounds(startX, startY, startWidth, startHeight);
|
||||
cardPanel.setAnimationPanel(true);
|
||||
Container parent = mainPanel.getParent();
|
||||
if (parent != null && !parent.equals(layeredPane)) {
|
||||
layeredPane.add(animationPanel);
|
||||
layeredPane.setLayer(animationPanel, JLayeredPane.MODAL_LAYER);
|
||||
layeredPane.add(mainPanel);
|
||||
layeredPane.setLayer(mainPanel, JLayeredPane.MODAL_LAYER);
|
||||
}
|
||||
|
||||
new Animation(700) {
|
||||
|
|
@ -241,7 +251,7 @@ public abstract class Animation {
|
|||
}
|
||||
currentX -= currentWidth / 2;
|
||||
currentY -= currentHeight / 2;
|
||||
animationPanel.setCardBounds(currentX, currentY, currentWidth, currentHeight);
|
||||
mainPanel.setCardBounds(currentX, currentY, currentWidth, currentHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -249,11 +259,11 @@ public abstract class Animation {
|
|||
EventQueue.invokeLater(() -> {
|
||||
if (placeholder != null) {
|
||||
placeholder.setDisplayEnabled(true);
|
||||
placeholder.transferResources(animationPanel);
|
||||
placeholder.transferResources(cardPanel);
|
||||
}
|
||||
animationPanel.setVisible(false);
|
||||
animationPanel.repaint();
|
||||
layeredPane.remove(animationPanel);
|
||||
mainPanel.setVisible(false);
|
||||
mainPanel.repaint();
|
||||
layeredPane.remove(mainPanel);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -261,18 +271,21 @@ public abstract class Animation {
|
|||
}
|
||||
|
||||
public static void moveCard(final int startX, final int startY, final int startWidth, final int endX, final int endY,
|
||||
final int endWidth, final CardPanel animationPanel, final CardPanel placeholder, final JLayeredPane layeredPane,
|
||||
final int speed) {
|
||||
final int endWidth, final MageCard cardToAnimate, final CardPanel placeholder, final JLayeredPane layeredPane,
|
||||
final int speed) {
|
||||
CardPanel cardPanel = (CardPanel) cardToAnimate.getMainPanel();
|
||||
MageCard mainPanel = cardToAnimate.getTopPanelRef();
|
||||
|
||||
UI.invokeLater(() -> {
|
||||
final int startHeight = Math.round(startWidth * CardPanel.ASPECT_RATIO);
|
||||
final int endHeight = Math.round(endWidth * CardPanel.ASPECT_RATIO);
|
||||
|
||||
animationPanel.setCardBounds(startX, startY, startWidth, startHeight);
|
||||
animationPanel.setAnimationPanel(true);
|
||||
Container parent = animationPanel.getParent();
|
||||
mainPanel.setCardBounds(startX, startY, startWidth, startHeight);
|
||||
cardPanel.setAnimationPanel(true);
|
||||
Container parent = mainPanel.getParent();
|
||||
if (parent != null && !parent.equals(layeredPane)) {
|
||||
layeredPane.add(animationPanel);
|
||||
layeredPane.setLayer(animationPanel, JLayeredPane.MODAL_LAYER);
|
||||
layeredPane.add(mainPanel);
|
||||
layeredPane.setLayer(mainPanel, JLayeredPane.MODAL_LAYER);
|
||||
}
|
||||
|
||||
new Animation(speed) {
|
||||
|
|
@ -282,7 +295,7 @@ public abstract class Animation {
|
|||
int currentY = startY + Math.round((endY - startY) * percentage);
|
||||
int currentWidth = startWidth + Math.round((endWidth - startWidth) * percentage);
|
||||
int currentHeight = startHeight + Math.round((endHeight - startHeight) * percentage);
|
||||
animationPanel.setCardBounds(currentX, currentY, currentWidth, currentHeight);
|
||||
mainPanel.setCardBounds(currentX, currentY, currentWidth, currentHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -290,11 +303,11 @@ public abstract class Animation {
|
|||
EventQueue.invokeLater(() -> {
|
||||
if (placeholder != null) {
|
||||
placeholder.setDisplayEnabled(true);
|
||||
placeholder.transferResources(animationPanel);
|
||||
placeholder.transferResources(cardPanel);
|
||||
}
|
||||
animationPanel.setVisible(false);
|
||||
animationPanel.repaint();
|
||||
layeredPane.remove(animationPanel);
|
||||
mainPanel.setVisible(false);
|
||||
mainPanel.repaint();
|
||||
layeredPane.remove(mainPanel);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -327,7 +340,7 @@ public abstract class Animation {
|
|||
protected void update(float percentage) {
|
||||
int currentWidth = startWidth + Math.round((endWidth - startWidth) * percentage);
|
||||
int currentHeight = startHeight + Math.round((endHeight - startHeight) * percentage);
|
||||
Point startPos = SwingUtilities.convertPoint(overPanel.getParent(), overPanel.getCardLocation(), layeredPane);
|
||||
Point startPos = SwingUtilities.convertPoint(overPanel.getParent(), overPanel.getCardLocation().getCardPoint(), layeredPane);
|
||||
int centerX = startPos.x + Math.round(endWidth / 2f);
|
||||
int centerY = startPos.y + Math.round(endHeight / 2f);
|
||||
int currentX = Math.max(0, centerX - Math.round(currentWidth / 2f));
|
||||
|
|
@ -353,7 +366,7 @@ public abstract class Animation {
|
|||
}
|
||||
}
|
||||
|
||||
public static void showCard(final MagePermanent card, int count) {
|
||||
public static void showCard(final MageCard card, int count) {
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -376,7 +389,7 @@ public abstract class Animation {
|
|||
};
|
||||
}
|
||||
|
||||
public static void hideCard(final MagePermanent card, int count) {
|
||||
public static void hideCard(final MageCard card, int count) {
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,13 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import mage.cards.MagePermanent;
|
||||
import mage.cards.TextPopup;
|
||||
import mage.cards.*;
|
||||
import mage.cards.action.ActionCallback;
|
||||
import mage.cards.action.TransferData;
|
||||
import mage.client.plugins.adapters.MageActionCallback;
|
||||
import mage.client.plugins.impl.Plugins;
|
||||
import mage.client.util.GUISizeHelper;
|
||||
import mage.client.util.audio.AudioManager;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.EnlargeMode;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.*;
|
||||
import mage.view.AbilityView;
|
||||
import mage.view.CardView;
|
||||
import mage.view.PermanentView;
|
||||
|
|
@ -24,19 +21,22 @@ import java.awt.event.*;
|
|||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Main class for drawing Mage card object.
|
||||
*
|
||||
* @author arcane, nantuko, noxx
|
||||
* WARNING, if you want to catch mouse events then use cardEventSource and related code. You can't use outer listeners.
|
||||
*
|
||||
* @author arcane, nantuko, noxx, JayDi85
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public abstract class CardPanel extends MagePermanent implements MouseListener, MouseMotionListener, MouseWheelListener, ComponentListener {
|
||||
public abstract class CardPanel extends MagePermanent implements ComponentListener, MouseListener, MouseMotionListener, MouseWheelListener {
|
||||
|
||||
private static final long serialVersionUID = -3272134219262184410L;
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(CardPanel.class);
|
||||
private static final Logger logger = Logger.getLogger(CardPanel.class);
|
||||
|
||||
public static final double TAPPED_ANGLE = Math.PI / 2;
|
||||
public static final double FLIPPED_ANGLE = Math.PI;
|
||||
|
|
@ -57,7 +57,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
private double tappedAngle = 0;
|
||||
private double flippedAngle = 0;
|
||||
|
||||
private final List<MagePermanent> links = new ArrayList<>();
|
||||
private final List<MageCard> links = new ArrayList<>();
|
||||
|
||||
public final JPanel buttonPanel;
|
||||
private JButton dayNightButton;
|
||||
|
|
@ -65,7 +65,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
|
||||
private boolean displayEnabled = true;
|
||||
private boolean isAnimationPanel;
|
||||
private int cardXOffset, cardYOffset, cardWidth, cardHeight;
|
||||
private int cardWidth, cardHeight;
|
||||
private int symbolWidth;
|
||||
|
||||
private boolean isSelected;
|
||||
|
|
@ -82,7 +82,12 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
|
||||
private boolean isPermanent;
|
||||
private boolean hasSickness;
|
||||
private String zone;
|
||||
private Zone zone;
|
||||
|
||||
// mouse clicks
|
||||
private int mouseClicksCount = 0;
|
||||
private java.util.Timer mouseResetTimer = null;
|
||||
static private final int MOUSE_DOUBLE_CLICK_RESET_MS = 200;
|
||||
|
||||
// Permanent and card renders are different (another sizes and positions of panel, tapped, etc -- that's weird)
|
||||
// Some card view components support only permanents (BattlefieldPanel), but another support only cards (CardArea)
|
||||
|
|
@ -95,7 +100,8 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
private boolean transformed;
|
||||
private boolean animationInProgress = false;
|
||||
|
||||
private JPanel cardArea;
|
||||
private Container cardContainer;
|
||||
private MageCard topPanel;
|
||||
|
||||
// default offset, e.g. for battlefield
|
||||
private int yCardCaptionOffsetPercent = 8; // card caption offset (use for moving card caption view center, below mana icons -- for more good UI)
|
||||
|
|
@ -104,6 +110,8 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
private JPopupMenu popupMenu;
|
||||
|
||||
public CardPanel(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback, final boolean foil, Dimension dimension, boolean needFullPermanentRender) {
|
||||
// warning, it can be used under MageLayer so make all rotates or other card manipulation as parent
|
||||
|
||||
// Store away params
|
||||
this.setGameCard(newGameCard);
|
||||
this.callback = callback;
|
||||
|
|
@ -154,7 +162,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
if (animationInProgress || isTapped() || isPermanent) {
|
||||
return;
|
||||
}
|
||||
Animation.transformCard(CardPanel.this, CardPanel.this, true);
|
||||
Animation.transformCard(this);
|
||||
});
|
||||
|
||||
// Add it
|
||||
|
|
@ -183,6 +191,8 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
setOpaque(false);
|
||||
|
||||
// JPanel event listeners
|
||||
|
||||
// all listeneres to process mouse and another events
|
||||
addMouseListener(this);
|
||||
addMouseMotionListener(this);
|
||||
addMouseWheelListener(this);
|
||||
|
|
@ -201,7 +211,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
@Override
|
||||
public void doLayout() {
|
||||
// Position transform and show source buttons
|
||||
buttonPanel.setLocation(cardXOffset, cardYOffset);
|
||||
buttonPanel.setLocation(0, 0);
|
||||
buttonPanel.setSize(cardWidth, cardHeight);
|
||||
int x = cardWidth / 20;
|
||||
int y = cardHeight / 10;
|
||||
|
|
@ -255,12 +265,12 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
public abstract void transferResources(CardPanel panel);
|
||||
|
||||
@Override
|
||||
public void setZone(String zone) {
|
||||
public void setZone(Zone zone) {
|
||||
this.zone = zone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getZone() {
|
||||
public Zone getZone() {
|
||||
return zone;
|
||||
}
|
||||
|
||||
|
|
@ -290,15 +300,21 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<MagePermanent> getLinks() {
|
||||
public List<MageCard> getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MageCardSpace getOuterSpace() {
|
||||
return MageCardSpace.empty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChoosable(boolean isChoosable) {
|
||||
this.isChoosable = isChoosable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChoosable() {
|
||||
return this.isChoosable;
|
||||
}
|
||||
|
|
@ -312,8 +328,18 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setCardAreaRef(JPanel cardArea) {
|
||||
this.cardArea = cardArea;
|
||||
public void setCardContainerRef(Container cardContainer) {
|
||||
this.cardContainer = cardContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTopPanelRef(MageCard topPanel) {
|
||||
this.topPanel = topPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MageCard getTopPanelRef() {
|
||||
return this.topPanel;
|
||||
}
|
||||
|
||||
public void setShowCastingCost(boolean showCastingCost) {
|
||||
|
|
@ -333,25 +359,9 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
if (!displayEnabled) {
|
||||
return;
|
||||
}
|
||||
if (!isValid()) {
|
||||
super.validate();
|
||||
}
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
if (transformAngle < 1) {
|
||||
float edgeOffset = (cardWidth + cardXOffset) / 2f;
|
||||
g2d.translate(edgeOffset * (1 - transformAngle), 0);
|
||||
g2d.scale(transformAngle, 1);
|
||||
}
|
||||
if (getTappedAngle() + getFlippedAngle() > 0) {
|
||||
g2d = (Graphics2D) g2d.create();
|
||||
float edgeOffset = cardWidth / 2f;
|
||||
double angle = getTappedAngle() + (Math.abs(getFlippedAngle() - FLIPPED_ANGLE) < 0.001 ? 0 : getFlippedAngle());
|
||||
g2d.rotate(angle, cardXOffset + edgeOffset, cardYOffset + cardHeight - edgeOffset);
|
||||
}
|
||||
super.paint(g2d);
|
||||
// card rotating implemented by top layer panel
|
||||
// TODO: is CardPanel can be used without MageLayer?
|
||||
super.paint(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -373,70 +383,34 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
@Override
|
||||
public void setCardBounds(int x, int y, int cardWidth, int cardHeight) {
|
||||
if (cardWidth == this.cardWidth && cardHeight == this.cardHeight) {
|
||||
setBounds(x - cardXOffset, y - cardYOffset, getWidth(), getHeight());
|
||||
return;
|
||||
}
|
||||
|
||||
this.cardWidth = cardWidth;
|
||||
this.symbolWidth = cardWidth / 7;
|
||||
this.cardHeight = cardHeight;
|
||||
if (this.isPermanent && needFullPermanentRender) {
|
||||
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;
|
||||
int width = -xOffset + rotCenterX + rotCenterToTopCorner;
|
||||
int height = -yOffset + rotCenterY + rotCenterToBottomCorner;
|
||||
setBounds(x + xOffset, y + yOffset, width, height);
|
||||
// coords changed
|
||||
//noinspection deprecation
|
||||
setBounds(x, y, getWidth(), getHeight());
|
||||
} else {
|
||||
cardXOffset = 0;
|
||||
cardYOffset = 0;
|
||||
int width = cardXOffset * 2 + cardWidth;
|
||||
int height = cardYOffset * 2 + cardHeight;
|
||||
setBounds(x - cardXOffset, y - cardYOffset, width, height);
|
||||
// coords + sizes changed
|
||||
this.cardWidth = cardWidth;
|
||||
this.symbolWidth = cardWidth / 7;
|
||||
this.cardHeight = cardHeight;
|
||||
// no needs in size settings here - all outer/draw spaces calcs by top parent panel
|
||||
//noinspection deprecation
|
||||
setBounds(x, y, cardWidth, cardHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public int getXOffset(int cardWidth) {
|
||||
if (this.isPermanent && needFullPermanentRender) {
|
||||
int rotCenterX = Math.round(cardWidth / 2f);
|
||||
int rotCenterToBottomCorner = Math.round(cardWidth * CardPanel.ROT_CENTER_TO_BOTTOM_CORNER);
|
||||
int xOffset = rotCenterX - rotCenterToBottomCorner;
|
||||
return xOffset;
|
||||
} else {
|
||||
return cardXOffset;
|
||||
}
|
||||
}
|
||||
|
||||
public final int getYOffset(int cardWidth, int cardHeight) {
|
||||
if (this.isPermanent && needFullPermanentRender) {
|
||||
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;
|
||||
} else {
|
||||
return cardYOffset;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final int getCardX() {
|
||||
return getX() + cardXOffset;
|
||||
return getX() + this.getOuterSpace().getLeft();
|
||||
}
|
||||
|
||||
public final int getCardY() {
|
||||
return getY() + cardYOffset;
|
||||
return getY() + this.getOuterSpace().getTop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getCardWidth() {
|
||||
return cardWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getCardHeight() {
|
||||
return cardHeight;
|
||||
}
|
||||
|
|
@ -445,13 +419,6 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
return symbolWidth;
|
||||
}
|
||||
|
||||
public final Point getCardLocation() {
|
||||
Point p = getLocation();
|
||||
p.x += cardXOffset;
|
||||
p.y += cardYOffset;
|
||||
return p;
|
||||
}
|
||||
|
||||
public final CardView getCard() {
|
||||
return this.getGameCard();
|
||||
}
|
||||
|
|
@ -466,12 +433,38 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
return alpha;
|
||||
}
|
||||
|
||||
public final int getCardXOffset() {
|
||||
return cardXOffset;
|
||||
}
|
||||
@Override
|
||||
public MageCardAnimationSettings getAnimationSettings(int offsetX, int offsetY, float cardBoundWidth, float cardBoundHeight) {
|
||||
// card panel can be rotated after tap so send drawning settings to rotate parent panel too
|
||||
MageCardAnimationSettings settings = new MageCardAnimationSettings();
|
||||
|
||||
public final int getCardYOffset() {
|
||||
return cardYOffset;
|
||||
// display
|
||||
settings.withVisible(this.displayEnabled);
|
||||
|
||||
// TODO: remove cardXOffset and cardYOffset
|
||||
|
||||
// animate tap
|
||||
if (getTappedAngle() + getFlippedAngle() > 0) {
|
||||
// Rectangle rotation to keep bottom left corner
|
||||
// Algorithm logic:
|
||||
// 1. Take the start and the final figure positions (example: vertical and horizontal)
|
||||
// 2. Find share figure between start/end positions;
|
||||
// 3. Find center of the share figure;
|
||||
// 4. Rotate from that center.
|
||||
// Rotate center schema: https://user-images.githubusercontent.com/8344157/104398558-6981b500-5568-11eb-9e97-5c16926d481b.png
|
||||
double angle = getTappedAngle() + (Math.abs(getFlippedAngle() - FLIPPED_ANGLE) < 0.001 ? 0 : getFlippedAngle());
|
||||
float edgeOffset = cardBoundWidth / 2f;
|
||||
settings.withRotate(angle, offsetX + edgeOffset, offsetY + cardBoundHeight - edgeOffset);
|
||||
}
|
||||
|
||||
// animate transform (shrink/flip animation)
|
||||
if (transformAngle < 1) {
|
||||
float edgeOffset = cardBoundWidth / 2f;
|
||||
settings.withTranslate((offsetX + edgeOffset) * (1 - transformAngle), 0);
|
||||
settings.withScale(transformAngle, 1);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -542,14 +535,14 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
boolean needsTapping = isTapped() != ((PermanentView) card).isTapped();
|
||||
boolean needsFlipping = isFlipped() != ((PermanentView) card).isFlipped();
|
||||
if (needsTapping || needsFlipping) {
|
||||
Animation.tapCardToggle(this, this, needsTapping, needsFlipping);
|
||||
Animation.tapCardToggle(this, needsTapping, needsFlipping);
|
||||
}
|
||||
if (needsTapping && ((PermanentView) card).isTapped()) {
|
||||
AudioManager.playTapPermanent();
|
||||
}
|
||||
boolean needsTranforming = isTransformed() != card.isTransformed();
|
||||
if (needsTranforming) {
|
||||
Animation.transformCard(this, this, card.isTransformed());
|
||||
Animation.transformCard(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -589,27 +582,6 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int x, int y) {
|
||||
return containsThis(x, y, true);
|
||||
}
|
||||
|
||||
public boolean containsThis(int x, int y, boolean root) {
|
||||
Point component = getLocation();
|
||||
|
||||
int cx = getCardX() - component.x;
|
||||
int cy = getCardY() - component.y;
|
||||
int cw = cardWidth;
|
||||
int ch = cardHeight;
|
||||
if (isTapped()) {
|
||||
cy = ch - cw + cx;
|
||||
ch = cw;
|
||||
cw = cardHeight;
|
||||
}
|
||||
|
||||
return x >= cx && x <= cx + cw && y >= cy && y <= cy + ch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CardView getOriginal() {
|
||||
return this.getGameCard();
|
||||
|
|
@ -617,6 +589,43 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
data.setComponent(this);
|
||||
data.setCard(this.getGameCard());
|
||||
data.setGameId(this.gameId);
|
||||
|
||||
// popup menu processing
|
||||
if (e.isPopupTrigger() || SwingUtilities.isRightMouseButton(e)) {
|
||||
callback.popupMenuCard(e, data);
|
||||
return;
|
||||
}
|
||||
|
||||
// double clicks processing, see https://stackoverflow.com/questions/4051659/identifying-double-click-in-java
|
||||
// logic: run timer to reset clicks counter
|
||||
mouseClicksCount = e.getClickCount();
|
||||
if (mouseClicksCount > 1) {
|
||||
// forced to double click
|
||||
if (mouseResetTimer != null) {
|
||||
mouseResetTimer.cancel();
|
||||
}
|
||||
callback.mouseClicked(e, data, true);
|
||||
} else {
|
||||
// can be single or double click, start the reset timer
|
||||
if (mouseResetTimer != null) {
|
||||
mouseResetTimer.cancel();
|
||||
}
|
||||
mouseResetTimer = new java.util.Timer("mouseResetTimer", false);
|
||||
mouseResetTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mouseClicksCount == 1) {
|
||||
callback.mouseClicked(e, data, false);
|
||||
} else if (mouseClicksCount > 1) {
|
||||
callback.mouseClicked(e, data, true);
|
||||
}
|
||||
mouseClicksCount = 0;
|
||||
}
|
||||
}, MOUSE_DOUBLE_CLICK_RESET_MS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -626,7 +635,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
}
|
||||
if (!tooltipShowing) {
|
||||
synchronized (this) {
|
||||
if (!tooltipShowing) {
|
||||
if (!tooltipShowing) { // TODO: remove tooltip showing to callback processing code, not here
|
||||
TransferData transferData = getTransferDataForMouseEntered();
|
||||
if (this.isShowing()) {
|
||||
tooltipShowing = true;
|
||||
|
|
@ -637,31 +646,15 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
data.setComponent(this);
|
||||
callback.mouseDragged(e, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
if (getGameCard().hideInfo()) {
|
||||
return;
|
||||
}
|
||||
data.setComponent(this);
|
||||
callback.mouseMoved(e, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
if (getGameCard().hideInfo()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tooltipShowing) {
|
||||
synchronized (this) {
|
||||
if (tooltipShowing) {
|
||||
tooltipShowing = false;
|
||||
tooltipShowing = false; // TODO: same, move code for callback processing
|
||||
data.setComponent(this);
|
||||
data.setCard(this.getGameCard());
|
||||
data.setPopupText(tooltipText);
|
||||
|
|
@ -681,21 +674,55 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
data.setComponent(this);
|
||||
data.setCard(this.getGameCard());
|
||||
data.setGameId(this.gameId);
|
||||
callback.mouseReleased(e, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
data.setComponent(this);
|
||||
data.setCard(this.getGameCard());
|
||||
data.setGameId(this.gameId);
|
||||
callback.mouseDragged(e, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
if (getGameCard().hideInfo()) {
|
||||
return;
|
||||
}
|
||||
data.setComponent(this);
|
||||
data.setCard(this.getGameCard());
|
||||
data.setGameId(this.gameId);
|
||||
callback.mouseMoved(e, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||
if (getGameCard().hideInfo()) {
|
||||
return;
|
||||
}
|
||||
data.setComponent(this);
|
||||
data.setCard(this.getGameCard());
|
||||
data.setGameId(this.gameId);
|
||||
callback.mouseWheelMoved(e, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares data to be sent to action callback on client side.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private TransferData getTransferDataForMouseEntered() {
|
||||
MageCard cardPanel = this.getTopPanelRef();
|
||||
data.setComponent(this);
|
||||
data.setCard(this.getGameCard());
|
||||
data.setPopupText(tooltipText);
|
||||
data.setGameId(this.gameId);
|
||||
data.setLocationOnScreen(data.getComponent().getLocationOnScreen()); // we need this for popup
|
||||
data.setPopupOffsetX(isTapped() ? cardHeight + cardXOffset + POPUP_X_GAP : cardWidth + cardXOffset + POPUP_X_GAP);
|
||||
data.setLocationOnScreen(cardPanel.getCardLocationOnScreen().getCardPoint()); // we need this for popup
|
||||
data.setPopupOffsetX(isTapped() ? cardHeight + POPUP_X_GAP : cardWidth + POPUP_X_GAP);
|
||||
data.setPopupOffsetY(40);
|
||||
return data;
|
||||
}
|
||||
|
|
@ -760,7 +787,9 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
public void update(PermanentView card) {
|
||||
this.hasSickness = card.hasSummoningSickness();
|
||||
this.showCopySourceButton.setVisible(card.isCopy());
|
||||
update((CardView) card);
|
||||
|
||||
// must update from top layer (e.g. card icons)
|
||||
this.getTopPanelRef().update(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -771,12 +800,6 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
throw new IllegalStateException("Is not permanent.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCallback(ActionCallback callback, UUID gameId) {
|
||||
this.callback = callback;
|
||||
this.gameId = gameId;
|
||||
}
|
||||
|
||||
public void setTransformed(boolean transformed) {
|
||||
this.transformed = transformed;
|
||||
}
|
||||
|
|
@ -798,7 +821,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
dayNightButton.setIcon(new ImageIcon(night));
|
||||
}
|
||||
if (this.getGameCard().getSecondCardFace() == null) {
|
||||
LOGGER.error("no second side for card to transform!");
|
||||
logger.error("no second side for card to transform!");
|
||||
return;
|
||||
}
|
||||
if (!isPermanent) { // use only for custom transformation (when pressing day-night button)
|
||||
|
|
@ -829,16 +852,8 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
}
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||
if (getGameCard().hideInfo()) {
|
||||
return;
|
||||
}
|
||||
data.setComponent(this);
|
||||
callback.mouseWheelMoved(e, data);
|
||||
}
|
||||
|
||||
public JPanel getCardArea() {
|
||||
return cardArea;
|
||||
public Container getCardContainer() {
|
||||
return cardContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -922,4 +937,32 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
public void setFlippedAngle(double flippedAngle) {
|
||||
this.flippedAngle = flippedAngle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int x, int y) {
|
||||
// if you need a mouse related features in the tapped state then implement contains here (see MageLayer for info)
|
||||
// example: you want a working button
|
||||
//return super.contains(x, y);
|
||||
|
||||
// Swing uses relative coords here (0,0 is component's top left corner)
|
||||
MageCardLocation needLocation = this.getCardLocation();
|
||||
Rectangle normalRect = new Rectangle(
|
||||
0,
|
||||
0,
|
||||
needLocation.getCardWidth(),
|
||||
needLocation.getCardHeight()
|
||||
);
|
||||
Rectangle animatedRect = MageLayer.animateCoords(this, normalRect);
|
||||
return animatedRect.contains(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Font getFont() {
|
||||
Font res = super.getFont();
|
||||
if (res == null) {
|
||||
// workaround: sometimes the card panels haven't default font
|
||||
res = GUISizeHelper.getCardFont();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.mage.card.arcane;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.cards.MageCardLocation;
|
||||
import mage.cards.action.ActionCallback;
|
||||
import mage.client.constants.Constants;
|
||||
import mage.client.dialog.PreferencesDialog;
|
||||
|
|
@ -11,11 +12,11 @@ import mage.components.ImagePanel;
|
|||
import mage.components.ImagePanelStyle;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.SubType;
|
||||
import mage.util.DebugUtil;
|
||||
import mage.view.CardView;
|
||||
import mage.view.CounterView;
|
||||
import mage.view.PermanentView;
|
||||
import mage.view.StackAbilityView;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jdesktop.swingx.graphics.GraphicsUtilities;
|
||||
import org.mage.plugins.card.images.ImageCache;
|
||||
import org.mage.plugins.card.utils.impl.ImageManagerImpl;
|
||||
|
|
@ -27,18 +28,14 @@ import java.util.StringTokenizer;
|
|||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Class for drawing the mage card object by using a form based JComponent
|
||||
* approach
|
||||
* Render mode: IMAGE
|
||||
*
|
||||
* @author arcane, nantuko, noxx, stravant, JayDi85
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class CardPanelComponentImpl extends CardPanel {
|
||||
public class CardPanelRenderModeImage extends CardPanel {
|
||||
|
||||
private static final long serialVersionUID = -3272134219262184411L;
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(CardPanelComponentImpl.class);
|
||||
|
||||
private static final int WIDTH_LIMIT = 90; // card width limit to create smaller counter
|
||||
|
||||
private static final float ROUNDED_CORNER_SIZE = 0.1f;
|
||||
|
|
@ -47,10 +44,6 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
private static final int TEXT_GLOW_SIZE = 6;
|
||||
private static final float TEXT_GLOW_INTENSITY = 3f;
|
||||
|
||||
// size to show icons and text (help to see full size card without text)
|
||||
private static final int CARD_MIN_SIZE_FOR_ICONS = 60;
|
||||
private static final int CARD_MAX_SIZE_FOR_ICONS = 200;
|
||||
|
||||
// text min size for image render mode
|
||||
private static final int CARD_TITLE_FONT_MIN_SIZE = 13;
|
||||
private static final int CARD_PT_FONT_MIN_SIZE = 17;
|
||||
|
|
@ -58,9 +51,10 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
public final ScaledImagePanel imagePanel;
|
||||
private ImagePanel overlayPanel;
|
||||
|
||||
private JPanel iconPanel;
|
||||
private JButton typeButton;
|
||||
private JPanel ptPanel;
|
||||
// triggered/activated/permanent icon
|
||||
private JPanel typeIconPanel;
|
||||
private JButton typeIconButton;
|
||||
private final JPanel ptPanel;
|
||||
|
||||
private JPanel counterPanel;
|
||||
private JLabel loyaltyCounterLabel;
|
||||
|
|
@ -83,7 +77,7 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
private boolean hasImage = false;
|
||||
|
||||
private boolean displayTitleAnyway;
|
||||
private boolean displayFullImagePath;
|
||||
private final boolean displayFullImagePath;
|
||||
|
||||
private final static SoftValuesLoadingCache<Key, BufferedImage> IMAGE_CACHE;
|
||||
|
||||
|
|
@ -95,12 +89,12 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
this.overlayPanel = overlayPanel;
|
||||
}
|
||||
|
||||
public JPanel getIconPanel() {
|
||||
return iconPanel;
|
||||
public JPanel getTypeIconPanel() {
|
||||
return typeIconPanel;
|
||||
}
|
||||
|
||||
public void setIconPanel(JPanel iconPanel) {
|
||||
this.iconPanel = iconPanel;
|
||||
public void setTypeIconPanel(JPanel typeIconPanel) {
|
||||
this.typeIconPanel = typeIconPanel;
|
||||
}
|
||||
|
||||
public JPanel getCounterPanel() {
|
||||
|
|
@ -113,6 +107,7 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
|
||||
static class Key {
|
||||
|
||||
final Insets border;
|
||||
final int width;
|
||||
final int height;
|
||||
final int cardWidth;
|
||||
|
|
@ -126,7 +121,8 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
final boolean canAttack;
|
||||
final boolean canBlock;
|
||||
|
||||
public Key(int width, int height, int cardWidth, int cardHeight, int cardXOffset, int cardYOffset, boolean hasImage, boolean isSelected, boolean isChoosable, boolean isPlayable, boolean canAttack, boolean canBlock) {
|
||||
public Key(Insets border, int width, int height, int cardWidth, int cardHeight, int cardXOffset, int cardYOffset, boolean hasImage, boolean isSelected, boolean isChoosable, boolean isPlayable, boolean canAttack, boolean canBlock) {
|
||||
this.border = border;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.cardWidth = cardWidth;
|
||||
|
|
@ -144,6 +140,10 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 3;
|
||||
hash = 19 * hash + this.border.left;
|
||||
hash = 19 * hash + this.border.right;
|
||||
hash = 19 * hash + this.border.top;
|
||||
hash = 19 * hash + this.border.bottom;
|
||||
hash = 19 * hash + this.width;
|
||||
hash = 19 * hash + this.height;
|
||||
hash = 19 * hash + this.cardWidth;
|
||||
|
|
@ -171,6 +171,18 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
return false;
|
||||
}
|
||||
final Key other = (Key) obj;
|
||||
if (this.border.left != other.border.left) {
|
||||
return false;
|
||||
}
|
||||
if (this.border.right != other.border.right) {
|
||||
return false;
|
||||
}
|
||||
if (this.border.top != other.border.top) {
|
||||
return false;
|
||||
}
|
||||
if (this.border.bottom != other.border.bottom) {
|
||||
return false;
|
||||
}
|
||||
if (this.width != other.width) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -209,7 +221,7 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
}
|
||||
|
||||
static {
|
||||
IMAGE_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(CardPanelComponentImpl::createImage));
|
||||
IMAGE_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(CardPanelRenderModeImage::createImage));
|
||||
}
|
||||
|
||||
static private boolean canShowCardIcons(int cardFullWidth, boolean cardHasImage) {
|
||||
|
|
@ -220,27 +232,29 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
}
|
||||
|
||||
private static class CardSizes {
|
||||
|
||||
// from bigger to smaller
|
||||
Rectangle rectFull;
|
||||
Rectangle rectSelection;
|
||||
Rectangle rectBorder;
|
||||
Rectangle rectCard;
|
||||
|
||||
CardSizes(int offsetX, int offsetY, int fullWidth, int fullHeight) {
|
||||
CardSizes(Insets border, int offsetX, int offsetY, int fullWidth, int fullHeight) {
|
||||
|
||||
int realBorderSizeX = Math.round(fullWidth * BLACK_BORDER_SIZE);
|
||||
int realBorderSizeY = Math.round(fullWidth * BLACK_BORDER_SIZE);
|
||||
int realSelectionSizeX = Math.round(fullWidth * SELECTION_BORDER_SIZE);
|
||||
int realSelectionSizeY = Math.round(fullWidth * SELECTION_BORDER_SIZE);
|
||||
int realBorderSizeX = Math.max(1, Math.round(fullWidth * BLACK_BORDER_SIZE));
|
||||
int realBorderSizeY = Math.max(1, Math.round(fullHeight * BLACK_BORDER_SIZE));
|
||||
int realSelectionSizeX = Math.max(1, Math.round(fullWidth * SELECTION_BORDER_SIZE));
|
||||
int realSelectionSizeY = Math.max(1, Math.round(fullHeight * SELECTION_BORDER_SIZE));
|
||||
|
||||
// card full size = select border + black border + real card
|
||||
rectFull = new Rectangle(offsetX, offsetY, fullWidth, fullHeight);
|
||||
rectFull = new Rectangle(offsetX + border.left, offsetY + border.top, fullWidth - border.left - border.right, fullHeight - border.top - border.bottom);
|
||||
rectSelection = new Rectangle(rectFull.x, rectFull.y, rectFull.width, rectFull.height);
|
||||
rectBorder = new Rectangle(rectSelection.x + realSelectionSizeX, rectSelection.y + realSelectionSizeY, rectSelection.width - 2 * realSelectionSizeX, rectSelection.height - 2 * realSelectionSizeY);
|
||||
rectCard = new Rectangle(rectBorder.x + realBorderSizeX, rectBorder.y + realBorderSizeY, rectBorder.width - 2 * realBorderSizeX, rectBorder.height - 2 * realBorderSizeY);
|
||||
}
|
||||
}
|
||||
|
||||
public CardPanelComponentImpl(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback, final boolean foil, Dimension dimension, boolean needFullPermanentRender) {
|
||||
public CardPanelRenderModeImage(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback, final boolean foil, Dimension dimension, boolean needFullPermanentRender) {
|
||||
// Call to super
|
||||
super(newGameCard, gameId, loadImage, callback, foil, dimension, needFullPermanentRender);
|
||||
|
||||
|
|
@ -290,8 +304,6 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
// Title Text
|
||||
titleText = new GlowText();
|
||||
setTitle(getGameCard());
|
||||
// int fontSize = (int) cardHeight / 11;
|
||||
// titleText.setFont(getFont().deriveFont(Font.BOLD, fontSize));
|
||||
titleText.setForeground(Color.white);
|
||||
titleText.setGlow(Color.black, TEXT_GLOW_SIZE, TEXT_GLOW_INTENSITY);
|
||||
titleText.setWrap(true);
|
||||
|
|
@ -326,7 +338,9 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
|
||||
// Imagel panel
|
||||
imagePanel = new ScaledImagePanel();
|
||||
imagePanel.setBorder(BorderFactory.createLineBorder(Color.white));
|
||||
if (DebugUtil.GUI_RENDER_IMAGE_DRAW_IMAGE_BORDER) {
|
||||
imagePanel.setBorder(BorderFactory.createLineBorder(Color.white));
|
||||
}
|
||||
add(imagePanel);
|
||||
|
||||
// Do we need to load?
|
||||
|
|
@ -338,21 +352,21 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
}
|
||||
|
||||
private void setTypeIcon(BufferedImage bufferedImage, String toolTipText) {
|
||||
setIconPanel(new JPanel());
|
||||
getIconPanel().setLayout(null);
|
||||
getIconPanel().setOpaque(false);
|
||||
add(getIconPanel());
|
||||
setTypeIconPanel(new JPanel());
|
||||
getTypeIconPanel().setLayout(null);
|
||||
getTypeIconPanel().setOpaque(false);
|
||||
add(getTypeIconPanel());
|
||||
|
||||
typeButton = new JButton("");
|
||||
typeButton.setLocation(2, 2);
|
||||
typeButton.setSize(25, 25);
|
||||
typeIconButton = new JButton("");
|
||||
typeIconButton.setLocation(2, 2);
|
||||
typeIconButton.setSize(25, 25);
|
||||
|
||||
getIconPanel().setVisible(true);
|
||||
typeButton.setIcon(new ImageIcon(bufferedImage));
|
||||
getTypeIconPanel().setVisible(true);
|
||||
typeIconButton.setIcon(new ImageIcon(bufferedImage));
|
||||
if (toolTipText != null) {
|
||||
typeButton.setToolTipText(toolTipText);
|
||||
typeIconButton.setToolTipText(toolTipText);
|
||||
}
|
||||
getIconPanel().add(typeButton);
|
||||
getTypeIconPanel().add(typeIconButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -388,8 +402,8 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
|
||||
@Override
|
||||
public void transferResources(final CardPanel panelAbstract) {
|
||||
if (panelAbstract instanceof CardPanelComponentImpl) {
|
||||
CardPanelComponentImpl panel = (CardPanelComponentImpl) panelAbstract;
|
||||
if (panelAbstract instanceof CardPanelRenderModeImage) {
|
||||
CardPanelRenderModeImage panel = (CardPanelRenderModeImage) panelAbstract;
|
||||
synchronized (panel.imagePanel) {
|
||||
if (panel.imagePanel.hasImage()) {
|
||||
setImage(panel.imagePanel.getSrcImage());
|
||||
|
|
@ -416,27 +430,35 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
g2d.setComposite(composite);
|
||||
}
|
||||
|
||||
// draw background (selected/chooseable/playable)
|
||||
MageCardLocation cardLocation = getCardLocation();
|
||||
g2d.drawImage(
|
||||
IMAGE_CACHE.getOrThrow(
|
||||
new Key(getWidth(), getHeight(), getCardWidth(), getCardHeight(), getCardXOffset(), getCardYOffset(),
|
||||
new Key(getInsets(),
|
||||
cardLocation.getCardWidth(), cardLocation.getCardHeight(),
|
||||
cardLocation.getCardWidth(), cardLocation.getCardHeight(),
|
||||
0,
|
||||
0,
|
||||
hasImage, isSelected(), isChoosable(), getGameCard().isPlayable(), getGameCard().isCanAttack(),
|
||||
getGameCard().isCanBlock())),
|
||||
0, 0, null);
|
||||
0, 0, cardLocation.getCardWidth(), cardLocation.getCardHeight(), null);
|
||||
g2d.dispose();
|
||||
}
|
||||
|
||||
private static BufferedImage createImage(Key key) {
|
||||
int cardWidth = key.cardWidth;
|
||||
int cardHeight = key.cardHeight;
|
||||
// draw background image with selection
|
||||
Insets componentBorder = key.border;
|
||||
int renderWidth = key.cardWidth;
|
||||
int renderHeight = key.cardHeight;
|
||||
int cardXOffset = key.cardXOffset;
|
||||
int cardYOffset = key.cardYOffset;
|
||||
|
||||
BufferedImage image = GraphicsUtilities.createCompatibleTranslucentImage(key.width, key.height);
|
||||
BufferedImage image = GraphicsUtilities.createCompatibleTranslucentImage(renderWidth, renderHeight);
|
||||
Graphics2D g2d = image.createGraphics();
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
// card full size = select border + black border + real card
|
||||
CardSizes sizes = new CardSizes(cardXOffset, cardYOffset, cardWidth, cardHeight);
|
||||
CardSizes sizes = new CardSizes(componentBorder, cardXOffset, cardYOffset, renderWidth, renderHeight);
|
||||
|
||||
// corners for selection and for border
|
||||
int cornerSizeSelection = Math.max(4, Math.round(sizes.rectSelection.width * ROUNDED_CORNER_SIZE));
|
||||
|
|
@ -446,6 +468,7 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
|
||||
// draw selection
|
||||
if (key.isSelected) {
|
||||
// TODO: add themes color support
|
||||
g2d.setColor(Color.green);
|
||||
g2d.fillRoundRect(sizes.rectSelection.x + 1, sizes.rectSelection.y + 1, sizes.rectSelection.width - 2, sizes.rectSelection.height - 2, cornerSizeSelection, cornerSizeSelection);
|
||||
} else if (key.isChoosable) {
|
||||
|
|
@ -456,7 +479,7 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
g2d.fillRoundRect(sizes.rectSelection.x, sizes.rectSelection.y, sizes.rectSelection.width, sizes.rectSelection.height, cornerSizeSelection, cornerSizeSelection);
|
||||
}
|
||||
|
||||
// draw attack or block border (?inner part of selection?)
|
||||
// draw attack or block border (?inner part of a selection?)
|
||||
if (key.canAttack || key.canBlock) {
|
||||
g2d.setColor(new Color(255, 50, 50, 230));
|
||||
g2d.fillRoundRect(sizes.rectSelection.x + 1, sizes.rectSelection.y + 1, sizes.rectSelection.width - 2, sizes.rectSelection.height - 2, cornerSizeSelection, cornerSizeSelection);
|
||||
|
|
@ -473,13 +496,6 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
}
|
||||
|
||||
// draw real card by component (see imagePanel and other layout's items)
|
||||
|
||||
//TODO:uncomment
|
||||
/*
|
||||
if (gameCard.isAttacking()) {
|
||||
g2d.setColor(new Color(200,10,10,200));
|
||||
g2d.fillRoundRect(cardXOffset+1, cardYOffset+1, cardWidth-2, cardHeight-2, cornerSize, cornerSize);
|
||||
}*/
|
||||
g2d.dispose();
|
||||
|
||||
return image;
|
||||
|
|
@ -489,10 +505,8 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
protected void paintChildren(Graphics g) {
|
||||
super.paintChildren(g);
|
||||
|
||||
CardSizes realCard = new CardSizes(getCardXOffset(), getCardYOffset(), getCardWidth(), getCardHeight());
|
||||
|
||||
/*
|
||||
// draw recs for debug
|
||||
// debug draw recs
|
||||
|
||||
// full card
|
||||
g.setColor(new Color(255, 0, 0));
|
||||
|
|
@ -522,8 +536,10 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
int manaMarginRight = Math.round(22f / 672f * getCardWidth());
|
||||
int manaMarginTop = Math.round(24f / 936f * getCardHeight());
|
||||
|
||||
int manaX = getCardXOffset() + getCardWidth() - manaMarginRight - manaWidth;
|
||||
int manaY = getCardYOffset() + manaMarginTop;
|
||||
int cardOffsetX = 0;
|
||||
int cardOffsetY = 0;
|
||||
int manaX = cardOffsetX + getCardWidth() - manaMarginRight - manaWidth;
|
||||
int manaY = cardOffsetY + manaMarginTop;
|
||||
|
||||
ManaSymbols.draw(g, manaCost, manaX, manaY, getSymbolWidth(), ModernCardRenderer.MANA_ICONS_TEXT_COLOR, symbolMarginX);
|
||||
}
|
||||
|
|
@ -547,12 +563,12 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
public void doLayout() {
|
||||
super.doLayout();
|
||||
|
||||
int cardWidth = getCardWidth();
|
||||
int cardHeight = getCardHeight();
|
||||
int cardXOffset = getCardXOffset();
|
||||
int cardYOffset = getCardYOffset();
|
||||
int cardWidth = getCardLocation().getCardWidth(); // must use current panel sizes to scale real image
|
||||
int cardHeight = getCardLocation().getCardHeight();
|
||||
int cardXOffset = 0;
|
||||
int cardYOffset = 0;
|
||||
|
||||
CardSizes sizes = new CardSizes(cardXOffset, cardYOffset, cardWidth, cardHeight);
|
||||
CardSizes sizes = new CardSizes(getInsets(), cardXOffset, cardYOffset, cardWidth, cardHeight);
|
||||
|
||||
// origin card without selection
|
||||
Rectangle realCardSize = sizes.rectBorder;
|
||||
|
|
@ -566,10 +582,11 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
getOverlayPanel().setVisible(false);
|
||||
}
|
||||
|
||||
if (getIconPanel() != null) {
|
||||
getIconPanel().setLocation(realCardSize.x, realCardSize.y);
|
||||
getIconPanel().setSize(realCardSize.width, realCardSize.height);
|
||||
if (getTypeIconPanel() != null) {
|
||||
getTypeIconPanel().setLocation(realCardSize.x, realCardSize.y);
|
||||
getTypeIconPanel().setSize(realCardSize.width, realCardSize.height);
|
||||
}
|
||||
|
||||
if (getCounterPanel() != null) {
|
||||
getCounterPanel().setLocation(realCardSize.x, realCardSize.y);
|
||||
getCounterPanel().setSize(realCardSize.width, realCardSize.height);
|
||||
|
|
@ -591,10 +608,6 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
|
||||
// TITLE
|
||||
|
||||
//old version - text hide on small fonts, why?
|
||||
//int fontHeight = Math.round(cardHeight * (26f / 672));
|
||||
//boolean showText = (!isAnimationPanel() && fontHeight < 12);
|
||||
|
||||
boolean showText = !isAnimationPanel() && canShowCardIcons(cardWidth, hasImage);
|
||||
titleText.setVisible(showText);
|
||||
ptText1.setVisible(showText && !ptText1.getText().isEmpty());
|
||||
|
|
@ -609,7 +622,7 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
// margins from card black border to text, not need? text show up good without margins
|
||||
int titleMarginLeft = 0; //Math.round(28f / 672f * cardWidth);
|
||||
int titleMarginRight = 0;
|
||||
int titleMarginTop = 0 + Math.round(getCardCaptionTopOffset() / 100f * cardHeight);//Math.round(28f / 936f * cardHeight);
|
||||
int titleMarginTop = Math.round(getCardCaptionTopOffset() / 100f * cardHeight);//Math.round(28f / 936f * cardHeight);
|
||||
int titleMarginBottom = 0;
|
||||
titleText.setBounds(
|
||||
imagePanel.getX() + titleMarginLeft,
|
||||
|
|
@ -778,11 +791,7 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
setTitle(getGameCard());
|
||||
|
||||
// Summoning Sickness overlay
|
||||
if (hasSickness() && getGameCard().isCreature() && isPermanent()) {
|
||||
getOverlayPanel().setVisible(true);
|
||||
} else {
|
||||
getOverlayPanel().setVisible(false);
|
||||
}
|
||||
getOverlayPanel().setVisible(hasSickness() && getGameCard().isCreature() && isPermanent());
|
||||
|
||||
// Update counters panel
|
||||
if (getCounterPanel() != null) {
|
||||
|
|
@ -852,7 +861,6 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
otherCounterLabel.setVisible(false);
|
||||
getCounterPanel().setVisible(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static ImageIcon getCounterImageWithAmount(int amount, BufferedImage image, int cardWidth) {
|
||||
|
|
@ -11,7 +11,6 @@ import mage.view.CardView;
|
|||
import mage.view.CounterView;
|
||||
import mage.view.PermanentView;
|
||||
import mage.view.StackAbilityView;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jdesktop.swingx.graphics.GraphicsUtilities;
|
||||
import org.mage.plugins.card.images.ImageCache;
|
||||
|
||||
|
|
@ -21,9 +20,10 @@ import java.util.UUID;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class CardPanelRenderImpl extends CardPanel {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(CardPanelRenderImpl.class);
|
||||
/**
|
||||
* Render mode: MTGO
|
||||
*/
|
||||
public class CardPanelRenderModeMTGO extends CardPanel {
|
||||
|
||||
private static boolean cardViewEquals(CardView a, CardView b) {
|
||||
if (a == b) {
|
||||
|
|
@ -200,7 +200,7 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
final ImageKey other = (ImageKey) object;
|
||||
|
||||
// Compare
|
||||
if ((artImage != null) != (other.artImage != null)) {
|
||||
if ((artImage == null) == (other.artImage != null)) {
|
||||
return false;
|
||||
}
|
||||
if (width != other.width) {
|
||||
|
|
@ -241,8 +241,8 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
private BufferedImage cardImage;
|
||||
private CardRenderer cardRenderer;
|
||||
|
||||
public CardPanelRenderImpl(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback,
|
||||
final boolean foil, Dimension dimension, boolean needFullPermanentRender) {
|
||||
public CardPanelRenderModeMTGO(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback,
|
||||
final boolean foil, Dimension dimension, boolean needFullPermanentRender) {
|
||||
// Call to super
|
||||
super(newGameCard, gameId, loadImage, callback, foil, dimension, needFullPermanentRender);
|
||||
|
||||
|
|
@ -255,8 +255,8 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
|
||||
@Override
|
||||
public void transferResources(CardPanel panel) {
|
||||
if (panel instanceof CardPanelRenderImpl) {
|
||||
CardPanelRenderImpl impl = (CardPanelRenderImpl) panel;
|
||||
if (panel instanceof CardPanelRenderModeMTGO) {
|
||||
CardPanelRenderModeMTGO impl = (CardPanelRenderModeMTGO) panel;
|
||||
|
||||
// Use the art image and current rendered image from the card
|
||||
artImage = impl.artImage;
|
||||
|
|
@ -285,16 +285,15 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
}
|
||||
|
||||
// And draw the image we now have
|
||||
g.drawImage(cardImage, getCardXOffset(), getCardYOffset(), null);
|
||||
int cardOffsetX = 0;
|
||||
int cardOffsetY = 0;
|
||||
g.drawImage(cardImage, cardOffsetX, cardOffsetY, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an appropriate card renderer for the
|
||||
*/
|
||||
/**
|
||||
* Render the card to a new BufferedImage at it's current dimensions
|
||||
*
|
||||
* @return
|
||||
* @return image
|
||||
*/
|
||||
private BufferedImage renderCard() {
|
||||
int cardWidth = getCardWidth();
|
||||
|
|
@ -411,6 +410,7 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
}
|
||||
|
||||
private BufferedImage getFaceDownImage() {
|
||||
// TODO: add download default images
|
||||
if (isPermanent()) {
|
||||
if (((PermanentView) getGameCard()).isMorphed()) {
|
||||
return ImageCache.getMorphImage();
|
||||
|
|
@ -4,7 +4,7 @@ import mage.cards.ArtRect;
|
|||
import mage.view.CardView;
|
||||
|
||||
/**
|
||||
* Created by StravantUser on 2017-03-30.
|
||||
* @author StravantUser
|
||||
*/
|
||||
public class CardRendererFactory {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,16 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.util.DebugUtil;
|
||||
import mage.view.CardView;
|
||||
import mage.view.PermanentView;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.font.LineMetrics;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
|
@ -253,4 +259,90 @@ public final class CardRendererUtils {
|
|||
return defaultColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce rect by percent (add empty space from all sides and keep rect position)
|
||||
* Example usage: reduce rect to fit auto-size text
|
||||
*
|
||||
* @param rect
|
||||
* @param reduceFactor
|
||||
* @return
|
||||
*/
|
||||
public static Rectangle reduceRect(Rectangle rect, float reduceFactor) {
|
||||
float newWidth = rect.width * reduceFactor;
|
||||
float newHeight = rect.height * reduceFactor;
|
||||
int offsetX = Math.round((rect.width - newWidth) / 2f);
|
||||
int offsetY = Math.round((rect.height - newHeight) / 2f);
|
||||
return new Rectangle(rect.x + offsetX, rect.y + offsetY, Math.round(newWidth), Math.round(newHeight));
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a String centered in the middle of a rectangle.
|
||||
*
|
||||
* @param g2d The graphics instance
|
||||
* @param text The string to draw
|
||||
* @param rect The rectangle to center the text in
|
||||
* @param font
|
||||
* @param isAutoScaleFont if the text is too big then it will scale a font to fit it in the rect
|
||||
*/
|
||||
public static void drawCenteredText(Graphics2D g2d, String text, Rectangle rect, Font font, boolean isAutoScaleFont) {
|
||||
if (DebugUtil.GUI_RENDER_CENTERED_TEXT_DRAW_DEBUG_LINES) {
|
||||
g2d.drawLine(rect.x, rect.y + rect.height / 2, rect.x + rect.width, rect.y + rect.height / 2);
|
||||
g2d.drawLine(rect.x + rect.width / 2, rect.y, rect.x + rect.width / 2, rect.y + rect.height);
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/23730104/1276632
|
||||
Font affectedFont = font;
|
||||
if (isAutoScaleFont) {
|
||||
affectedFont = scaleFont(g2d, text, rect, font);
|
||||
}
|
||||
|
||||
g2d.setFont(affectedFont);
|
||||
FontRenderContext frc = g2d.getFontRenderContext();
|
||||
GlyphVector gv = affectedFont.createGlyphVector(frc, text);
|
||||
Rectangle2D box = gv.getVisualBounds();
|
||||
float offsetX = (float) (((rect.getWidth() - box.getWidth()) / 2d) + (-box.getX()));
|
||||
float offsetY = (float) (((rect.getHeight() - box.getHeight()) / 2d) + (-box.getY()));
|
||||
|
||||
g2d.drawString(text, rect.x + offsetX, rect.y + offsetY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto scale font to fit current text inside the rect (e.g. decrease font size for too big text)
|
||||
*
|
||||
* @param g2d graphics context
|
||||
* @param text text to draw
|
||||
* @param font base font
|
||||
* @param rect the bounds for fitting the string
|
||||
* @return a scaled font
|
||||
*/
|
||||
private static Font scaleFont(Graphics2D g2d, String text, Rectangle rect, Font font) {
|
||||
// https://stackoverflow.com/a/876266/1276632
|
||||
FontRenderContext frc = g2d.getFontRenderContext();
|
||||
|
||||
double needWidth = rect.getWidth();
|
||||
double needHeight = rect.getHeight();
|
||||
|
||||
float fontMinSize = 1f;
|
||||
float fontMaxSize = 1000f;
|
||||
Font scaledFont = font;
|
||||
float scaledFontSize = scaledFont.getSize();
|
||||
|
||||
while (fontMaxSize - fontMinSize > 1f) {
|
||||
scaledFont = scaledFont.deriveFont(scaledFontSize);
|
||||
|
||||
TextLayout layout = new TextLayout(text, scaledFont, frc);
|
||||
float currentWidth = layout.getVisibleAdvance();
|
||||
LineMetrics metrics = scaledFont.getLineMetrics(text, frc);
|
||||
float currentHeight = metrics.getHeight();
|
||||
|
||||
if ((currentWidth > needWidth) || (currentHeight > needHeight)) {
|
||||
fontMaxSize = scaledFontSize;
|
||||
} else {
|
||||
fontMinSize = scaledFontSize;
|
||||
}
|
||||
scaledFontSize = (fontMinSize + fontMaxSize) / 2f;
|
||||
}
|
||||
|
||||
return scaledFont.deriveFont((float) Math.floor(scaledFontSize));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
624
Mage.Client/src/main/java/org/mage/card/arcane/MageLayer.java
Normal file
624
Mage.Client/src/main/java/org/mage/card/arcane/MageLayer.java
Normal file
|
|
@ -0,0 +1,624 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import mage.abilities.icon.CardIcon;
|
||||
import mage.abilities.icon.CardIconCategory;
|
||||
import mage.abilities.icon.CardIconRenderSettings;
|
||||
import mage.abilities.icon.system.PlayableCountIcon;
|
||||
import mage.cards.MageCard;
|
||||
import mage.cards.MageCardAnimationSettings;
|
||||
import mage.cards.MageCardLocation;
|
||||
import mage.cards.MageCardSpace;
|
||||
import mage.client.cards.CardIconsPanel;
|
||||
import mage.client.cards.CardIconsPanelFactory;
|
||||
import mage.constants.Zone;
|
||||
import mage.util.DebugUtil;
|
||||
import mage.view.CardView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.awt.event.MouseWheelListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Additional layer for mage cards (example: layer with card icons).
|
||||
* One MageCard can have multiple layers in the future.
|
||||
* <p>
|
||||
* WARNING, all added listeners goes to card's main panel (mouse, events, etc)
|
||||
*
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class MageLayer extends MageCard {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MageLayer.class);
|
||||
|
||||
JLayeredPane mainContainer;
|
||||
JPanel mainLayerCard;
|
||||
JPanel mainLayerIcons;
|
||||
JPanel mainLayerDebug = null;
|
||||
|
||||
MageCard mainPanel;
|
||||
|
||||
// empty spaces to control real card size in the center
|
||||
JPanel spaceLeft;
|
||||
JPanel spaceRight;
|
||||
JPanel spaceTop;
|
||||
JPanel spaceBottom;
|
||||
|
||||
// drawing spaces, you must ignore it in animations and other calcs
|
||||
MageCardSpace lastOuterSpace = MageCardSpace.empty;
|
||||
|
||||
// card icons
|
||||
CardIconRenderSettings iconsRender;
|
||||
List<CardIconsPanel> iconsPanels = new ArrayList<>(); // for calcs only
|
||||
CardIconsPanel iconsDebugPanel;
|
||||
CardIconsPanel iconsAbilitiesPanel;
|
||||
CardIconsPanel iconsPlayablePanel;
|
||||
|
||||
public MageLayer(MageCard mainPanel, CardIconRenderSettings iconsRender) {
|
||||
this.mainPanel = mainPanel;
|
||||
this.mainPanel.setTopPanelRef(this);
|
||||
|
||||
// component structure (border layout):
|
||||
// - main container: JLayeredPane (center)
|
||||
// * layer with card: custom size, border layout
|
||||
// - main panel + spaces
|
||||
// * layer with icons: custom size
|
||||
// * layer with debug drawing
|
||||
|
||||
// component
|
||||
this.setLayout(new BorderLayout());
|
||||
this.setOpaque(false);
|
||||
|
||||
// main container
|
||||
this.mainContainer = new JLayeredPane();
|
||||
this.mainContainer.setOpaque(false);
|
||||
this.add(this.mainContainer, BorderLayout.CENTER);
|
||||
|
||||
// card layer
|
||||
this.mainLayerCard = new JPanel(new BorderLayout());
|
||||
this.mainLayerCard.setOpaque(false);
|
||||
this.mainContainer.add(this.mainLayerCard, (Integer) 0);
|
||||
// main panel + spaces
|
||||
this.mainLayerCard.add(this.mainPanel, BorderLayout.CENTER);
|
||||
this.initEmptySpaces();
|
||||
|
||||
// icons layer
|
||||
this.mainLayerIcons = new JPanel(null);
|
||||
this.mainLayerIcons.setOpaque(false);
|
||||
this.mainContainer.add(this.mainLayerIcons, (Integer) 10);
|
||||
|
||||
// debug layer
|
||||
if (DebugUtil.GUI_CARD_DRAW_MOUSE_CONTAINS_BOUNDS) {
|
||||
this.mainLayerDebug = new JPanel(null);
|
||||
this.mainLayerDebug.setOpaque(false);
|
||||
this.mainLayerDebug.setBorder(BorderFactory.createLineBorder(Color.MAGENTA));
|
||||
this.mainContainer.add(this.mainLayerDebug, (Integer) 20);
|
||||
}
|
||||
|
||||
// init icons panels, real icons and sizes will added by setCardBounds and setSizes
|
||||
this.iconsRender = iconsRender;
|
||||
this.initCardIconsPanels();
|
||||
|
||||
// Warning, you must ignore outer/draw spaces, use getCardLocation to find a real component and card size/position
|
||||
// If you inherits a MageLayer then you must implements contains(int x, int y) for correct mouse events
|
||||
|
||||
if (DebugUtil.GUI_CARD_DRAW_OUTER_BORDER) {
|
||||
this.setBorder(BorderFactory.createLineBorder(Color.red));
|
||||
}
|
||||
if (DebugUtil.GUI_CARD_DRAW_INNER_BORDER) {
|
||||
this.mainPanel.setBorder(BorderFactory.createLineBorder(Color.green));
|
||||
}
|
||||
}
|
||||
|
||||
private void initEmptySpaces() {
|
||||
this.spaceLeft = new JPanel(null);
|
||||
this.spaceLeft.setOpaque(false);
|
||||
this.mainLayerCard.add(this.spaceLeft, BorderLayout.WEST);
|
||||
//
|
||||
this.spaceRight = new JPanel(null);
|
||||
this.spaceRight.setOpaque(false);
|
||||
this.mainLayerCard.add(this.spaceRight, BorderLayout.EAST);
|
||||
//
|
||||
this.spaceTop = new JPanel(null);
|
||||
this.spaceTop.setOpaque(false);
|
||||
this.mainLayerCard.add(this.spaceTop, BorderLayout.NORTH);
|
||||
//
|
||||
this.spaceBottom = new JPanel(null);
|
||||
this.spaceBottom.setOpaque(false);
|
||||
this.mainLayerCard.add(this.spaceBottom, BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
private void initCardIconsPanels() {
|
||||
this.iconsDebugPanel = null;
|
||||
this.iconsAbilitiesPanel = null;
|
||||
this.iconsPlayablePanel = null;
|
||||
|
||||
if (this.iconsRender.isDebugMode()) {
|
||||
// DEBUG MODE -- only one debug panel
|
||||
this.iconsDebugPanel = CardIconsPanelFactory.createDebugPanel(this.iconsRender);
|
||||
this.iconsPanels.add(this.iconsDebugPanel);
|
||||
} else {
|
||||
// NORMAL mode -- multiple panels
|
||||
this.iconsAbilitiesPanel = CardIconsPanelFactory.createAbilitiesPanel();
|
||||
this.iconsPanels.add(this.iconsAbilitiesPanel);
|
||||
this.iconsPlayablePanel = CardIconsPanelFactory.createPlayablePanel();
|
||||
this.iconsPanels.add(this.iconsPlayablePanel);
|
||||
}
|
||||
|
||||
this.iconsPanels.forEach(panel -> this.mainLayerIcons.add(panel));
|
||||
}
|
||||
|
||||
private void setEmptySpaces(int left, int right, int top, int bottom) {
|
||||
this.setEmptySpaces(new MageCardSpace(left, right, top, bottom));
|
||||
}
|
||||
|
||||
private void setEmptySpaces(MageCardSpace space) {
|
||||
Border border = space.getDebugColor() == null ? null : BorderFactory.createLineBorder(space.getDebugColor());
|
||||
|
||||
this.spaceLeft.setPreferredSize(new Dimension(space.getLeft(), 0));
|
||||
this.spaceLeft.setBorder(border);
|
||||
//
|
||||
this.spaceRight.setPreferredSize(new Dimension(space.getRight(), 0));
|
||||
this.spaceRight.setBorder(border);
|
||||
//
|
||||
this.spaceTop.setPreferredSize(new Dimension(0, space.getTop()));
|
||||
this.spaceTop.setBorder(border);
|
||||
//
|
||||
this.spaceBottom.setPreferredSize(new Dimension(0, space.getBottom()));
|
||||
this.spaceBottom.setBorder(border);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MageCard getMainPanel() {
|
||||
return mainPanel.getMainPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBeginAnimation() {
|
||||
mainPanel.onBeginAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEndAnimation() {
|
||||
mainPanel.onEndAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTapped() {
|
||||
return mainPanel.isTapped();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlipped() {
|
||||
return mainPanel.isFlipped();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(float transparency) {
|
||||
mainPanel.setAlpha(transparency);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAlpha() {
|
||||
return mainPanel.getAlpha();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CardView getOriginal() {
|
||||
return mainPanel.getOriginal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCardCaptionTopOffset(int yOffsetPercent) {
|
||||
mainPanel.setCardCaptionTopOffset(yOffsetPercent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale inner card to draw additional icons or something (example: card icons in outer space)
|
||||
*
|
||||
* @param renderWidth
|
||||
* @param renderHeight
|
||||
* @return
|
||||
*/
|
||||
private MageCardSpace getAdditionalSpaces(int renderWidth, int renderHeight) {
|
||||
return new MageCardSpace(0, 0, Math.round(renderHeight * 0f), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCardBounds(int x, int y, int width, int height) {
|
||||
// base idea: child layers should not know about parent layer
|
||||
//
|
||||
// render logic:
|
||||
// * scale the current layer to fit additional elemenst like icons
|
||||
// * draw child layer with new sizes
|
||||
//
|
||||
// animation logic (maybe it can be change in the future):
|
||||
// * animation implemented as g2d graphic context scale in Paint() method
|
||||
// * all layers and elements must be moved as one object
|
||||
// * only the main panel (child) can do a calcs for the animation (so send parent sizes to recalc it)
|
||||
|
||||
// if (this.getTopPanelRef() == this && this.getOriginal().getName().equals("Kathari Remnant")) { // for debug only
|
||||
if (this.getTopPanelRef() == this) { // TODO: is it support multi layer drawing?
|
||||
|
||||
// scale inner card and create space for additional drawing like icons
|
||||
MageCardSpace innerSpace = getAdditionalSpaces(width, height);
|
||||
|
||||
// extra space for animation and other drawing
|
||||
// WTF, I'm tired with render calcs, so make BIG draw spaces for any needs
|
||||
MageCardSpace outerSpace = new MageCardSpace(width * 2, width * 2, height * 2, height * 2);
|
||||
//MageCardSpace outerSpace = new MageCardSpace(50, 30, 150, 20);
|
||||
this.lastOuterSpace = outerSpace;
|
||||
|
||||
// construct new spaces (outer + inner)
|
||||
MageCardSpace fullSpace = MageCardSpace.combine(innerSpace, outerSpace).withDebugColor(innerSpace.getDebugColor());
|
||||
this.setEmptySpaces(fullSpace);
|
||||
//noinspection deprecation - it's ok to use inner setBounds here
|
||||
this.setBounds(x - outerSpace.getLeft(), y - outerSpace.getTop(), width + outerSpace.getWidth(), height + outerSpace.getHeight());
|
||||
mainPanel.setCardBounds(x + innerSpace.getLeft(), y + innerSpace.getTop(), width - innerSpace.getWidth(), height - innerSpace.getHeight());
|
||||
} else {
|
||||
this.setEmptySpaces(0, 0, 0, 0);
|
||||
//noinspection deprecation - it's ok to use inner setBounds here
|
||||
this.setBounds(x, y, width, height);
|
||||
mainPanel.setCardBounds(x, y, width, height);
|
||||
}
|
||||
|
||||
MageCardLocation location = this.getCardLocation();
|
||||
|
||||
// panel sizes
|
||||
this.mainLayerCard.setBounds(0, 0, location.getComponentWidth(), location.getComponentHeight());
|
||||
this.mainLayerIcons.setBounds(0, 0, location.getComponentWidth(), location.getComponentHeight());
|
||||
|
||||
// icons sizes
|
||||
Rectangle cardSize = new Rectangle(location.getCardRelativeX(), location.getCardRelativeY(), location.getCardWidth(), location.getCardHeight());
|
||||
iconsPanels.forEach(panel -> {
|
||||
panel.updateSizes(cardSize);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(CardView card) {
|
||||
// icons update
|
||||
updateCardIcons(card);
|
||||
|
||||
// card update
|
||||
mainPanel.update(card);
|
||||
}
|
||||
|
||||
private void updateCardIcons(CardView card) {
|
||||
Map<CardIconsPanel, List<CardIcon>> newIcons = new HashMap<>();
|
||||
this.iconsPanels.forEach(panel -> newIcons.put(panel, new ArrayList<>()));
|
||||
|
||||
List<CardIcon> allIcons = new ArrayList<>();
|
||||
// main icons
|
||||
allIcons.addAll(card.getCardIcons());
|
||||
// playable icons
|
||||
if (card.getPlayableStats().getPlayableImportantAmount() > 0) {
|
||||
allIcons.add(new PlayableCountIcon(card.getPlayableStats()));
|
||||
}
|
||||
|
||||
// create panels
|
||||
allIcons.forEach(cardIcon -> {
|
||||
CardIconCategory category = cardIcon.getIconType().getCategory();
|
||||
// debug must take all icons
|
||||
if (iconsDebugPanel != null) {
|
||||
newIcons.get(iconsDebugPanel).add(cardIcon);
|
||||
}
|
||||
if (iconsPlayablePanel != null && category == CardIconCategory.PLAYABLE_COUNT) {
|
||||
newIcons.get(iconsPlayablePanel).add(cardIcon);
|
||||
}
|
||||
if (iconsAbilitiesPanel != null && category == CardIconCategory.ABILITY) {
|
||||
newIcons.get(iconsAbilitiesPanel).add(cardIcon);
|
||||
}
|
||||
});
|
||||
this.iconsPanels.forEach(panel -> panel.updateIcons(newIcons.get(panel)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateArtImage() {
|
||||
mainPanel.updateArtImage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getImage() {
|
||||
return mainPanel.getImage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setZone(Zone zone) {
|
||||
mainPanel.setZone(zone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Zone getZone() {
|
||||
return mainPanel.getZone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toggleTransformed() {
|
||||
mainPanel.toggleTransformed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransformed() {
|
||||
return mainPanel.isTransformed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showCardTitle() {
|
||||
mainPanel.showCardTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(boolean selected) {
|
||||
mainPanel.setSelected(selected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCardContainerRef(Container cardContainer) {
|
||||
mainPanel.setCardContainerRef(cardContainer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTopPanelRef(MageCard mageCard) {
|
||||
mainPanel.setTopPanelRef(mageCard);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MageCard getTopPanelRef() {
|
||||
return mainPanel.getTopPanelRef();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Container getCardContainer() {
|
||||
return mainPanel.getCardContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChoosable(boolean isChoosable) {
|
||||
mainPanel.setChoosable(isChoosable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChoosable() {
|
||||
return mainPanel.isChoosable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPopupMenu(JPopupMenu popupMenu) {
|
||||
mainPanel.setPopupMenu(popupMenu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPopupMenu getPopupMenu() {
|
||||
return mainPanel.getPopupMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
mainPanel.cleanUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCardWidth() {
|
||||
return mainPanel.getCardWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCardHeight() {
|
||||
return mainPanel.getCardHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MageCardAnimationSettings getAnimationSettings(int offsetX, int offsetY, float cardBoundWidth, float cardBoundHeight) {
|
||||
return mainPanel.getAnimationSettings(offsetX, offsetY, cardBoundWidth, cardBoundHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MageCard> getLinks() {
|
||||
return mainPanel.getLinks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MageCardSpace getOuterSpace() {
|
||||
return this.lastOuterSpace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MageCardLocation getCardLocation() {
|
||||
// TODO: is it support multi layers?
|
||||
if (this.getTopPanelRef() == this) {
|
||||
//noinspection deprecation (it's ok to call native getLocation here)
|
||||
return new MageCardLocation(this.getLocation(), this.getOuterSpace(), this.getBounds());
|
||||
} else {
|
||||
return super.getCardLocation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCardLocation(int x, int y) {
|
||||
// TODO: is it support multi layers?
|
||||
if (this.getTopPanelRef() == this) {
|
||||
// see setCardBounds for more coords cals
|
||||
//noinspection deprecation - it's ok to use inner setLocation here
|
||||
this.setLocation(x - lastOuterSpace.getLeft(), y - lastOuterSpace.getTop());
|
||||
} else {
|
||||
this.getTopPanelRef().setCardLocation(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MageCardLocation getCardLocationOnScreen() {
|
||||
// TODO: is it support multi layers?
|
||||
if (this.getTopPanelRef() == this) {
|
||||
//noinspection deprecation - it's ok to use inner getLocation here
|
||||
return new MageCardLocation(this.getLocationOnScreen(), this.getOuterSpace(), this.getBounds());
|
||||
} else {
|
||||
return super.getCardLocationOnScreen();
|
||||
}
|
||||
}
|
||||
|
||||
// ADDITIONAL METHODS FROM real components (e.g. set bounds or other things)
|
||||
// TODO: move it to interface for require?
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mainPanel.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addMouseListener(MouseListener l) {
|
||||
//super.addMouseListener(l);
|
||||
mainPanel.addMouseListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void removeMouseListener(MouseListener l) {
|
||||
//super.removeMouseListener(l);
|
||||
mainPanel.removeMouseListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addMouseMotionListener(MouseMotionListener l) {
|
||||
//super.addMouseMotionListener(l);
|
||||
mainPanel.addMouseMotionListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void removeMouseMotionListener(MouseMotionListener l) {
|
||||
//super.removeMouseMotionListener(l);
|
||||
mainPanel.removeMouseMotionListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addMouseWheelListener(MouseWheelListener l) {
|
||||
//super.addMouseWheelListener(l);
|
||||
mainPanel.addMouseWheelListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void removeMouseWheelListener(MouseWheelListener l) {
|
||||
//super.removeMouseWheelListener(l);
|
||||
mainPanel.removeMouseWheelListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
// inner card panel can decide about transform/scale settings (example: tapped),
|
||||
// so the top parent layer must be scaled too
|
||||
|
||||
// real card can be put on any parent layer's position (see outer spaces), so the render logic here:
|
||||
// * find real card sizes (without outer spaces)
|
||||
// * calc new sizes for the animation/rotation
|
||||
// * apply outer spaces to calculated sizes
|
||||
// TODO: is it support multi layers?
|
||||
int offsetX = this.getOuterSpace().getLeft();
|
||||
int offsetY = this.getOuterSpace().getTop();
|
||||
int extraWidth = this.getOuterSpace().getWidth();
|
||||
int extraHeight = this.getOuterSpace().getHeight();
|
||||
Rectangle componentRect = this.getCardLocation().getComponentBounds();
|
||||
MageCardAnimationSettings settings = getAnimationSettings(
|
||||
offsetX,
|
||||
offsetY,
|
||||
componentRect.width - extraWidth,
|
||||
componentRect.height - extraHeight
|
||||
);
|
||||
|
||||
if (!settings.isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isValid() || !mainPanel.isValid()) {
|
||||
mainPanel.validate();
|
||||
super.validate();
|
||||
}
|
||||
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
settings.doTransforms(g2d);
|
||||
|
||||
super.paint(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int x, int y) {
|
||||
// TODO: is it work with multi layer?
|
||||
// Mouse coords checking to find a child component under the mouse (example: show card hint on mouse over or button click)
|
||||
// Swing uses relative coords here (0,0 is component's top left corner)
|
||||
// WARNING, when you fail a parent coord check then all childs goes to ignore (example: top layer miss check,
|
||||
// then no card panel get it and no card hints on mouse over)
|
||||
MageCardLocation needLocation = this.getCardLocation();
|
||||
|
||||
// TODO: added contains support for icons hint
|
||||
// implement idea: use custom "contains" methods for all components structure: from top layer to icon label
|
||||
// another implement idea: save last AffineTransforms from paint method, translate it to current component and check coords (most accurate method)
|
||||
|
||||
// extra size for icons (workaround to fix tooltips over icons)
|
||||
Rectangle iconsOffset = new Rectangle(0, 0);
|
||||
if (this.iconsPanels.stream().anyMatch(Component::isVisible)) {
|
||||
CardIconsPanel samplePanel = this.iconsPanels.stream().findFirst().get();
|
||||
iconsOffset.x = -samplePanel.getHalfSize();
|
||||
iconsOffset.y = -samplePanel.getHalfSize();
|
||||
iconsOffset.height = samplePanel.getHalfSize();
|
||||
iconsOffset.width = samplePanel.getHalfSize();
|
||||
}
|
||||
|
||||
Rectangle normalRect = new Rectangle(
|
||||
needLocation.getCardRelativeX() + iconsOffset.x,
|
||||
needLocation.getCardRelativeY() + iconsOffset.y,
|
||||
needLocation.getCardWidth() + iconsOffset.width,
|
||||
needLocation.getCardHeight() + iconsOffset.height
|
||||
);
|
||||
Rectangle animatedRect = animateCoords(this, normalRect);
|
||||
|
||||
// debug draw just for color info, real draw will be transformed/animated with card, so you can look at draw rect
|
||||
if (DebugUtil.GUI_CARD_DRAW_MOUSE_CONTAINS_BOUNDS) {
|
||||
this.mainLayerDebug.setBounds(animatedRect.x, animatedRect.y, animatedRect.width, animatedRect.height);
|
||||
if (animatedRect.contains(x, y)) {
|
||||
this.mainLayerDebug.setBorder(BorderFactory.createLineBorder(Color.green));
|
||||
} else {
|
||||
this.mainLayerDebug.setBorder(BorderFactory.createLineBorder(Color.MAGENTA));
|
||||
}
|
||||
}
|
||||
|
||||
return animatedRect.contains(x, y);
|
||||
}
|
||||
|
||||
public static Rectangle animateCoords(MageCard card, Rectangle normalRect) {
|
||||
int needX = normalRect.x;
|
||||
int needY = normalRect.y;
|
||||
int needW = normalRect.width;
|
||||
int needH = normalRect.height;
|
||||
int cx = needX;
|
||||
int cy = needY;
|
||||
int cw = needW;
|
||||
int ch = needH;
|
||||
|
||||
if (card.isTapped()) {
|
||||
// TODO: add rotate support for non 90 angles in the future
|
||||
// rotate by 90 only
|
||||
// example before:
|
||||
// * coord: 50, 150
|
||||
// * size: 126 x 176
|
||||
// example after:
|
||||
// * coord: 50, 150 + 176 - 126
|
||||
// * size: 176 x 126
|
||||
cx = needX;
|
||||
cy = needY + needH - needW;
|
||||
cw = needH;
|
||||
ch = needW;
|
||||
}
|
||||
|
||||
return new Rectangle(cx, cy, cw, ch);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +1,5 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.FilteredImageSource;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.awt.image.RGBImageFilter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.IntStream;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import mage.abilities.hint.HintUtils;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.ExpansionRepository;
|
||||
|
|
@ -30,23 +12,30 @@ import mage.client.util.ImageHelper;
|
|||
import mage.client.util.gui.BufferedImageBuilder;
|
||||
import mage.client.util.gui.GuiDisplayUtil;
|
||||
import mage.constants.Rarity;
|
||||
import mage.utils.StreamUtils;
|
||||
import org.apache.batik.anim.dom.SVGDOMImplementation;
|
||||
import org.apache.batik.transcoder.TranscoderException;
|
||||
import org.apache.batik.transcoder.TranscoderInput;
|
||||
import org.apache.batik.transcoder.TranscoderOutput;
|
||||
import org.apache.batik.transcoder.TranscodingHints;
|
||||
import org.apache.batik.transcoder.image.ImageTranscoder;
|
||||
import org.apache.batik.util.SVGConstants;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.mage.plugins.card.utils.CardImageUtils;
|
||||
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public final class ManaSymbols {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(ManaSymbols.class);
|
||||
private static final Map<Integer, Map<String, BufferedImage>> manaImages = new HashMap<>();
|
||||
private static final Logger logger = Logger.getLogger(ManaSymbols.class);
|
||||
|
||||
private static final String CSS_FILE_NAME = "mana-svg-settings.css";
|
||||
private static final String CSS_ADDITIONAL_SETTINGS = "";
|
||||
|
||||
private static final Map<Integer, Map<String, BufferedImage>> manaImages = new HashMap<>();
|
||||
private static final Map<String, Map<Rarity, Image>> setImages = new ConcurrentHashMap<>();
|
||||
|
||||
private static final Set<String> onlyMythics = new HashSet<>();
|
||||
|
|
@ -81,55 +70,20 @@ public final class ManaSymbols {
|
|||
private static final Pattern REPLACE_SYMBOLS_PATTERN = Pattern.compile("\\{([^}/]*)/?([^}]*)\\}");
|
||||
|
||||
private static final String[] symbols = new String[]{
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
|
||||
"B", "BG", "BR", "BP", "2B",
|
||||
"G", "GU", "GW", "GP", "2G",
|
||||
"R", "RG", "RW", "RP", "2R",
|
||||
"S", "T", "Q",
|
||||
"U", "UB", "UR", "UP", "2U",
|
||||
"W", "WB", "WU", "WP", "2W",
|
||||
"X", "C", "E"};
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
|
||||
"B", "BG", "BR", "BP", "2B",
|
||||
"G", "GU", "GW", "GP", "2G",
|
||||
"R", "RG", "RW", "RP", "2R",
|
||||
"S", "T", "Q",
|
||||
"U", "UB", "UR", "UP", "2U",
|
||||
"W", "WB", "WU", "WP", "2W",
|
||||
"X", "C", "E"};
|
||||
|
||||
private static final JLabel labelRender = new JLabel(); // render mana text
|
||||
|
||||
private static String getSvgPathToCss() {
|
||||
return getImagesDir() + File.separator + "temp" + File.separator + "batic-svg-settings.css";
|
||||
}
|
||||
|
||||
private static void prepareSvg(Boolean forceToCreateCss) {
|
||||
File f = new File(getSvgPathToCss());
|
||||
|
||||
if (forceToCreateCss || !f.exists()) {
|
||||
|
||||
// Rendering hints can't be set programatically, so
|
||||
// we override defaults with a temporary stylesheet.
|
||||
// These defaults emphasize quality and precision, and
|
||||
// are more similar to the defaults of other SVG viewers.
|
||||
// SVG documents can still override these defaults.
|
||||
String css = "svg {"
|
||||
+ "shape-rendering: geometricPrecision;"
|
||||
+ "text-rendering: geometricPrecision;"
|
||||
+ "color-rendering: optimizeQuality;"
|
||||
+ "image-rendering: optimizeQuality;"
|
||||
+ "}";
|
||||
|
||||
FileWriter w = null;
|
||||
try {
|
||||
f.getParentFile().mkdirs();
|
||||
f.createNewFile();
|
||||
w = new FileWriter(f);
|
||||
w.write(css);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Can't create css file for svg", e);
|
||||
} finally {
|
||||
StreamUtils.closeQuietly(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadImages() {
|
||||
LOGGER.info("Loading symbols...");
|
||||
logger.info("Loading symbols...");
|
||||
|
||||
// TODO: delete files rename jpg->gif (it was for backward compatibility for one of the old version?)
|
||||
renameSymbols(getResourceSymbolsPath(ResourceSymbolSize.SMALL));
|
||||
|
|
@ -138,8 +92,8 @@ public final class ManaSymbols {
|
|||
//renameSymbols(getSymbolsPath(ResourceSymbolSize.SVG)); // not need
|
||||
// TODO: remove medium sets files to "medium" folder like symbols above?
|
||||
|
||||
// prepare svg settings
|
||||
prepareSvg(true);
|
||||
// prepare svg's css settings
|
||||
SvgUtils.prepareCss(CSS_FILE_NAME, CSS_ADDITIONAL_SETTINGS, true);
|
||||
|
||||
// preload symbol images
|
||||
loadSymbolImages(15);
|
||||
|
|
@ -164,7 +118,7 @@ public final class ManaSymbols {
|
|||
ImageIO.write(image, "png", newFile);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("Can't generate png image for symbol:" + symbol);
|
||||
logger.warn("Can't generate png image for symbol:" + symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -173,7 +127,7 @@ public final class ManaSymbols {
|
|||
java.util.List<String> setCodes = ExpansionRepository.instance.getSetCodes();
|
||||
if (setCodes == null) {
|
||||
// the cards db file is probaly not included in the client. It will be created after the first connect to a server.
|
||||
LOGGER.warn("No db information for sets found. Connect to a server to create database file on client side. Then try to restart the client.");
|
||||
logger.warn("No db information for sets found. Connect to a server to create database file on client side. Then try to restart the client.");
|
||||
return;
|
||||
}
|
||||
for (String set : setCodes) {
|
||||
|
|
@ -270,136 +224,16 @@ public final class ManaSymbols {
|
|||
}
|
||||
}
|
||||
|
||||
public static BufferedImage loadSVG(File svgFile, int resizeToWidth, int resizeToHeight, boolean useShadow) throws IOException {
|
||||
// debug: disable shadow gen, need to test it
|
||||
useShadow = false;
|
||||
|
||||
// load SVG image
|
||||
// base loader code: https://stackoverflow.com/questions/11435671/how-to-get-a-buffererimage-from-a-svg
|
||||
// resize code: https://vibranttechie.wordpress.com/2015/05/15/svg-loading-to-javafx-stage-and-auto-scaling-when-stage-resize/
|
||||
if (useShadow && ((resizeToWidth <= 0) || (resizeToHeight <= 0))) {
|
||||
throw new IllegalArgumentException("Must use non zero sizes for shadow.");
|
||||
}
|
||||
|
||||
final BufferedImage[] imagePointer = new BufferedImage[1];
|
||||
|
||||
// css settings for svg
|
||||
prepareSvg(false);
|
||||
File cssFile = new File(getSvgPathToCss());
|
||||
|
||||
TranscodingHints transcoderHints = new TranscodingHints();
|
||||
|
||||
// resize
|
||||
int shadowX = 0;
|
||||
int shadowY = 0;
|
||||
if (useShadow) {
|
||||
// shadow size (16px image: 1px left, 2px bottom)
|
||||
shadowX = 1 * Math.round(1f / 16f * resizeToWidth);
|
||||
shadowY = 2 * Math.round(1f / 16f * resizeToHeight);
|
||||
resizeToWidth = resizeToWidth - shadowX;
|
||||
resizeToHeight = resizeToHeight - shadowY;
|
||||
}
|
||||
|
||||
if (resizeToWidth > 0) {
|
||||
transcoderHints.put(ImageTranscoder.KEY_WIDTH, (float) resizeToWidth); //your image width
|
||||
}
|
||||
if (resizeToHeight > 0) {
|
||||
transcoderHints.put(ImageTranscoder.KEY_HEIGHT, (float) resizeToHeight); //your image height
|
||||
}
|
||||
|
||||
transcoderHints.put(ImageTranscoder.KEY_XML_PARSER_VALIDATING, Boolean.FALSE);
|
||||
transcoderHints.put(ImageTranscoder.KEY_DOM_IMPLEMENTATION,
|
||||
SVGDOMImplementation.getDOMImplementation());
|
||||
transcoderHints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT_NAMESPACE_URI,
|
||||
SVGConstants.SVG_NAMESPACE_URI);
|
||||
transcoderHints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT, "svg");
|
||||
transcoderHints.put(ImageTranscoder.KEY_USER_STYLESHEET_URI, cssFile.toURI().toString());
|
||||
|
||||
try {
|
||||
TranscoderInput input = new TranscoderInput(new FileInputStream(svgFile));
|
||||
ImageTranscoder t = new ImageTranscoder() {
|
||||
|
||||
@Override
|
||||
public BufferedImage createImage(int w, int h) {
|
||||
return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeImage(BufferedImage image, TranscoderOutput out)
|
||||
throws TranscoderException {
|
||||
imagePointer[0] = image;
|
||||
}
|
||||
};
|
||||
t.setTranscodingHints(transcoderHints);
|
||||
t.transcode(input, null);
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Couldn't convert svg file: " + svgFile + " , reason: " + e.getMessage());
|
||||
}
|
||||
|
||||
BufferedImage originImage = imagePointer[0];
|
||||
|
||||
if (useShadow && (originImage.getWidth() > 0)) {
|
||||
// draw shadow
|
||||
// origin image was reduces in sizes to fit shadow
|
||||
// see https://stackoverflow.com/a/40833715/1276632
|
||||
|
||||
// a filter which converts all colors except 0 to black
|
||||
ImageProducer prod = new FilteredImageSource(originImage.getSource(), new RGBImageFilter() {
|
||||
@Override
|
||||
public int filterRGB(int x, int y, int rgb) {
|
||||
if (rgb == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return 0xff000000;
|
||||
}
|
||||
}
|
||||
});
|
||||
// create whe black image
|
||||
Image shadow = Toolkit.getDefaultToolkit().createImage(prod);
|
||||
// result
|
||||
BufferedImage result = new BufferedImage(originImage.getWidth() + shadowX, originImage.getHeight() + shadowY, originImage.getType());
|
||||
Graphics2D g = (Graphics2D) result.getGraphics();
|
||||
// draw shadow with offset (left bottom)
|
||||
g.drawImage(shadow, -1 * shadowX, shadowY, null);
|
||||
// draw original image
|
||||
g.drawImage(originImage, 0, 0, null);
|
||||
return result;
|
||||
} else {
|
||||
// return origin image without shadow
|
||||
return originImage;
|
||||
}
|
||||
|
||||
/*
|
||||
BufferedImage base = GraphicsUtilities.createCompatibleTranslucentImage(w, h);
|
||||
Graphics2D g2 = base.createGraphics();
|
||||
g2.setColor(Color.WHITE);
|
||||
g2.fillRoundRect(0, 0, image.getWidth(), image.getHeight(), 10, 10);
|
||||
g2.dispose();
|
||||
|
||||
ShadowRenderer renderer = new ShadowRenderer(shadowSize, 0.5f,
|
||||
Color.GRAY);
|
||||
return renderer.createShadow(base);
|
||||
*/
|
||||
//imagePointer[0];
|
||||
}
|
||||
|
||||
public static File getSymbolFileNameAsSVG(String symbol) {
|
||||
return new File(getResourceSymbolsPath(ResourceSymbolSize.SVG) + symbol + ".svg");
|
||||
}
|
||||
|
||||
private static BufferedImage loadSymbolAsSVG(String symbol, int resizeToWidth, int resizeToHeight) {
|
||||
|
||||
File sourceFile = getSymbolFileNameAsSVG(symbol);
|
||||
return loadSymbolAsSVG(sourceFile, resizeToWidth, resizeToHeight);
|
||||
}
|
||||
|
||||
private static BufferedImage loadSymbolAsSVG(File sourceFile, int resizeToWidth, int resizeToHeight) {
|
||||
private static BufferedImage loadSymbolAsSVG(InputStream svgFile, String svgInfo, int resizeToWidth, int resizeToHeight) {
|
||||
try {
|
||||
// no need to resize svg (lib already do it on load)
|
||||
return loadSVG(sourceFile, resizeToWidth, resizeToHeight, true);
|
||||
|
||||
return SvgUtils.loadSVG(svgFile, svgInfo, CSS_FILE_NAME, CSS_ADDITIONAL_SETTINGS, resizeToWidth, resizeToHeight, true);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Can't load svg symbol: " + sourceFile.getPath() + " , reason: " + e.getMessage());
|
||||
logger.error("Can't load svg symbol: " + svgInfo + " , reason: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -441,7 +275,7 @@ public final class ManaSymbols {
|
|||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Can't load gif symbol: " + sourceFile.getPath());
|
||||
logger.error("Can't load gif symbol: " + sourceFile.getPath());
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -463,9 +297,16 @@ public final class ManaSymbols {
|
|||
File file;
|
||||
|
||||
// svg
|
||||
file = getSymbolFileNameAsSVG(symbol);
|
||||
if (file.exists()) {
|
||||
image = loadSymbolAsSVG(file, size, size);
|
||||
if (SvgUtils.haveSvgSupport()) {
|
||||
file = getSymbolFileNameAsSVG(symbol);
|
||||
if (file.exists()) {
|
||||
try {
|
||||
InputStream fileStream = new FileInputStream(file);
|
||||
image = loadSymbolAsSVG(fileStream, file.getPath(), size, size);
|
||||
} catch (FileNotFoundException e) {
|
||||
// it's ok to hide error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// gif
|
||||
|
|
@ -501,7 +342,7 @@ public final class ManaSymbols {
|
|||
}
|
||||
|
||||
if (!errorInfo.isEmpty()) {
|
||||
LOGGER.warn("Symbols can't be load for size " + size + ": " + errorInfo);
|
||||
logger.warn("Symbols can't be load for size " + size + ": " + errorInfo);
|
||||
}
|
||||
|
||||
manaImages.put(size, sizedSymbols);
|
||||
|
|
@ -527,7 +368,7 @@ public final class ManaSymbols {
|
|||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Couldn't rename mana symbols on " + path, e);
|
||||
logger.error("Couldn't rename mana symbols on " + path, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -604,7 +445,7 @@ public final class ManaSymbols {
|
|||
loadSymbolImages(symbolWidth);
|
||||
}
|
||||
|
||||
// TODO: replace with jlabel render (look at table rendere)?
|
||||
// TODO: replace with jlabel render (look at table renderer)?
|
||||
|
||||
/*
|
||||
// NEW version with component draw
|
||||
|
|
@ -677,7 +518,6 @@ public final class ManaSymbols {
|
|||
labelRender.setVerticalAlignment(SwingConstants.CENTER);
|
||||
labelRender.setForeground(symbolsTextColor);
|
||||
labelRender.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
//labelRender.setBorder(new LineBorder(new Color(125, 250, 250), 1)); // debug draw
|
||||
|
||||
// fix font size for mana text
|
||||
// work for labels WITHOUT borders
|
||||
|
|
@ -727,6 +567,7 @@ public final class ManaSymbols {
|
|||
CHAT,
|
||||
DIALOG,
|
||||
TOOLTIP,
|
||||
CARD_ICON_HINT
|
||||
}
|
||||
|
||||
private static String filePathToUrl(String path) {
|
||||
|
|
@ -739,6 +580,13 @@ public final class ManaSymbols {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace images/icons code by real html links. Uses in many places.
|
||||
*
|
||||
* @param value
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public static synchronized String replaceSymbolsWithHTML(String value, Type type) {
|
||||
|
||||
// mana cost to HTML images (urls to files)
|
||||
|
|
@ -757,6 +605,7 @@ public final class ManaSymbols {
|
|||
case TOOLTIP:
|
||||
symbolSize = GUISizeHelper.symbolTooltipSize;
|
||||
break;
|
||||
case CARD_ICON_HINT:
|
||||
default:
|
||||
symbolSize = 11;
|
||||
break;
|
||||
|
|
@ -786,7 +635,7 @@ public final class ManaSymbols {
|
|||
replaced = replaced.replace(CardInfo.SPLIT_MANA_SEPARATOR_FULL, CardInfo.SPLIT_MANA_SEPARATOR_RENDER);
|
||||
replaced = REPLACE_SYMBOLS_PATTERN.matcher(replaced).replaceAll(
|
||||
"<img src='" + filePathToUrl(htmlImagesPath) + "$1$2" + ".png' alt='$1$2' width="
|
||||
+ symbolSize + " height=" + symbolSize + '>');
|
||||
+ symbolSize + " height=" + symbolSize + '>');
|
||||
|
||||
// replace hint icons
|
||||
if (replaced.contains(HintUtils.HINT_ICON_GOOD)) {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import java.util.StringTokenizer;
|
|||
public final class ManaSymbolsCellRenderer extends DefaultTableCellRenderer {
|
||||
|
||||
// base panel to render
|
||||
private JPanel renderPanel = new JPanel();
|
||||
private final JPanel renderPanel = new JPanel();
|
||||
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
|
||||
|
|
@ -48,7 +48,6 @@ public final class ManaSymbolsCellRenderer extends DefaultTableCellRenderer {
|
|||
JLabel symbolLabel = new JLabel();
|
||||
symbolLabel.setFont(GUISizeHelper.tableFont);
|
||||
symbolLabel.setBorder(new EmptyBorder(0, symbolHorizontalMargin, 0, 0));
|
||||
//symbolLabel.setBorder(new LineBorder(new Color(150, 150, 150))); // debug draw
|
||||
|
||||
BufferedImage image = ManaSymbols.getSizedManaSymbol(symbol, symbolWidth);
|
||||
if (image != null) {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by StravantUser on 2017-03-30.
|
||||
* @author StravantUser
|
||||
*/
|
||||
public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
|||
List<TextboxRule> keywords = new ArrayList<>();
|
||||
}
|
||||
|
||||
private static ArrayList<CardType> ONLY_LAND_TYPE = new ArrayList<CardType>() {
|
||||
private static final ArrayList<CardType> ONLY_LAND_TYPE = new ArrayList<CardType>() {
|
||||
{
|
||||
add(CardType.LAND);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,22 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
import javax.swing.JPanel;
|
||||
import mage.client.util.TransformedImageCache;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class ScaledImagePanel extends JPanel {
|
||||
|
||||
private static final long serialVersionUID = -1523279873208605664L;
|
||||
private volatile BufferedImage srcImage;
|
||||
|
||||
public ScaledImagePanel () {
|
||||
public ScaledImagePanel() {
|
||||
super(false);
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
public void clearImage () {
|
||||
|
||||
public void clearImage() {
|
||||
srcImage = null;
|
||||
repaint();
|
||||
}
|
||||
|
|
@ -23,17 +25,24 @@ public class ScaledImagePanel extends JPanel {
|
|||
this.srcImage = srcImage;
|
||||
}
|
||||
|
||||
public boolean hasImage () {
|
||||
public boolean hasImage() {
|
||||
return srcImage != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint (Graphics g) {
|
||||
public void paint(Graphics g) {
|
||||
if (srcImage == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
g.drawImage(TransformedImageCache.getResizedImage(srcImage, getWidth(), getHeight()), 0, 0, null);
|
||||
Insets border = getInsets();
|
||||
int x = border.left;
|
||||
int y = border.top;
|
||||
int width = getWidth() - border.left - border.right;
|
||||
int height = getHeight() - border.top - border.bottom;
|
||||
g.drawImage(TransformedImageCache.getResizedImage(srcImage, width, height), x, y, width, height, null);
|
||||
|
||||
super.paint(g);
|
||||
}
|
||||
|
||||
public BufferedImage getSrcImage() {
|
||||
|
|
|
|||
230
Mage.Client/src/main/java/org/mage/card/arcane/SvgUtils.java
Normal file
230
Mage.Client/src/main/java/org/mage/card/arcane/SvgUtils.java
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import mage.abilities.icon.abilities.FlyingAbilityIcon;
|
||||
import mage.utils.StreamUtils;
|
||||
import org.apache.batik.anim.dom.SVGDOMImplementation;
|
||||
import org.apache.batik.transcoder.TranscoderInput;
|
||||
import org.apache.batik.transcoder.TranscoderOutput;
|
||||
import org.apache.batik.transcoder.TranscodingHints;
|
||||
import org.apache.batik.transcoder.image.ImageTranscoder;
|
||||
import org.apache.batik.util.SVGConstants;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.mage.plugins.card.utils.impl.ImageManagerImpl;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.FilteredImageSource;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.awt.image.RGBImageFilter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class SvgUtils {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SvgUtils.class);
|
||||
|
||||
private static boolean haveSvgSupport = false;
|
||||
|
||||
// basic css settings for good svg rendering quality, other default settings can be defined by additional param
|
||||
private static final String CSS_BASE_SETTINGS = ""
|
||||
+ "shape-rendering: geometricPrecision;"
|
||||
+ "text-rendering: geometricPrecision;"
|
||||
+ "color-rendering: optimizeQuality;"
|
||||
+ "image-rendering: optimizeQuality;";
|
||||
|
||||
private static String getSvgTempFolder() {
|
||||
return getImagesDir() + File.separator + "temp";
|
||||
}
|
||||
|
||||
public static String getSvgTempFile(String fileName) {
|
||||
return getSvgTempFolder() + File.separator + fileName;
|
||||
}
|
||||
|
||||
public static void prepareCss(String cssFileName, String cssAdditionalSettings, Boolean forceToCreateCss) {
|
||||
// css must be created all the time, so ignore svg check here
|
||||
//if (!SvgUtils.haveSvgSupport())
|
||||
|
||||
File cssFile = new File(SvgUtils.getSvgTempFile(cssFileName));
|
||||
if (forceToCreateCss || !cssFile.exists()) {
|
||||
|
||||
// Rendering hints can't be set programatically, so
|
||||
// we override defaults with a temporary stylesheet.
|
||||
// These defaults emphasize quality and precision, and
|
||||
// are more similar to the defaults of other SVG viewers.
|
||||
// SVG documents can still override these defaults.
|
||||
String css = "svg {"
|
||||
+ CSS_BASE_SETTINGS
|
||||
+ cssAdditionalSettings
|
||||
+ "}";
|
||||
FileWriter w = null;
|
||||
try {
|
||||
cssFile.getParentFile().mkdirs();
|
||||
cssFile.createNewFile();
|
||||
w = new FileWriter(cssFile);
|
||||
w.write(css);
|
||||
} catch (Throwable e) {
|
||||
logger.error("Can't create css file for svg: " + cssFile.toPath().toAbsolutePath().toString(), e);
|
||||
} finally {
|
||||
StreamUtils.closeQuietly(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load svg file content as image
|
||||
*
|
||||
* @param svgFile content (can be resource or file)
|
||||
* @param svgInfo info to show in logs or errors
|
||||
* @param cssFileName css settings
|
||||
* @param cssAdditionalSettings additional css settings (warning, if you change additional settings then css file must be re-created)
|
||||
* @param resizeToWidth image size
|
||||
* @param resizeToHeight image size
|
||||
* @param useShadow draw image with shadow (not implemented)
|
||||
* @return can return null on error (some linux systems can have compatibility problem with different java/svg libs)
|
||||
* @throws IOException
|
||||
*/
|
||||
public static BufferedImage loadSVG(InputStream svgFile, String svgInfo,
|
||||
String cssFileName, String cssAdditionalSettings,
|
||||
int resizeToWidth, int resizeToHeight, boolean useShadow) throws IOException {
|
||||
if (svgFile == null) {
|
||||
throw new IllegalArgumentException("Empty svg data or unknown file");
|
||||
}
|
||||
|
||||
// load SVG image
|
||||
// base loader code: https://stackoverflow.com/questions/11435671/how-to-get-a-buffererimage-from-a-svg
|
||||
// resize code: https://vibranttechie.wordpress.com/2015/05/15/svg-loading-to-javafx-stage-and-auto-scaling-when-stage-resize/
|
||||
useShadow = false; // TODO: implement shadow drawing
|
||||
if (useShadow && ((resizeToWidth <= 0) || (resizeToHeight <= 0))) {
|
||||
throw new IllegalArgumentException("Must use non zero sizes for shadow");
|
||||
}
|
||||
|
||||
final BufferedImage[] imagePointer = new BufferedImage[1];
|
||||
|
||||
// css settings for svg
|
||||
SvgUtils.prepareCss(cssFileName, cssAdditionalSettings, false);
|
||||
File cssFile = new File(SvgUtils.getSvgTempFile(cssFileName));
|
||||
|
||||
TranscodingHints transcoderHints = new TranscodingHints();
|
||||
|
||||
// resize
|
||||
int shadowX = 0;
|
||||
int shadowY = 0;
|
||||
if (useShadow) {
|
||||
// shadow size (16px image: 1px left, 2px bottom)
|
||||
shadowX = 1 * Math.round(1f / 16f * resizeToWidth);
|
||||
shadowY = 2 * Math.round(1f / 16f * resizeToHeight);
|
||||
resizeToWidth = resizeToWidth - shadowX;
|
||||
resizeToHeight = resizeToHeight - shadowY;
|
||||
}
|
||||
|
||||
if (resizeToWidth > 0) {
|
||||
transcoderHints.put(ImageTranscoder.KEY_WIDTH, (float) resizeToWidth); //your image width
|
||||
}
|
||||
if (resizeToHeight > 0) {
|
||||
transcoderHints.put(ImageTranscoder.KEY_HEIGHT, (float) resizeToHeight); //your image height
|
||||
}
|
||||
|
||||
transcoderHints.put(ImageTranscoder.KEY_XML_PARSER_VALIDATING, Boolean.FALSE);
|
||||
transcoderHints.put(ImageTranscoder.KEY_DOM_IMPLEMENTATION,
|
||||
SVGDOMImplementation.getDOMImplementation());
|
||||
transcoderHints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT_NAMESPACE_URI,
|
||||
SVGConstants.SVG_NAMESPACE_URI);
|
||||
transcoderHints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT, "svg");
|
||||
transcoderHints.put(ImageTranscoder.KEY_USER_STYLESHEET_URI, cssFile.toURI().toString());
|
||||
|
||||
try {
|
||||
TranscoderInput input = new TranscoderInput(svgFile);
|
||||
ImageTranscoder t = new ImageTranscoder() {
|
||||
|
||||
@Override
|
||||
public BufferedImage createImage(int w, int h) {
|
||||
return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeImage(BufferedImage image, TranscoderOutput out) {
|
||||
imagePointer[0] = image;
|
||||
}
|
||||
};
|
||||
t.setTranscodingHints(transcoderHints);
|
||||
t.transcode(input, null);
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Can't load svg file: " + svgInfo + " , reason: " + e.getMessage());
|
||||
}
|
||||
|
||||
BufferedImage originImage = imagePointer[0];
|
||||
|
||||
if (useShadow && (originImage.getWidth() > 0)) {
|
||||
// draw shadow
|
||||
// origin image was reduces in sizes to fit shadow
|
||||
// see https://stackoverflow.com/a/40833715/1276632
|
||||
|
||||
// a filter which converts all colors except 0 to black
|
||||
ImageProducer prod = new FilteredImageSource(originImage.getSource(), new RGBImageFilter() {
|
||||
@Override
|
||||
public int filterRGB(int x, int y, int rgb) {
|
||||
if (rgb == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return 0xff000000;
|
||||
}
|
||||
}
|
||||
});
|
||||
// create whe black image
|
||||
Image shadow = Toolkit.getDefaultToolkit().createImage(prod);
|
||||
// result
|
||||
BufferedImage result = new BufferedImage(originImage.getWidth() + shadowX, originImage.getHeight() + shadowY, originImage.getType());
|
||||
Graphics2D g = (Graphics2D) result.getGraphics();
|
||||
// draw shadow with offset (left bottom)
|
||||
g.drawImage(shadow, -1 * shadowX, shadowY, null);
|
||||
// draw original image
|
||||
g.drawImage(originImage, 0, 0, null);
|
||||
return result;
|
||||
} else {
|
||||
// return origin image without shadow
|
||||
return originImage;
|
||||
}
|
||||
|
||||
/*
|
||||
BufferedImage base = GraphicsUtilities.createCompatibleTranslucentImage(w, h);
|
||||
Graphics2D g2 = base.createGraphics();
|
||||
g2.setColor(Color.WHITE);
|
||||
g2.fillRoundRect(0, 0, image.getWidth(), image.getHeight(), 10, 10);
|
||||
g2.dispose();
|
||||
|
||||
ShadowRenderer renderer = new ShadowRenderer(shadowSize, 0.5f,
|
||||
Color.GRAY);
|
||||
return renderer.createShadow(base);
|
||||
*/
|
||||
//imagePointer[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current system support svg (some linux systems can have compatibility problems due to different java/svg libs)
|
||||
* <p>
|
||||
* Call it on app's start
|
||||
*
|
||||
* @return true on support, also save result for haveSvgSupport
|
||||
*/
|
||||
public static boolean checkSvgSupport() {
|
||||
// usa sample icon for svg support testing
|
||||
// direct call, no needs in cache
|
||||
BufferedImage sampleImage = ImageManagerImpl.instance.getCardIcon(FlyingAbilityIcon.instance.getIconType().getResourceName(), 32);
|
||||
haveSvgSupport = (sampleImage != null && sampleImage.getWidth() > 0);
|
||||
if (!haveSvgSupport) {
|
||||
logger.warn("WARNING, your system doesn't support svg images, so card icons will be disabled. Please, make a bug report in the github.");
|
||||
}
|
||||
return haveSvgSupport;
|
||||
}
|
||||
|
||||
public static boolean haveSvgSupport() {
|
||||
return haveSvgSupport;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ import java.util.regex.Pattern;
|
|||
*/
|
||||
public final class TextboxRuleParser {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(CardPanel.class);
|
||||
private static final Logger LOGGER = Logger.getLogger(TextboxRuleParser.class);
|
||||
|
||||
private static final Pattern BasicManaAbility = Pattern.compile("\\{T\\}: Add \\{(\\w)\\}\\.");
|
||||
private static final Pattern LevelAbilityPattern = Pattern.compile("Level (\\d+)-?(\\d*)(\\+?)");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package org.mage.plugins.card;
|
||||
|
||||
import mage.cards.MageCard;
|
||||
import mage.cards.MagePermanent;
|
||||
import mage.cards.action.ActionCallback;
|
||||
import mage.client.util.GUISizeHelper;
|
||||
|
|
@ -45,8 +46,8 @@ public class CardPluginImpl implements CardPlugin {
|
|||
|
||||
private static final Logger LOGGER = Logger.getLogger(CardPluginImpl.class);
|
||||
|
||||
private static final int GUTTER_Y = 15;
|
||||
private static final int GUTTER_X = 5;
|
||||
private static final int GUTTER_Y = 15; // top offset before cards
|
||||
private static final int GUTTER_X = 15; // left offset before cards
|
||||
static final float EXTRA_CARD_SPACING_X = 0.04f;
|
||||
private static final float CARD_SPACING_Y = 0.03f;
|
||||
private static final float STACK_SPACING_X = 0.07f;
|
||||
|
|
@ -54,9 +55,10 @@ public class CardPluginImpl implements CardPlugin {
|
|||
private static final float ATTACHMENT_SPACING_Y = 0.13f;
|
||||
|
||||
private static final int landStackMax = 5;
|
||||
// private int cardWidthMin = 50, cardWidthMax = Constants.CARD_SIZE_FULL.width;
|
||||
private int cardWidthMin = (int) GUISizeHelper.battlefieldCardMinDimension.getWidth();
|
||||
private int cardWidthMax = (int) GUISizeHelper.battlefieldCardMaxDimension.getWidth();
|
||||
// card width increment for auto-size searching (bigger value - faster draw speed on screen size, but not as accurate)
|
||||
private static final int CARD_WIDTH_AUTO_FIT_INCREMENT = 10;
|
||||
|
||||
private static final boolean stackVertical = false;
|
||||
|
||||
|
|
@ -98,12 +100,12 @@ public class CardPluginImpl implements CardPlugin {
|
|||
* Temporary card rendering shim. Split card rendering isn't implemented
|
||||
* yet, so use old component based rendering for the split cards.
|
||||
*/
|
||||
private CardPanel makePanel(CardView view, UUID gameId, boolean loadImage, ActionCallback callback, boolean isFoil, Dimension dimension, int renderMode, boolean needFullPermanentRender) {
|
||||
private CardPanel makeCardPanel(CardView view, UUID gameId, boolean loadImage, ActionCallback callback, boolean isFoil, Dimension dimension, int renderMode, boolean needFullPermanentRender) {
|
||||
switch (renderMode) {
|
||||
case 0:
|
||||
return new CardPanelRenderImpl(view, gameId, loadImage, callback, isFoil, dimension, needFullPermanentRender);
|
||||
return new CardPanelRenderModeMTGO(view, gameId, loadImage, callback, isFoil, dimension, needFullPermanentRender);
|
||||
case 1:
|
||||
return new CardPanelComponentImpl(view, gameId, loadImage, callback, isFoil, dimension, needFullPermanentRender);
|
||||
return new CardPanelRenderModeImage(view, gameId, loadImage, callback, isFoil, dimension, needFullPermanentRender);
|
||||
default:
|
||||
throw new IllegalStateException("Unknown render mode " + renderMode);
|
||||
|
||||
|
|
@ -111,43 +113,45 @@ public class CardPluginImpl implements CardPlugin {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MagePermanent getMagePermanent(PermanentView permanent, Dimension dimension, UUID gameId, ActionCallback callback, boolean canBeFoil, boolean loadImage, int renderMode, boolean needFullPermanentRender) {
|
||||
CardPanel cardPanel = makePanel(permanent, gameId, loadImage, callback, false, dimension, renderMode, needFullPermanentRender);
|
||||
public MageCard getMagePermanent(PermanentView permanent, Dimension dimension, UUID gameId, ActionCallback callback, boolean canBeFoil, boolean loadImage, int renderMode, boolean needFullPermanentRender) {
|
||||
CardPanel cardPanel = makeCardPanel(permanent, gameId, loadImage, callback, false, dimension, renderMode, needFullPermanentRender);
|
||||
cardPanel.setShowCastingCost(true);
|
||||
return cardPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MagePermanent getMageCard(CardView cardView, Dimension dimension, UUID gameId, ActionCallback callback, boolean canBeFoil, boolean loadImage, int renderMode, boolean needFullPermanentRender) {
|
||||
CardPanel cardPanel = makePanel(cardView, gameId, loadImage, callback, false, dimension, renderMode, needFullPermanentRender);
|
||||
public MageCard getMageCard(CardView cardView, Dimension dimension, UUID gameId, ActionCallback callback, boolean canBeFoil, boolean loadImage, int renderMode, boolean needFullPermanentRender) {
|
||||
CardPanel cardPanel = makeCardPanel(cardView, gameId, loadImage, callback, false, dimension, renderMode, needFullPermanentRender);
|
||||
cardPanel.setShowCastingCost(true);
|
||||
return cardPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sortPermanents(Map<String, JComponent> ui, Map<UUID, MagePermanent> permanents, boolean nonPermanentsOwnRow, boolean topPanel) {
|
||||
//TODO: add caching
|
||||
public int sortPermanents(Map<String, JComponent> ui, Map<UUID, MageCard> cards, boolean nonPermanentsOwnRow, boolean topPanel) {
|
||||
//requires to find out is position have been changed that includes:
|
||||
//adding/removing permanents, type change
|
||||
|
||||
// must return new height, so battlefield scrolls can be enabled on too big sizes
|
||||
|
||||
if (ui == null) {
|
||||
throw new RuntimeException("Error: no components");
|
||||
}
|
||||
JComponent component = ui.get("battlefieldPanel");
|
||||
|
||||
if (component == null) {
|
||||
throw new RuntimeException("Error: battlefieldPanel is missing");
|
||||
throw new RuntimeException("No battlefield ui for layout");
|
||||
}
|
||||
|
||||
JLayeredPane battlefieldPanel = (JLayeredPane) component;
|
||||
JComponent jPanel = ui.get("jPanel");
|
||||
JLayeredPane battlefieldPanel = (JLayeredPane) ui.get("battlefieldPanel");
|
||||
JComponent cardsPanel = ui.get("jPanel");
|
||||
JScrollPane scrollPane = (JScrollPane) ui.get("scrollPane");
|
||||
if (battlefieldPanel == null || cardsPanel == null || scrollPane == null) {
|
||||
throw new RuntimeException("No battlefield components for layout");
|
||||
}
|
||||
|
||||
Row rowAllLands = new Row();
|
||||
|
||||
outerLoop:
|
||||
//
|
||||
for (MagePermanent permanent : permanents.values()) {
|
||||
if (!permanent.isLand() || permanent.isCreature()) {
|
||||
for (MageCard card : cards.values()) {
|
||||
MagePermanent perm = (MagePermanent) card.getMainPanel(); // all cards must be MagePermanent on battlefield
|
||||
|
||||
if (!perm.isLand() || perm.isCreature()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -155,35 +159,36 @@ public class CardPluginImpl implements CardPlugin {
|
|||
|
||||
// Find already added lands with the same name.
|
||||
for (int i = 0, n = rowAllLands.size(); i < n; i++) {
|
||||
// stack contains main card panel, but for any size/order manipulation you must use top layer panel
|
||||
Stack stack = rowAllLands.get(i);
|
||||
MagePermanent firstPanel = stack.get(0);
|
||||
if (firstPanel.getOriginal().getName().equals(permanent.getOriginal().getName())) {
|
||||
MagePermanent firstPanelPerm = stack.get(0);
|
||||
if (firstPanelPerm.getOriginal().getName().equals(perm.getOriginal().getName())) {
|
||||
|
||||
if (!empty(firstPanel.getOriginalPermanent().getAttachments())) {
|
||||
if (!empty(firstPanelPerm.getOriginalPermanent().getAttachments())) {
|
||||
// Put this land to the left of lands with the same name and attachments.
|
||||
insertIndex = i;
|
||||
break;
|
||||
}
|
||||
List<CounterView> counters = firstPanel.getOriginalPermanent().getCounters();
|
||||
List<CounterView> counters = firstPanelPerm.getOriginalPermanent().getCounters();
|
||||
if (counters != null && !counters.isEmpty()) {
|
||||
// don't put to first panel if it has counters
|
||||
insertIndex = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty(permanent.getOriginalPermanent().getAttachments()) || stack.size() == landStackMax) {
|
||||
if (!empty(perm.getOriginalPermanent().getAttachments()) || stack.size() == landStackMax) {
|
||||
// If this land has attachments or the stack is full, put it to the right.
|
||||
insertIndex = i + 1;
|
||||
continue;
|
||||
}
|
||||
counters = permanent.getOriginalPermanent().getCounters();
|
||||
counters = perm.getOriginalPermanent().getCounters();
|
||||
if (counters != null && !counters.isEmpty()) {
|
||||
// if a land has counter, put it to the right
|
||||
insertIndex = i + 1;
|
||||
continue;
|
||||
}
|
||||
// Add to stack.
|
||||
stack.add(0, permanent);
|
||||
stack.add(0, perm);
|
||||
continue outerLoop;
|
||||
}
|
||||
if (insertIndex != -1) {
|
||||
|
|
@ -193,22 +198,22 @@ public class CardPluginImpl implements CardPlugin {
|
|||
|
||||
Stack stack = new Stack();
|
||||
|
||||
if (permanent.getOriginalPermanent().getAttachments() != null
|
||||
&& !permanent.getOriginalPermanent().getAttachments().isEmpty()
|
||||
&& !permanent.getOriginalPermanent().isAttachedTo()) {
|
||||
if (perm.getOriginalPermanent().getAttachments() != null
|
||||
&& !perm.getOriginalPermanent().getAttachments().isEmpty()
|
||||
&& !perm.getOriginalPermanent().isAttachedTo()) {
|
||||
// get the number of all attachements and sub attachments
|
||||
AttachmentLayoutInfos ali = calculateNeededNumberOfVerticalColumns(0, permanents, permanent);
|
||||
AttachmentLayoutInfos ali = calculateNeededNumberOfVerticalColumns(0, cards, card);
|
||||
stack.setMaxAttachedCount(ali.getAttachments());
|
||||
stack.setAttachmentColumns(ali.getColumns());
|
||||
}
|
||||
|
||||
stack.add(permanent);
|
||||
stack.add(perm);
|
||||
rowAllLands.add(insertIndex == -1 ? rowAllLands.size() : insertIndex, stack);
|
||||
}
|
||||
|
||||
Row rowAllCreatures = new Row(permanents, RowType.creature);
|
||||
Row rowAllOthers = new Row(permanents, RowType.other);
|
||||
Row rowAllAttached = new Row(permanents, RowType.attached);
|
||||
Row rowAllCreatures = new Row(cards, RowType.creature);
|
||||
Row rowAllOthers = new Row(cards, RowType.other);
|
||||
Row rowAllAttached = new Row(cards, RowType.attached);
|
||||
|
||||
boolean othersOnTheRight = true;
|
||||
if (nonPermanentsOwnRow) {
|
||||
|
|
@ -217,6 +222,7 @@ public class CardPluginImpl implements CardPlugin {
|
|||
rowAllOthers.clear();
|
||||
}
|
||||
|
||||
// try to auto-fit cards
|
||||
cardWidth = cardWidthMax;
|
||||
Rectangle rect = battlefieldPanel.getVisibleRect();
|
||||
playAreaWidth = rect.width;
|
||||
|
|
@ -226,7 +232,7 @@ public class CardPluginImpl implements CardPlugin {
|
|||
// calculate values based on the card size that is changing with every iteration
|
||||
cardHeight = Math.round(cardWidth * CardPanel.ASPECT_RATIO);
|
||||
extraCardSpacingX = Math.round(cardWidth * EXTRA_CARD_SPACING_X);
|
||||
cardSpacingX = cardHeight - cardWidth + extraCardSpacingX;
|
||||
cardSpacingX = cardHeight - cardWidth + extraCardSpacingX; // need space for tap animation (horizontal position)
|
||||
cardSpacingY = Math.round(cardHeight * CARD_SPACING_Y);
|
||||
stackSpacingX = stackVertical ? 0 : Math.round(cardWidth * STACK_SPACING_X);
|
||||
stackSpacingY = Math.round(cardHeight * STACK_SPACING_Y);
|
||||
|
|
@ -248,7 +254,6 @@ public class CardPluginImpl implements CardPlugin {
|
|||
addOthersIndex = rows.size();
|
||||
wrap(lands, rows, rows.size());
|
||||
wrap(others, rows, rows.size());
|
||||
|
||||
}
|
||||
|
||||
// Store the current rows and others.
|
||||
|
|
@ -277,9 +282,7 @@ public class CardPluginImpl implements CardPlugin {
|
|||
if (creatures.isEmpty() && lands.isEmpty() && others.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
//FIXME: -1 is too slow. why not binary search?
|
||||
cardWidth -= 3;
|
||||
|
||||
cardWidth -= CARD_WIDTH_AUTO_FIT_INCREMENT;
|
||||
}
|
||||
|
||||
// Get size of all the rows.
|
||||
|
|
@ -297,7 +300,7 @@ public class CardPluginImpl implements CardPlugin {
|
|||
maxRowWidth = Math.max(maxRowWidth, x);
|
||||
}
|
||||
|
||||
// Position all card panels.
|
||||
// Position all card panels
|
||||
y = GUTTER_Y;
|
||||
for (Row row : rows) {
|
||||
int rowBottom = 0;
|
||||
|
|
@ -312,21 +315,21 @@ public class CardPluginImpl implements CardPlugin {
|
|||
}
|
||||
}
|
||||
for (int panelIndex = 0, panelCount = stack.size(); panelIndex < panelCount; panelIndex++) {
|
||||
MagePermanent panel = stack.get(panelIndex);
|
||||
MagePermanent panelPerm = stack.get(panelIndex); // it's original card panel, but you must change top layer
|
||||
int stackPosition = panelCount - panelIndex - 1;
|
||||
if (jPanel != null) {
|
||||
jPanel.setComponentZOrder(panel, panelIndex);
|
||||
if (cardsPanel != null) {
|
||||
cardsPanel.setComponentZOrder(panelPerm.getTopPanelRef(), panelIndex);
|
||||
}
|
||||
int panelX = x + (stackPosition * stackSpacingX);
|
||||
int panelY = y + (stackPosition * stackSpacingY);
|
||||
try {
|
||||
// may cause:
|
||||
// java.lang.IllegalArgumentException: illegal component position 26 should be less then 26
|
||||
battlefieldPanel.moveToFront(panel);
|
||||
battlefieldPanel.moveToFront(panelPerm.getTopPanelRef());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
panel.setCardBounds(panelX, panelY, cardWidth, cardHeight);
|
||||
panelPerm.getTopPanelRef().setCardBounds(panelX, panelY, cardWidth, cardHeight);
|
||||
}
|
||||
rowBottom = Math.max(rowBottom, y + stack.getHeight());
|
||||
x += stack.getWidth();
|
||||
|
|
@ -337,11 +340,14 @@ public class CardPluginImpl implements CardPlugin {
|
|||
// we need this only for defining card size
|
||||
// attached permanents will be handled separately
|
||||
for (Stack stack : rowAllAttached) {
|
||||
for (MagePermanent panel : stack) {
|
||||
panel.setCardBounds(0, 0, cardWidth, cardHeight);
|
||||
for (MagePermanent panelPerm : stack) {
|
||||
panelPerm.getTopPanelRef().setCardBounds(0, 0, cardWidth, cardHeight);
|
||||
}
|
||||
}
|
||||
|
||||
// scrollbars speed
|
||||
scrollPane.getVerticalScrollBar().setUnitIncrement(GUISizeHelper.getCardsScrollbarUnitInc(cardHeight));
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
|
|
@ -351,7 +357,7 @@ public class CardPluginImpl implements CardPlugin {
|
|||
|
||||
private int wrap(Row sourceRow, List<Row> rows, int insertIndex) {
|
||||
// The cards are sure to fit (with vertical scrolling) at the minimum card width.
|
||||
boolean allowHeightOverflow = cardWidth == cardWidthMin;
|
||||
boolean allowHeightOverflow = (cardWidth <= cardWidthMin);
|
||||
|
||||
Row currentRow = new Row();
|
||||
for (int i = 0, n = sourceRow.size() - 1; i <= n; i++) {
|
||||
|
|
@ -413,15 +419,17 @@ public class CardPluginImpl implements CardPlugin {
|
|||
return height - cardSpacingY + GUTTER_Y * 2;
|
||||
}
|
||||
|
||||
private AttachmentLayoutInfos calculateNeededNumberOfVerticalColumns(int currentCol, Map<UUID, MagePermanent> permanents, MagePermanent permanentWithAttachments) {
|
||||
private AttachmentLayoutInfos calculateNeededNumberOfVerticalColumns(int currentCol, Map<UUID, MageCard> cards, MageCard cardWithAttachments) {
|
||||
int maxCol = ++currentCol;
|
||||
int attachments = 0;
|
||||
for (UUID attachmentId : permanentWithAttachments.getOriginalPermanent().getAttachments()) {
|
||||
MagePermanent attachedPermanent = permanents.get(attachmentId);
|
||||
if (attachedPermanent != null) {
|
||||
MagePermanent permWithAttachments = (MagePermanent) cardWithAttachments.getMainPanel();
|
||||
for (UUID attachmentId : permWithAttachments.getOriginalPermanent().getAttachments()) {
|
||||
MageCard attachedCard = cards.get(attachmentId);
|
||||
if (attachedCard != null) {
|
||||
attachments++;
|
||||
if (attachedPermanent.getOriginalPermanent().getAttachments() != null && !attachedPermanent.getOriginalPermanent().getAttachments().isEmpty()) {
|
||||
AttachmentLayoutInfos attachmentLayoutInfos = calculateNeededNumberOfVerticalColumns(currentCol, permanents, attachedPermanent);
|
||||
MagePermanent attachedPerm = (MagePermanent) attachedCard.getMainPanel();
|
||||
if (attachedPerm.getOriginalPermanent().getAttachments() != null && !attachedPerm.getOriginalPermanent().getAttachments().isEmpty()) {
|
||||
AttachmentLayoutInfos attachmentLayoutInfos = calculateNeededNumberOfVerticalColumns(currentCol, cards, attachedCard);
|
||||
if (attachmentLayoutInfos.getColumns() > maxCol) {
|
||||
maxCol = attachmentLayoutInfos.getColumns();
|
||||
attachments += attachmentLayoutInfos.getAttachments();
|
||||
|
|
@ -435,16 +443,16 @@ public class CardPluginImpl implements CardPlugin {
|
|||
private enum RowType {
|
||||
land, creature, other, attached;
|
||||
|
||||
public boolean isType(MagePermanent card) {
|
||||
public boolean isType(MagePermanent permanent) {
|
||||
switch (this) {
|
||||
case land:
|
||||
return card.isLand();
|
||||
return permanent.isLand();
|
||||
case creature:
|
||||
return card.isCreature();
|
||||
return permanent.isCreature();
|
||||
case other:
|
||||
return !card.isLand() && !card.isCreature();
|
||||
return !permanent.isLand() && !permanent.isCreature();
|
||||
case attached:
|
||||
return card.getOriginalPermanent().isAttachedToPermanent();
|
||||
return permanent.getOriginalPermanent().isAttachedToPermanent();
|
||||
default:
|
||||
throw new RuntimeException("Unhandled type: " + this);
|
||||
}
|
||||
|
|
@ -459,24 +467,26 @@ public class CardPluginImpl implements CardPlugin {
|
|||
super(16);
|
||||
}
|
||||
|
||||
public Row(Map<UUID, MagePermanent> permanents, RowType type) {
|
||||
public Row(Map<UUID, MageCard> cards, RowType type) {
|
||||
this();
|
||||
addAll(permanents, type);
|
||||
addAll(cards, type);
|
||||
}
|
||||
|
||||
private void addAll(Map<UUID, MagePermanent> permanents, RowType type) {
|
||||
for (MagePermanent permanent : permanents.values()) {
|
||||
if (!type.isType(permanent)) {
|
||||
private void addAll(Map<UUID, MageCard> cards, RowType type) {
|
||||
for (MageCard card : cards.values()) {
|
||||
MagePermanent perm = (MagePermanent) card.getMainPanel();
|
||||
|
||||
if (!type.isType(perm)) {
|
||||
continue;
|
||||
}
|
||||
// all attached permanents are grouped separately later
|
||||
if (type != RowType.attached && RowType.attached.isType(permanent)) {
|
||||
if (type != RowType.attached && RowType.attached.isType(perm)) {
|
||||
continue;
|
||||
}
|
||||
Stack stack = new Stack();
|
||||
stack.add(permanent);
|
||||
if (permanent.getOriginalPermanent().getAttachments() != null) {
|
||||
AttachmentLayoutInfos ali = calculateNeededNumberOfVerticalColumns(0, permanents, permanent);
|
||||
stack.add(perm);
|
||||
if (perm.getOriginalPermanent().getAttachments() != null) {
|
||||
AttachmentLayoutInfos ali = calculateNeededNumberOfVerticalColumns(0, cards, card);
|
||||
stack.setMaxAttachedCount(ali.getAttachments());
|
||||
stack.setAttachmentColumns(ali.getColumns());
|
||||
}
|
||||
|
|
@ -666,7 +676,7 @@ public class CardPluginImpl implements CardPlugin {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onAddCard(MagePermanent card, int count) {
|
||||
public void onAddCard(MageCard card, int count) {
|
||||
if (card != null) {
|
||||
Animation.showCard(card, count > 0 ? count : 1);
|
||||
try {
|
||||
|
|
@ -680,7 +690,7 @@ public class CardPluginImpl implements CardPlugin {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onRemoveCard(MagePermanent card, int count) {
|
||||
public void onRemoveCard(MageCard card, int count) {
|
||||
if (card != null) {
|
||||
Animation.hideCard(card, count > 0 ? count : 1);
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* AbstractBoundBean.java
|
||||
*
|
||||
* Created on 24.08.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* BoundBean.java
|
||||
*
|
||||
* Created on 24.08.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
/**
|
||||
* EventListenerList.java
|
||||
*
|
||||
* Created on 08.04.2010
|
||||
*/
|
||||
package org.mage.plugins.card.dl.beans;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,5 @@
|
|||
/**
|
||||
* PropertyChangeSupport.java
|
||||
*
|
||||
* Created on 16.07.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The class PropertyChangeSupport.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* ListenableCollections.java
|
||||
*
|
||||
* Created on 25.04.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans.collections;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* AbstractProperties.java
|
||||
*
|
||||
* Created on 24.08.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans.properties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* AbstractProperty.java
|
||||
*
|
||||
* Created on 24.08.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans.properties;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* CompoundProperties.java
|
||||
*
|
||||
* Created on 24.08.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans.properties;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* Properties.java
|
||||
*
|
||||
* Created on 24.08.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans.properties;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* Property.java
|
||||
*
|
||||
* Created on 24.08.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans.properties;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* BoundProperties.java
|
||||
*
|
||||
* Created on 24.08.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans.properties.basic;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* BasicProperty.java
|
||||
*
|
||||
* Created on 16.07.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans.properties.basic;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* BoundProperties.java
|
||||
*
|
||||
* Created on 24.08.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans.properties.bound;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* BasicProperty.java
|
||||
*
|
||||
* Created on 16.07.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans.properties.bound;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,8 @@
|
|||
/**
|
||||
* PropertyChangeListListener.java
|
||||
*
|
||||
* Created on 16.07.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans.properties.bound;
|
||||
|
||||
import org.mage.plugins.card.dl.beans.PropertyChangeSupport;
|
||||
import org.mage.plugins.card.dl.beans.collections.ListenableCollections.ListListener;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The class PropertyChangeListListener.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* PropertyChangeMapListener.java
|
||||
*
|
||||
* Created on 16.07.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans.properties.bound;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* PropertyChangeSetListener.java
|
||||
*
|
||||
* Created on 16.07.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.beans.properties.bound;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +1,11 @@
|
|||
/**
|
||||
* AbstractLaternaBean.java
|
||||
* <p>
|
||||
* Created on 25.08.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.lm;
|
||||
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.mage.plugins.card.dl.beans.AbstractBoundBean;
|
||||
import org.mage.plugins.card.dl.beans.EventListenerList;
|
||||
import org.mage.plugins.card.dl.beans.properties.Properties;
|
||||
import org.mage.plugins.card.dl.beans.properties.bound.BoundProperties;
|
||||
|
||||
|
||||
/**
|
||||
* The class AbstractLaternaBean.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* GathererSymbols.java
|
||||
* <p>
|
||||
* Created on 25.08.2010
|
||||
*/
|
||||
|
||||
package org.mage.plugins.card.dl.sources;
|
||||
|
||||
import mage.client.constants.Constants;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
/**
|
||||
* GathererSymbols.java
|
||||
*
|
||||
* Created on 25.08.2010
|
||||
*/
|
||||
package org.mage.plugins.card.dl.sources;
|
||||
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import net.java.truevfs.access.TFileOutputStream;
|
|||
import org.apache.log4j.Logger;
|
||||
import org.mage.plugins.card.dl.sources.DirectLinksForDownload;
|
||||
import org.mage.plugins.card.utils.CardImageUtils;
|
||||
import org.mage.plugins.card.utils.impl.ImageManagerImpl;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
|
|
@ -45,14 +46,18 @@ public final class ImageCache {
|
|||
|
||||
private static final SoftValuesLoadingCache<String, BufferedImage> IMAGE_CACHE;
|
||||
private static final SoftValuesLoadingCache<String, BufferedImage> FACE_IMAGE_CACHE;
|
||||
private static final SoftValuesLoadingCache<String, BufferedImage> CARD_ICONS_CACHE;
|
||||
|
||||
/**
|
||||
* Common pattern for keys. See ImageCache.getKey for structure info
|
||||
*/
|
||||
private static final Pattern KEY_PATTERN = Pattern.compile("(.*)#(.*)#(.*)#(.*)#(.*)#(.*)");
|
||||
private static final Pattern CARD_ICON_KEY_PATTERN = Pattern.compile("(.*)#(.*)");
|
||||
|
||||
static {
|
||||
// softValues() = Specifies that each value (not key) stored in the map should be wrapped in a SoftReference (by default, strong references are used). Softly-referenced objects will be garbage-collected in a globally least-recently-used manner, in response to memory demand.
|
||||
// softValues() = Specifies that each value (not key) stored in the map should be wrapped in a SoftReference
|
||||
// (by default, strong references are used). Softly-referenced objects will be garbage-collected in a
|
||||
// globally least-recently-used manner, in response to memory demand.
|
||||
IMAGE_CACHE = SoftValuesLoadingCache.from(new Function<String, BufferedImage>() {
|
||||
@Override
|
||||
public BufferedImage apply(String key) {
|
||||
|
|
@ -219,10 +224,33 @@ public final class ImageCache {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
CARD_ICONS_CACHE = SoftValuesLoadingCache.from(key -> {
|
||||
try {
|
||||
Matcher m = CARD_ICON_KEY_PATTERN.matcher(key);
|
||||
|
||||
if (m.matches()) {
|
||||
int cardSize = Integer.parseInt(m.group(1));
|
||||
String resourceName = m.group(2);
|
||||
BufferedImage image = ImageManagerImpl.instance.getCardIcon(resourceName, cardSize);
|
||||
return image;
|
||||
} else {
|
||||
throw new RuntimeException("Wrong card icons image key format: " + key);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
if (ex instanceof ComputationException) {
|
||||
throw (ComputationException) ex;
|
||||
} else {
|
||||
throw new ComputationException(ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void clearCache() {
|
||||
IMAGE_CACHE.invalidateAll();
|
||||
FACE_IMAGE_CACHE.invalidateAll();
|
||||
CARD_ICONS_CACHE.invalidateAll();
|
||||
}
|
||||
|
||||
public static String getFilePath(CardView card, int width) {
|
||||
|
|
@ -335,7 +363,7 @@ public final class ImageCache {
|
|||
BufferedImage cornerImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
// corner
|
||||
float ROUNDED_CORNER_SIZE = 0.11f; // see CardPanelComponentImpl
|
||||
float ROUNDED_CORNER_SIZE = 0.11f; // see CardPanelRenderModeImage
|
||||
int cornerSizeBorder = Math.max(4, Math.round(image.getWidth() * ROUNDED_CORNER_SIZE));
|
||||
|
||||
// corner mask
|
||||
|
|
@ -394,13 +422,14 @@ public final class ImageCache {
|
|||
return getImage(getKey(card, card.getName(), ""));
|
||||
}
|
||||
|
||||
// public static BufferedImage getImageFaceOriginal(CardView card) {
|
||||
// return getFaceImage(getFaceKey(card, card.getName(), card.getExpansionSetCode()));
|
||||
// }
|
||||
public static BufferedImage getImageOriginalAlternateName(CardView card) {
|
||||
return getImage(getKey(card, card.getAlternateName(), ""));
|
||||
}
|
||||
|
||||
public static BufferedImage getCardIconImage(String resourceName, int iconSize) {
|
||||
return getCardIconImage(getCardIconKey(resourceName, iconSize));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Image corresponding to the key
|
||||
*/
|
||||
|
|
@ -432,6 +461,18 @@ public final class ImageCache {
|
|||
}
|
||||
}
|
||||
|
||||
private static BufferedImage getCardIconImage(String key) {
|
||||
try {
|
||||
return CARD_ICONS_CACHE.getOrNull(key);
|
||||
} catch (ComputationException ex) {
|
||||
if (ex.getCause() instanceof NullPointerException) {
|
||||
return null;
|
||||
}
|
||||
LOGGER.error(ex, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Image corresponding to the key only if it already exists in
|
||||
* the cache.
|
||||
|
|
@ -461,13 +502,9 @@ public final class ImageCache {
|
|||
return name + '#' + set + "####";
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Returns the map key for the flip image of a card, without any suffixes for the image size.
|
||||
// */
|
||||
// private static String getKeyAlternateName(CardView card, String alternateName) {
|
||||
// return alternateName + "#" + card.getExpansionSetCode() + "#" +card.getType()+ "#" + card.getCardNumber() + "#"
|
||||
// + (card.getTokenSetCode() == null ? "":card.getTokenSetCode());
|
||||
// }
|
||||
private static String getCardIconKey(String resourceName, int size) {
|
||||
return size + "#" + resourceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load image from file
|
||||
|
|
|
|||
|
|
@ -1,50 +1,83 @@
|
|||
package org.mage.plugins.card.utils;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public interface ImageManager {
|
||||
|
||||
Image getAppImage();
|
||||
|
||||
Image getAppSmallImage();
|
||||
|
||||
Image getAppFlashedImage();
|
||||
|
||||
Image getSicknessImage();
|
||||
|
||||
Image getDayImage();
|
||||
|
||||
Image getNightImage();
|
||||
|
||||
|
||||
Image getTokenIconImage();
|
||||
|
||||
Image getTriggeredAbilityImage();
|
||||
|
||||
Image getActivatedAbilityImage();
|
||||
|
||||
Image getLookedAtImage();
|
||||
|
||||
Image getRevealedImage();
|
||||
|
||||
Image getExileImage();
|
||||
|
||||
Image getCopyInformIconImage();
|
||||
|
||||
Image getCounterImageViolet();
|
||||
|
||||
Image getCounterImageRed();
|
||||
|
||||
Image getCounterImageGreen();
|
||||
|
||||
Image getCounterImageGrey();
|
||||
|
||||
Image getDlgAcceptButtonImage();
|
||||
|
||||
Image getDlgActiveAcceptButtonImage();
|
||||
|
||||
Image getDlgCancelButtonImage();
|
||||
|
||||
Image getDlgActiveCancelButtonImage();
|
||||
|
||||
Image getDlgPrevButtonImage();
|
||||
|
||||
Image getDlgActivePrevButtonImage();
|
||||
|
||||
Image getDlgNextButtonImage();
|
||||
|
||||
Image getDlgActiveNextButtonImage();
|
||||
|
||||
Image getSwitchHandsButtonImage();
|
||||
|
||||
Image getStopWatchButtonImage();
|
||||
|
||||
Image getConcedeButtonImage();
|
||||
|
||||
Image getCancelSkipButtonImage();
|
||||
|
||||
Image getSkipNextTurnButtonImage();
|
||||
|
||||
Image getSkipEndTurnButtonImage();
|
||||
|
||||
Image getSkipMainButtonImage();
|
||||
|
||||
Image getSkipStackButtonImage();
|
||||
|
||||
Image getSkipEndStepBeforeYourTurnButtonImage();
|
||||
|
||||
Image getSkipYourNextTurnButtonImage();
|
||||
|
||||
Image getToggleRecordMacroButtonImage();
|
||||
|
||||
BufferedImage getCardIcon(String resourceName, int size);
|
||||
|
||||
Image getPhaseImage(String phase);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,34 @@
|
|||
package org.mage.plugins.card.utils.impl;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Image;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.CropImageFilter;
|
||||
import java.awt.image.FilteredImageSource;
|
||||
import java.awt.image.WritableRaster;
|
||||
import mage.client.dialog.PreferencesDialog;
|
||||
import mage.client.util.gui.BufferedImageBuilder;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.mage.card.arcane.SvgUtils;
|
||||
import org.mage.plugins.card.utils.ImageManager;
|
||||
import org.mage.plugins.card.utils.Transparency;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import mage.client.dialog.PreferencesDialog;
|
||||
import mage.client.util.gui.BufferedImageBuilder;
|
||||
import org.mage.plugins.card.utils.ImageManager;
|
||||
import org.mage.plugins.card.utils.Transparency;
|
||||
|
||||
public enum ImageManagerImpl implements ImageManager {
|
||||
instance;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ImageManagerImpl.class);
|
||||
|
||||
ImageManagerImpl() {
|
||||
init();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
String[] phases = {"Untap", "Upkeep", "Draw", "Main1",
|
||||
"Combat_Start", "Combat_Attack", "Combat_Block", "Combat_Damage", "Combat_End",
|
||||
"Main2", "Cleanup", "Next_Turn"};
|
||||
"Combat_Start", "Combat_Attack", "Combat_Block", "Combat_Damage", "Combat_End",
|
||||
"Main2", "Cleanup", "Next_Turn"};
|
||||
phasesImages = new HashMap<>();
|
||||
for (String name : phases) {
|
||||
Image image = getImageFromResource(
|
||||
|
|
@ -224,6 +222,7 @@ public enum ImageManagerImpl implements ImageManager {
|
|||
return imageDlgAcceptButton;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Image getDlgActiveAcceptButtonImage() {
|
||||
if (imageDlgActiveAcceptButton == null) {
|
||||
|
|
@ -363,6 +362,22 @@ public enum ImageManagerImpl implements ImageManager {
|
|||
return imageToggleRecordMacroButton;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getCardIcon(String resourceName, int size) {
|
||||
// icon must be same, but color can be changed by themes
|
||||
InputStream data = ImageManager.class.getResourceAsStream(PreferencesDialog.getCurrentTheme().getCardIconsResourcePath(resourceName));
|
||||
try {
|
||||
// no need to resize svg (lib already do it on load)
|
||||
return SvgUtils.loadSVG(data, "card icon = " + resourceName,
|
||||
PreferencesDialog.getCurrentTheme().getCardIconsCssFile(),
|
||||
PreferencesDialog.getCurrentTheme().getCardIconsCssSettings(),
|
||||
size, size, false);
|
||||
} catch (Exception e) {
|
||||
logger.error("Can't load card icon: " + resourceName + " , reason: " + e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected static Image getImageFromResourceTransparent(String path, Color mask, Rectangle rec) {
|
||||
BufferedImage image;
|
||||
Image imageCardTransparent;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue