* UI: improves double faces cards render:

* Fixed that it doesn't update card image and text after transform button pressed (#6217);
 * Fixed that card lost selection and can't be selected again after transform button pressed;
This commit is contained in:
Oleg Agafonov 2020-01-22 09:43:26 +04:00
parent a7c4e44632
commit 2f66e168ab
8 changed files with 93 additions and 75 deletions

View file

@ -523,7 +523,19 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
*/
@Override
public void update(CardView card) {
this.setUpdateCard(card);
if (card == null) {
return;
}
if (transformed && card.equals(this.temporary)) {
// update can be called from different places (after transform click, after selection change, etc)
// if card temporary transformed before (by icon click) then do not update full data (as example, after selection changed)
this.isChoosable = card.isChoosable();
this.isSelected = card.isSelected();
return;
} else {
this.setUpdateCard(card);
}
// Animation update
if (isPermanent && (card instanceof PermanentView)) {
@ -769,10 +781,18 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
this.transformed = transformed;
}
private void copySelections(CardView source, CardView dest) {
if (source != null && dest != null) {
dest.setSelected(source.isSelected());
dest.setChoosable(source.isChoosable());
}
}
@Override
public void toggleTransformed() {
this.transformed = !this.transformed;
if (transformed) {
// show night card
if (dayNightButton != null) { // if transformbable card is copied, button can be null
BufferedImage night = ImageManagerImpl.instance.getNightImage();
dayNightButton.setIcon(new ImageIcon(night));
@ -782,15 +802,19 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
return;
}
if (!isPermanent) { // use only for custom transformation (when pressing day-night button)
copySelections(this.getGameCard(), this.getGameCard().getSecondCardFace());
this.setTemporary(this.getGameCard());
update(this.getGameCard().getSecondCardFace());
}
} else {
// show day card
if (dayNightButton != null) { // if transformbable card is copied, button can be null
BufferedImage day = ImageManagerImpl.instance.getDayImage();
dayNightButton.setIcon(new ImageIcon(day));
}
if (!isPermanent) { // use only for custom transformation (when pressing day-night button)
copySelections(this.getGameCard().getSecondCardFace(), this.getGameCard());
update(this.getTemporary());
this.setTemporary(null);
}

View file

@ -15,11 +15,13 @@ public class CardPanelAttributes {
public final int cardHeight;
public final boolean isSelected;
public final boolean isChoosable;
public CardPanelAttributes(int cardWidth, int cardHeight, boolean isChoosable, boolean isSelected) {
public final boolean isTransformed;
public CardPanelAttributes(int cardWidth, int cardHeight, boolean isChoosable, boolean isSelected, boolean isTransformed) {
this.cardWidth = cardWidth;
this.cardHeight = cardHeight;
this.isChoosable = isChoosable;
this.isSelected = isSelected;
this.isTransformed = isTransformed;
}
}

View file

@ -775,11 +775,12 @@ public class CardPanelComponentImpl extends CardPanel {
// Super
super.update(card);
updatePTTexts(card);
setTitle(card);
// real card to show stores in getGameCard (e.g. after user clicks on night icon -- night card must be rendered)
updatePTTexts(getGameCard());
setTitle(getGameCard());
// Summoning Sickness overlay
if (hasSickness() && card.isCreature() && isPermanent()) {
if (hasSickness() && getGameCard().isCreature() && isPermanent()) {
getOverlayPanel().setVisible(true);
} else {
getOverlayPanel().setVisible(false);

View file

@ -31,7 +31,7 @@ public class CardPanelRenderImpl extends CardPanel {
if (a.getClass() != b.getClass()) {
return false;
}
if (!a.getName().equals(b.getName())) {
if (!a.getDisplayName().equals(b.getDisplayName())) {
return false;
}
if (!a.getPower().equals(b.getPower())) {
@ -117,16 +117,18 @@ public class CardPanelRenderImpl extends CardPanel {
final int height;
final boolean isChoosable;
final boolean isSelected;
final boolean isTransformed;
final CardView view;
final int hashCode;
public ImageKey(CardView view, BufferedImage artImage, int width, int height, boolean isChoosable, boolean isSelected) {
public ImageKey(CardView view, BufferedImage artImage, int width, int height, boolean isChoosable, boolean isSelected, boolean isTransformed) {
this.view = view;
this.artImage = artImage;
this.width = width;
this.height = height;
this.isChoosable = isChoosable;
this.isSelected = isSelected;
this.isTransformed = isTransformed;
this.hashCode = hashCodeImpl();
}
@ -137,6 +139,7 @@ public class CardPanelRenderImpl extends CardPanel {
sb.append((char) height);
sb.append((char) (isSelected ? 1 : 0));
sb.append((char) (isChoosable ? 1 : 0));
sb.append((char) (isTransformed ? 1 : 0));
sb.append((char) (this.view.isPlayable() ? 1 : 0));
sb.append((char) (this.view.isCanAttack() ? 1 : 0));
sb.append((char) (this.view.isCanBlock() ? 1 : 0));
@ -146,7 +149,7 @@ public class CardPanelRenderImpl extends CardPanel {
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.getDisplayName());
sb.append(this.view.getPower());
sb.append(this.view.getToughness());
sb.append(this.view.getLoyalty());
@ -237,7 +240,7 @@ public class CardPanelRenderImpl extends CardPanel {
super(newGameCard, gameId, loadImage, callback, foil, dimension, needFullPermanentRender);
// Renderer
cardRenderer = cardRendererFactory.create(getGameCard(), isTransformed());
cardRenderer = cardRendererFactory.create(getGameCard());
// Draw the parts
initialDraw();
@ -261,11 +264,12 @@ public class CardPanelRenderImpl extends CardPanel {
protected void paintCard(Graphics2D g) {
// Render the card if we don't have an image ready to use
if (cardImage == null) {
LOGGER.warn("new image: " + getGameCard().getDisplayName() + "; transformed " + (isTransformed() ? "yes" : "no"));
// Try to get card image from cache based on our card characteristics
ImageKey key
= new ImageKey(getGameCard(), artImage,
ImageKey key = new ImageKey(getGameCard(), artImage,
getCardWidth(), getCardHeight(),
isChoosable(), isSelected());
isChoosable(), isSelected(), isTransformed());
try {
cardImage = IMAGE_CACHE.get(key, this::renderCard);
} catch (ExecutionException e) {
@ -301,18 +305,18 @@ public class CardPanelRenderImpl extends CardPanel {
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
// Attributes
CardPanelAttributes attribs
= new CardPanelAttributes(cardWidth, cardHeight, isChoosable(), isSelected());
// Draw card itself
cardRenderer.draw(g2d, attribs, image);
cardRenderer.draw(g2d, getAttributes(), image);
// Done
g2d.dispose();
return image;
}
private CardPanelAttributes getAttributes() {
return new CardPanelAttributes(getCardWidth(), getCardHeight(), isChoosable(), isSelected(), isTransformed());
}
private int updateArtImageStamp;
@Override
@ -382,7 +386,7 @@ public class CardPanelRenderImpl extends CardPanel {
// Update renderer
cardImage = null;
cardRenderer = cardRendererFactory.create(getGameCard(), isTransformed());
cardRenderer = cardRendererFactory.create(getGameCard());
cardRenderer.setArtImage(artImage);
cardRenderer.setFaceArtImage(faceArtImage);

View file

@ -60,9 +60,6 @@ public abstract class CardRenderer {
// The card to be rendered
protected final CardView cardView;
// Is the card transformed?
protected final boolean isTransformed;
// The card image
protected BufferedImage artImage;
@ -123,10 +120,9 @@ public abstract class CardRenderer {
// without knowing the dimensions that the card will be rendered at.
// Then, the CardRenderer can be called on multiple times to render the
// card at various sizes (for instance, during animation)
public CardRenderer(CardView card, boolean isTransformed) {
public CardRenderer(CardView card) {
// Set base parameters
this.cardView = card;
this.isTransformed = isTransformed;
if (card.getArtRect() == ArtRect.SPLIT_FUSED) {
parseRules(card.getLeftSplitRules(), textboxKeywords, textboxRules);
@ -218,7 +214,7 @@ public abstract class CardRenderer {
drawBorder(g);
drawBackground(g);
drawArt(g);
drawFrame(g, image);
drawFrame(g, attribs, image);
if (!cardView.isAbility()) {
drawOverlays(g);
drawCounters(g);
@ -233,7 +229,7 @@ public abstract class CardRenderer {
protected abstract void drawArt(Graphics2D g);
protected abstract void drawFrame(Graphics2D g, BufferedImage image);
protected abstract void drawFrame(Graphics2D g, CardPanelAttributes attribs, BufferedImage image);
// Template methods that are possible to override, but unlikely to be
// overridden.

View file

@ -7,17 +7,17 @@ import mage.view.CardView;
* Created by StravantUser on 2017-03-30.
*/
public class CardRendererFactory {
public CardRendererFactory() {
public CardRendererFactory() {
}
public CardRenderer create(CardView card, boolean isTransformed) {
public CardRenderer create(CardView card) {
if (card.isSplitCard() && card.getArtRect() != ArtRect.SPLIT_FUSED) {
// Split fused cards still render with the normal frame, showing all abilities
// from both halves in one frame.
return new ModernSplitCardRenderer(card, isTransformed);
return new ModernSplitCardRenderer(card);
} else {
return new ModernCardRenderer(card, isTransformed);
return new ModernCardRenderer(card);
}
}
}

View file

@ -216,9 +216,9 @@ public class ModernCardRenderer extends CardRenderer {
// Processed mana cost string
protected final String manaCostString;
public ModernCardRenderer(CardView card, boolean isTransformed) {
public ModernCardRenderer(CardView card) {
// Pass off to parent
super(card, isTransformed);
super(card);
// Mana cost string
manaCostString = ManaSymbols.getStringManaCost(cardView.getManaCost());
@ -454,13 +454,13 @@ public class ModernCardRenderer extends CardRenderer {
}
@Override
protected void drawFrame(Graphics2D g, BufferedImage image) {
protected void drawFrame(Graphics2D g, CardPanelAttributes attribs, BufferedImage image) {
// Get the card colors to base the frame on
ObjectColor frameColors = getFrameObjectColor();
// Get the border paint
Color boxColor = getBoxColor(frameColors, cardView.getCardTypes(), isTransformed);
Color additionalBoxColor = getAdditionalBoxColor(frameColors, cardView.getCardTypes(), isTransformed);
Color boxColor = getBoxColor(frameColors, cardView.getCardTypes(), attribs.isTransformed);
Color additionalBoxColor = getAdditionalBoxColor(frameColors, cardView.getCardTypes(), attribs.isTransformed);
Paint textboxPaint = getTextboxPaint(frameColors, cardView.getCardTypes(), cardWidth);
Paint borderPaint = getBorderPaint(frameColors, cardView.getCardTypes(), cardWidth);
@ -547,19 +547,16 @@ public class ModernCardRenderer extends CardRenderer {
cardWidth - totalContentInset - 1, typeLineY + boxHeight,
1, cardHeight - borderWidth * 3 - typeLineY - boxHeight);
// Draw the type line
drawTypeLine(g, getCardTypeLine(),
drawTypeLine(g, attribs, getCardTypeLine(),
totalContentInset, typeLineY,
contentWidth, boxHeight, true);
}
// Draw the transform circle
int nameOffset = drawTransformationCircle(g, borderPaint);
// Draw the transform circle
nameOffset = drawTransformationCircle(g, borderPaint);
int nameOffset = drawTransformationCircle(g, attribs, borderPaint);
// Draw the name line
drawNameLine(g, cardView.getDisplayName(), manaCostString,
drawNameLine(g, attribs, cardView.getDisplayName(), manaCostString,
totalContentInset + nameOffset, totalContentInset,
contentWidth - nameOffset, boxHeight);
@ -625,10 +622,10 @@ public class ModernCardRenderer extends CardRenderer {
x, y, w, h,
contentInset,
borderPaint, boxColor);
drawTypeLine(g, getCardSuperTypeLine(),
drawTypeLine(g, attribs, getCardSuperTypeLine(),
totalContentInset + contentInset, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset,
contentWidth / 2 - boxHeight, boxHeight - 4, false);
drawTypeLine(g, getCardSubTypeLine(),
drawTypeLine(g, attribs, getCardSubTypeLine(),
totalContentInset + 4 * contentWidth / 7 + boxHeight, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset,
3 * contentWidth / 7 - boxHeight - contentInset, boxHeight - 4, true);
drawRulesText(g, textboxKeywords, textboxRules,
@ -651,7 +648,7 @@ public class ModernCardRenderer extends CardRenderer {
}
// Draw the bottom right stuff
drawBottomRight(g, borderPaint, boxColor);
drawBottomRight(g, attribs, borderPaint, boxColor);
}
public void drawZendikarCurvedFace(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2,
@ -836,7 +833,7 @@ public class ModernCardRenderer extends CardRenderer {
}
// Draw the name line
protected void drawNameLine(Graphics2D g, String baseName, String manaCost, int x, int y, int w, int h) {
protected void drawNameLine(Graphics2D g, CardPanelAttributes attribs, String baseName, String manaCost, int x, int y, int w, int h) {
// Width of the mana symbols
int manaCostWidth;
if (cardView.isAbility()) {
@ -873,7 +870,7 @@ public class ModernCardRenderer extends CardRenderer {
}
if (breakIndex > 0) {
TextLayout layout = measure.getLayout(0, breakIndex);
g.setColor(getBoxTextColor());
g.setColor(getBoxTextColor(attribs));
layout.draw(g, x, y + boxTextOffset + boxTextHeight - 1);
}
}
@ -885,7 +882,7 @@ public class ModernCardRenderer extends CardRenderer {
}
// Draw the type line (color indicator, types, and expansion symbol)
protected void drawTypeLine(Graphics2D g, String baseTypeLine, int x, int y, int w, int h, boolean withSymbol) {
protected void drawTypeLine(Graphics2D g, CardPanelAttributes attribs, String baseTypeLine, int x, int y, int w, int h, boolean withSymbol) {
// Draw expansion symbol
int expansionSymbolWidth = 0;
if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_RENDERING_SET_SYMBOL, "false").equals("false")) {
@ -921,7 +918,7 @@ public class ModernCardRenderer extends CardRenderer {
}
if (breakIndex > 0) {
TextLayout layout = measure.getLayout(0, breakIndex);
g.setColor(getBoxTextColor());
g.setColor(getBoxTextColor(attribs));
layout.draw(g, x, y + (h - boxTextHeight) / 2 + boxTextHeight - 1);
}
}
@ -973,7 +970,7 @@ public class ModernCardRenderer extends CardRenderer {
}
// Draw the P/T and/or Loyalty boxes
protected void drawBottomRight(Graphics2D g, Paint borderPaint, Color fill) {
protected void drawBottomRight(Graphics2D g, CardPanelAttributes attribs, Paint borderPaint, Color fill) {
// No bottom right for abilities
if (cardView.isAbility()) {
return;
@ -1030,7 +1027,7 @@ public class ModernCardRenderer extends CardRenderer {
}
defaultTextLight = true;
} else {
defaultTextColor = getBoxTextColor();
defaultTextColor = getBoxTextColor(attribs);
defaultTextLight = !defaultTextColor.equals(Color.black);
}
g.setColor(defaultTextColor);
@ -1413,26 +1410,20 @@ public class ModernCardRenderer extends CardRenderer {
return advance;
}
// Draw the transformation circle if there is one, and return the
// horizontal width taken up into the content space by it.
protected boolean isNightCard() {
return isTransformed;
protected boolean isTransformCard(CardPanelAttributes attribs) {
return cardView.canTransform() || attribs.isTransformed;
}
protected boolean isTransformCard() {
return cardView.canTransform() || isTransformed;
}
protected int drawTransformationCircle(Graphics2D g, Paint borderPaint) {
protected int drawTransformationCircle(Graphics2D g, CardPanelAttributes attribs, Paint borderPaint) {
int transformCircleOffset = 0;
if (isTransformCard()) {
if (isTransformCard(attribs)) {
transformCircleOffset = boxHeight - contentInset;
g.setPaint(borderPaint);
g.drawOval(borderWidth, totalContentInset, boxHeight - 1, boxHeight - 1);
g.setColor(Color.black);
g.fillOval(borderWidth + 1, totalContentInset + 1, boxHeight - 2, boxHeight - 2);
g.setColor(Color.white);
if (isTransformed) {
if (attribs.isTransformed) {
g.fillArc(borderWidth + 3, totalContentInset + 3, boxHeight - 6, boxHeight - 6, 90, 270);
g.setColor(Color.black);
g.fillArc(borderWidth + 3 + 3, totalContentInset + 3, boxHeight - 6 - 3, boxHeight - 6, 90, 270);
@ -1457,8 +1448,8 @@ public class ModernCardRenderer extends CardRenderer {
}
// Determine the color of the name / type line text
protected Color getBoxTextColor() {
if (isTransformed) {
protected Color getBoxTextColor(CardPanelAttributes attribs) {
if (attribs.isTransformed) {
return Color.white;
} else if (cardView.isAbility()) {
return Color.white;

View file

@ -47,8 +47,8 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
private boolean isFuse = false;
private boolean isAftermath = false;
public ModernSplitCardRenderer(CardView view, boolean isTransformed) {
super(view, isTransformed);
public ModernSplitCardRenderer(CardView view) {
super(view);
rightHalf.manaCostString = ManaSymbols.getStringManaCost(cardView.getRightSplitCosts().getSymbols());
leftHalf.manaCostString = ManaSymbols.getStringManaCost(cardView.getLeftSplitCosts().getSymbols());
@ -227,9 +227,9 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
}
}
protected void drawSplitHalfFrame(Graphics2D g, HalfCardProps half, int typeLineY) {
protected void drawSplitHalfFrame(Graphics2D g, CardPanelAttributes attribs, HalfCardProps half, int typeLineY) {
// Get the border paint
Color boxColor = getBoxColor(half.color, cardView.getCardTypes(), isTransformed);
Color boxColor = getBoxColor(half.color, cardView.getCardTypes(), attribs.isTransformed);
Paint textboxPaint = getTextboxPaint(half.color, cardView.getCardTypes(), cardWidth);
Paint borderPaint = getBorderPaint(half.color, cardView.getCardTypes(), cardWidth);
@ -260,12 +260,12 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
borderPaint, boxColor);
// Draw the name line
drawNameLine(g, half.name, half.manaCostString,
drawNameLine(g, attribs, half.name, half.manaCostString,
0, 0,
half.cw, boxHeight);
// Draw the type line
drawTypeLine(g, half.typeLineString,
drawTypeLine(g, attribs, half.typeLineString,
0, typeLineY,
half.cw, boxHeight - 4, true);
@ -306,13 +306,13 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
}
@Override
protected void drawFrame(Graphics2D g, BufferedImage image) {
protected void drawFrame(Graphics2D g, CardPanelAttributes attribs, BufferedImage image) {
if (isAftermath()) {
drawSplitHalfFrame(getUnmodifiedHalfContext(g), leftHalf, (int) (leftHalf.ch * TYPE_LINE_Y_FRAC));
drawSplitHalfFrame(getAftermathHalfContext(g), rightHalf, (rightHalf.ch - boxHeight) / 2);
drawSplitHalfFrame(getUnmodifiedHalfContext(g), attribs, leftHalf, (int) (leftHalf.ch * TYPE_LINE_Y_FRAC));
drawSplitHalfFrame(getAftermathHalfContext(g), attribs, rightHalf, (rightHalf.ch - boxHeight) / 2);
} else {
drawSplitHalfFrame(getLeftHalfContext(g), leftHalf, (int) (leftHalf.ch * TYPE_LINE_Y_FRAC));
drawSplitHalfFrame(getRightHalfContext(g), rightHalf, (int) (rightHalf.ch * TYPE_LINE_Y_FRAC));
drawSplitHalfFrame(getLeftHalfContext(g), attribs, leftHalf, (int) (leftHalf.ch * TYPE_LINE_Y_FRAC));
drawSplitHalfFrame(getRightHalfContext(g), attribs, rightHalf, (int) (rightHalf.ch * TYPE_LINE_Y_FRAC));
if (isFuse()) {
Graphics2D g2 = getRightHalfContext(g);
int totalFuseBoxWidth = rightHalf.cw * 2 + 2 * borderWidth + dividerSize;
@ -323,7 +323,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
totalFuseBoxWidth, boxHeight,
contentInset,
borderPaint, boxColor);
drawNameLine(g2, "Fuse (You may cast both halves from your hand)", "",
drawNameLine(g2, attribs, "Fuse (You may cast both halves from your hand)", "",
0, rightHalf.ch,
totalFuseBoxWidth - 2 * borderWidth, boxHeight);
}