mirror of
https://github.com/correl/mage.git
synced 2025-01-12 19:25:44 +00:00
Merge pull request #2030 from draxdyn/performance
Improve GUI performance
This commit is contained in:
commit
d220c739a8
19 changed files with 673 additions and 376 deletions
|
@ -119,6 +119,7 @@ import mage.client.table.TablesPane;
|
||||||
import mage.client.tournament.TournamentPane;
|
import mage.client.tournament.TournamentPane;
|
||||||
import mage.client.util.EDTExceptionHandler;
|
import mage.client.util.EDTExceptionHandler;
|
||||||
import mage.client.util.GUISizeHelper;
|
import mage.client.util.GUISizeHelper;
|
||||||
|
import mage.client.util.ImageCaches;
|
||||||
import mage.client.util.SettingsManager;
|
import mage.client.util.SettingsManager;
|
||||||
import mage.client.util.SystemUtil;
|
import mage.client.util.SystemUtil;
|
||||||
import mage.client.util.audio.MusicPlayer;
|
import mage.client.util.audio.MusicPlayer;
|
||||||
|
@ -1470,6 +1471,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void changeGUISize() {
|
public void changeGUISize() {
|
||||||
|
ImageCaches.flush();
|
||||||
setGUISize();
|
setGUISize();
|
||||||
Plugins.getInstance().changeGUISize();
|
Plugins.getInstance().changeGUISize();
|
||||||
CountryUtil.changeGUISize();
|
CountryUtil.changeGUISize();
|
||||||
|
|
|
@ -54,6 +54,7 @@ import mage.client.plugins.impl.Plugins;
|
||||||
import mage.client.util.ImageHelper;
|
import mage.client.util.ImageHelper;
|
||||||
import mage.constants.EnlargeMode;
|
import mage.constants.EnlargeMode;
|
||||||
import org.jdesktop.swingx.JXPanel;
|
import org.jdesktop.swingx.JXPanel;
|
||||||
|
import mage.client.util.TransformedImageCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for displaying big image of the card
|
* Class for displaying big image of the card
|
||||||
|
@ -103,7 +104,13 @@ public class BigCard extends JComponent {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCard(UUID cardId, EnlargeMode enlargeMode, Image image, List<String> strings) {
|
public void setCard(UUID cardId, EnlargeMode enlargeMode, Image image, List<String> strings, boolean rotate) {
|
||||||
|
if (rotate && getWidth() > getHeight()) {
|
||||||
|
image = TransformedImageCache.getRotatedResizedImage((BufferedImage)image, getHeight(), getWidth(), Math.toRadians(90.0));
|
||||||
|
} else {
|
||||||
|
image = TransformedImageCache.getResizedImage((BufferedImage)image, getWidth(), getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
if (this.cardId == null || !enlargeMode.equals(this.enlargeMode) || !this.cardId.equals(cardId)) {
|
if (this.cardId == null || !enlargeMode.equals(this.enlargeMode) || !this.cardId.equals(cardId)) {
|
||||||
if (this.panel != null) {
|
if (this.panel != null) {
|
||||||
remove(this.panel);
|
remove(this.panel);
|
||||||
|
|
|
@ -374,7 +374,7 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis
|
||||||
@Override
|
@Override
|
||||||
public void mouseMoved(MouseEvent arg0) {
|
public void mouseMoved(MouseEvent arg0) {
|
||||||
this.bigCard.showTextComponent();
|
this.bigCard.showTextComponent();
|
||||||
this.bigCard.setCard(card.getId(), EnlargeMode.NORMAL, image, getRules());
|
this.bigCard.setCard(card.getId(), EnlargeMode.NORMAL, image, getRules(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -56,6 +56,8 @@ import mage.client.util.ImageHelper;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.view.CounterView;
|
import mage.view.CounterView;
|
||||||
import mage.view.PermanentView;
|
import mage.view.PermanentView;
|
||||||
|
import org.mage.plugins.card.images.ImageCache;
|
||||||
|
import mage.client.util.TransformedImageCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -215,7 +217,7 @@ public class Permanent extends Card {
|
||||||
Graphics2D g = (Graphics2D) tappedImage.getGraphics();
|
Graphics2D g = (Graphics2D) tappedImage.getGraphics();
|
||||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
|
||||||
g.drawImage(this.createImage(ImageHelper.rotate(small, dimension)), 0, 0, this);
|
g.drawImage(TransformedImageCache.getRotatedResizedImage(small, dimension.frameWidth, dimension.frameHeight, Math.toRadians(90.0)), 0, 0, this);
|
||||||
|
|
||||||
g.dispose();
|
g.dispose();
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,9 +139,7 @@ public class ColorPane extends JEditorPane {
|
||||||
if (hyperlinkEnabled) {
|
if (hyperlinkEnabled) {
|
||||||
text = text.replaceAll("(<font color=[^>]*>([^<]*)) (\\[[0-9a-fA-F]*\\])</font>", "<a href=\"#$2\">$1</a> $3");
|
text = text.replaceAll("(<font color=[^>]*>([^<]*)) (\\[[0-9a-fA-F]*\\])</font>", "<a href=\"#$2\">$1</a> $3");
|
||||||
}
|
}
|
||||||
setEditable(true);
|
|
||||||
kit.insertHTML(doc, doc.getLength(), text, 0, 0, null);
|
kit.insertHTML(doc, doc.getLength(), text, 0, 0, null);
|
||||||
setEditable(false);
|
|
||||||
int len = getDocument().getLength();
|
int len = getDocument().getLength();
|
||||||
setCaretPosition(len);
|
setCaretPosition(len);
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
package mage.client.components;
|
package mage.client.components;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.MapMaker;
|
||||||
import java.awt.BasicStroke;
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
import mage.client.util.ImageCaches;
|
||||||
import org.jdesktop.swingx.graphics.GraphicsUtilities;
|
import org.jdesktop.swingx.graphics.GraphicsUtilities;
|
||||||
import org.jdesktop.swingx.graphics.ShadowRenderer;
|
import org.jdesktop.swingx.graphics.ShadowRenderer;
|
||||||
|
|
||||||
|
@ -21,23 +27,145 @@ public class MageRoundPane extends JPanel {
|
||||||
|
|
||||||
private int X_OFFSET = 30;
|
private int X_OFFSET = 30;
|
||||||
private int Y_OFFSET = 30;
|
private int Y_OFFSET = 30;
|
||||||
private BufferedImage shadow = null;
|
|
||||||
private final Color defaultBackgroundColor = new Color(255, 255, 255, 200);
|
private final Color defaultBackgroundColor = new Color(255, 255, 255, 200);
|
||||||
private Color backgroundColor = defaultBackgroundColor;
|
private Color backgroundColor = defaultBackgroundColor;
|
||||||
private final int alpha = 0;
|
private final int alpha = 0;
|
||||||
|
private static Map<ShadowKey, BufferedImage> SHADOW_IMAGE_CACHE;
|
||||||
|
private static Map<Key, BufferedImage> IMAGE_CACHE;
|
||||||
|
|
||||||
|
static {
|
||||||
|
SHADOW_IMAGE_CACHE = ImageCaches.register(new MapMaker().softValues().makeComputingMap(new Function<ShadowKey, BufferedImage>() {
|
||||||
|
@Override
|
||||||
|
public BufferedImage apply(ShadowKey key) {
|
||||||
|
return createShadowImage(key);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
IMAGE_CACHE = ImageCaches.register(new MapMaker().softValues().makeComputingMap(new Function<Key, BufferedImage>() {
|
||||||
|
@Override
|
||||||
|
public BufferedImage apply(Key key) {
|
||||||
|
return createImage(key);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static class ShadowKey
|
||||||
|
{
|
||||||
|
final int width;
|
||||||
|
final int height;
|
||||||
|
|
||||||
|
public ShadowKey(int width, int height) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 7;
|
||||||
|
hash = 97 * hash + this.width;
|
||||||
|
hash = 97 * hash + this.height;
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final ShadowKey other = (ShadowKey) obj;
|
||||||
|
if (this.width != other.width) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.height != other.height) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static class Key
|
||||||
|
{
|
||||||
|
final int width;
|
||||||
|
final int height;
|
||||||
|
final int xOffset;
|
||||||
|
final int yOffset;
|
||||||
|
final Color backgroundColor;
|
||||||
|
|
||||||
|
public Key(int width, int height, int xOffset, int yOffset, Color backgroundColor) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.xOffset = xOffset;
|
||||||
|
this.yOffset = yOffset;
|
||||||
|
this.backgroundColor = backgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 5;
|
||||||
|
hash = 59 * hash + this.width;
|
||||||
|
hash = 59 * hash + this.height;
|
||||||
|
hash = 59 * hash + this.xOffset;
|
||||||
|
hash = 59 * hash + this.yOffset;
|
||||||
|
hash = 59 * hash + Objects.hashCode(this.backgroundColor);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Key other = (Key) obj;
|
||||||
|
if (this.width != other.width) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.height != other.height) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.xOffset != other.xOffset) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.yOffset != other.yOffset) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Objects.equals(this.backgroundColor, other.backgroundColor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintComponent(Graphics g) {
|
protected void paintComponent(Graphics g) {
|
||||||
int x = X_OFFSET;
|
g.drawImage(IMAGE_CACHE.get(new Key(getWidth(), getHeight(), X_OFFSET, Y_OFFSET, backgroundColor)), 0, 0, null);
|
||||||
int y = Y_OFFSET;
|
}
|
||||||
int w = getWidth() - 2 * X_OFFSET;
|
|
||||||
int h = getHeight() - 2 * Y_OFFSET;
|
private static BufferedImage createImage(Key key) {
|
||||||
|
int x = key.xOffset;
|
||||||
|
int y = key.yOffset;
|
||||||
|
int w = key.width - 2 * key.xOffset;
|
||||||
|
int h = key.height - 2 * key.yOffset;
|
||||||
int arc = 10;
|
int arc = 10;
|
||||||
|
|
||||||
Graphics2D g2 = (Graphics2D) g.create();
|
BufferedImage image = GraphicsUtilities.createCompatibleTranslucentImage(key.width, key.height);
|
||||||
|
Graphics2D g2 = image.createGraphics();
|
||||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
|
||||||
if (shadow != null) {
|
BufferedImage shadow = SHADOW_IMAGE_CACHE.get(new ShadowKey(w, h));
|
||||||
|
|
||||||
|
{
|
||||||
int xOffset = (shadow.getWidth() - w) / 2;
|
int xOffset = (shadow.getWidth() - w) / 2;
|
||||||
int yOffset = (shadow.getHeight() - h) / 2;
|
int yOffset = (shadow.getHeight() - h) / 2;
|
||||||
g2.drawImage(shadow, x - xOffset, y - yOffset, null);
|
g2.drawImage(shadow, x - xOffset, y - yOffset, null);
|
||||||
|
@ -54,7 +182,7 @@ public class MageRoundPane extends JPanel {
|
||||||
g2.fillRoundRect(x, y, w, h, arc, arc);
|
g2.fillRoundRect(x, y, w, h, arc, arc);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
g2.setColor(backgroundColor);
|
g2.setColor(key.backgroundColor);
|
||||||
g2.fillRoundRect(x, y, w, h, arc, arc);
|
g2.fillRoundRect(x, y, w, h, arc, arc);
|
||||||
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -66,6 +194,7 @@ public class MageRoundPane extends JPanel {
|
||||||
// ////////////////////////////////////////////////////////////////
|
// ////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
g2.dispose();
|
g2.dispose();
|
||||||
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setXOffset(int x_offset) {
|
public void setXOffset(int x_offset) {
|
||||||
|
@ -76,24 +205,21 @@ public class MageRoundPane extends JPanel {
|
||||||
Y_OFFSET = y_offset;
|
Y_OFFSET = y_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static BufferedImage createShadowImage(ShadowKey key) {
|
||||||
public void setBounds(int x, int y, int width, int height) {
|
int w = key.width;
|
||||||
super.setBounds(x, y, width, height);
|
int h = key.height;
|
||||||
|
|
||||||
int w = getWidth() - 2 * X_OFFSET;
|
|
||||||
int h = getHeight() - 2 * Y_OFFSET;
|
|
||||||
int arc = 10;
|
int arc = 10;
|
||||||
int shadowSize = 50;
|
int shadowSize = 50;
|
||||||
|
|
||||||
shadow = GraphicsUtilities.createCompatibleTranslucentImage(w, h);
|
BufferedImage base = GraphicsUtilities.createCompatibleTranslucentImage(w, h);
|
||||||
Graphics2D g2 = shadow.createGraphics();
|
Graphics2D g2 = base.createGraphics();
|
||||||
g2.setColor(Color.WHITE);
|
g2.setColor(Color.WHITE);
|
||||||
g2.fillRoundRect(0, 0, w, h, arc, arc);
|
g2.fillRoundRect(0, 0, w, h, arc, arc);
|
||||||
g2.dispose();
|
g2.dispose();
|
||||||
|
|
||||||
ShadowRenderer renderer = new ShadowRenderer(shadowSize, 0.5f,
|
ShadowRenderer renderer = new ShadowRenderer(shadowSize, 0.5f,
|
||||||
Color.GRAY);
|
Color.GRAY);
|
||||||
shadow = renderer.createShadow(shadow);
|
return renderer.createShadow(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showDialog(boolean bShow) {
|
public void showDialog(boolean bShow) {
|
||||||
|
|
|
@ -13,6 +13,8 @@ import org.mage.card.arcane.UI;
|
||||||
* @author nantuko
|
* @author nantuko
|
||||||
*/
|
*/
|
||||||
public class MageTextArea extends JEditorPane {
|
public class MageTextArea extends JEditorPane {
|
||||||
|
private String currentText;
|
||||||
|
private int currentPanelWidth;
|
||||||
|
|
||||||
public MageTextArea() {
|
public MageTextArea() {
|
||||||
UI.setHTMLEditorKit(this);
|
UI.setHTMLEditorKit(this);
|
||||||
|
@ -31,6 +33,12 @@ public class MageTextArea extends JEditorPane {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(text.equals(currentText) && panelWidth == currentPanelWidth)
|
||||||
|
return;
|
||||||
|
|
||||||
|
currentText = text;
|
||||||
|
currentPanelWidth = panelWidth;
|
||||||
|
|
||||||
final StringBuilder buffer = new StringBuilder(512);
|
final StringBuilder buffer = new StringBuilder(512);
|
||||||
// Dialog is a java logical font family, so it should work on all systems
|
// Dialog is a java logical font family, so it should work on all systems
|
||||||
buffer.append("<html><body style='font-family:Dialog;font-size:");
|
buffer.append("<html><body style='font-family:Dialog;font-size:");
|
||||||
|
|
|
@ -409,8 +409,7 @@ public class TableModel extends AbstractTableModel implements ICardGrid {
|
||||||
Image image = Plugins.getInstance().getOriginalImage(card);
|
Image image = Plugins.getInstance().getOriginalImage(card);
|
||||||
if (image != null && image instanceof BufferedImage) {
|
if (image != null && image instanceof BufferedImage) {
|
||||||
// XXX: scaled to fit width
|
// XXX: scaled to fit width
|
||||||
image = ImageHelper.getResizedImage((BufferedImage) image, bigCard.getWidth());
|
bigCard.setCard(card.getId(), EnlargeMode.NORMAL, image, new ArrayList<String>(), false);
|
||||||
bigCard.setCard(card.getId(), EnlargeMode.NORMAL, image, new ArrayList<String>());
|
|
||||||
} else {
|
} else {
|
||||||
drawCardText(card);
|
drawCardText(card);
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,7 +228,7 @@ public class DraftPanel extends javax.swing.JPanel {
|
||||||
int height = left * 18;
|
int height = left * 18;
|
||||||
lblTableImage.setSize(new Dimension(lblTableImage.getWidth(), height));
|
lblTableImage.setSize(new Dimension(lblTableImage.getWidth(), height));
|
||||||
Image tableImage = ImageHelper.getImageFromResources(draftView.getBoosterNum() == 2 ? "/draft/table_left.png" : "/draft/table_right.png");
|
Image tableImage = ImageHelper.getImageFromResources(draftView.getBoosterNum() == 2 ? "/draft/table_left.png" : "/draft/table_right.png");
|
||||||
BufferedImage resizedTable = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(tableImage, BufferedImage.TYPE_INT_ARGB), lblTableImage.getWidth());
|
BufferedImage resizedTable = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(tableImage, BufferedImage.TYPE_INT_ARGB), lblTableImage.getWidth(), lblTableImage.getHeight());
|
||||||
lblTableImage.setIcon(new ImageIcon(resizedTable));
|
lblTableImage.setIcon(new ImageIcon(resizedTable));
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
|
@ -155,6 +155,7 @@ public class MageActionCallback implements ActionCallback {
|
||||||
}
|
}
|
||||||
data.locationOnScreen = data.component.getLocationOnScreen();
|
data.locationOnScreen = data.component.getLocationOnScreen();
|
||||||
}
|
}
|
||||||
|
data.popupText.updateText();
|
||||||
tooltipPopup = factory.getPopup(data.component, data.popupText, (int) data.locationOnScreen.getX() + data.popupOffsetX, (int) data.locationOnScreen.getY() + data.popupOffsetY + 40);
|
tooltipPopup = factory.getPopup(data.component, data.popupText, (int) data.locationOnScreen.getX() + data.popupOffsetX, (int) data.locationOnScreen.getY() + data.popupOffsetY + 40);
|
||||||
tooltipPopup.show();
|
tooltipPopup.show();
|
||||||
// hack to get popup to resize to fit text
|
// hack to get popup to resize to fit text
|
||||||
|
@ -597,13 +598,7 @@ public class MageActionCallback implements ActionCallback {
|
||||||
private void displayCardInfo(MageCard mageCard, Image image, BigCard bigCard) {
|
private void displayCardInfo(MageCard mageCard, Image image, BigCard bigCard) {
|
||||||
if (image != null && image instanceof BufferedImage) {
|
if (image != null && image instanceof BufferedImage) {
|
||||||
// XXX: scaled to fit width
|
// XXX: scaled to fit width
|
||||||
if (mageCard.getOriginal().isToRotate() && bigCard.getWidth() > bigCard.getHeight()) {
|
bigCard.setCard(mageCard.getOriginal().getId(), enlargeMode, image, mageCard.getOriginal().getRules(), mageCard.getOriginal().isToRotate());
|
||||||
image = ImageHelper.getResizedImage((BufferedImage) image, bigCard.getHeight());
|
|
||||||
image = ImageHelper.rotate((BufferedImage) image, Math.toRadians(90));
|
|
||||||
} else {
|
|
||||||
image = ImageHelper.getResizedImage((BufferedImage) image, bigCard.getWidth());
|
|
||||||
}
|
|
||||||
bigCard.setCard(mageCard.getOriginal().getId(), enlargeMode, image, mageCard.getOriginal().getRules());
|
|
||||||
// if it's an ability, show only the ability text as overlay
|
// if it's an ability, show only the ability text as overlay
|
||||||
if (mageCard.getOriginal().isAbility() && enlargeMode.equals(EnlargeMode.NORMAL)) {
|
if (mageCard.getOriginal().isAbility() && enlargeMode.equals(EnlargeMode.NORMAL)) {
|
||||||
bigCard.showTextComponent();
|
bigCard.showTextComponent();
|
||||||
|
|
34
Mage.Client/src/main/java/mage/client/util/ImageCaches.java
Normal file
34
Mage.Client/src/main/java/mage/client/util/ImageCaches.java
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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 mage.client.util;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author user
|
||||||
|
*/
|
||||||
|
public class ImageCaches {
|
||||||
|
private static Vector<Map> IMAGE_CACHES;
|
||||||
|
|
||||||
|
static {
|
||||||
|
IMAGE_CACHES = new Vector<Map>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map register(Map map)
|
||||||
|
{
|
||||||
|
IMAGE_CACHES.add(map);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void flush()
|
||||||
|
{
|
||||||
|
for (Map map : IMAGE_CACHES) {
|
||||||
|
map.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,6 +52,7 @@ import static mage.client.constants.Constants.FRAME_MAX_WIDTH;
|
||||||
import static mage.client.constants.Constants.SYMBOL_MAX_SPACE;
|
import static mage.client.constants.Constants.SYMBOL_MAX_SPACE;
|
||||||
import mage.view.CardView;
|
import mage.view.CardView;
|
||||||
import org.mage.card.arcane.UI;
|
import org.mage.card.arcane.UI;
|
||||||
|
import org.mage.plugins.card.images.ImageCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -70,21 +71,6 @@ public class ImageHelper {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param ref - image name
|
|
||||||
* @param height - height after scaling
|
|
||||||
* @return a scaled image that preserves the original aspect ratio, with a
|
|
||||||
* specified height
|
|
||||||
*/
|
|
||||||
public static BufferedImage loadImage(String ref, int height) {
|
|
||||||
BufferedImage image = loadImage(ref);
|
|
||||||
if (image != null) {
|
|
||||||
return scaleImage(image, height);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BufferedImage loadImage(String ref) {
|
public static BufferedImage loadImage(String ref) {
|
||||||
if (!images.containsKey(ref)) {
|
if (!images.containsKey(ref)) {
|
||||||
try {
|
try {
|
||||||
|
@ -107,67 +93,7 @@ public class ImageHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BufferedImage scaleImage(BufferedImage image, int width, int height) {
|
public static BufferedImage scaleImage(BufferedImage image, int width, int height) {
|
||||||
BufferedImage scaledImage = image;
|
return TransformedImageCache.getResizedImage(image, width, height);
|
||||||
int w = image.getWidth();
|
|
||||||
int h = image.getHeight();
|
|
||||||
do {
|
|
||||||
w /= 2;
|
|
||||||
h /= 2;
|
|
||||||
if (w < width || h < height) {
|
|
||||||
w = width;
|
|
||||||
h = height;
|
|
||||||
}
|
|
||||||
BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
|
||||||
Graphics2D graphics2D = newImage.createGraphics();
|
|
||||||
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
|
||||||
graphics2D.drawImage(scaledImage, 0, 0, w, h, null);
|
|
||||||
graphics2D.dispose();
|
|
||||||
scaledImage = newImage;
|
|
||||||
} while (w != width || h != height);
|
|
||||||
return scaledImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BufferedImage scaleImage(BufferedImage image, int height) {
|
|
||||||
double ratio = height / (double) image.getHeight();
|
|
||||||
int width = (int) (image.getWidth() * ratio);
|
|
||||||
return scaleImage(image, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MemoryImageSource rotate(Image image, CardDimensions dimensions) {
|
|
||||||
int buffer[] = new int[dimensions.frameWidth * dimensions.frameHeight];
|
|
||||||
int rotate[] = new int[dimensions.frameHeight * dimensions.frameWidth];
|
|
||||||
PixelGrabber grabber = new PixelGrabber(image, 0, 0, dimensions.frameWidth, dimensions.frameHeight, buffer, 0, dimensions.frameWidth);
|
|
||||||
try {
|
|
||||||
grabber.grabPixels();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
for (int y = 0; y < dimensions.frameHeight; y++) {
|
|
||||||
for (int x = 0; x < dimensions.frameWidth; x++) {
|
|
||||||
rotate[((dimensions.frameWidth - x - 1) * dimensions.frameHeight) + y] = buffer[(y * dimensions.frameWidth) + x];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new MemoryImageSource(dimensions.frameHeight, dimensions.frameWidth, rotate, 0, dimensions.frameHeight);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BufferedImage rotate(BufferedImage image, double angle) {
|
|
||||||
double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
|
|
||||||
int w = image.getWidth(), h = image.getHeight();
|
|
||||||
int neww = (int) Math.floor(w * cos + h * sin), newh = (int) Math.floor(h * cos + w * sin);
|
|
||||||
|
|
||||||
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
|
||||||
GraphicsDevice gs = ge.getDefaultScreenDevice();
|
|
||||||
GraphicsConfiguration gc = gs.getDefaultConfiguration();
|
|
||||||
|
|
||||||
BufferedImage result = gc.createCompatibleImage(neww, newh, Transparency.TRANSLUCENT);
|
|
||||||
Graphics2D g = result.createGraphics();
|
|
||||||
g.translate((neww - w) / 2, (newh - h) / 2);
|
|
||||||
g.rotate(angle, w / 2, h / 2);
|
|
||||||
g.drawRenderedImage(image, null);
|
|
||||||
g.dispose();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawCosts(List<String> costs, Graphics2D g, int xOffset, int yOffset, ImageObserver o) {
|
public static void drawCosts(List<String> costs, Graphics2D g, int xOffset, int yOffset, ImageObserver o) {
|
||||||
|
@ -191,26 +117,7 @@ public class ImageHelper {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static BufferedImage getResizedImage(BufferedImage original, int width, int height) {
|
public static BufferedImage getResizedImage(BufferedImage original, int width, int height) {
|
||||||
ResampleOp resampleOp = new ResampleOp(width, height);
|
return TransformedImageCache.getResizedImage(original, width, height);
|
||||||
BufferedImage image = resampleOp.filter(original, null);
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an image scaled to fit width panel
|
|
||||||
*
|
|
||||||
* @param original
|
|
||||||
* @param width
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static BufferedImage getResizedImage(BufferedImage original, int width) {
|
|
||||||
if (width != original.getWidth()) {
|
|
||||||
double ratio = width / (double) original.getWidth();
|
|
||||||
int height = (int) (original.getHeight() * ratio);
|
|
||||||
return getResizedImage(original, width, height);
|
|
||||||
} else {
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -223,17 +130,7 @@ public class ImageHelper {
|
||||||
* @return scaled image
|
* @return scaled image
|
||||||
*/
|
*/
|
||||||
public static BufferedImage scale(BufferedImage sbi, int imageType, int dWidth, int dHeight) {
|
public static BufferedImage scale(BufferedImage sbi, int imageType, int dWidth, int dHeight) {
|
||||||
BufferedImage dbi = null;
|
return TransformedImageCache.getResizedImage(sbi, dWidth, dHeight);
|
||||||
if (sbi != null) {
|
|
||||||
double fWidth = dWidth / sbi.getWidth();
|
|
||||||
double fHeight = dHeight / sbi.getHeight();
|
|
||||||
dbi = new BufferedImage(dWidth, dHeight, imageType);
|
|
||||||
Graphics2D g = dbi.createGraphics();
|
|
||||||
AffineTransform at = AffineTransform.getScaleInstance(fWidth, fHeight);
|
|
||||||
g.drawRenderedImage(sbi, at);
|
|
||||||
g.dispose();
|
|
||||||
}
|
|
||||||
return dbi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -244,9 +141,7 @@ public class ImageHelper {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static BufferedImage getResizedImage(BufferedImage original, Rectangle sizeNeed) {
|
public static BufferedImage getResizedImage(BufferedImage original, Rectangle sizeNeed) {
|
||||||
ResampleOp resampleOp = new ResampleOp(sizeNeed.width, sizeNeed.height);
|
return TransformedImageCache.getResizedImage(original, sizeNeed.width, sizeNeed.height);
|
||||||
BufferedImage image = resampleOp.filter(original, null);
|
|
||||||
return image;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
/*
|
||||||
|
* 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 mage.client.util;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.MapMaker;
|
||||||
|
import com.mortennobel.imagescaling.ResampleOp;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.GraphicsConfiguration;
|
||||||
|
import java.awt.GraphicsDevice;
|
||||||
|
import java.awt.GraphicsEnvironment;
|
||||||
|
import java.awt.Transparency;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.Map;
|
||||||
|
import mage.client.util.ImageHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author user
|
||||||
|
*/
|
||||||
|
public class TransformedImageCache {
|
||||||
|
private final static class Key
|
||||||
|
{
|
||||||
|
final int width;
|
||||||
|
final int height;
|
||||||
|
final double angle;
|
||||||
|
|
||||||
|
public Key(int width, int height, double angle) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.angle = angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 3;
|
||||||
|
hash = 53 * hash + this.width;
|
||||||
|
hash = 53 * hash + this.height;
|
||||||
|
hash = 53 * hash + (int) (Double.doubleToLongBits(this.angle) ^ (Double.doubleToLongBits(this.angle) >>> 32));
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Key other = (Key) obj;
|
||||||
|
if (this.width != other.width) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.height != other.height) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Double.doubleToLongBits(this.angle) != Double.doubleToLongBits(other.angle)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<Key, Map<BufferedImage, BufferedImage>> IMAGE_CACHE;
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
// TODO: can we use a single map?
|
||||||
|
IMAGE_CACHE = ImageCaches.register(new MapMaker().softValues().makeComputingMap(new Function<Key, Map<BufferedImage, BufferedImage>>() {
|
||||||
|
@Override
|
||||||
|
public Map<BufferedImage, BufferedImage> apply(final Key key) {
|
||||||
|
return new MapMaker().weakKeys().softValues().makeComputingMap(new Function<BufferedImage, BufferedImage>() {
|
||||||
|
@Override
|
||||||
|
public BufferedImage apply(BufferedImage image) {
|
||||||
|
if(key.width != image.getWidth() || key.height != image.getHeight())
|
||||||
|
image = resizeImage(image, key.width, key.height);
|
||||||
|
if(key.angle != 0.0)
|
||||||
|
image = rotateImage(image, key.angle);
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BufferedImage rotateImage(BufferedImage image, double angle) {
|
||||||
|
double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
|
||||||
|
int w = image.getWidth(), h = image.getHeight();
|
||||||
|
int neww = (int) Math.floor(w * cos + h * sin), newh = (int) Math.floor(h * cos + w * sin);
|
||||||
|
|
||||||
|
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||||
|
GraphicsDevice gs = ge.getDefaultScreenDevice();
|
||||||
|
GraphicsConfiguration gc = gs.getDefaultConfiguration();
|
||||||
|
|
||||||
|
BufferedImage result = gc.createCompatibleImage(neww, newh, Transparency.TRANSLUCENT);
|
||||||
|
Graphics2D g = result.createGraphics();
|
||||||
|
g.translate((neww - w) / 2, (newh - h) / 2);
|
||||||
|
g.rotate(angle, w / 2, h / 2);
|
||||||
|
g.drawRenderedImage(image, null);
|
||||||
|
g.dispose();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BufferedImage resizeImage(BufferedImage original, int width, int height) {
|
||||||
|
ResampleOp resampleOp = new ResampleOp(width, height);
|
||||||
|
BufferedImage image = resampleOp.filter(original, null);
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BufferedImage getResizedImage(BufferedImage image, int width, int height)
|
||||||
|
{
|
||||||
|
return getRotatedResizedImage(image, width, height, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BufferedImage getRotatedImage(BufferedImage image, double angle)
|
||||||
|
{
|
||||||
|
return getRotatedResizedImage(image, -1, -1, angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BufferedImage getRotatedResizedImage(BufferedImage image, int width, int height, double angle)
|
||||||
|
{
|
||||||
|
int imageWidth = image.getWidth();
|
||||||
|
int imageHeight = image.getHeight();
|
||||||
|
|
||||||
|
if(angle == 0.0 && (width < 0 || imageWidth == width) && (height < 0 || imageHeight == height))
|
||||||
|
return image;
|
||||||
|
|
||||||
|
int resWidth;
|
||||||
|
int resHeight;
|
||||||
|
if(width < 0 && height < 0) {
|
||||||
|
resWidth = imageWidth;
|
||||||
|
resHeight = imageHeight;
|
||||||
|
} else if((height < 0) || (width >= 0 && imageHeight * width <= imageWidth * height)) {
|
||||||
|
resWidth = width;
|
||||||
|
resHeight = imageHeight * width / imageWidth;
|
||||||
|
} else {
|
||||||
|
resWidth = imageWidth * height / imageHeight;
|
||||||
|
resHeight = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(angle == 0.0 && imageWidth == resWidth && imageHeight == resHeight)
|
||||||
|
return image;
|
||||||
|
|
||||||
|
return IMAGE_CACHE.get(new Key(resWidth, resHeight, angle)).get(image);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,8 @@ import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
public abstract class Animation {
|
public abstract class Animation {
|
||||||
|
private static boolean ENABLED = true;
|
||||||
|
|
||||||
private static final long TARGET_MILLIS_PER_FRAME = 30;
|
private static final long TARGET_MILLIS_PER_FRAME = 30;
|
||||||
|
|
||||||
private static Timer timer = new Timer("Animation", true);
|
private static Timer timer = new Timer("Animation", true);
|
||||||
|
@ -25,6 +27,18 @@ public abstract class Animation {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Animation (final long duration, long delay) {
|
public Animation (final long duration, long delay) {
|
||||||
|
if(!ENABLED) {
|
||||||
|
UI.invokeLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run () {
|
||||||
|
start();
|
||||||
|
//update(1.0f);
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
timerTask = new TimerTask() {
|
timerTask = new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run () {
|
public void run () {
|
||||||
|
@ -171,6 +185,12 @@ public abstract class Animation {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void end () {
|
protected void end () {
|
||||||
|
if (!state) {
|
||||||
|
parent.toggleTransformed();
|
||||||
|
}
|
||||||
|
state = true;
|
||||||
|
panel.transformAngle = 0;
|
||||||
|
|
||||||
parent.onEndAnimation();
|
parent.onEndAnimation();
|
||||||
parent.repaint();
|
parent.repaint();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.mage.card.arcane;
|
package org.mage.card.arcane;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.MapMaker;
|
||||||
import java.awt.AlphaComposite;
|
import java.awt.AlphaComposite;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
|
@ -23,6 +25,7 @@ import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
|
@ -38,6 +41,7 @@ import mage.cards.action.TransferData;
|
||||||
import mage.client.dialog.PreferencesDialog;
|
import mage.client.dialog.PreferencesDialog;
|
||||||
import mage.client.plugins.adapters.MageActionCallback;
|
import mage.client.plugins.adapters.MageActionCallback;
|
||||||
import mage.client.plugins.impl.Plugins;
|
import mage.client.plugins.impl.Plugins;
|
||||||
|
import mage.client.util.ImageCaches;
|
||||||
import mage.client.util.ImageHelper;
|
import mage.client.util.ImageHelper;
|
||||||
import mage.client.util.audio.AudioManager;
|
import mage.client.util.audio.AudioManager;
|
||||||
import mage.components.ImagePanel;
|
import mage.components.ImagePanel;
|
||||||
|
@ -52,8 +56,7 @@ import mage.view.PermanentView;
|
||||||
import mage.view.StackAbilityView;
|
import mage.view.StackAbilityView;
|
||||||
import net.java.truevfs.access.TFile;
|
import net.java.truevfs.access.TFile;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.mage.card.arcane.ScaledImagePanel.MultipassType;
|
import org.jdesktop.swingx.graphics.GraphicsUtilities;
|
||||||
import org.mage.card.arcane.ScaledImagePanel.ScalingType;
|
|
||||||
import static org.mage.plugins.card.constants.Constants.THUMBNAIL_SIZE_FULL;
|
import static org.mage.plugins.card.constants.Constants.THUMBNAIL_SIZE_FULL;
|
||||||
import org.mage.plugins.card.dl.sources.DirectLinksForDownload;
|
import org.mage.plugins.card.dl.sources.DirectLinksForDownload;
|
||||||
import org.mage.plugins.card.images.ImageCache;
|
import org.mage.plugins.card.images.ImageCache;
|
||||||
|
@ -160,6 +163,111 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
|
||||||
// if this is set, it's opened if the user right clicks on the card panel
|
// if this is set, it's opened if the user right clicks on the card panel
|
||||||
private JPopupMenu popupMenu;
|
private JPopupMenu popupMenu;
|
||||||
|
|
||||||
|
private static Map<Key, BufferedImage> IMAGE_CACHE;
|
||||||
|
|
||||||
|
private final static class Key
|
||||||
|
{
|
||||||
|
final int width;
|
||||||
|
final int height;
|
||||||
|
final int cardWidth;
|
||||||
|
final int cardHeight;
|
||||||
|
final int cardXOffset;
|
||||||
|
final int cardYOffset;
|
||||||
|
final boolean hasImage;
|
||||||
|
final boolean isSelected;
|
||||||
|
final boolean isChoosable;
|
||||||
|
final boolean isPlayable;
|
||||||
|
final boolean canAttack;
|
||||||
|
|
||||||
|
public Key(int width, int height, int cardWidth, int cardHeight, int cardXOffset, int cardYOffset, boolean hasImage, boolean isSelected, boolean isChoosable, boolean isPlayable, boolean canAttack) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.cardWidth = cardWidth;
|
||||||
|
this.cardHeight = cardHeight;
|
||||||
|
this.cardXOffset = cardXOffset;
|
||||||
|
this.cardYOffset = cardYOffset;
|
||||||
|
this.hasImage = hasImage;
|
||||||
|
this.isSelected = isSelected;
|
||||||
|
this.isChoosable = isChoosable;
|
||||||
|
this.isPlayable = isPlayable;
|
||||||
|
this.canAttack = canAttack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 3;
|
||||||
|
hash = 19 * hash + this.width;
|
||||||
|
hash = 19 * hash + this.height;
|
||||||
|
hash = 19 * hash + this.cardWidth;
|
||||||
|
hash = 19 * hash + this.cardHeight;
|
||||||
|
hash = 19 * hash + this.cardXOffset;
|
||||||
|
hash = 19 * hash + this.cardYOffset;
|
||||||
|
hash = 19 * hash + (this.hasImage ? 1 : 0);
|
||||||
|
hash = 19 * hash + (this.isSelected ? 1 : 0);
|
||||||
|
hash = 19 * hash + (this.isChoosable ? 1 : 0);
|
||||||
|
hash = 19 * hash + (this.isPlayable ? 1 : 0);
|
||||||
|
hash = 19 * hash + (this.canAttack ? 1 : 0);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Key other = (Key) obj;
|
||||||
|
if (this.width != other.width) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.height != other.height) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.cardWidth != other.cardWidth) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.cardHeight != other.cardHeight) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.cardXOffset != other.cardXOffset) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.cardYOffset != other.cardYOffset) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.hasImage != other.hasImage) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.isSelected != other.isSelected) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.isChoosable != other.isChoosable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.isPlayable != other.isPlayable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.canAttack != other.canAttack) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
IMAGE_CACHE = ImageCaches.register(new MapMaker().softValues().makeComputingMap(new Function<Key, BufferedImage>() {
|
||||||
|
@Override
|
||||||
|
public BufferedImage apply(Key key) {
|
||||||
|
return createImage(key);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
public CardPanel(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback, final boolean foil, Dimension dimension) {
|
public CardPanel(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback, final boolean foil, Dimension dimension) {
|
||||||
this.gameCard = newGameCard;
|
this.gameCard = newGameCard;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
@ -304,9 +412,6 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
|
||||||
imagePanel = new ScaledImagePanel();
|
imagePanel = new ScaledImagePanel();
|
||||||
imagePanel.setBorder(BorderFactory.createLineBorder(Color.white));
|
imagePanel.setBorder(BorderFactory.createLineBorder(Color.white));
|
||||||
add(imagePanel);
|
add(imagePanel);
|
||||||
imagePanel.setScaleLarger(true);
|
|
||||||
imagePanel.setScalingType(ScalingType.nearestNeighbor);
|
|
||||||
imagePanel.setScalingMultiPassType(MultipassType.none);
|
|
||||||
|
|
||||||
String cardType = getType(newGameCard);
|
String cardType = getType(newGameCard);
|
||||||
tooltipText.setText(getText(cardType, newGameCard));
|
tooltipText.setText(getText(cardType, newGameCard));
|
||||||
|
@ -387,7 +492,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
|
||||||
titleText.setText(!displayTitleAnyway && hasImage ? "" : card.getName());
|
titleText.setText(!displayTitleAnyway && hasImage ? "" : card.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setImage(Image srcImage) {
|
private void setImage(BufferedImage srcImage) {
|
||||||
synchronized (imagePanel) {
|
synchronized (imagePanel) {
|
||||||
imagePanel.setImage(srcImage);
|
imagePanel.setImage(srcImage);
|
||||||
repaint();
|
repaint();
|
||||||
|
@ -413,10 +518,6 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
|
||||||
return zone;
|
return zone;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setScalingType(ScalingType scalingType) {
|
|
||||||
imagePanel.setScalingType(scalingType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDisplayEnabled(boolean displayEnabled) {
|
public void setDisplayEnabled(boolean displayEnabled) {
|
||||||
this.displayEnabled = displayEnabled;
|
this.displayEnabled = displayEnabled;
|
||||||
}
|
}
|
||||||
|
@ -484,15 +585,28 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintComponent(Graphics g) {
|
protected void paintComponent(Graphics g) {
|
||||||
Graphics2D g2d = (Graphics2D) g;
|
Graphics2D g2d = (Graphics2D)(g.create());
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
|
||||||
|
|
||||||
if (alpha != 1.0f) {
|
if (alpha != 1.0f) {
|
||||||
AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha);
|
AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha);
|
||||||
g2d.setComposite(composite);
|
g2d.setComposite(composite);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasImage) {
|
g2d.drawImage(IMAGE_CACHE.get(new Key(getWidth(), getHeight(), cardWidth, cardHeight, cardXOffset, cardYOffset, hasImage, isSelected, isChoosable, isPlayable, canAttack)), 0, 0, null);
|
||||||
|
g2d.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BufferedImage createImage(Key key) {
|
||||||
|
int cardWidth = key.cardWidth;
|
||||||
|
int cardHeight = key.cardHeight;
|
||||||
|
int cardXOffset = key.cardXOffset;
|
||||||
|
int cardYOffset = key.cardYOffset;
|
||||||
|
|
||||||
|
BufferedImage image = GraphicsUtilities.createCompatibleTranslucentImage(key.width, key.height);
|
||||||
|
Graphics2D g2d = image.createGraphics();
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
|
||||||
|
if (!key.hasImage) {
|
||||||
g2d.setColor(new Color(30, 200, 200, 120));
|
g2d.setColor(new Color(30, 200, 200, 120));
|
||||||
} else {
|
} else {
|
||||||
g2d.setColor(new Color(0, 0, 0, 0));
|
g2d.setColor(new Color(0, 0, 0, 0));
|
||||||
|
@ -501,19 +615,19 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
|
||||||
int cornerSize = Math.max(4, Math.round(cardWidth * ROUNDED_CORNER_SIZE));
|
int cornerSize = Math.max(4, Math.round(cardWidth * ROUNDED_CORNER_SIZE));
|
||||||
g2d.fillRoundRect(cardXOffset, cardYOffset, cardWidth, cardHeight, cornerSize, cornerSize);
|
g2d.fillRoundRect(cardXOffset, cardYOffset, cardWidth, cardHeight, cornerSize, cornerSize);
|
||||||
|
|
||||||
if (isSelected) {
|
if (key.isSelected) {
|
||||||
g2d.setColor(Color.green);
|
g2d.setColor(Color.green);
|
||||||
g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize);
|
g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize);
|
||||||
} else if (isChoosable) {
|
} else if (key.isChoosable) {
|
||||||
g2d.setColor(new Color(250, 250, 0, 230));
|
g2d.setColor(new Color(250, 250, 0, 230));
|
||||||
g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize);
|
g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize);
|
||||||
} else if (isPlayable) {
|
} else if (key.isPlayable) {
|
||||||
g2d.setColor(new Color(153, 102, 204, 200));
|
g2d.setColor(new Color(153, 102, 204, 200));
|
||||||
//g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize);
|
//g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize);
|
||||||
g2d.fillRoundRect(cardXOffset, cardYOffset, cardWidth, cardHeight, cornerSize, cornerSize);
|
g2d.fillRoundRect(cardXOffset, cardYOffset, cardWidth, cardHeight, cornerSize, cornerSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canAttack) {
|
if (key.canAttack) {
|
||||||
g2d.setColor(new Color(0, 0, 255, 230));
|
g2d.setColor(new Color(0, 0, 255, 230));
|
||||||
g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize);
|
g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize);
|
||||||
}
|
}
|
||||||
|
@ -524,6 +638,9 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
|
||||||
g2d.setColor(new Color(200,10,10,200));
|
g2d.setColor(new Color(200,10,10,200));
|
||||||
g2d.fillRoundRect(cardXOffset+1, cardYOffset+1, cardWidth-2, cardHeight-2, cornerSize, cornerSize);
|
g2d.fillRoundRect(cardXOffset+1, cardYOffset+1, cardWidth-2, cardHeight-2, cornerSize, cornerSize);
|
||||||
}*/
|
}*/
|
||||||
|
g2d.dispose();
|
||||||
|
|
||||||
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -619,12 +736,6 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
|
||||||
|
|
||||||
ptText.setLocation(cardXOffset + ptX - TEXT_GLOW_SIZE / 2 - offsetX, cardYOffset + ptY - TEXT_GLOW_SIZE / 2);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1063,7 +1174,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
|
||||||
if (gameCard.hideInfo()) {
|
if (gameCard.hideInfo()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (getMousePosition(true) != null) {
|
if (this.contains(e.getPoint())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (tooltipShowing) {
|
if (tooltipShowing) {
|
||||||
|
|
|
@ -1,15 +1,30 @@
|
||||||
package org.mage.card.arcane;
|
package org.mage.card.arcane;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.MapMaker;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.font.FontRenderContext;
|
import java.awt.font.FontRenderContext;
|
||||||
import java.awt.font.LineBreakMeasurer;
|
import java.awt.font.LineBreakMeasurer;
|
||||||
import java.awt.font.TextAttribute;
|
import java.awt.font.TextAttribute;
|
||||||
import java.awt.font.TextLayout;
|
import java.awt.font.TextLayout;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.lang.ref.SoftReference;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.text.AttributedCharacterIterator;
|
import java.text.AttributedCharacterIterator;
|
||||||
import java.text.AttributedString;
|
import java.text.AttributedString;
|
||||||
import java.text.BreakIterator;
|
import java.text.BreakIterator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import mage.client.util.ImageCaches;
|
||||||
|
import org.jdesktop.swingx.graphics.GraphicsUtilities;
|
||||||
|
|
||||||
public class GlowText extends JLabel {
|
public class GlowText extends JLabel {
|
||||||
private static final long serialVersionUID = 1827677946939348001L;
|
private static final long serialVersionUID = 1827677946939348001L;
|
||||||
|
@ -19,6 +34,109 @@ public class GlowText extends JLabel {
|
||||||
private Color glowColor;
|
private Color glowColor;
|
||||||
private boolean wrap;
|
private boolean wrap;
|
||||||
private int lineCount = 0;
|
private int lineCount = 0;
|
||||||
|
private static Map<Key, BufferedImage> IMAGE_CACHE;
|
||||||
|
|
||||||
|
private final static class Key
|
||||||
|
{
|
||||||
|
final int width;
|
||||||
|
final int height;
|
||||||
|
final String text;
|
||||||
|
final Map<TextAttribute,?> fontAttributes;
|
||||||
|
final Color color;
|
||||||
|
final int glowSize;
|
||||||
|
final float glowIntensity;
|
||||||
|
final Color glowColor;
|
||||||
|
final boolean wrap;
|
||||||
|
|
||||||
|
// used to pass the native font to the create function so we don't waste performance recreating it, but without holding onto the native object
|
||||||
|
final transient WeakReference<Font> originalFont;
|
||||||
|
|
||||||
|
Font getFont() {
|
||||||
|
Font res = this.originalFont.get();
|
||||||
|
if(res == null)
|
||||||
|
res = Font.getFont(this.fontAttributes);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Key(int width, int height, String text, Font font, Color color, int glowSize, float glowIntensity, Color glowColor, boolean wrap) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.text = text;
|
||||||
|
this.originalFont = new WeakReference<>(font);
|
||||||
|
this.fontAttributes = font.getAttributes();
|
||||||
|
this.color = color;
|
||||||
|
this.glowSize = glowSize;
|
||||||
|
this.glowIntensity = glowIntensity;
|
||||||
|
this.glowColor = glowColor;
|
||||||
|
this.wrap = wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 3;
|
||||||
|
hash = 23 * hash + this.width;
|
||||||
|
hash = 23 * hash + this.height;
|
||||||
|
hash = 23 * hash + Objects.hashCode(this.text);
|
||||||
|
hash = 23 * hash + Objects.hashCode(this.fontAttributes);
|
||||||
|
hash = 23 * hash + Objects.hashCode(this.color);
|
||||||
|
hash = 23 * hash + this.glowSize;
|
||||||
|
hash = 23 * hash + Float.floatToIntBits(this.glowIntensity);
|
||||||
|
hash = 23 * hash + Objects.hashCode(this.glowColor);
|
||||||
|
hash = 23 * hash + (this.wrap ? 1 : 0);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Key other = (Key) obj;
|
||||||
|
if (this.width != other.width) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.height != other.height) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.glowSize != other.glowSize) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Float.floatToIntBits(this.glowIntensity) != Float.floatToIntBits(other.glowIntensity)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.wrap != other.wrap) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Objects.equals(this.text, other.text)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Objects.equals(this.fontAttributes, other.fontAttributes)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Objects.equals(this.color, other.color)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Objects.equals(this.glowColor, other.glowColor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
IMAGE_CACHE = ImageCaches.register(new MapMaker().softValues().makeComputingMap(new Function<Key, BufferedImage>() {
|
||||||
|
@Override
|
||||||
|
public BufferedImage apply(Key key) {
|
||||||
|
return createImage(key);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
public void setGlow (Color glowColor, int size, float intensity) {
|
public void setGlow (Color glowColor, int size, float intensity) {
|
||||||
this.glowColor = glowColor;
|
this.glowColor = glowColor;
|
||||||
|
@ -38,32 +156,32 @@ public class GlowText extends JLabel {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setText (String text) {
|
|
||||||
super.setText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint (Graphics g) {
|
public void paint (Graphics g) {
|
||||||
if (getText().length() == 0) {
|
if (getText().length() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Graphics2D g2d = (Graphics2D)g;
|
g.drawImage(IMAGE_CACHE.get(new Key(getWidth(), getHeight(), getText(), getFont(), getForeground(), glowSize, glowIntensity, glowColor, wrap)), 0, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BufferedImage createImage (Key key) {
|
||||||
|
Dimension size = new Dimension(key.width, key.height);
|
||||||
|
BufferedImage image = GraphicsUtilities.createCompatibleTranslucentImage(size.width, size.height);
|
||||||
|
Graphics2D g2d = image.createGraphics();
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||||
|
|
||||||
Dimension size = getSize();
|
|
||||||
int textX = 0, textY = 0;
|
int textX = 0, textY = 0;
|
||||||
int wrapWidth = Math.max(0, wrap ? size.width - glowSize : Integer.MAX_VALUE);
|
int wrapWidth = Math.max(0, key.wrap ? size.width - key.glowSize : Integer.MAX_VALUE);
|
||||||
|
|
||||||
AttributedString attributedString = new AttributedString(getText());
|
AttributedString attributedString = new AttributedString(key.text);
|
||||||
attributedString.addAttribute(TextAttribute.FONT, getFont());
|
attributedString.addAttribute(TextAttribute.FONT, key.getFont());
|
||||||
AttributedCharacterIterator charIterator = attributedString.getIterator();
|
AttributedCharacterIterator charIterator = attributedString.getIterator();
|
||||||
FontRenderContext fontContext = g2d.getFontRenderContext();
|
FontRenderContext fontContext = g2d.getFontRenderContext();
|
||||||
|
|
||||||
LineBreakMeasurer measurer = new LineBreakMeasurer(charIterator, BreakIterator.getWordInstance(Locale.ENGLISH), fontContext);
|
LineBreakMeasurer measurer = new LineBreakMeasurer(charIterator, BreakIterator.getWordInstance(Locale.ENGLISH), fontContext);
|
||||||
lineCount = 0;
|
int lineCount = 0;
|
||||||
while (measurer.getPosition() < charIterator.getEndIndex()) {
|
while (measurer.getPosition() < charIterator.getEndIndex()) {
|
||||||
//TextLayout textLayout = measurer.nextLayout(wrapWidth);
|
//TextLayout textLayout = measurer.nextLayout(wrapWidth);
|
||||||
lineCount++;
|
lineCount++;
|
||||||
|
@ -83,23 +201,21 @@ public class GlowText extends JLabel {
|
||||||
float ascent = textLayout.getAscent();
|
float ascent = textLayout.getAscent();
|
||||||
textY += ascent; // Move down to baseline.
|
textY += ascent; // Move down to baseline.
|
||||||
|
|
||||||
g2d.setColor(glowColor);
|
g2d.setColor(key.glowColor);
|
||||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f));
|
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f));
|
||||||
|
int glowSize = key.glowSize;
|
||||||
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);
|
||||||
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.setColor(key.color);
|
||||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
|
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
|
||||||
textLayout.draw(g2d, textX + glowSize / 2, textY + glowSize / 2);
|
textLayout.draw(g2d, textX + glowSize / 2, textY + glowSize / 2);
|
||||||
|
|
||||||
textY += textLayout.getDescent() + textLayout.getLeading(); // Move down to top of next line.
|
textY += textLayout.getDescent() + textLayout.getLeading(); // Move down to top of next line.
|
||||||
}
|
}
|
||||||
}
|
return image;
|
||||||
|
|
||||||
public int getLineCount() {
|
|
||||||
return this.lineCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGlowColor(Color glowColor) {
|
public void setGlowColor(Color glowColor) {
|
||||||
|
|
|
@ -7,188 +7,35 @@ import java.awt.RenderingHints;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
import mage.client.util.TransformedImageCache;
|
||||||
|
|
||||||
public class ScaledImagePanel extends JPanel {
|
public class ScaledImagePanel extends JPanel {
|
||||||
private static final long serialVersionUID = -1523279873208605664L;
|
private static final long serialVersionUID = -1523279873208605664L;
|
||||||
private volatile Image srcImage;
|
private volatile BufferedImage srcImage;
|
||||||
|
|
||||||
private ScalingType scalingType = ScalingType.bilinear;
|
|
||||||
private boolean scaleLarger;
|
|
||||||
private MultipassType multiPassType = MultipassType.bilinear;
|
|
||||||
|
|
||||||
public ScaledImagePanel () {
|
public ScaledImagePanel () {
|
||||||
super(false);
|
super(false);
|
||||||
setOpaque(false);
|
setOpaque(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setImage(Image srcImage) {
|
public void setImage(BufferedImage srcImage) {
|
||||||
this.srcImage = srcImage;
|
this.srcImage = srcImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearImage () {
|
|
||||||
srcImage = null;
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setScalingMultiPassType (MultipassType multiPassType) {
|
|
||||||
this.multiPassType = multiPassType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setScalingType (ScalingType scalingType) {
|
|
||||||
this.scalingType = scalingType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setScaleLarger (boolean scaleLarger) {
|
|
||||||
this.scaleLarger = scaleLarger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasImage () {
|
public boolean hasImage () {
|
||||||
return srcImage != null;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint (Graphics g) {
|
public void paint (Graphics g) {
|
||||||
if (srcImage == null) {
|
if (srcImage == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Graphics2D g2 = (Graphics2D)g.create();
|
g.drawImage(TransformedImageCache.getResizedImage(srcImage, getWidth(), getHeight()), 0, 0, null);
|
||||||
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) {
|
public BufferedImage getSrcImage() {
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Image getSrcImage() {
|
|
||||||
return srcImage;
|
return srcImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ScalingInfo {
|
|
||||||
public int targetWidth;
|
|
||||||
public int targetHeight;
|
|
||||||
public int srcWidth;
|
|
||||||
public int srcHeight;
|
|
||||||
public int x;
|
|
||||||
public int y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static enum MultipassType {
|
|
||||||
none, nearestNeighbor, bilinear, bicubic
|
|
||||||
}
|
|
||||||
|
|
||||||
public static enum ScalingType {
|
|
||||||
nearestNeighbor, replicate, bilinear, bicubic, areaAveraging
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.mage.plugins.card.images;
|
package org.mage.plugins.card.images;
|
||||||
|
|
||||||
|
import mage.client.util.TransformedImageCache;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.collect.ComputationException;
|
import com.google.common.collect.ComputationException;
|
||||||
import com.google.common.collect.MapMaker;
|
import com.google.common.collect.MapMaker;
|
||||||
|
@ -274,7 +275,7 @@ public class ImageCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BufferedImage makeThumbnail(BufferedImage original, String path) {
|
public static BufferedImage makeThumbnail(BufferedImage original, String path) {
|
||||||
BufferedImage image = getResizedImage(original, Constants.THUMBNAIL_SIZE_FULL);
|
BufferedImage image = TransformedImageCache.getResizedImage(original, Constants.THUMBNAIL_SIZE_FULL.width, Constants.THUMBNAIL_SIZE_FULL.height);
|
||||||
TFile imageFile = getTFile(path);
|
TFile imageFile = getTFile(path);
|
||||||
if (imageFile == null) {
|
if (imageFile == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -312,36 +313,7 @@ public class ImageCache {
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResampleOp resampleOp = new ResampleOp(tgtWidth, tgtHeight);
|
return TransformedImageCache.getResizedImage(original, tgtWidth, tgtHeight);
|
||||||
BufferedImage image = resampleOp.filter(original, null);
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an image scaled to the size appropriate for the card picture
|
|
||||||
* panel For future use.
|
|
||||||
*/
|
|
||||||
private static BufferedImage getFullSizeImage(BufferedImage original, double scale) {
|
|
||||||
if (scale == 1) {
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
ResampleOp resampleOp = new ResampleOp((int) (original.getWidth() * scale), (int) (original.getHeight() * scale));
|
|
||||||
BufferedImage image = resampleOp.filter(original, null);
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an image scaled to the size appropriate for the card picture
|
|
||||||
* panel
|
|
||||||
*
|
|
||||||
* @param original
|
|
||||||
* @param sizeNeed
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static BufferedImage getResizedImage(BufferedImage original, Rectangle sizeNeed) {
|
|
||||||
ResampleOp resampleOp = new ResampleOp(sizeNeed.width, sizeNeed.height);
|
|
||||||
BufferedImage image = resampleOp.filter(original, null);
|
|
||||||
return image;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -364,11 +336,11 @@ public class ImageCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
double scale = Math.min((double) width / original.getWidth(), (double) height / original.getHeight());
|
double scale = Math.min((double) width / original.getWidth(), (double) height / original.getHeight());
|
||||||
if (scale > 1) {
|
if (scale >= 1) {
|
||||||
scale = 1;
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getFullSizeImage(original, scale);
|
return TransformedImageCache.getResizedImage(original, (int)(original.getWidth() * scale), (int)(original.getHeight() * scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TFile getTFile(String path) {
|
public static TFile getTFile(String path) {
|
||||||
|
|
|
@ -39,6 +39,8 @@ package mage.cards;
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
*/
|
*/
|
||||||
public class TextPopup extends javax.swing.JPanel {
|
public class TextPopup extends javax.swing.JPanel {
|
||||||
|
private String text;
|
||||||
|
private boolean needsUpdate;
|
||||||
|
|
||||||
/** Creates new form TextPopup */
|
/** Creates new form TextPopup */
|
||||||
public TextPopup() {
|
public TextPopup() {
|
||||||
|
@ -46,7 +48,17 @@ public class TextPopup extends javax.swing.JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setText(String text) {
|
public void setText(String text) {
|
||||||
popupText.setText(text);
|
if(!text.equals(this.text)) {
|
||||||
|
this.text = text;
|
||||||
|
this.needsUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateText() {
|
||||||
|
if(this.needsUpdate) {
|
||||||
|
popupText.setText(this.text);
|
||||||
|
this.needsUpdate = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This method is called from within the constructor to
|
/** This method is called from within the constructor to
|
||||||
|
|
Loading…
Reference in a new issue