mirror of
https://github.com/correl/mage.git
synced 2024-12-24 11:50:45 +00:00
Preparations for new card drawing in Mage.Card.Plugin.
This commit is contained in:
parent
c63324dcc6
commit
a779289ec2
12 changed files with 1435 additions and 0 deletions
25
Mage.Common/src/mage/utils/CardUtil.java
Normal file
25
Mage.Common/src/mage/utils/CardUtil.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
package mage.utils;
|
||||
|
||||
import mage.Constants.CardType;
|
||||
import mage.view.CardView;
|
||||
|
||||
/**
|
||||
* Utility class for {@link CardView}
|
||||
*
|
||||
* @version 0.1 02.11.2010
|
||||
* @author nantuko
|
||||
*/
|
||||
public class CardUtil {
|
||||
|
||||
public static boolean isCreature(CardView card) {
|
||||
return is(card, CardType.CREATURE);
|
||||
}
|
||||
|
||||
public static boolean isPlaneswalker(CardView card) {
|
||||
return is(card, CardType.PLANESWALKER);
|
||||
}
|
||||
|
||||
public static boolean is(CardView card, CardType type) {
|
||||
return card.getCardTypes().contains(type);
|
||||
}
|
||||
}
|
|
@ -64,6 +64,7 @@ public class CardView implements Serializable {
|
|||
protected String art;
|
||||
protected Rarity rarity;
|
||||
protected String expansionSetCode;
|
||||
protected boolean tapped;
|
||||
|
||||
public List<UUID> targets;
|
||||
|
||||
|
@ -96,6 +97,9 @@ public class CardView implements Serializable {
|
|||
this.expansionSetCode = card.getExpansionSetCode();
|
||||
}
|
||||
|
||||
//FIXME
|
||||
this.tapped = false;
|
||||
|
||||
if (card instanceof Spell) {
|
||||
Spell<?> spell = (Spell<?>)card;
|
||||
if (spell.getSpellAbility().getTargets().size() > 0) {
|
||||
|
|
|
@ -17,11 +17,21 @@
|
|||
<description>Plugin for drawing card</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>Mage-Common</artifactId>
|
||||
<version>${mage-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.plugins.jspf</groupId>
|
||||
<artifactId>jspf-core</artifactId>
|
||||
<version>${jspf-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.9</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package org.mage.card;
|
||||
|
||||
public abstract class MageCard {
|
||||
abstract public void onBeginAnimation();
|
||||
abstract public void onEndAnimation();
|
||||
abstract public void repaint();
|
||||
abstract public boolean isTapped();
|
||||
abstract public void setTransparency(double transparency);
|
||||
}
|
|
@ -0,0 +1,322 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import java.awt.Container;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Point;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.mage.card.MageCard;
|
||||
|
||||
abstract public class Animation {
|
||||
static private final long TARGET_MILLIS_PER_FRAME = 30;
|
||||
//static private final float HALF_PI = (float)(Math.PI / 2);
|
||||
|
||||
static private Timer timer = new Timer("Animation", true);
|
||||
|
||||
//static private CardPanel delayedCardPanel;
|
||||
//static private long delayedTime;
|
||||
static private CardPanel enlargedCardPanel;
|
||||
static private CardPanel enlargedAnimationPanel;
|
||||
static private Object enlargeLock = new Object();
|
||||
|
||||
private TimerTask timerTask;
|
||||
private FrameTimer frameTimer;
|
||||
private long elapsed;
|
||||
|
||||
public Animation (final long duration) {
|
||||
this(duration, 0);
|
||||
}
|
||||
|
||||
public Animation (final long duration, long delay) {
|
||||
timerTask = new TimerTask() {
|
||||
public void run () {
|
||||
if (frameTimer == null) {
|
||||
start();
|
||||
frameTimer = new FrameTimer();
|
||||
}
|
||||
elapsed += frameTimer.getTimeSinceLastFrame();
|
||||
if (elapsed >= duration) {
|
||||
cancel();
|
||||
elapsed = duration;
|
||||
}
|
||||
update(elapsed / (float)duration);
|
||||
if (elapsed == duration) end();
|
||||
}
|
||||
};
|
||||
timer.scheduleAtFixedRate(timerTask, delay, TARGET_MILLIS_PER_FRAME);
|
||||
}
|
||||
|
||||
abstract protected void update (float percentage);
|
||||
|
||||
protected void cancel () {
|
||||
timerTask.cancel();
|
||||
end();
|
||||
}
|
||||
|
||||
protected void start () {
|
||||
}
|
||||
|
||||
protected void end () {
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses averaging of the time between the past few frames to provide smooth animation.
|
||||
*/
|
||||
private class FrameTimer {
|
||||
static private final int SAMPLES = 6;
|
||||
static private final long MAX_FRAME = 100; // Max time for one frame, to weed out spikes.
|
||||
|
||||
private long samples[] = new long[SAMPLES];
|
||||
private int sampleIndex;
|
||||
|
||||
public FrameTimer () {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
for (int i = SAMPLES - 1; i >= 0; i--)
|
||||
samples[i] = currentTime - (SAMPLES - i) * TARGET_MILLIS_PER_FRAME;
|
||||
}
|
||||
|
||||
public long getTimeSinceLastFrame () {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
int id = sampleIndex - 1;
|
||||
if (id < 0) id += SAMPLES;
|
||||
|
||||
long timeSinceLastSample = currentTime - samples[id];
|
||||
|
||||
// If the slice was too big, advance all the previous times by the diff.
|
||||
if (timeSinceLastSample > MAX_FRAME) {
|
||||
long diff = timeSinceLastSample - MAX_FRAME;
|
||||
for (int i = 0; i < SAMPLES; i++)
|
||||
samples[i] += diff;
|
||||
}
|
||||
|
||||
long timeSinceOldestSample = currentTime - samples[sampleIndex];
|
||||
samples[sampleIndex] = currentTime;
|
||||
sampleIndex = (sampleIndex + 1) % SAMPLES;
|
||||
|
||||
return timeSinceOldestSample / (long)SAMPLES;
|
||||
}
|
||||
}
|
||||
|
||||
static public void tapCardToggle (final CardPanel panel, final MageCard parent) {
|
||||
new Animation(300) {
|
||||
protected void start () {
|
||||
parent.onBeginAnimation();
|
||||
}
|
||||
|
||||
protected void update (float percentage) {
|
||||
panel.tappedAngle = CardPanel.TAPPED_ANGLE * percentage;
|
||||
if (!panel.gameCard.isTapped()) panel.tappedAngle = CardPanel.TAPPED_ANGLE - panel.tappedAngle;
|
||||
panel.repaint();
|
||||
}
|
||||
|
||||
protected void end () {
|
||||
panel.tappedAngle = panel.gameCard.isTapped() ? CardPanel.TAPPED_ANGLE : 0;
|
||||
parent.onEndAnimation();
|
||||
parent.repaint();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// static public void moveCardToPlay (Component source, final CardPanel dest, final CardPanel animationPanel) {
|
||||
static public 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) {
|
||||
UI.invokeLater(new Runnable() {
|
||||
public void run () {
|
||||
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();
|
||||
if (parent != layeredPane) {
|
||||
layeredPane.add(animationPanel);
|
||||
layeredPane.setLayer(animationPanel, JLayeredPane.MODAL_LAYER);
|
||||
}
|
||||
|
||||
new Animation(700) {
|
||||
protected void update (float percentage) {
|
||||
if (placeholder != null && !placeholder.isShowing()) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
int currentX = startX + Math.round((endX - startX + endWidth / 2f) * percentage);
|
||||
int currentY = startY + Math.round((endY - startY + endHeight / 2f) * percentage);
|
||||
int currentWidth, currentHeight;
|
||||
int midWidth = Math.max(200, endWidth * 2);
|
||||
int midHeight = Math.round(midWidth * CardPanel.ASPECT_RATIO);
|
||||
if (percentage <= 0.5f) {
|
||||
percentage = percentage * 2;
|
||||
float pp = sqrta * (1 - percentage);
|
||||
percentage = 1 - a * pp * pp;
|
||||
currentWidth = startWidth + Math.round((midWidth - startWidth) * percentage);
|
||||
currentHeight = startHeight + Math.round((midHeight - startHeight) * percentage);
|
||||
} else {
|
||||
percentage = (percentage - 0.5f) * 2;
|
||||
float pp = sqrta * percentage;
|
||||
percentage = a * pp * pp;
|
||||
currentWidth = midWidth + Math.round((endWidth - midWidth) * percentage);
|
||||
currentHeight = midHeight + Math.round((endHeight - midHeight) * percentage);
|
||||
}
|
||||
currentX -= Math.round(currentWidth / 2);
|
||||
currentY -= Math.round(currentHeight / 2);
|
||||
animationPanel.setCardBounds(currentX, currentY, currentWidth, currentHeight);
|
||||
}
|
||||
|
||||
protected void end () {
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
public void run () {
|
||||
if (placeholder != null) {
|
||||
placeholder.setDisplayEnabled(true);
|
||||
placeholder.setImage(animationPanel);
|
||||
}
|
||||
animationPanel.setVisible(false);
|
||||
animationPanel.repaint();
|
||||
layeredPane.remove(animationPanel);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static public 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) {
|
||||
UI.invokeLater(new Runnable() {
|
||||
public void run () {
|
||||
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();
|
||||
if (parent != layeredPane) {
|
||||
layeredPane.add(animationPanel);
|
||||
layeredPane.setLayer(animationPanel, JLayeredPane.MODAL_LAYER);
|
||||
}
|
||||
|
||||
new Animation(speed) {
|
||||
protected void update (float percentage) {
|
||||
int currentX = startX + Math.round((endX - startX) * percentage);
|
||||
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);
|
||||
}
|
||||
|
||||
protected void end () {
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
public void run () {
|
||||
if (placeholder != null) {
|
||||
placeholder.setDisplayEnabled(true);
|
||||
placeholder.setImage(animationPanel);
|
||||
}
|
||||
animationPanel.setVisible(false);
|
||||
animationPanel.repaint();
|
||||
layeredPane.remove(animationPanel);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static public void shrinkCard () {
|
||||
CardPanel enlargedCardPanel, enlargedAnimationPanel;
|
||||
synchronized (enlargeLock) {
|
||||
//delayedCardPanel = null;
|
||||
//delayedTime = 0;
|
||||
enlargedCardPanel = Animation.enlargedCardPanel;
|
||||
enlargedAnimationPanel = Animation.enlargedAnimationPanel;
|
||||
if (enlargedAnimationPanel == null) return;
|
||||
Animation.enlargedCardPanel = null;
|
||||
Animation.enlargedAnimationPanel = null;
|
||||
}
|
||||
|
||||
final CardPanel overPanel = enlargedCardPanel, animationPanel = enlargedAnimationPanel;
|
||||
|
||||
animationPanel.setAnimationPanel(true);
|
||||
final JLayeredPane layeredPane = SwingUtilities.getRootPane(overPanel).getLayeredPane();
|
||||
layeredPane.setLayer(animationPanel, JLayeredPane.MODAL_LAYER);
|
||||
|
||||
final int startWidth = animationPanel.getCardWidth();
|
||||
final int startHeight = Math.round(startWidth * CardPanel.ASPECT_RATIO);
|
||||
final int endWidth = overPanel.getCardWidth();
|
||||
final int endHeight = Math.round(endWidth * CardPanel.ASPECT_RATIO);
|
||||
|
||||
new Animation(200) {
|
||||
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);
|
||||
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));
|
||||
currentX = Math.min(currentX, layeredPane.getWidth() - currentWidth);
|
||||
int currentY = Math.max(0, centerY - Math.round(currentHeight / 2f));
|
||||
currentY = Math.min(currentY, layeredPane.getHeight() - currentHeight);
|
||||
animationPanel.tappedAngle = overPanel.tappedAngle * percentage;
|
||||
animationPanel.setCardBounds(currentX, currentY, currentWidth, currentHeight);
|
||||
}
|
||||
|
||||
protected void end () {
|
||||
animationPanel.setVisible(false);
|
||||
animationPanel.repaint();
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
public void run () {
|
||||
layeredPane.remove(animationPanel);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static public boolean isShowingEnlargedCard () {
|
||||
synchronized (enlargeLock) {
|
||||
return enlargedAnimationPanel != null;
|
||||
}
|
||||
}
|
||||
|
||||
static public void showCard(final CardPanel panel) {
|
||||
new Animation(600) {
|
||||
protected void start () {
|
||||
}
|
||||
|
||||
protected void update (float percentage) {
|
||||
float alpha = percentage;
|
||||
panel.setAlpha(alpha);
|
||||
panel.repaint();
|
||||
}
|
||||
|
||||
protected void end () {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static public void hideCard(final CardPanel panel, final MageCard card) {
|
||||
new Animation(600) {
|
||||
protected void start () {
|
||||
}
|
||||
|
||||
protected void update (float percentage) {
|
||||
float alpha = 1 - percentage;
|
||||
panel.setAlpha(alpha);
|
||||
card.setTransparency(alpha);
|
||||
card.repaint();
|
||||
}
|
||||
|
||||
protected void end () {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,410 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import mage.utils.CardUtil;
|
||||
import mage.view.PermanentView;
|
||||
|
||||
import org.mage.card.arcane.ScaledImagePanel.MultipassType;
|
||||
import org.mage.card.arcane.ScaledImagePanel.ScalingType;
|
||||
|
||||
@SuppressWarnings({"unchecked","rawtypes"})
|
||||
public class CardPanel extends JPanel {
|
||||
private static final long serialVersionUID = -3272134219262184410L;
|
||||
static public final double TAPPED_ANGLE = Math.PI / 2;
|
||||
static public final float ASPECT_RATIO = 3.5f / 2.5f;
|
||||
//static public final float ASPECT_RATIO = 1.0f;
|
||||
|
||||
static public CardPanel dragAnimationPanel;
|
||||
|
||||
public static final Rectangle CARD_SIZE_FULL = new Rectangle(101, 149);
|
||||
|
||||
static private final float ROUNDED_CORNER_SIZE = 0.1f;
|
||||
//static private final float SELECTED_BORDER_SIZE = 0.01f;
|
||||
static private final float BLACK_BORDER_SIZE = 0.03f;
|
||||
static private final int TEXT_GLOW_SIZE = 6;
|
||||
static private final float TEXT_GLOW_INTENSITY = 3f;
|
||||
static private final float rotCenterToTopCorner = 1.0295630140987000315797369464196f;
|
||||
static private final float rotCenterToBottomCorner = 0.7071067811865475244008443621048f;
|
||||
|
||||
public PermanentView gameCard;
|
||||
public CardPanel attachedToPanel;
|
||||
public List<CardPanel> attachedPanels = new ArrayList();
|
||||
public double tappedAngle = 0;
|
||||
public ScaledImagePanel imagePanel;
|
||||
public ScaledImagePanel overlayPanel;
|
||||
|
||||
private GlowText titleText;
|
||||
private GlowText ptText;
|
||||
private List<CardPanel> imageLoadListeners = new ArrayList(2);
|
||||
private boolean displayEnabled = true;
|
||||
private boolean isAnimationPanel;
|
||||
private int cardXOffset, cardYOffset, cardWidth, cardHeight;
|
||||
|
||||
private boolean isSelected;
|
||||
private boolean showCastingCost;
|
||||
private boolean hasImage = false;
|
||||
private float alpha = 1.0f;
|
||||
|
||||
public CardPanel (PermanentView newGameCard, boolean loadImage) {
|
||||
this.gameCard = newGameCard;
|
||||
|
||||
//for container debug (don't remove)
|
||||
//setBorder(BorderFactory.createLineBorder(Color.green));
|
||||
|
||||
setBackground(Color.black);
|
||||
setOpaque(false);
|
||||
|
||||
titleText = new GlowText();
|
||||
setText(gameCard);
|
||||
titleText.setFont(getFont().deriveFont(Font.BOLD, 13f));
|
||||
titleText.setForeground(Color.white);
|
||||
titleText.setGlow(Color.black, TEXT_GLOW_SIZE, TEXT_GLOW_INTENSITY);
|
||||
titleText.setWrap(true);
|
||||
add(titleText);
|
||||
|
||||
ptText = new GlowText();
|
||||
if (CardUtil.isCreature(gameCard)) {
|
||||
ptText.setText(gameCard.getPower() + "/" + gameCard.getToughness());
|
||||
} else if (CardUtil.isPlaneswalker(gameCard)) {
|
||||
ptText.setText(gameCard.getOriginal().getLoyalty());
|
||||
}
|
||||
ptText.setFont(getFont().deriveFont(Font.BOLD, 13f));
|
||||
ptText.setForeground(Color.white);
|
||||
ptText.setGlow(Color.black, TEXT_GLOW_SIZE, TEXT_GLOW_INTENSITY);
|
||||
add(ptText);
|
||||
|
||||
overlayPanel = new ScaledImagePanel();
|
||||
overlayPanel.setBorder(BorderFactory.createLineBorder(Color.white));
|
||||
add(overlayPanel);
|
||||
overlayPanel.setScaleLarger(true);
|
||||
overlayPanel.setScalingType(ScalingType.nearestNeighbor);
|
||||
overlayPanel.setScalingBlur(true);
|
||||
overlayPanel.setScalingMultiPassType(MultipassType.none);
|
||||
|
||||
//TODO: Image sickness = ImageManager.getSicknessImage();
|
||||
Image sickness = null;
|
||||
overlayPanel.setImage(sickness, sickness);
|
||||
|
||||
imagePanel = new ScaledImagePanel();
|
||||
imagePanel.setBorder(BorderFactory.createLineBorder(Color.white));
|
||||
add(imagePanel);
|
||||
imagePanel.setScaleLarger(true);
|
||||
imagePanel.setScalingType(ScalingType.nearestNeighbor);
|
||||
imagePanel.setScalingBlur(true);
|
||||
imagePanel.setScalingMultiPassType(MultipassType.none);
|
||||
|
||||
if (!loadImage) return;
|
||||
|
||||
Util.threadPool.submit(new Runnable() {
|
||||
public void run () {
|
||||
BufferedImage srcImage = null; //TODO: ImageCache.getImageOriginal(gameCard);
|
||||
tappedAngle = gameCard.isTapped() ? CardPanel.TAPPED_ANGLE : 0;
|
||||
if (srcImage != null) {
|
||||
//setImage(srcImage, ImageUtil.getBlurredImage(srcImage, 3, 1.0f));
|
||||
hasImage = true;
|
||||
setText(gameCard);
|
||||
setImage(srcImage, srcImage);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setText(PermanentView card) {
|
||||
if (hasImage) {
|
||||
titleText.setText("");
|
||||
} else {
|
||||
titleText.setText(card.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void setImage (Image srcImage, Image srcImageBlurred) {
|
||||
synchronized (imagePanel) {
|
||||
imagePanel.setImage(srcImage, srcImageBlurred);
|
||||
repaint();
|
||||
for (CardPanel cardPanel : imageLoadListeners) {
|
||||
cardPanel.setImage(srcImage, srcImageBlurred);
|
||||
cardPanel.repaint();
|
||||
}
|
||||
imageLoadListeners.clear();
|
||||
}
|
||||
layout();
|
||||
}
|
||||
|
||||
public void setImage (final CardPanel panel) {
|
||||
synchronized (panel.imagePanel) {
|
||||
if (panel.imagePanel.hasImage())
|
||||
setImage(panel.imagePanel.srcImage, panel.imagePanel.srcImageBlurred);
|
||||
else
|
||||
panel.imageLoadListeners.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void setScalingType (ScalingType scalingType) {
|
||||
imagePanel.setScalingType(scalingType);
|
||||
}
|
||||
|
||||
public void setDisplayEnabled (boolean displayEnabled) {
|
||||
this.displayEnabled = displayEnabled;
|
||||
}
|
||||
|
||||
public boolean isDisplayEnabled () {
|
||||
return displayEnabled;
|
||||
}
|
||||
|
||||
public void setAnimationPanel (boolean isAnimationPanel) {
|
||||
this.isAnimationPanel = isAnimationPanel;
|
||||
}
|
||||
|
||||
public void setSelected (boolean isSelected) {
|
||||
this.isSelected = isSelected;
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void setAttacking (boolean isAttacking) {
|
||||
//TODO:uncomment
|
||||
//this.gameCard.setAttacking(isAttacking);
|
||||
repaint();
|
||||
}
|
||||
|
||||
public boolean getSelected() {
|
||||
return this.isSelected;
|
||||
}
|
||||
|
||||
public void setShowCastingCost (boolean showCastingCost) {
|
||||
this.showCastingCost = showCastingCost;
|
||||
}
|
||||
|
||||
public void paint (Graphics g) {
|
||||
if (!displayEnabled) return;
|
||||
if (!isValid()) super.validate();
|
||||
Graphics2D g2d = (Graphics2D)g;
|
||||
if (tappedAngle > 0) {
|
||||
g2d = (Graphics2D)g2d.create();
|
||||
float edgeOffset = cardWidth / 2f;
|
||||
g2d.rotate(tappedAngle, cardXOffset + edgeOffset, cardYOffset + cardHeight - edgeOffset);
|
||||
}
|
||||
super.paint(g2d);
|
||||
}
|
||||
|
||||
protected void paintComponent (Graphics g) {
|
||||
Graphics2D g2d = (Graphics2D)g;
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
if (alpha != 1.0f) {
|
||||
AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha);
|
||||
g2d.setComposite(composite);
|
||||
}
|
||||
|
||||
//TODO:uncomment
|
||||
/*
|
||||
if (!hasImage && gameCard.getTableID() > 0) {
|
||||
g2d.setColor(new Color(30,200,200,120));
|
||||
} else {
|
||||
g2d.setColor(new Color(0,0,0,200));
|
||||
}
|
||||
*/
|
||||
g2d.setColor(new Color(30,200,200,120));
|
||||
|
||||
//for debug repainting
|
||||
//g2d.setColor(new Color(MyRandom.random.nextInt(255),MyRandom.random.nextInt(255),MyRandom.random.nextInt(255),150));
|
||||
int cornerSize = Math.max(4, Math.round(cardWidth * ROUNDED_CORNER_SIZE));
|
||||
g2d.fillRoundRect(cardXOffset, cardYOffset, cardWidth, cardHeight, cornerSize, cornerSize);
|
||||
if (isSelected) {
|
||||
//g2d.setColor(new Color(0,250,0,200));
|
||||
g2d.setColor(new Color(200,120,40,200));
|
||||
g2d.fillRoundRect(cardXOffset+1, cardYOffset+1, cardWidth-2, cardHeight-2, cornerSize, cornerSize);
|
||||
}
|
||||
|
||||
//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);
|
||||
}*/
|
||||
|
||||
/*if (isSelected) {
|
||||
g2d.setColor(Color.green);
|
||||
int offset = gameCard.isTapped() ? 1 : 0;
|
||||
for (int i = 1, n = Math.max(1, Math.round(cardWidth * SELECTED_BORDER_SIZE)); i <= n; i++)
|
||||
g2d.drawRoundRect(cardXOffset - i, cardYOffset - i + offset, cardWidth + i * 2 - 1, cardHeight + i * 2 - 1,
|
||||
cornerSize, cornerSize);
|
||||
}*/
|
||||
}
|
||||
|
||||
protected void paintChildren (Graphics g) {
|
||||
super.paintChildren(g);
|
||||
|
||||
if (showCastingCost && !isAnimationPanel && cardWidth < 200 && cardWidth > 60) {
|
||||
//TODO:uncomment
|
||||
/*int width = ManaSymbols.getWidth(gameCard.getManaCost());
|
||||
ManaSymbols.draw(g, gameCard.getManaCost(), cardXOffset + 8, cardHeight - 9);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
public void layout () {
|
||||
int borderSize = Math.round(cardWidth * BLACK_BORDER_SIZE);
|
||||
imagePanel.setLocation(cardXOffset + borderSize, cardYOffset + borderSize);
|
||||
imagePanel.setSize(cardWidth - borderSize * 2, cardHeight - borderSize * 2);
|
||||
|
||||
//TODO: uncomment
|
||||
/*if (gameCard.hasSickness() && gameCard.isCreature() && gameCard.getTableID() != 0) {
|
||||
overlayPanel.setLocation(cardXOffset + borderSize, cardYOffset + borderSize);
|
||||
overlayPanel.setSize(cardWidth - borderSize * 2, cardHeight - borderSize * 2);
|
||||
} else {
|
||||
overlayPanel.setVisible(false);
|
||||
}*/
|
||||
overlayPanel.setVisible(false);
|
||||
|
||||
int fontHeight = Math.round(cardHeight * (27f / 680));
|
||||
boolean showText = (!isAnimationPanel && fontHeight < 12);
|
||||
titleText.setVisible(showText);
|
||||
ptText.setVisible(showText);
|
||||
|
||||
int titleX = Math.round(cardWidth * (20f / 480));
|
||||
int titleY = Math.round(cardHeight * (9f / 680));
|
||||
titleText.setBounds(cardXOffset + titleX, cardYOffset + titleY, cardWidth - titleX, cardHeight);
|
||||
|
||||
Dimension ptSize = ptText.getPreferredSize();
|
||||
ptText.setSize(ptSize.width, ptSize.height);
|
||||
int ptX = Math.round(cardWidth * (420f / 480)) - ptSize.width / 2;
|
||||
int ptY = Math.round(cardHeight * (675f / 680)) - ptSize.height;
|
||||
|
||||
int offsetX = Math.round((CARD_SIZE_FULL.width - cardWidth) / 10.0f);
|
||||
|
||||
ptText.setLocation(cardXOffset + ptX - TEXT_GLOW_SIZE / 2 - offsetX, cardYOffset + ptY - TEXT_GLOW_SIZE / 2);
|
||||
|
||||
if (isAnimationPanel || cardWidth < 200)
|
||||
imagePanel.setScalingType(ScalingType.nearestNeighbor);
|
||||
else
|
||||
imagePanel.setScalingType(ScalingType.bilinear);
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return gameCard.toString();
|
||||
}
|
||||
|
||||
public void setCardBounds (int x, int y, int width, int height) {
|
||||
cardWidth = width;
|
||||
cardHeight = height;
|
||||
int rotCenterX = Math.round(width / 2f);
|
||||
int rotCenterY = height - rotCenterX;
|
||||
int rotCenterToTopCorner = Math.round(width * CardPanel.rotCenterToTopCorner);
|
||||
int rotCenterToBottomCorner = Math.round(width * CardPanel.rotCenterToBottomCorner);
|
||||
int xOffset = rotCenterX - rotCenterToBottomCorner;
|
||||
int yOffset = rotCenterY - rotCenterToTopCorner;
|
||||
cardXOffset = -xOffset;
|
||||
cardYOffset = -yOffset;
|
||||
width = -xOffset + rotCenterX + rotCenterToTopCorner;
|
||||
height = -yOffset + rotCenterY + rotCenterToBottomCorner;
|
||||
setBounds(x + xOffset, y + yOffset, width, height);
|
||||
}
|
||||
|
||||
public void repaint () {
|
||||
Rectangle b = getBounds();
|
||||
JRootPane rootPane = SwingUtilities.getRootPane(this);
|
||||
if (rootPane == null) return;
|
||||
Point p = SwingUtilities.convertPoint(getParent(), b.x, b.y, rootPane);
|
||||
rootPane.repaint(p.x, p.y, b.width, b.height);
|
||||
}
|
||||
|
||||
public int getCardX () {
|
||||
return getX() + cardXOffset;
|
||||
}
|
||||
|
||||
public int getCardY () {
|
||||
return getY() + cardYOffset;
|
||||
}
|
||||
|
||||
public int getCardWidth () {
|
||||
return cardWidth;
|
||||
}
|
||||
|
||||
public int getCardHeight () {
|
||||
return cardHeight;
|
||||
}
|
||||
|
||||
public Point getCardLocation () {
|
||||
Point p = getLocation();
|
||||
p.x += cardXOffset;
|
||||
p.y += cardYOffset;
|
||||
return p;
|
||||
}
|
||||
|
||||
public PermanentView getCard() {
|
||||
return this.gameCard;
|
||||
}
|
||||
|
||||
public void setCard(PermanentView card) {
|
||||
if (CardUtil.isCreature(card) && CardUtil.isPlaneswalker(card)) {
|
||||
ptText.setText(card.getPower() + "/" + card.getToughness() + " (" + card.getLoyalty() + ")");
|
||||
} else if (CardUtil.isCreature(card)) {
|
||||
ptText.setText(card.getPower() + "/" + card.getToughness());
|
||||
} else if (CardUtil.isPlaneswalker(card)) {
|
||||
ptText.setText(card.getLoyalty());
|
||||
} else {
|
||||
ptText.setText("");
|
||||
}
|
||||
setText(card);
|
||||
this.gameCard = card;
|
||||
//TODO: uncomment
|
||||
/*if (gameCard.hasSickness() && gameCard.isCreature() && gameCard.getTableID() != 0) {
|
||||
overlayPanel.setVisible(true);
|
||||
} else {
|
||||
overlayPanel.setVisible(false);
|
||||
}*/
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void setAlpha(float alpha) {
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
return alpha;
|
||||
}
|
||||
|
||||
public int getCardXOffset() {
|
||||
return cardXOffset;
|
||||
}
|
||||
|
||||
public int getCardYOffset() {
|
||||
return cardYOffset;
|
||||
}
|
||||
|
||||
public void updateImage() {
|
||||
if (!hasImage) {
|
||||
Util.threadPool.submit(new Runnable() {
|
||||
public void run () {
|
||||
//TODO: BufferedImage srcImage = ImageCache.getImageOriginal(gameCard);
|
||||
BufferedImage srcImage = null;
|
||||
tappedAngle = gameCard.isTapped() ? CardPanel.TAPPED_ANGLE : 0;
|
||||
if (srcImage != null) {
|
||||
hasImage = true;
|
||||
setText(gameCard);
|
||||
setImage(srcImage, srcImage);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.LineBreakMeasurer;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.text.AttributedString;
|
||||
import java.text.BreakIterator;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
|
||||
public class GlowText extends JLabel {
|
||||
private static final long serialVersionUID = 1827677946939348001L;
|
||||
private int glowSize;
|
||||
@SuppressWarnings("unused")
|
||||
private float glowIntensity;
|
||||
private Color glowColor;
|
||||
private boolean wrap;
|
||||
private int lineCount = 0;
|
||||
|
||||
public void setGlow (Color glowColor, int size, float intensity) {
|
||||
this.glowColor = glowColor;
|
||||
this.glowSize = size;
|
||||
this.glowIntensity = intensity;
|
||||
}
|
||||
|
||||
public void setWrap (boolean wrap) {
|
||||
this.wrap = wrap;
|
||||
}
|
||||
|
||||
public Dimension getPreferredSize () {
|
||||
Dimension size = super.getPreferredSize();
|
||||
size.width += glowSize;
|
||||
size.height += glowSize / 2;
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setText (String text) {
|
||||
super.setText(text);
|
||||
}
|
||||
|
||||
public void paint (Graphics g) {
|
||||
if (getText().length() == 0) return;
|
||||
|
||||
Graphics2D g2d = (Graphics2D)g;
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
|
||||
Dimension size = getSize();
|
||||
int textX = 0, textY = 0;
|
||||
int wrapWidth = Math.max(0, wrap ? size.width - glowSize : Integer.MAX_VALUE);
|
||||
|
||||
AttributedString attributedString = new AttributedString(getText());
|
||||
attributedString.addAttribute(TextAttribute.FONT, getFont());
|
||||
AttributedCharacterIterator charIterator = attributedString.getIterator();
|
||||
FontRenderContext fontContext = g2d.getFontRenderContext();
|
||||
|
||||
LineBreakMeasurer measurer = new LineBreakMeasurer(charIterator, BreakIterator.getWordInstance(Locale.ENGLISH), fontContext);
|
||||
lineCount = 0;
|
||||
while (measurer.getPosition() < charIterator.getEndIndex()) {
|
||||
//TextLayout textLayout = measurer.nextLayout(wrapWidth);
|
||||
lineCount++;
|
||||
if (lineCount > 2) break;
|
||||
}
|
||||
charIterator.first();
|
||||
// Use char wrap if word wrap would cause more than two lines of text.
|
||||
if (lineCount > 2)
|
||||
measurer = new LineBreakMeasurer(charIterator, BreakIterator.getCharacterInstance(Locale.ENGLISH), fontContext);
|
||||
else
|
||||
measurer.setPosition(0);
|
||||
while (measurer.getPosition() < charIterator.getEndIndex()) {
|
||||
TextLayout textLayout = measurer.nextLayout(wrapWidth);
|
||||
float ascent = textLayout.getAscent();
|
||||
textY += ascent; // Move down to baseline.
|
||||
|
||||
g2d.setColor(glowColor);
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f));
|
||||
textLayout.draw(g2d, textX + glowSize / 2 + 1, textY + glowSize / 2 - 1);
|
||||
textLayout.draw(g2d, textX + glowSize / 2 + 1, textY + glowSize / 2 + 1);
|
||||
textLayout.draw(g2d, textX + glowSize / 2 - 1, textY + glowSize / 2 - 1);
|
||||
textLayout.draw(g2d, textX + glowSize / 2 - 1, textY + glowSize / 2 + 1);
|
||||
|
||||
g2d.setColor(getForeground());
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
|
||||
textLayout.draw(g2d, textX + glowSize / 2, textY + glowSize / 2);
|
||||
|
||||
textY += textLayout.getDescent() + textLayout.getLeading(); // Move down to top of next line.
|
||||
}
|
||||
}
|
||||
|
||||
public int getLineCount() {
|
||||
return this.lineCount;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.mage.card.constants.Constants;
|
||||
|
||||
public class ManaSymbols {
|
||||
private static final Logger log = Logger.getLogger(ManaSymbols.class);
|
||||
static private final Map<String, Image> manaImages = new HashMap<String, Image>();
|
||||
static private Pattern replaceSymbolsPattern = Pattern.compile("\\{([^}/]*)/?([^}]*)\\}");
|
||||
|
||||
static public void loadImages () {
|
||||
String[] symbols = new String[] {"0", "1", "10", "11", "12", "15", "16", "2", "3", "4", "5", "6", "7", "8", "9", "B", "BG",
|
||||
"BR", "G", "GU", "GW", "R", "RG", "RW", "S", "T", "U", "UB", "UR", "W", "WB", "WU", "X", "Y", "Z", "slash"};
|
||||
//TODO: replace by downloading
|
||||
for (String symbol : symbols)
|
||||
manaImages.put(symbol, UI.getImageIcon(Constants.RESOURCE_PATH_MANA + "/" + symbol + ".png").getImage());
|
||||
}
|
||||
|
||||
static public void draw (Graphics g, String manaCost, int x, int y) {
|
||||
if (manaCost.length() == 0) return;
|
||||
manaCost = manaCost.replace("\\", "");
|
||||
manaCost = UI.getDisplayManaCost(manaCost);
|
||||
StringTokenizer tok = new StringTokenizer(manaCost, " ");
|
||||
while (tok.hasMoreTokens()) {
|
||||
String symbol = tok.nextToken().substring(0);
|
||||
Image image = manaImages.get(symbol);
|
||||
if (image == null) {
|
||||
log.error("Symbol not recognized \"" + symbol + "\" in mana cost: " + manaCost);
|
||||
continue;
|
||||
}
|
||||
g.drawImage(image, x, y, null);
|
||||
x += symbol.length() > 2 ? 10 : 12; // slash.png is only 10 pixels wide.
|
||||
}
|
||||
}
|
||||
|
||||
static public int getWidth (String manaCost) {
|
||||
int width = 0;
|
||||
manaCost = manaCost.replace("\\", "");
|
||||
StringTokenizer tok = new StringTokenizer(manaCost, " ");
|
||||
while (tok.hasMoreTokens()) {
|
||||
String symbol = tok.nextToken().substring(0);
|
||||
width += symbol.length() > 2 ? 10 : 12; // slash.png is only 10 pixels wide.
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
static public synchronized String replaceSymbolsWithHTML (String value, boolean small) {
|
||||
if (small)
|
||||
return replaceSymbolsPattern.matcher(value).replaceAll("<img src='file:images/symbols-11/$1$2.png' width=11 height=11>");
|
||||
else {
|
||||
value = value.replace("{slash}", "<img src='file:images/symbols-13/slash.png' width=10 height=13>");
|
||||
return replaceSymbolsPattern.matcher(value).replaceAll("<img src='file:images/symbols-13/$1$2.png' width=13 height=13>");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
public class ScaledImagePanel extends JPanel {
|
||||
private static final long serialVersionUID = -1523279873208605664L;
|
||||
public volatile Image srcImage;
|
||||
public volatile Image srcImageBlurred;
|
||||
|
||||
private ScalingType scalingType = ScalingType.bilinear;
|
||||
private boolean scaleLarger;
|
||||
private MultipassType multiPassType = MultipassType.bilinear;
|
||||
private boolean blur;
|
||||
|
||||
public ScaledImagePanel () {
|
||||
super(false);
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
public void setImage (Image srcImage, Image srcImageBlurred) {
|
||||
this.srcImage = srcImage;
|
||||
this.srcImageBlurred = srcImageBlurred;
|
||||
}
|
||||
|
||||
public void clearImage () {
|
||||
srcImage = null;
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void setScalingMultiPassType (MultipassType multiPassType) {
|
||||
this.multiPassType = multiPassType;
|
||||
}
|
||||
|
||||
public void setScalingType (ScalingType scalingType) {
|
||||
this.scalingType = scalingType;
|
||||
}
|
||||
|
||||
public void setScalingBlur (boolean blur) {
|
||||
this.blur = blur;
|
||||
}
|
||||
|
||||
public void setScaleLarger (boolean scaleLarger) {
|
||||
this.scaleLarger = scaleLarger;
|
||||
}
|
||||
|
||||
public boolean hasImage () {
|
||||
return srcImage != null;
|
||||
}
|
||||
|
||||
private ScalingInfo getScalingInfo () {
|
||||
int panelWidth = getWidth();
|
||||
int panelHeight = getHeight();
|
||||
int srcWidth = srcImage.getWidth(null);
|
||||
int srcHeight = srcImage.getHeight(null);
|
||||
int targetWidth = srcWidth;
|
||||
int targetHeight = srcHeight;
|
||||
if (scaleLarger || srcWidth > panelWidth || srcHeight > panelHeight) {
|
||||
targetWidth = Math.round(panelHeight * (srcWidth / (float)srcHeight));
|
||||
if (targetWidth > panelWidth) {
|
||||
targetHeight = Math.round(panelWidth * (srcHeight / (float)srcWidth));
|
||||
targetWidth = panelWidth;
|
||||
} else
|
||||
targetHeight = panelHeight;
|
||||
}
|
||||
ScalingInfo info = new ScalingInfo();
|
||||
info.targetWidth = targetWidth;
|
||||
info.targetHeight = targetHeight;
|
||||
info.srcWidth = srcWidth;
|
||||
info.srcHeight = srcHeight;
|
||||
info.x = panelWidth / 2 - targetWidth / 2;
|
||||
info.y = panelHeight / 2 - targetHeight / 2;
|
||||
return info;
|
||||
}
|
||||
|
||||
public void paint (Graphics g) {
|
||||
if (srcImage == null) return;
|
||||
|
||||
Graphics2D g2 = (Graphics2D)g.create();
|
||||
ScalingInfo info = getScalingInfo();
|
||||
|
||||
switch (scalingType) {
|
||||
case nearestNeighbor:
|
||||
scaleWithDrawImage(g2, info, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
|
||||
break;
|
||||
case bilinear:
|
||||
scaleWithDrawImage(g2, info, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
break;
|
||||
case bicubic:
|
||||
scaleWithDrawImage(g2, info, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
break;
|
||||
case areaAveraging:
|
||||
scaleWithGetScaledInstance(g2, info, Image.SCALE_AREA_AVERAGING);
|
||||
break;
|
||||
case replicate:
|
||||
scaleWithGetScaledInstance(g2, info, Image.SCALE_REPLICATE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void scaleWithGetScaledInstance (Graphics2D g2, ScalingInfo info, int hints) {
|
||||
Image srcImage = getSourceImage(info);
|
||||
Image scaledImage = srcImage.getScaledInstance(info.targetWidth, info.targetHeight, hints);
|
||||
g2.drawImage(scaledImage, info.x, info.y, null);
|
||||
}
|
||||
|
||||
private void scaleWithDrawImage (Graphics2D g2, ScalingInfo info, Object hint) {
|
||||
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
|
||||
|
||||
int tempDestWidth = info.srcWidth / 2, tempDestHeight = info.srcHeight / 2;
|
||||
if (tempDestWidth < info.targetWidth) tempDestWidth = info.targetWidth;
|
||||
if (tempDestHeight < info.targetHeight) tempDestHeight = info.targetHeight;
|
||||
|
||||
Image srcImage = getSourceImage(info);
|
||||
|
||||
// If not doing multipass or multipass only needs a single pass, just scale it once directly to the panel surface.
|
||||
if (multiPassType == MultipassType.none || (tempDestWidth == info.targetWidth && tempDestHeight == info.targetHeight)) {
|
||||
g2.drawImage(srcImage, info.x, info.y, info.targetWidth, info.targetHeight, null);
|
||||
return;
|
||||
}
|
||||
|
||||
BufferedImage tempImage = new BufferedImage(tempDestWidth, tempDestHeight, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g2temp = tempImage.createGraphics();
|
||||
switch (multiPassType) {
|
||||
case nearestNeighbor:
|
||||
g2temp.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
|
||||
break;
|
||||
case bilinear:
|
||||
g2temp.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
break;
|
||||
case bicubic:
|
||||
g2temp.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
break;
|
||||
}
|
||||
// Render first pass from image to temp.
|
||||
g2temp.drawImage(srcImage, 0, 0, tempDestWidth, tempDestHeight, null);
|
||||
// Render passes between the first and last pass.
|
||||
int tempSrcWidth = tempDestWidth;
|
||||
int tempSrcHeight = tempDestHeight;
|
||||
while (true) {
|
||||
if (tempDestWidth > info.targetWidth) {
|
||||
tempDestWidth = tempDestWidth / 2;
|
||||
if (tempDestWidth < info.targetWidth) tempDestWidth = info.targetWidth;
|
||||
}
|
||||
|
||||
if (tempDestHeight > info.targetHeight) {
|
||||
tempDestHeight = tempDestHeight / 2;
|
||||
if (tempDestHeight < info.targetHeight) tempDestHeight = info.targetHeight;
|
||||
}
|
||||
|
||||
if (tempDestWidth == info.targetWidth && tempDestHeight == info.targetHeight) break;
|
||||
|
||||
g2temp.drawImage(tempImage, 0, 0, tempDestWidth, tempDestHeight, 0, 0, tempSrcWidth, tempSrcHeight, null);
|
||||
|
||||
tempSrcWidth = tempDestWidth;
|
||||
tempSrcHeight = tempDestHeight;
|
||||
}
|
||||
g2temp.dispose();
|
||||
// Render last pass from temp to panel surface.
|
||||
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
|
||||
g2.drawImage(tempImage, info.x, info.y, info.x + info.targetWidth, info.y + info.targetHeight, 0, 0, tempSrcWidth,
|
||||
tempSrcHeight, null);
|
||||
}
|
||||
|
||||
private Image getSourceImage (ScalingInfo info) {
|
||||
if (!blur || srcImageBlurred == null) return srcImage;
|
||||
if (info.srcWidth / 2 < info.targetWidth || info.srcHeight / 2 < info.targetHeight) return srcImage;
|
||||
return srcImageBlurred;
|
||||
}
|
||||
|
||||
static private class ScalingInfo {
|
||||
public int targetWidth;
|
||||
public int targetHeight;
|
||||
public int srcWidth;
|
||||
public int srcHeight;
|
||||
public int x;
|
||||
public int y;
|
||||
}
|
||||
|
||||
static public enum MultipassType {
|
||||
none, nearestNeighbor, bilinear, bicubic
|
||||
}
|
||||
|
||||
static public enum ScalingType {
|
||||
nearestNeighbor, replicate, bilinear, bicubic, areaAveraging
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Font;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Point;
|
||||
import java.awt.Toolkit;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.ViewportLayout;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.TitledBorder;
|
||||
import javax.swing.text.Element;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.text.View;
|
||||
import javax.swing.text.ViewFactory;
|
||||
import javax.swing.text.html.HTML;
|
||||
import javax.swing.text.html.HTMLEditorKit;
|
||||
import javax.swing.text.html.ImageView;
|
||||
|
||||
/**
|
||||
* UI utility functions.
|
||||
*/
|
||||
public class UI {
|
||||
static private Hashtable<URL, Image> imageCache = new Hashtable<URL, Image>();
|
||||
|
||||
static public JToggleButton getToggleButton () {
|
||||
JToggleButton button = new JToggleButton();
|
||||
button.setMargin(new Insets(2, 4, 2, 4));
|
||||
return button;
|
||||
}
|
||||
|
||||
static public JButton getButton () {
|
||||
JButton button = new JButton();
|
||||
button.setMargin(new Insets(2, 4, 2, 4));
|
||||
return button;
|
||||
}
|
||||
|
||||
static public void setTitle (JPanel panel, String title) {
|
||||
Border border = panel.getBorder();
|
||||
if (border instanceof TitledBorder) {
|
||||
((TitledBorder)panel.getBorder()).setTitle(title);
|
||||
panel.repaint();
|
||||
} else
|
||||
panel.setBorder(BorderFactory.createTitledBorder(title));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
static public URL getFileURL (String path) {
|
||||
File file = new File(path);
|
||||
if (file.exists()) {
|
||||
try {
|
||||
return file.toURL();
|
||||
} catch (MalformedURLException ignored) {
|
||||
}
|
||||
}
|
||||
return UI.class.getResource(path);
|
||||
}
|
||||
|
||||
static public ImageIcon getImageIcon (String path) {
|
||||
try {
|
||||
InputStream stream;
|
||||
stream = UI.class.getResourceAsStream(path);
|
||||
if (stream == null && new File(path).exists()) stream = new FileInputStream(path);
|
||||
if (stream == null) throw new RuntimeException("Image not found: " + path);
|
||||
byte[] data = new byte[stream.available()];
|
||||
stream.read(data);
|
||||
return new ImageIcon(data);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException("Error reading image: " + path);
|
||||
}
|
||||
}
|
||||
|
||||
static public void setHTMLEditorKit (JEditorPane editorPane) {
|
||||
editorPane.getDocument().putProperty("imageCache", imageCache); // Read internally by ImageView, but never written.
|
||||
// Extend all this shit to cache images.
|
||||
editorPane.setEditorKit(new HTMLEditorKit() {
|
||||
private static final long serialVersionUID = -54602188235105448L;
|
||||
|
||||
public ViewFactory getViewFactory () {
|
||||
return new HTMLFactory() {
|
||||
public View create (Element elem) {
|
||||
Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
|
||||
if (o instanceof HTML.Tag) {
|
||||
HTML.Tag kind = (HTML.Tag)o;
|
||||
if (kind == HTML.Tag.IMG) return new ImageView(elem) {
|
||||
public URL getImageURL () {
|
||||
URL url = super.getImageURL();
|
||||
// Put an image into the cache to be read by other ImageView methods.
|
||||
if (url != null && imageCache.get(url) == null)
|
||||
imageCache.put(url, Toolkit.getDefaultToolkit().createImage(url));
|
||||
return url;
|
||||
}
|
||||
};
|
||||
}
|
||||
return super.create(elem);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static public void setVerticalScrollingView (JScrollPane scrollPane, final Component view) {
|
||||
final JViewport viewport = new JViewport();
|
||||
viewport.setLayout(new ViewportLayout() {
|
||||
private static final long serialVersionUID = 7701568740313788935L;
|
||||
public void layoutContainer (Container parent) {
|
||||
viewport.setViewPosition(new Point(0, 0));
|
||||
Dimension viewportSize = viewport.getSize();
|
||||
int width = viewportSize.width;
|
||||
int height = Math.max(view.getPreferredSize().height, viewportSize.height);
|
||||
viewport.setViewSize(new Dimension(width, height));
|
||||
}
|
||||
});
|
||||
viewport.setView(view);
|
||||
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
scrollPane.setViewport(viewport);
|
||||
}
|
||||
|
||||
static public String getDisplayManaCost (String manaCost) {
|
||||
manaCost = manaCost.replace("/", "{slash}");
|
||||
// A pipe in the cost means "process left of the pipe as the card color, but display right of the pipe as the cost".
|
||||
int pipePosition = manaCost.indexOf("{|}");
|
||||
if (pipePosition != -1) manaCost = manaCost.substring(pipePosition + 3);
|
||||
return manaCost;
|
||||
}
|
||||
|
||||
static public void invokeLater (Runnable runnable) {
|
||||
EventQueue.invokeLater(runnable);
|
||||
}
|
||||
|
||||
static public void invokeAndWait (Runnable runnable) {
|
||||
if (EventQueue.isDispatchThread()) {
|
||||
runnable.run();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
EventQueue.invokeAndWait(runnable);
|
||||
} catch (InterruptedException ex) {
|
||||
} catch (InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static public void setSystemLookAndFeel () {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception ex) {
|
||||
System.err.println("Error setting look and feel:");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
static public void setDefaultFont (Font font) {
|
||||
for (Object key : Collections.list(UIManager.getDefaults().keys())) {
|
||||
Object value = UIManager.get(key);
|
||||
if (value instanceof javax.swing.plaf.FontUIResource) UIManager.put(key, font);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package org.mage.card.arcane;
|
||||
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Robot;
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public class Util {
|
||||
static public final boolean isMac = System.getProperty("os.name").toLowerCase().indexOf("mac") != -1;
|
||||
static public final boolean isWindows = System.getProperty("os.name").toLowerCase().indexOf("windows") == -1;
|
||||
|
||||
static public Robot robot;
|
||||
static {
|
||||
try {
|
||||
new Robot();
|
||||
} catch (AWTException ex) {
|
||||
throw new RuntimeException("Error creating robot.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
static public ThreadPoolExecutor threadPool;
|
||||
static private int threadCount;
|
||||
static {
|
||||
threadPool = new ThreadPoolExecutor(4, 4, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), new ThreadFactory() {
|
||||
public Thread newThread (Runnable runnable) {
|
||||
threadCount++;
|
||||
Thread thread = new Thread(runnable, "Util" + threadCount);
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
}
|
||||
});
|
||||
threadPool.prestartAllCoreThreads();
|
||||
}
|
||||
|
||||
public static void broadcast (byte[] data, int port) throws IOException {
|
||||
DatagramSocket socket = new DatagramSocket();
|
||||
broadcast(socket, data, port, NetworkInterface.getNetworkInterfaces());
|
||||
socket.close();
|
||||
}
|
||||
|
||||
private static void broadcast (DatagramSocket socket, byte[] data, int port, Enumeration<NetworkInterface> ifaces)
|
||||
throws IOException {
|
||||
for (NetworkInterface iface : Collections.list(ifaces)) {
|
||||
for (InetAddress address : Collections.list(iface.getInetAddresses())) {
|
||||
if (!address.isSiteLocalAddress()) continue;
|
||||
// Java 1.5 doesn't support getting the subnet mask, so try the two most common.
|
||||
byte[] ip = address.getAddress();
|
||||
ip[3] = -1; // 255.255.255.0
|
||||
socket.send(new DatagramPacket(data, data.length, InetAddress.getByAddress(ip), port));
|
||||
ip[2] = -1; // 255.255.0.0
|
||||
socket.send(new DatagramPacket(data, data.length, InetAddress.getByAddress(ip), port));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public void sleep (int millis) {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
static public boolean classExists (String className) {
|
||||
try {
|
||||
Class.forName(className);
|
||||
return true;
|
||||
} catch (ClassNotFoundException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static public void wait (Object lock) {
|
||||
synchronized (lock) {
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void invokeAndWait (Runnable runnable) {
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(runnable);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Error invoking runnable in UI thread.", ex);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package org.mage.card.constants;
|
||||
|
||||
public class Constants {
|
||||
public static final String RESOURCE_PATH = "/images";
|
||||
public static final String RESOURCE_PATH_MANA = resourcePath("mana");
|
||||
|
||||
|
||||
/**
|
||||
* Build resource path.
|
||||
*
|
||||
* @param folder
|
||||
* @return
|
||||
*/
|
||||
private static String resourcePath(String folder) {
|
||||
return RESOURCE_PATH + "/" + folder;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue