diff --git a/.gitattributes b/.gitattributes index 9aa2f325d16..74f7e73cd45 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15398,6 +15398,7 @@ forge-gui/src/main/java/forge/gui/toolbox/FComboBox.java -text forge-gui/src/main/java/forge/gui/toolbox/FComboBoxPanel.java -text forge-gui/src/main/java/forge/gui/toolbox/FComboBoxWrapper.java -text forge-gui/src/main/java/forge/gui/toolbox/FDigitalClock.java -text +forge-gui/src/main/java/forge/gui/toolbox/FHtmlViewer.java -text forge-gui/src/main/java/forge/gui/toolbox/FLabel.java -text forge-gui/src/main/java/forge/gui/toolbox/FList.java -text forge-gui/src/main/java/forge/gui/toolbox/FMouseAdapter.java -text diff --git a/forge-gui/src/main/java/forge/game/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/game/player/PlayerControllerHuman.java index 4865ac167fd..06f1d6feb58 100644 --- a/forge-gui/src/main/java/forge/game/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/game/player/PlayerControllerHuman.java @@ -60,6 +60,7 @@ import forge.gui.input.InputSelectCards; import forge.gui.input.InputSelectCardsFromList; import forge.gui.match.CMatchUI; import forge.gui.match.controllers.CMessage; +import forge.gui.toolbox.FSkin; import forge.item.PaperCard; import forge.properties.ForgePreferences.FPref; import forge.util.Lang; @@ -125,7 +126,7 @@ public class PlayerControllerHuman extends PlayerController { if (enabled) { hasEnabled = true; } - GuiUtils.addMenuItem(menu, ab.toString(), + GuiUtils.addMenuItem(menu, FSkin.encodeSymbols(ab.toString()), shortcut > 0 ? KeyStroke.getKeyStroke(shortcut, 0) : null, new Runnable() { @Override diff --git a/forge-gui/src/main/java/forge/gui/CardDetailPanel.java b/forge-gui/src/main/java/forge/gui/CardDetailPanel.java index 178d7c2e8b7..70261fb8389 100644 --- a/forge-gui/src/main/java/forge/gui/CardDetailPanel.java +++ b/forge-gui/src/main/java/forge/gui/CardDetailPanel.java @@ -28,7 +28,6 @@ import java.util.Iterator; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JPanel; -import javax.swing.JTextArea; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.border.Border; @@ -52,7 +51,7 @@ import forge.gui.toolbox.FLabel; import forge.gui.toolbox.FPanel; import forge.gui.toolbox.FScrollPane; import forge.gui.toolbox.FSkin; -import forge.gui.toolbox.FTextArea; +import forge.gui.toolbox.FHtmlViewer; import forge.item.IPaperCard; import forge.item.InventoryItemFromSet; import forge.item.OpenablePack; @@ -76,7 +75,7 @@ public class CardDetailPanel extends FPanel { private final FLabel powerToughnessLabel; private final FLabel idLabel; private final JLabel setInfoLabel; - private final FTextArea cdArea; + private final FHtmlViewer cdArea; private final FScrollPane scrArea; public CardDetailPanel(final Card card) { @@ -133,7 +132,7 @@ public class CardDetailPanel extends FPanel { this.setInfoLabel.setHorizontalAlignment(SwingConstants.CENTER); //4, 12 - this.cdArea = new FTextArea(); + this.cdArea = new FHtmlViewer(); this.cdArea.setFont(new java.awt.Font("Dialog", 0, 14)); this.cdArea.setBorder(new EmptyBorder(4, 4, 4, 4)); this.cdArea.setOpaque(false); @@ -230,7 +229,7 @@ public class CardDetailPanel extends FPanel { if ( card.isSplitCard() && card.getCurState() == CardCharacteristicName.Original) { manaCost = card.getRules().getMainPart().getManaCost().toString() + " // " + card.getRules().getOtherPart().getManaCost().toString(); } - this.nameCostLabel.setText(card.getName() + " - " + manaCost); + this.nameCostLabel.setText(FSkin.encodeSymbols(card.getName() + " - " + manaCost)); } this.typeLabel.setText(formatCardType(card)); @@ -601,7 +600,7 @@ public class CardDetailPanel extends FPanel { String mustBlockThese = Lang.joinHomogenous(card.getMustBlockCards()); area.append("Must block " + mustBlockThese); } - return area.toString(); + return FSkin.encodeSymbols(area.toString()); } /** @return JLabel */ @@ -625,7 +624,7 @@ public class CardDetailPanel extends FPanel { } /** @return JLabel */ - public JTextArea getCDArea() { + public FHtmlViewer getCDArea() { return this.cdArea; } diff --git a/forge-gui/src/main/java/forge/gui/toolbox/FHtmlViewer.java b/forge-gui/src/main/java/forge/gui/toolbox/FHtmlViewer.java new file mode 100644 index 00000000000..d933b99714e --- /dev/null +++ b/forge-gui/src/main/java/forge/gui/toolbox/FHtmlViewer.java @@ -0,0 +1,34 @@ +package forge.gui.toolbox; + +import javax.swing.JEditorPane; + +/** + * Viewer for HTML + * + */ +@SuppressWarnings("serial") +public class FHtmlViewer extends JEditorPane { + /** */ + public FHtmlViewer() { + super(); + FSkin.JTextComponentSkin skin = FSkin.get(this); + skin.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT)); + skin.setCaretColor(FSkin.getColor(FSkin.Colors.CLR_TEXT)); + this.setOpaque(false); + this.setFocusable(false); + this.setEditable(false); + this.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE); + this.setContentType("text/html"); + } + + /** @param str {@java.lang.String} */ + public FHtmlViewer(final String str) { + this(); + this.setText(str); + } + + @Override + public void setText(String text) { + super.setText(text.replaceAll("(\r\n)|(\n)", "
")); //replace line breaks with
elements + } +} diff --git a/forge-gui/src/main/java/forge/gui/toolbox/FSkin.java b/forge-gui/src/main/java/forge/gui/toolbox/FSkin.java index 52b5f4439b9..64c72422a60 100644 --- a/forge-gui/src/main/java/forge/gui/toolbox/FSkin.java +++ b/forge-gui/src/main/java/forge/gui/toolbox/FSkin.java @@ -32,8 +32,10 @@ import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; +import java.net.MalformedURLException; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; @@ -58,6 +60,7 @@ import forge.FThreads; import forge.Singletons; import forge.gui.GuiUtils; import forge.properties.ForgePreferences; +import forge.properties.NewConstants; import forge.properties.ForgePreferences.FPref; import forge.view.FView; @@ -965,6 +968,24 @@ public enum FSkin { return scaledImage; } + public boolean save(String path, int w, int h) { + final BufferedImage resizedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + + final Graphics2D g2d = resizedImage.createGraphics(); + g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2d.drawImage(this.image, 0, 0, w, h, 0, 0, this.getWidth(), this.getHeight(), null); + g2d.dispose(); + + File outputfile = new File(path); + try { + ImageIO.write(resizedImage, "png", outputfile); + return true; + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + public SkinImage scale(double scale) { return scale(scale, scale); } @@ -1626,6 +1647,32 @@ public enum FSkin { } } + private final static Map encodingSymbolLookup = new LinkedHashMap(); //must be LinkedHashMap so iteration order is same as add order + + private static void addEncodingSymbol(String key, SkinProp skinProp) { + String path = NewConstants.CACHE_SYMBOLS_DIR + "/" + key.replace('/', '_') + ".png"; + if (!getImage(skinProp).save(path, 13, 13)) { return; } + + try { + encodingSymbolLookup.put(key, new File(path).toURI().toURL().toString()); //cache image url as string + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + + public static String encodeSymbols(String in) { + String out = in; + for (Entry e : encodingSymbolLookup.entrySet()) { + //replace symbol if followed by space, comma, semi-colon, or if it ends line + out = out.replaceAll("(?"); + } + if (!out.equals(in)) { + out = out.replaceAll("'> +"; //need to wrap in HTML tags to ensure text rendered as HTML so symbols appear + } + return out; + } + private static final String FILE_SKINS_DIR = "res/skins/", FILE_ICON_SPRITE = "sprite_icons.png", @@ -1835,6 +1882,52 @@ public enum FSkin { FSkin.bimPreferredSprite = null; FSkin.bimDefaultAvatars = null; FSkin.bimPreferredAvatars = null; + + //establish encoding symbols + File dir = new File(NewConstants.CACHE_SYMBOLS_DIR); + if (!dir.mkdir()) { //ensure symbols directory exists and is empty + for (File file : dir.listFiles()) { + file.delete(); + } + } + encodingSymbolLookup.clear(); + + addEncodingSymbol("W/U", ManaImages.IMG_WHITE_BLUE); + addEncodingSymbol("U/B", ManaImages.IMG_BLUE_BLACK); + addEncodingSymbol("B/R", ManaImages.IMG_BLACK_RED); + addEncodingSymbol("R/G", ManaImages.IMG_RED_GREEN); + addEncodingSymbol("G/W", ManaImages.IMG_GREEN_WHITE); + addEncodingSymbol("W/B", ManaImages.IMG_WHITE_BLACK); + addEncodingSymbol("U/R", ManaImages.IMG_BLUE_RED); + addEncodingSymbol("B/G", ManaImages.IMG_BLACK_GREEN); + addEncodingSymbol("R/W", ManaImages.IMG_RED_WHITE); + addEncodingSymbol("G/U", ManaImages.IMG_GREEN_BLUE); + addEncodingSymbol("2/W", ManaImages.IMG_2W); + addEncodingSymbol("2/U", ManaImages.IMG_2U); + addEncodingSymbol("2/B", ManaImages.IMG_2B); + addEncodingSymbol("2/R", ManaImages.IMG_2R); + addEncodingSymbol("2/G", ManaImages.IMG_2G); + addEncodingSymbol("W/P", ManaImages.IMG_PHRYX_WHITE); + addEncodingSymbol("U/P", ManaImages.IMG_PHRYX_BLUE); + addEncodingSymbol("B/P", ManaImages.IMG_PHRYX_BLACK); + addEncodingSymbol("R/P", ManaImages.IMG_PHRYX_RED); + addEncodingSymbol("G/P", ManaImages.IMG_PHRYX_GREEN); + addEncodingSymbol("W", ManaImages.IMG_WHITE); //NOTE: single character symbols must come after multi-character symbols to ensure the correct symbol is used + addEncodingSymbol("U", ManaImages.IMG_BLUE); + addEncodingSymbol("B", ManaImages.IMG_BLACK); + addEncodingSymbol("R", ManaImages.IMG_RED); + addEncodingSymbol("G", ManaImages.IMG_GREEN); + for (int i = 0; i <= 20; i++) { + try { + addEncodingSymbol(String.valueOf(i), ColorlessManaImages.valueOf("IMG_" + i)); + } + catch (Exception e) {} //ignore exception from non-existant mana image + } + addEncodingSymbol("X", ColorlessManaImages.IMG_X); + addEncodingSymbol("Y", ColorlessManaImages.IMG_Y); + addEncodingSymbol("Z", ColorlessManaImages.IMG_Z); + addEncodingSymbol("Tap", GameplayImages.IMG_TAP); + addEncodingSymbol("Untap", GameplayImages.IMG_UNTAP); // Set look and feel after skin loaded FView.SINGLETON_INSTANCE.setSplashProgessBarMessage("Setting look and feel..."); diff --git a/forge-gui/src/main/java/forge/properties/NewConstants.java b/forge-gui/src/main/java/forge/properties/NewConstants.java index 124ec2e4496..99ca31dc0c1 100644 --- a/forge-gui/src/main/java/forge/properties/NewConstants.java +++ b/forge-gui/src/main/java/forge/properties/NewConstants.java @@ -96,6 +96,7 @@ public final class NewConstants { public static final String DB_DIR = CACHE_DIR + "db/"; public static final String CACHE_TOKEN_PICS_DIR = _PICS_DIR + "tokens/"; public static final String CACHE_ICON_PICS_DIR = _PICS_DIR + "icons/"; + public static final String CACHE_SYMBOLS_DIR = _PICS_DIR + "symbols/"; public static final String CACHE_BOOSTER_PICS_DIR = _PICS_DIR + "boosters/"; public static final String CACHE_FATPACK_PICS_DIR = _PICS_DIR + "fatpacks/"; public static final String CACHE_PRECON_PICS_DIR = _PICS_DIR + "precons/";