diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java
index 075793e4433..c8bc92ee21c 100644
--- a/Mage.Client/src/main/java/mage/client/MageFrame.java
+++ b/Mage.Client/src/main/java/mage/client/MageFrame.java
@@ -66,6 +66,7 @@ import javax.swing.UIManager;
import mage.client.cards.CardsStorage;
import mage.client.components.MageComponents;
+import mage.client.components.arcane.ManaSymbols;
import mage.client.dialog.*;
import mage.client.plugins.impl.Plugins;
import mage.client.remote.Session;
@@ -151,6 +152,8 @@ public class MageFrame extends javax.swing.JFrame {
session.getUI().addComponent(MageComponents.CARD_INFO_PANE, cardInfoPane);
desktopPane.add(cardInfoPane, JLayeredPane.POPUP_LAYER);
+ ManaSymbols.loadImages();
+
String filename = "/background.jpg";
try {
if (Plugins.getInstance().isThemePluginLoaded()) {
diff --git a/Mage.Client/src/main/java/mage/client/components/MageTextArea.java b/Mage.Client/src/main/java/mage/client/components/MageTextArea.java
new file mode 100644
index 00000000000..b59c21e0561
--- /dev/null
+++ b/Mage.Client/src/main/java/mage/client/components/MageTextArea.java
@@ -0,0 +1,68 @@
+package mage.client.components;
+
+import mage.client.components.arcane.ManaSymbols;
+import mage.client.components.arcane.UI;
+import mage.view.CardView;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * Component for displaying text in mage.
+ * Supports drawing mana symbols.
+ *
+ * @author nantuko
+ */
+public class MageTextArea extends JEditorPane {
+
+ public MageTextArea() {
+ UI.setHTMLEditorKit(this);
+ setEditable(false);
+ setBackground(new Color(0, 0, 0, 0)); // transparent background
+ setFocusable(false);
+ setBorder(BorderFactory.createLineBorder(Color.red));
+ //setSelectionColor(new Color(0, 0, 0, 0));
+ }
+
+ public void setText(String text) {
+ setText(text, null);
+ }
+
+ public void setText(String text, CardView source) {
+ if (text == null) return;
+
+ boolean smallImages = false;
+ int fontSize = 12;
+
+ String fontFamily = "arial";
+
+ final StringBuffer buffer = new StringBuffer(512);
+ buffer.append("
");
+
+ text = text.replaceAll("#([^#]+)#", "$1");
+ text = text.replaceAll("\\s*//\\s*", "
");
+ text = text.replace("\r\n", "");
+ text += "
";
+
+ if (text.length() > 0) {
+ //buffer.append("
");
+ //text = text.replaceAll("\\{this\\}", card.getName());
+ //text = text.replaceAll("\\{source\\}", card.getName());
+ buffer.append(ManaSymbols.replaceSymbolsWithHTML(text, smallImages));
+ }
+
+ buffer.append("");
+
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ MageTextArea.super.setText(buffer.toString());
+ //System.out.println(buffer.toString());
+ setCaretPosition(0);
+ }
+ });
+ }
+}
diff --git a/Mage.Client/src/main/java/mage/client/components/arcane/ManaSymbols.java b/Mage.Client/src/main/java/mage/client/components/arcane/ManaSymbols.java
new file mode 100644
index 00000000000..80dff70037a
--- /dev/null
+++ b/Mage.Client/src/main/java/mage/client/components/arcane/ManaSymbols.java
@@ -0,0 +1,98 @@
+package mage.client.components.arcane;
+
+import mage.client.constants.Constants;
+import mage.client.util.gui.BufferedImageBuilder;
+import mage.client.util.gui.ImageResizeUtil;
+import org.apache.log4j.Logger;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+
+public class ManaSymbols {
+ private static final Logger log = Logger.getLogger(ManaSymbols.class);
+ static private final Map manaImages = new HashMap();
+ static private final Map manaImagesOriginal = new HashMap();
+ static private Pattern replaceSymbolsPattern = Pattern.compile("\\{([^}/]*)/?([^}]*)\\}");
+ static private boolean noManaSymbols = false;
+
+ 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"*/};
+ for (String symbol : symbols) {
+ File file = new File(Constants.RESOURCE_PATH_MANA_LARGE + "/" + symbol + ".jpg");
+ BufferedImageBuilder builder = new BufferedImageBuilder();
+ Rectangle r = new Rectangle(11, 11);
+ try {
+ Image image = UI.getImageIcon(file.getAbsolutePath()).getImage();
+ BufferedImage resized = ImageResizeUtil.getResizedImage(builder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), r);
+ manaImages.put(symbol, resized);
+ } catch (Exception e) {
+ noManaSymbols = true;
+ }
+ file = new File(Constants.RESOURCE_PATH_MANA_MEDIUM + "/" + symbol + ".jpg");
+ try {
+ Image image = UI.getImageIcon(file.getAbsolutePath()).getImage();
+ manaImagesOriginal.put(symbol, image);
+ } catch (Exception e) {}
+ }
+ }
+
+ static public Image getManaSymbolImage(String symbol) {
+ return manaImagesOriginal.get(symbol);
+ }
+
+ 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 String getStringManaCost(List manaCost) {
+ StringBuilder sb = new StringBuilder();
+ for (String s : manaCost) {
+ sb.append(s);
+ }
+ return sb.toString().replace("{", "").replace("}", " ").trim();
+ }
+
+ 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 (noManaSymbols) {
+ return value;
+ } else {
+ if (small)
+ return replaceSymbolsPattern.matcher(value).replaceAll("
");
+ else {
+ value = value.replace("{slash}", "
");
+ return replaceSymbolsPattern.matcher(value).replaceAll("
");
+ }
+ }
+ }
+}
diff --git a/Mage.Client/src/main/java/mage/client/components/arcane/UI.java b/Mage.Client/src/main/java/mage/client/components/arcane/UI.java
new file mode 100644
index 00000000000..88f2479a9ce
--- /dev/null
+++ b/Mage.Client/src/main/java/mage/client/components/arcane/UI.java
@@ -0,0 +1,163 @@
+package mage.client.components.arcane;
+
+import javax.swing.*;
+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;
+import java.awt.*;
+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;
+
+/**
+ * UI utility functions.
+ */
+public class UI {
+ static private Hashtable imageCache = new Hashtable();
+
+ 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);
+ }
+ }
+}
diff --git a/Mage.Client/src/main/java/mage/client/util/Constants.java b/Mage.Client/src/main/java/mage/client/constants/Constants.java
similarity index 87%
rename from Mage.Client/src/main/java/mage/client/util/Constants.java
rename to Mage.Client/src/main/java/mage/client/constants/Constants.java
index 05435cc70eb..2804f8d751b 100644
--- a/Mage.Client/src/main/java/mage/client/util/Constants.java
+++ b/Mage.Client/src/main/java/mage/client/constants/Constants.java
@@ -26,10 +26,11 @@
* or implied, of BetaSteward_at_googlemail.com.
*/
-package mage.client.util;
+package mage.client.constants;
import javax.swing.BorderFactory;
import javax.swing.border.Border;
+import java.io.File;
/**
*
@@ -73,4 +74,12 @@ public final class Constants {
public static final double SCALE_FACTOR = 0.5;
public static final String PLUGINS_DIRECTORY = "plugins/";
+
+ public static final String RESOURCE_PATH_MANA_LARGE = IO.imageBaseDir + "symbols" + File.separator + "large";
+ public static final String RESOURCE_PATH_MANA_MEDIUM = IO.imageBaseDir + "symbols" + File.separator + "medium";
+
+ public interface IO {
+ public static final String imageBaseDir = "plugins" + File.separator + "images" + File.separator;
+ public static final String IMAGE_PROPERTIES_FILE = "image.url.properties";
+ }
}
diff --git a/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java b/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java
index 676212c45a2..6301ec81bc5 100644
--- a/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java
+++ b/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java
@@ -45,6 +45,7 @@ import java.util.UUID;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import mage.client.MageFrame;
+import mage.client.components.MageTextArea;
import mage.client.remote.Session;
import mage.util.Logging;
@@ -182,7 +183,8 @@ public class FeedbackPanel extends javax.swing.JPanel {
btnRight = new javax.swing.JButton();
btnLeft = new javax.swing.JButton();
jScrollPane1 = new javax.swing.JScrollPane();
- lblMessage = new javax.swing.JTextArea();
+ //lblMessage = new javax.swing.JTextArea();
+ lblMessage = new MageTextArea();
btnSpecial = new javax.swing.JButton();
setBackground(new java.awt.Color(204, 204, 204));
@@ -204,14 +206,16 @@ public class FeedbackPanel extends javax.swing.JPanel {
jScrollPane1.setBorder(javax.swing.BorderFactory.createEtchedBorder());
jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
- lblMessage.setBackground(new java.awt.Color(204, 204, 204));
- lblMessage.setColumns(20);
+ //lblMessage.setBackground(new java.awt.Color(204, 204, 204));
+ /*lblMessage.setColumns(20);
lblMessage.setEditable(false);
lblMessage.setLineWrap(true);
lblMessage.setRows(2);
- lblMessage.setWrapStyleWord(true);
+ lblMessage.setWrapStyleWord(true);*/
+
lblMessage.setBorder(null);
jScrollPane1.setViewportView(lblMessage);
+ jScrollPane1.setBorder(null);
btnSpecial.setText("Special");
btnSpecial.addActionListener(new java.awt.event.ActionListener() {
@@ -265,12 +269,10 @@ public class FeedbackPanel extends javax.swing.JPanel {
}//GEN-LAST:event_btnSpecialActionPerformed
- // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnLeft;
private javax.swing.JButton btnRight;
private javax.swing.JButton btnSpecial;
private javax.swing.JScrollPane jScrollPane1;
- private javax.swing.JTextArea lblMessage;
- // End of variables declaration//GEN-END:variables
-
+ //private javax.swing.JTextArea lblMessage;
+ private MageTextArea lblMessage;
}
diff --git a/Mage.Client/src/main/java/mage/client/util/gui/BufferedImageBuilder.java b/Mage.Client/src/main/java/mage/client/util/gui/BufferedImageBuilder.java
new file mode 100644
index 00000000000..f10dea97ac7
--- /dev/null
+++ b/Mage.Client/src/main/java/mage/client/util/gui/BufferedImageBuilder.java
@@ -0,0 +1,58 @@
+package mage.client.util.gui;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.ImageObserver;
+
+public class BufferedImageBuilder {
+
+ private static final int DEFAULT_IMAGE_TYPE = BufferedImage.TYPE_INT_RGB;
+
+ public BufferedImage bufferImage(Image image) {
+ return bufferImage(image, DEFAULT_IMAGE_TYPE);
+ }
+
+ public BufferedImage bufferImage(Image image, int type) {
+ BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
+ Graphics2D g = bufferedImage.createGraphics();
+ g.drawImage(image, null, null);
+ //waitForImage(bufferedImage);
+ return bufferedImage;
+ }
+
+ private void waitForImage(BufferedImage bufferedImage) {
+ final ImageLoadStatus imageLoadStatus = new ImageLoadStatus();
+ bufferedImage.getHeight(new ImageObserver() {
+ public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
+ if (infoflags == ALLBITS) {
+ imageLoadStatus.heightDone = true;
+ return true;
+ }
+ return false;
+ }
+ });
+ bufferedImage.getWidth(new ImageObserver() {
+ public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
+ if (infoflags == ALLBITS) {
+ imageLoadStatus.widthDone = true;
+ return true;
+ }
+ return false;
+ }
+ });
+ while (!imageLoadStatus.widthDone && !imageLoadStatus.heightDone) {
+ try {
+ Thread.sleep(300);
+ } catch (InterruptedException e) {
+
+ }
+ }
+ }
+
+ class ImageLoadStatus {
+
+ public boolean widthDone = false;
+ public boolean heightDone = false;
+ }
+
+}
\ No newline at end of file
diff --git a/Mage.Client/src/main/java/mage/client/util/gui/ColorsChooser.java b/Mage.Client/src/main/java/mage/client/util/gui/ColorsChooser.java
index ac82f4d7dbe..001388f7941 100644
--- a/Mage.Client/src/main/java/mage/client/util/gui/ColorsChooser.java
+++ b/Mage.Client/src/main/java/mage/client/util/gui/ColorsChooser.java
@@ -1,10 +1,8 @@
package mage.client.util.gui;
-import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
-import java.awt.GridLayout;
import java.awt.Image;
import java.util.ArrayList;
import java.util.List;
@@ -17,8 +15,8 @@ import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
+import mage.client.constants.Constants;
import mage.client.plugins.impl.Plugins;
-import mage.client.util.Constants;
public class ColorsChooser extends JComboBox implements ListCellRenderer {
diff --git a/Mage.Client/src/main/java/mage/client/util/gui/ImageResizeUtil.java b/Mage.Client/src/main/java/mage/client/util/gui/ImageResizeUtil.java
new file mode 100644
index 00000000000..d12e5278aba
--- /dev/null
+++ b/Mage.Client/src/main/java/mage/client/util/gui/ImageResizeUtil.java
@@ -0,0 +1,18 @@
+package mage.client.util.gui;
+
+import com.mortennobel.imagescaling.ResampleOp;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+
+/**
+ * @author nantuko
+ */
+public class ImageResizeUtil {
+
+ public static BufferedImage getResizedImage(BufferedImage original, Rectangle sizeNeed) {
+ ResampleOp resampleOp = new ResampleOp(sizeNeed.width, sizeNeed.height);
+ BufferedImage image = resampleOp.filter(original, null);
+ return image;
+ }
+}