Most obvious bugs ironed out. Ready for PR.

This commit is contained in:
Mark Langen 2016-08-31 23:37:31 -06:00
parent d5415d2d04
commit d33f8a636e
19 changed files with 415 additions and 101 deletions

View file

@ -222,7 +222,7 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis
}
@Override
public void updateImage() {
public void updateArtImage() {
}

View file

@ -114,7 +114,7 @@ public class Cards extends javax.swing.JPanel {
setGUISize();
for (MageCard mageCard : cards.values()) {
mageCard.setCardBounds(0, 0, getCardDimension().width, getCardDimension().height);
mageCard.updateImage();
mageCard.updateArtImage();
mageCard.doLayout();
}
layoutCards();

View file

@ -223,7 +223,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
// this calls updateImage
toggleTransformed();
} else {
updateImage();
updateArtImage();
}
}
@ -372,7 +372,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
setBounds(x - cardXOffset, y - cardYOffset, getWidth(), getHeight());
return;
}
this.cardWidth = cardWidth;
this.symbolWidth = cardWidth / 7;
this.cardHeight = cardHeight;
@ -389,8 +389,8 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
int height = -yOffset + rotCenterY + rotCenterToBottomCorner;
setBounds(x + xOffset, y + yOffset, width, height);
} else {
cardXOffset = 5;
cardYOffset = 5;
cardXOffset = 0;
cardYOffset = 0;
int width = cardXOffset * 2 + cardWidth;
int height = cardYOffset * 2 + cardHeight;
setBounds(x - cardXOffset, y - cardYOffset, width, height);
@ -538,6 +538,11 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
// Update panel attributes
this.isChoosable = card.isChoosable();
this.isSelected = card.isSelected();
// Update art?
boolean mustUpdateArt =
(!gameCard.getName().equals(card.getName())) ||
(gameCard.isFaceDown() != card.isFaceDown());
// Set the new card
this.gameCard = card;
@ -546,8 +551,12 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
String cardType = getType(card);
tooltipText.setText(getText(cardType, card));
// Update the image and transform circle if needed
updateImage();
// Update the image
if (mustUpdateArt) {
updateArtImage();
}
// Update transform circle
if (card.canTransform()) {
BufferedImage transformIcon;
if (isTransformed() || card.isTransformed()) {
@ -783,7 +792,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
String temp = this.gameCard.getAlternateName();
this.gameCard.setAlternateName(this.gameCard.getOriginalName());
this.gameCard.setOriginalName(temp);
updateImage();
updateArtImage();
}
@Override

View file

@ -0,0 +1,25 @@
/*
* 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;
/**
* @author stravant@gmail.com
* Attributes of a card panel outside of the CardView itself that the renderer
* needs to know in order to render a card.
*/
public class CardPanelAttributes {
public final int cardWidth;
public final int cardHeight;
public final boolean isSelected;
public final boolean isChoosable;
public CardPanelAttributes(int cardWidth, int cardHeight, boolean isChoosable, boolean isSelected) {
this.cardWidth = cardWidth;
this.cardHeight = cardHeight;
this.isChoosable = isChoosable;
this.isSelected = isSelected;
}
}

View file

@ -503,7 +503,7 @@ public class CardPanelComponentImpl extends CardPanel {
// Update image
if (imagePanel != null && imagePanel.getSrcImage() != null) {
updateImage();
updateArtImage();
}
}
@ -523,15 +523,15 @@ public class CardPanelComponentImpl extends CardPanel {
///////////////////////////////////////////////////////////
// Image updating code
private int updateImageStamp;
private int updateArtImageStamp;
@Override
public void updateImage() {
public void updateArtImage() {
tappedAngle = isTapped() ? CardPanel.TAPPED_ANGLE : 0;
flippedAngle = isFlipped() ? CardPanel.FLIPPED_ANGLE : 0;
//final CardView gameCard = this.gameCard;
final int stamp = ++updateImageStamp;
final int stamp = ++updateArtImageStamp;
Util.threadPool.submit(new Runnable() {
@Override
@ -548,7 +548,7 @@ public class CardPanelComponentImpl extends CardPanel {
UI.invokeLater(new Runnable() {
@Override
public void run() {
if (stamp == updateImageStamp) {
if (stamp == updateArtImageStamp) {
hasImage = srcImage != null;
setText(gameCard);
setImage(srcImage);

View file

@ -14,6 +14,8 @@ import mage.cards.action.ActionCallback;
import mage.client.util.ImageCaches;
import mage.constants.CardType;
import mage.view.CardView;
import mage.view.CounterView;
import mage.view.PermanentView;
import org.apache.log4j.Logger;
import org.jdesktop.swingx.graphics.GraphicsUtilities;
import static org.mage.plugins.card.constants.Constants.THUMBNAIL_SIZE_FULL;
@ -27,6 +29,9 @@ public class CardPanelRenderImpl extends CardPanel {
if (a == b) {
return true;
}
if (a.getClass() != b.getClass()) {
return false;
}
if (!a.getName().equals(b.getName())) {
return false;
}
@ -60,6 +65,28 @@ public class CardPanelRenderImpl extends CardPanel {
if (!a.getExpansionSetCode().equals(b.getExpansionSetCode())) {
return false;
}
if (a.getCounters() == null) {
if (b.getCounters() != null) {
return false;
}
} else if (!a.getCounters().equals(b.getCounters())) {
return false;
}
if (a.isFaceDown() != b.isFaceDown()) {
return false;
}
if ((a instanceof PermanentView)) {
PermanentView aa = (PermanentView)a;
PermanentView bb = (PermanentView)b;
if (aa.hasSummoningSickness() != bb.hasSummoningSickness()) {
// Note: b must be a permanentview too as we aleady checked that classes
// are the same for a and b
return false;
}
if (aa.getDamage() != bb.getDamage()) {
return false;
}
}
return true;
}
@ -91,6 +118,11 @@ public class CardPanelRenderImpl extends CardPanel {
sb.append((char)(isChoosable ? 1 : 0));
sb.append((char)(this.view.isPlayable() ? 1 : 0));
sb.append((char)(this.view.isCanAttack() ? 1 : 0));
sb.append((char)(this.view.isFaceDown() ? 1 : 0));
if (this.view instanceof PermanentView) {
sb.append((char)(((PermanentView)this.view).hasSummoningSickness() ? 1 : 0));
sb.append((char)(((PermanentView)this.view).getDamage()));
}
sb.append(this.view.getName());
sb.append(this.view.getPower());
sb.append(this.view.getToughness());
@ -112,6 +144,11 @@ public class CardPanelRenderImpl extends CardPanel {
for (String s: this.view.getRules()) {
sb.append(s);
}
if (this.view.getCounters() != null) {
for (CounterView v: this.view.getCounters()) {
sb.append(v.getName()).append(v.getCount());
}
}
return sb.toString().hashCode();
}
@ -207,7 +244,7 @@ public class CardPanelRenderImpl extends CardPanel {
}
// And draw the image we now have
g.drawImage(cardImage, 0, 0, null);
g.drawImage(cardImage, getCardXOffset(), getCardYOffset(), null);
}
/**
@ -217,33 +254,34 @@ public class CardPanelRenderImpl extends CardPanel {
private BufferedImage renderCard() {
int cardWidth = getCardWidth();
int cardHeight = getCardHeight();
int cardXOffset = getCardXOffset();
int cardYOffset = getCardYOffset();
// Create image to render to
BufferedImage image =
GraphicsUtilities.createCompatibleTranslucentImage(getWidth(), getHeight());
GraphicsUtilities.createCompatibleTranslucentImage(cardWidth, cardHeight);
Graphics2D g2d = image.createGraphics();
// Render with Antialialsing
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// Attributes
CardPanelAttributes attribs =
new CardPanelAttributes(cardWidth, cardHeight, isChoosable(), isSelected());
// Draw card itself
g2d.translate(cardXOffset, cardYOffset);
cardRenderer.draw(g2d, cardWidth - cardXOffset, cardHeight - cardYOffset);
g2d.translate(-cardXOffset, -cardYOffset);
cardRenderer.draw(g2d, attribs);
// Done
g2d.dispose();
return image;
}
private int updateImageStamp;
private int updateArtImageStamp;
@Override
public void updateImage() {
public void updateArtImage() {
// Invalidate
artImage = null;
cardImage = null;
cardRenderer.setArtImage(null);
// Stop animation
tappedAngle = isTapped() ? CardPanel.TAPPED_ANGLE : 0;
@ -251,43 +289,49 @@ public class CardPanelRenderImpl extends CardPanel {
// Schedule a repaint
repaint();
// See if the image is already loaded
//artImage = ImageCache.tryGetImage(gameCard, getCardWidth(), getCardHeight());
//this.cardRenderer.setArtImage(artImage);
// Submit a task to draw with the card art when it arrives
final int stamp = ++updateImageStamp;
Util.threadPool.submit(new Runnable() {
@Override
public void run() {
try {
final BufferedImage srcImage;
if (gameCard.isFaceDown()) {
// Nothing to do
srcImage = null;
} else if (getCardWidth() > THUMBNAIL_SIZE_FULL.width) {
srcImage = ImageCache.getImage(gameCard, getCardWidth(), getCardHeight());
} else {
srcImage = ImageCache.getThumbnail(gameCard);
}
UI.invokeLater(new Runnable() {
@Override
public void run() {
if (stamp == updateImageStamp) {
CardPanelRenderImpl.this.artImage = srcImage;
CardPanelRenderImpl.this.cardRenderer.setArtImage(srcImage);
if (srcImage != null) {
// Invalidate and repaint
CardPanelRenderImpl.this.cardImage = null;
repaint();
if (artImage == null) {
final int stamp = ++updateArtImageStamp;
Util.threadPool.submit(new Runnable() {
@Override
public void run() {
try {
final BufferedImage srcImage;
if (gameCard.isFaceDown()) {
// Nothing to do
srcImage = null;
} else if (getCardWidth() > THUMBNAIL_SIZE_FULL.width) {
srcImage = ImageCache.getImage(gameCard, getCardWidth(), getCardHeight());
} else {
srcImage = ImageCache.getThumbnail(gameCard);
}
UI.invokeLater(new Runnable() {
@Override
public void run() {
if (stamp == updateArtImageStamp) {
artImage = srcImage;
cardRenderer.setArtImage(srcImage);
if (srcImage != null) {
// Invalidate and repaint
cardImage = null;
repaint();
}
}
}
}
});
} catch (Exception e) {
e.printStackTrace();
} catch (Error err) {
err.printStackTrace();
});
} catch (Exception e) {
e.printStackTrace();
} catch (Error err) {
err.printStackTrace();
}
}
}
});
});
}
}
@Override
@ -296,7 +340,9 @@ public class CardPanelRenderImpl extends CardPanel {
super.update(card);
// Update renderer
cardImage = null;
cardRenderer = new ModernCardRenderer(gameCard, isTransformed());
cardRenderer.setArtImage(artImage);
// Repaint
repaint();
@ -304,10 +350,15 @@ public class CardPanelRenderImpl extends CardPanel {
@Override
public void setCardBounds(int x, int y, int cardWidth, int cardHeight) {
int oldCardWidth = getCardWidth();
int oldCardHeight = getCardHeight();
super.setCardBounds(x, y, cardWidth, cardHeight);
// Rerender
cardImage = null;
// Rerender if card size changed
if (getCardWidth() != oldCardWidth || getCardHeight() != oldCardHeight) {
cardImage = null;
}
}
@Override

View file

@ -18,9 +18,11 @@ import java.awt.image.BufferedImage;
import java.text.AttributedString;
import java.util.ArrayList;
import java.util.List;
import mage.constants.AbilityType;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.counters.Counter;
import mage.utils.CardUtil;
import mage.view.CardView;
import mage.view.CounterView;
import mage.view.PermanentView;
@ -108,6 +110,10 @@ public abstract class CardRenderer {
protected int cardWidth;
protected int cardHeight;
// Is it selectable / selected
protected boolean isChoosable;
protected boolean isSelected;
// Radius of the corners of the cards
protected static float CORNER_RADIUS_FRAC = 0.1f; //x cardWidth
protected static int CORNER_RADIUS_MIN = 3;
@ -164,17 +170,21 @@ public abstract class CardRenderer {
// The Draw Method
// The draw method takes the information caculated by the constructor
// and uses it to draw to a concrete size of card and graphics.
public void draw(Graphics2D g, int cardWidth, int cardHeight) {
public void draw(Graphics2D g, CardPanelAttributes attribs) {
// Pre template method layout, to calculate shared layout info
layout(cardWidth, cardHeight);
layout(attribs.cardWidth, attribs.cardHeight);
isSelected = attribs.isSelected;
isChoosable = attribs.isChoosable;
// Call the template methods
drawBorder(g);
drawBackground(g);
drawArt(g);
drawFrame(g);
drawOverlays(g);
drawCounters(g);
if (!cardView.isAbility()) {
drawOverlays(g);
drawCounters(g);
}
}
// Template methods to be implemented by sub classes
@ -196,7 +206,7 @@ public abstract class CardRenderer {
// Draw summoning sickness overlay, and possibly other overlays
protected void drawOverlays(Graphics2D g) {
if (cardView instanceof PermanentView) {
if (CardUtil.isCreature(cardView) && cardView instanceof PermanentView) {
if (((PermanentView)cardView).hasSummoningSickness()) {
int x1 = (int)(0.2*cardWidth);
int x2 = (int)(0.8*cardWidth);
@ -229,7 +239,7 @@ public abstract class CardRenderer {
// Draw +1/+1 and other counters
protected void drawCounters(Graphics2D g) {
int xPos = (int)(0.7*cardWidth);
int xPos = (int)(0.65*cardWidth);
int yPos = (int)(0.15*cardHeight);
if (cardView.getCounters() != null) {
for (CounterView v: cardView.getCounters()) {
@ -245,7 +255,7 @@ public abstract class CardRenderer {
} else {
p = OTHER_COUNTER_POLY;
}
double scale = (0.1*0.18*cardWidth);
double scale = (0.1*0.25*cardWidth);
Graphics2D g2 = (Graphics2D)g.create();
g2.translate(xPos, yPos);
g2.scale(scale, scale);
@ -258,7 +268,7 @@ public abstract class CardRenderer {
int strW = g2.getFontMetrics().stringWidth(cstr);
g2.drawString(cstr, 5 - strW/2, 8);
g2.dispose();
yPos += ((int)(0.22*cardWidth));
yPos += ((int)(0.30*cardWidth));
}
}
}
@ -324,20 +334,31 @@ public abstract class CardRenderer {
// Get a string representing the type line
protected String getCardTypeLine() {
StringBuilder sbType = new StringBuilder();
for (String superType : cardView.getSuperTypes()) {
sbType.append(superType).append(" ");
}
for (CardType cardType : cardView.getCardTypes()) {
sbType.append(cardType.toString()).append(" ");
}
if (cardView.getSubTypes().size() > 0) {
sbType.append("- ");
for (String subType : cardView.getSubTypes()) {
sbType.append(subType).append(" ");
if (cardView.isAbility()) {
switch (cardView.getAbilityType()) {
case TRIGGERED:
return "Triggered Ability";
case ACTIVATED:
return "Activated Ability";
default:
return "??? Ability";
}
} else {
StringBuilder sbType = new StringBuilder();
for (String superType : cardView.getSuperTypes()) {
sbType.append(superType).append(" ");
}
for (CardType cardType : cardView.getCardTypes()) {
sbType.append(cardType.toString()).append(" ");
}
if (cardView.getSubTypes().size() > 0) {
sbType.append("- ");
for (String subType : cardView.getSubTypes()) {
sbType.append(subType).append(" ");
}
}
return sbType.toString();
}
return sbType.toString();
}
// Set the card art image (CardPanel will give it to us when it

View file

@ -8,6 +8,7 @@ package org.mage.card.arcane;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Image;
@ -22,7 +23,10 @@ import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.font.TextMeasurer;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
@ -35,6 +39,7 @@ import mage.ObjectColor;
import mage.constants.CardType;
import mage.view.CardView;
import mage.view.PermanentView;
import net.java.balloontip.styles.RoundedBalloonStyle;
import org.apache.log4j.Logger;
import org.mage.card.arcane.CardRenderer;
import org.mage.card.arcane.CardRendererUtils;
@ -82,6 +87,20 @@ public class ModernCardRenderer extends CardRenderer {
BufferedImage img = CardRendererUtils.toBufferedImage(icon.getImage());
return new TexturePaint(img, new Rectangle(0, 0, img.getWidth(), img.getHeight()));
}
private static Font loadFont(String name) {
try {
return Font.createFont(
Font.TRUETYPE_FONT,
ModernCardRenderer.class.getResourceAsStream("/cardrender/" + name + ".ttf"));
} catch (IOException e) {
LOGGER.info("Failed to load font `" + name + "`, couldn't find resource.");
} catch (FontFormatException e) {
LOGGER.info("Failed to load font `" + name + "`, bad format.");
}
return new Font("Arial", Font.PLAIN, 1);
}
public static Font BASE_BELEREN_FONT = loadFont("beleren-bold");
public static Paint BG_TEXTURE_WHITE = loadBackgroundTexture("white");
public static Paint BG_TEXTURE_BLUE = loadBackgroundTexture("blue");
public static Paint BG_TEXTURE_BLACK = loadBackgroundTexture("black");
@ -152,6 +171,7 @@ public class ModernCardRenderer extends CardRenderer {
// How far down the card is the type line placed?
protected static float TYPE_LINE_Y_FRAC = 0.57f; // x cardHeight
protected static float TYPE_LINE_Y_FRAC_TOKEN = 0.70f;
protected int typeLineY;
// How large is the box text, and how far is it down the boxes
@ -195,17 +215,21 @@ public class ModernCardRenderer extends CardRenderer {
BOX_HEIGHT_FRAC * cardHeight);
// Type line at
typeLineY = (int)(TYPE_LINE_Y_FRAC * cardHeight);
if (cardView.isToken()) {
typeLineY = (int)(TYPE_LINE_Y_FRAC_TOKEN * cardHeight);
} else {
typeLineY = (int)(TYPE_LINE_Y_FRAC * cardHeight);
}
// Box text height
boxTextHeight = getTextHeightForBoxHeight(boxHeight);
boxTextOffset = (boxHeight - boxTextHeight)/2;
boxTextFont = new Font("Beleren", Font.PLAIN, boxTextHeight);
boxTextFont = BASE_BELEREN_FONT.deriveFont(Font.PLAIN, boxTextHeight);
// Box text height
ptTextHeight = getPTTextHeightForLineHeight(boxHeight);
ptTextOffset = (boxHeight - ptTextHeight)/2;
ptTextFont = new Font("Beleren", Font.PLAIN, ptTextHeight);
ptTextFont = BASE_BELEREN_FONT.deriveFont(Font.PLAIN, ptTextHeight);
}
@Override
@ -213,6 +237,33 @@ public class ModernCardRenderer extends CardRenderer {
// Draw border as one rounded rectangle
g.setColor(Color.black);
g.fillRoundRect(0, 0, cardWidth, cardHeight, cornerRadius, cornerRadius);
// Selection Borders
Color borderColor;
if (isSelected) {
borderColor = Color.green;
} else if (isChoosable) {
borderColor = new Color(250, 250, 0, 230);
} else if (cardView.isPlayable()) {
borderColor = new Color(153, 102, 204, 200);
} else if (cardView instanceof PermanentView && ((PermanentView)cardView).isCanAttack()) {
borderColor = new Color(0, 0, 255, 230);
} else {
borderColor = null;
}
if (borderColor != null) {
float hwidth = borderWidth / 2.0f;
Graphics2D g2 = (Graphics2D)g.create();
g2.setColor(borderColor);
g2.setStroke(new BasicStroke(borderWidth));
RoundRectangle2D.Float rect
= new RoundRectangle2D.Float(
hwidth, hwidth,
cardWidth - borderWidth, cardHeight - borderWidth,
cornerRadius, cornerRadius);
g2.draw(rect);
g2.dispose();
}
}
@Override
@ -247,7 +298,7 @@ public class ModernCardRenderer extends CardRenderer {
@Override
protected void drawArt(Graphics2D g) {
if (artImage != null) {
if (artImage != null && !cardView.isFaceDown()) {
int imgWidth = artImage.getWidth();
int imgHeight = artImage.getHeight();
BufferedImage subImg =
@ -354,14 +405,29 @@ public class ModernCardRenderer extends CardRenderer {
// Draw the name line
protected void drawNameLine(Graphics2D g, int x, int y, int w, int h) {
// Width of the mana symbols
int manaCostWidth = CardRendererUtils.getManaCostWidth(manaCostString, boxTextHeight);
int manaCostWidth;
if (cardView.isAbility()) {
manaCostWidth = 0;
} else {
manaCostWidth = CardRendererUtils.getManaCostWidth(manaCostString, boxTextHeight);
}
// Available width for name. Add a little bit of slop so that one character
// can partially go underneath the mana cost
int availableWidth = w - manaCostWidth + 2;
// Draw the name
AttributedString str = new AttributedString(cardView.getName());
String nameStr;
if (cardView.isFaceDown()) {
if (cardView instanceof PermanentView && ((PermanentView)cardView).isManifested()) {
nameStr = "Manifest: " + cardView.getName();
} else {
nameStr = "Morph: " + cardView.getName();
}
} else {
nameStr = cardView.getName();
}
AttributedString str = new AttributedString(nameStr);
str.addAttribute(TextAttribute.FONT, boxTextFont);
TextMeasurer measure = new TextMeasurer(str.getIterator(), g.getFontRenderContext());
TextLayout layout = measure.getLayout(0, measure.getLineBreakIndex(0, availableWidth));
@ -369,13 +435,20 @@ public class ModernCardRenderer extends CardRenderer {
layout.draw(g, x, y + boxTextOffset + boxTextHeight - 1);
// Draw the mana symbols
ManaSymbols.draw(g, manaCostString, x + w - manaCostWidth, y + boxTextOffset, boxTextHeight);
if (!cardView.isAbility() && !cardView.isFaceDown()) {
ManaSymbols.draw(g, manaCostString, x + w - manaCostWidth, y + boxTextOffset, boxTextHeight);
}
}
// Draw the type line (color indicator, types, and expansion symbol)
protected void drawTypeLine(Graphics2D g, int x, int y, int w, int h) {
// Draw expansion symbol
int expansionSymbolWidth = drawExpansionSymbol(g, x, y, w, h);
int expansionSymbolWidth;
if (cardView.isAbility()) {
expansionSymbolWidth = 0;
} else {
expansionSymbolWidth = drawExpansionSymbol(g, x, y, w, h);
}
// Draw type line text
int availableWidth = w - expansionSymbolWidth + 1;
@ -387,16 +460,23 @@ public class ModernCardRenderer extends CardRenderer {
types = types.replace("Legendary", "L.");
}
AttributedString str = new AttributedString(types);
str.addAttribute(TextAttribute.FONT, boxTextFont);
TextMeasurer measure = new TextMeasurer(str.getIterator(), g.getFontRenderContext());
TextLayout layout = measure.getLayout(0, measure.getLineBreakIndex(0, availableWidth));
g.setColor(getBoxTextColor());
layout.draw(g, x, y + boxTextOffset + boxTextHeight - 1);
if (!types.isEmpty()) {
AttributedString str = new AttributedString(types);
str.addAttribute(TextAttribute.FONT, boxTextFont);
TextMeasurer measure = new TextMeasurer(str.getIterator(), g.getFontRenderContext());
TextLayout layout = measure.getLayout(0, measure.getLineBreakIndex(0, availableWidth));
g.setColor(getBoxTextColor());
layout.draw(g, x, y + boxTextOffset + boxTextHeight - 1);
}
}
// Draw the P/T and/or Loyalty boxes
protected void drawBottomRight(Graphics2D g, Paint borderPaint, Color fill) {
// No bottom right for abilities
if (cardView.isAbility()) {
return;
}
// Where to start drawing the things
int curY = cardHeight - (int)(0.03f*cardHeight);
@ -493,6 +573,20 @@ public class ModernCardRenderer extends CardRenderer {
// Advance
curY -= (int)(1.2*y);
}
// does it have damage on it?
if ((cardView instanceof PermanentView) && ((PermanentView)cardView).getDamage() > 0) {
int x = cardWidth - partWidth - borderWidth;
int y = curY - boxHeight;
String damage = "" + ((PermanentView)cardView).getDamage();
g.setFont(ptTextFont);
int txWidth = g.getFontMetrics().stringWidth(damage);
g.setColor(Color.red);
g.fillRect(x, y, partWidth, boxHeight);
g.setColor(Color.white);
g.drawRect(x, y, partWidth, boxHeight);
g.drawString(damage, x + (partWidth - txWidth)/2, curY - 1);
}
}
// Draw the card's textbox in a given rect
@ -763,6 +857,8 @@ public class ModernCardRenderer extends CardRenderer {
protected Color getBoxTextColor() {
if (isNightCard()) {
return Color.white;
} else if (cardView.isAbility()) {
return Color.white;
} else {
return Color.black;
}
@ -800,8 +896,10 @@ public class ModernCardRenderer extends CardRenderer {
}
// Get the box color for the given colors
protected static Color getBoxColor(ObjectColor colors, Collection<CardType> types, boolean isNightCard) {
if (colors.getColorCount() == 2 && types.contains(CardType.LAND)) {
protected Color getBoxColor(ObjectColor colors, Collection<CardType> types, boolean isNightCard) {
if (cardView.isAbility()) {
return Color.BLACK;
} else if (colors.getColorCount() == 2 && types.contains(CardType.LAND)) {
// Special case for two color lands. Boxes should be normal land colored
// rather than multicolor. Three or greater color lands use a multi-color
// box as normal.

View file

@ -17,6 +17,7 @@ import java.util.Deque;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import mage.client.dialog.PreferencesDialog;
import mage.view.CardView;
import org.apache.log4j.Logger;
@ -37,6 +38,11 @@ public class TextboxRuleParser {
// representing that information, which can be used to render the rule in
// the textbox of a card.
public static TextboxRule parse(CardView source, String rule) {
// Kill reminder text
if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_RENDERING_REMINDER_TEXT, "false").equals("false")) {
rule = CardRendererUtils.killReminderText(rule);
}
// List of regions to apply
ArrayList<TextboxRule.AttributeRegion> regions = new ArrayList<>();

View file

@ -200,6 +200,10 @@ public class ImageCache {
public static BufferedImage getThumbnail(CardView card) {
return getImage(getKey(card, card.getName(), "#thumb"));
}
public static BufferedImage tryGetThumbnail(CardView card) {
return tryGetImage(getKey(card, card.getName(), "#thumb"));
}
public static BufferedImage getImageOriginal(CardView card) {
return getImage(getKey(card, card.getName(), ""));
@ -230,6 +234,18 @@ public class ImageCache {
return null;
}
}
/**
* Returns the Image corresponding to the key only if it already exists
* in the cache.
*/
private static BufferedImage tryGetImage(String key) {
if (IMAGE_CACHE.containsKey(key)) {
return IMAGE_CACHE.get(key);
} else {
return null;
}
}
/**
* Returns the map key for a card, without any suffixes for the image size.
@ -343,6 +359,34 @@ public class ImageCache {
return TransformedImageCache.getResizedImage(original, (int) (original.getWidth() * scale), (int) (original.getHeight() * scale));
}
/**
* Returns the image appropriate to display for a card in a picture panel, but
* only it was ALREADY LOADED. That is, the call is immediate and will not block
* on file IO.
* @param card
* @param width
* @param height
* @return
*/
public static BufferedImage tryGetImage(CardView card, int width, int height) {
if (Constants.THUMBNAIL_SIZE_FULL.width + 10 > width) {
return tryGetThumbnail(card);
}
String key = getKey(card, card.getName(), Integer.toString(width));
BufferedImage original = tryGetImage(key);
if (original == null) {
LOGGER.debug(key + " not found");
return null;
}
double scale = Math.min((double) width / original.getWidth(), (double) height / original.getHeight());
if (scale >= 1) {
return original;
}
return TransformedImageCache.getResizedImage(original, (int) (original.getWidth() * scale), (int) (original.getHeight() * scale));
}
public static TFile getTFile(String path) {
try {