diff --git a/.gitattributes b/.gitattributes index e0239c2cdc0..43b20a32afc 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9343,6 +9343,23 @@ res/images/deckeditor/filter_sorcery_n.png -text svneol=unset#image/png res/images/deckeditor/filter_sorcery_y.png -text svneol=unset#image/png res/images/deckeditor/filter_white_n.png -text svneol=unset#image/png res/images/deckeditor/filter_white_y.png -text svneol=unset#image/png +res/images/skins/default/bg_splash.jpg -text +res/images/skins/default/btnLdown.png -text +res/images/skins/default/btnLover.png -text +res/images/skins/default/btnLup.png -text +res/images/skins/default/btnMdown.png -text +res/images/skins/default/btnMover.png -text +res/images/skins/default/btnMup.png -text +res/images/skins/default/btnRdown.png -text +res/images/skins/default/btnRover.png -text +res/images/skins/default/btnRup.png -text +res/images/skins/default/font1.ttf -text +res/images/skins/default/font2.ttf -text +res/images/skins/default/palette.jpg -text +res/images/skins/default/settings.txt -text +res/images/skins/default/texture1.jpg -text +res/images/skins/default/texture2.jpg -text +res/images/skins/default/texture3.jpg -text res/images/symbols-13/0.png -text svneol=unset#image/png res/images/symbols-13/1.png -text svneol=unset#image/png res/images/symbols-13/10.png -text svneol=unset#image/png @@ -10259,6 +10276,10 @@ src/main/java/forge/gui/input/Input_PayManaCostUtil.java svneol=native#text/plai src/main/java/forge/gui/input/Input_PayManaCost_Ability.java svneol=native#text/plain src/main/java/forge/gui/input/package-info.java svneol=native#text/plain src/main/java/forge/gui/package-info.java svneol=native#text/plain +src/main/java/forge/gui/skin/FButton.java -text +src/main/java/forge/gui/skin/FPanel.java -text +src/main/java/forge/gui/skin/FRoundedPanel.java -text +src/main/java/forge/gui/skin/FSkin.java -text src/main/java/forge/item/BoosterPack.java -text src/main/java/forge/item/CardDb.java -text src/main/java/forge/item/CardPrinted.java -text diff --git a/.gitignore b/.gitignore index d18dc44c0d9..f98d220611a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ res/cardsfolder/cardsfolder.zip res/decks/AI_o1.dck res/decks/o1.bdk res/gui/display_new_layout.xml +res/images/themes res/oracleScript.log res/quest/questData.dat res/quest/questData.dat.xml diff --git a/res/images/skins/default/bg_splash.jpg b/res/images/skins/default/bg_splash.jpg new file mode 100644 index 00000000000..6c929aa0f40 Binary files /dev/null and b/res/images/skins/default/bg_splash.jpg differ diff --git a/res/images/skins/default/btnLdown.png b/res/images/skins/default/btnLdown.png new file mode 100644 index 00000000000..1ebc3acbe33 Binary files /dev/null and b/res/images/skins/default/btnLdown.png differ diff --git a/res/images/skins/default/btnLover.png b/res/images/skins/default/btnLover.png new file mode 100644 index 00000000000..f1c1d5a88a1 Binary files /dev/null and b/res/images/skins/default/btnLover.png differ diff --git a/res/images/skins/default/btnLup.png b/res/images/skins/default/btnLup.png new file mode 100644 index 00000000000..26a28d34e1c Binary files /dev/null and b/res/images/skins/default/btnLup.png differ diff --git a/res/images/skins/default/btnMdown.png b/res/images/skins/default/btnMdown.png new file mode 100644 index 00000000000..d53b4fff943 Binary files /dev/null and b/res/images/skins/default/btnMdown.png differ diff --git a/res/images/skins/default/btnMover.png b/res/images/skins/default/btnMover.png new file mode 100644 index 00000000000..7e23fca1e26 Binary files /dev/null and b/res/images/skins/default/btnMover.png differ diff --git a/res/images/skins/default/btnMup.png b/res/images/skins/default/btnMup.png new file mode 100644 index 00000000000..f71f8d36d89 Binary files /dev/null and b/res/images/skins/default/btnMup.png differ diff --git a/res/images/skins/default/btnRdown.png b/res/images/skins/default/btnRdown.png new file mode 100644 index 00000000000..bd2037c3329 Binary files /dev/null and b/res/images/skins/default/btnRdown.png differ diff --git a/res/images/skins/default/btnRover.png b/res/images/skins/default/btnRover.png new file mode 100644 index 00000000000..89568942f54 Binary files /dev/null and b/res/images/skins/default/btnRover.png differ diff --git a/res/images/skins/default/btnRup.png b/res/images/skins/default/btnRup.png new file mode 100644 index 00000000000..1f70fe6b5fc Binary files /dev/null and b/res/images/skins/default/btnRup.png differ diff --git a/res/images/skins/default/font1.ttf b/res/images/skins/default/font1.ttf new file mode 100644 index 00000000000..8cd78415278 Binary files /dev/null and b/res/images/skins/default/font1.ttf differ diff --git a/res/images/skins/default/font2.ttf b/res/images/skins/default/font2.ttf new file mode 100644 index 00000000000..bd62e60aac9 Binary files /dev/null and b/res/images/skins/default/font2.ttf differ diff --git a/res/images/skins/default/palette.jpg b/res/images/skins/default/palette.jpg new file mode 100644 index 00000000000..e874623f4b5 Binary files /dev/null and b/res/images/skins/default/palette.jpg differ diff --git a/res/images/skins/default/settings.txt b/res/images/skins/default/settings.txt new file mode 100644 index 00000000000..da39ccc2a4f --- /dev/null +++ b/res/images/skins/default/settings.txt @@ -0,0 +1,16 @@ +# Settings are stored in a key=value format. +# Color values are stored as RR,GG,BB[,AA] values 0 to 255 +# Dimension values are stored as x,y +# Incomplete settings will make the file switch to the default theme. + +# Texture opacity settings, 0-100 +texture1opacity=100; +texture2opacity=100; +texture3opacity=100; + +# FRoundedPanel +shadowColor=150,150,150,150 +borderColor=0,0,0 +shadowDistance=5,5 +shadowThickness=5 +cornerDiameter=20 \ No newline at end of file diff --git a/res/images/skins/default/texture1.jpg b/res/images/skins/default/texture1.jpg new file mode 100644 index 00000000000..7c925524eb3 Binary files /dev/null and b/res/images/skins/default/texture1.jpg differ diff --git a/res/images/skins/default/texture2.jpg b/res/images/skins/default/texture2.jpg new file mode 100644 index 00000000000..6fc0e6f890f Binary files /dev/null and b/res/images/skins/default/texture2.jpg differ diff --git a/res/images/skins/default/texture3.jpg b/res/images/skins/default/texture3.jpg new file mode 100644 index 00000000000..023287f74d9 Binary files /dev/null and b/res/images/skins/default/texture3.jpg differ diff --git a/src/main/java/forge/AllZone.java b/src/main/java/forge/AllZone.java index 87ae6631229..ca6637d6cfa 100644 --- a/src/main/java/forge/AllZone.java +++ b/src/main/java/forge/AllZone.java @@ -12,6 +12,7 @@ import forge.card.trigger.TriggerHandler; import forge.deck.DeckManager; import forge.game.GameSummary; import forge.gui.input.InputControl; +import forge.gui.skin.FSkin; import forge.model.FGameState; import forge.properties.ForgeProps; import forge.properties.NewConstants; @@ -39,6 +40,9 @@ public final class AllZone implements NewConstants { // blank } + /** Global SKIN. */ + private static FSkin SKIN = null; + /** Global questData. */ private static forge.quest.data.QuestData questData = null; @@ -53,7 +57,7 @@ public final class AllZone implements NewConstants { /** Constant COLOR_CHANGER. */ private static final ColorChanger COLOR_CHANGER = new ColorChanger(); - + // Phase is now a prerequisite for CardFactory /** Global cardFactory. */ private static CardFactoryInterface cardFactory = null; @@ -494,4 +498,26 @@ public final class AllZone implements NewConstants { public static ColorChanger getColorChanger() { return COLOR_CHANGER; } + + /** + *

getSkin.

+ * Gets current display skin. + * + * @return a {@link forge.gui.skin.FSkin} object. + * @since 1.0.15 + */ + public static FSkin getSkin() { + return SKIN; + } + + /** + *

setSkin.

+ * Sets current display skin. + * + * @param attackers a {@link forge.gui.skin.FSkin} object. + * @since 1.0.15 + */ + public static void setSkin(final FSkin fs) { + SKIN = fs; + } } //AllZone diff --git a/src/main/java/forge/gui/GuiUtils.java b/src/main/java/forge/gui/GuiUtils.java index eb8cccc3d41..b96c4d34b84 100644 --- a/src/main/java/forge/gui/GuiUtils.java +++ b/src/main/java/forge/gui/GuiUtils.java @@ -17,11 +17,13 @@ import net.slightlymagic.braids.util.UtilFunctions; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; +import java.awt.FontFormatException; import java.awt.Image; import java.awt.Rectangle; import java.awt.Window; import java.awt.image.BufferedImage; import java.io.File; +import java.io.IOException; import java.util.Collection; import java.util.Iterator; import java.util.List; @@ -306,4 +308,24 @@ public final class GuiUtils { bounds.y = (screen.height - bounds.height) / 2; frame.setBounds(bounds); } + + /** + * Attempts to create a font from a filename. Concise error reported + * if exceptions found. + * + * @param {@link java.lang.String} filename + */ + public static Font newFont(String filename) { + File file = new File(filename); + Font ttf = null; + + try { + ttf = Font.createFont(Font.TRUETYPE_FONT,file); + } catch (FontFormatException e) { + System.err.println("GuiUtils > newFont: bad font format \"" + filename + "\""); + } catch (IOException e) { + System.err.println("GuiUtils > newFont: can't find \""+filename+"\""); + } + return ttf; + } } diff --git a/src/main/java/forge/gui/skin/FButton.java b/src/main/java/forge/gui/skin/FButton.java new file mode 100644 index 00000000000..0a5cfce9014 --- /dev/null +++ b/src/main/java/forge/gui/skin/FButton.java @@ -0,0 +1,95 @@ +package forge.gui.skin; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import javax.swing.JButton; +import forge.AllZone; + +/** + * The core JButton used throughout the Forge project. + * Follows skin font and theme button styling. + * + */ +@SuppressWarnings("serial") +public class FButton extends JButton { + protected Image imgL, imgM, imgR; + private int w, h = 0; + private boolean allImagesPresent = false; + private RenderingHints rh; + private FSkin skin; + private AlphaComposite disabledComposite = + AlphaComposite.getInstance(AlphaComposite.SRC_OVER,0.25f); + + public FButton(String msg) { + super(msg); + this.skin = AllZone.getSkin(); + this.setOpaque(false); + this.setForeground(skin.txt1a); + this.setBackground(Color.red); + this.setContentAreaFilled(false); + this.setFont(skin.font1.deriveFont(Font.PLAIN,14)); + this.imgL = skin.btnLup.getImage(); + this.imgM = skin.btnMup.getImage(); + this.imgR = skin.btnRup.getImage(); + + rh = new RenderingHints( + RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON + ); + + if(this.imgL != null && this.imgM != null && this.imgR != null) { + allImagesPresent = true; + } + + this.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseEntered(java.awt.event.MouseEvent evt) { + if(isEnabled()) { + imgL = skin.btnLover.getImage(); + imgM = skin.btnMover.getImage(); + imgR = skin.btnRover.getImage(); + } + } + public void mouseExited(java.awt.event.MouseEvent evt) { + if(isEnabled()) { + imgL = skin.btnLup.getImage(); + imgM = skin.btnMup.getImage(); + imgR = skin.btnRup.getImage(); + } + } + public void mousePressed(java.awt.event.MouseEvent evt) { + if(isEnabled()) { + imgL = skin.btnLdown.getImage(); + imgM = skin.btnMdown.getImage(); + imgR = skin.btnRdown.getImage(); + } + } + }); + } + + protected void paintComponent(Graphics g) { + if(!allImagesPresent) { + return; + } + + Graphics2D g2d = (Graphics2D)g; + g2d.setRenderingHints(rh); + + if(!isEnabled()) { + g2d.setComposite(disabledComposite); + } + + w = this.getWidth(); + h = this.getHeight(); + + g2d.drawImage(imgL,0,0,h,h,null); + g2d.drawImage(imgM,h,0,w - 2*h,h,null); + g2d.drawImage(imgR,w-h,0,h,h,null); + + super.paintComponent(g); + } +} \ No newline at end of file diff --git a/src/main/java/forge/gui/skin/FPanel.java b/src/main/java/forge/gui/skin/FPanel.java new file mode 100644 index 00000000000..204db44b565 --- /dev/null +++ b/src/main/java/forge/gui/skin/FPanel.java @@ -0,0 +1,55 @@ +package forge.gui.skin; + +import java.awt.Graphics; +import java.awt.LayoutManager; +import javax.swing.ImageIcon; +import javax.swing.JPanel; + +/**

FPanel.

+ * The core JPanel used throughout the Forge project. + * Allows tiled images and ... + * + */ +@SuppressWarnings("serial") +public class FPanel extends JPanel { + private ImageIcon bgImg = null; + private int w, h, iw, ih, x, y = 0; + + public FPanel() { + super(); + } + + public FPanel(LayoutManager lm) { + this(); + this.setLayout(lm); + } + + protected void paintComponent(Graphics g) { + //System.out.print("\nRepainting. "); + if(this.bgImg != null) { + w = getWidth(); + h = getHeight(); + iw = this.bgImg.getIconWidth(); + ih = this.bgImg.getIconHeight(); + + while(x < w) { + while(y < h) { + g.drawImage(bgImg.getImage(),x,y,null); + y += ih; + } + x += iw; + y = 0; + } + x = 0; + } + + super.paintComponent(g); + } + + public void setBGImg(ImageIcon icon) { + this.bgImg = icon; + if(this.bgImg != null) { + this.setOpaque(false); + } + } +} diff --git a/src/main/java/forge/gui/skin/FRoundedPanel.java b/src/main/java/forge/gui/skin/FRoundedPanel.java new file mode 100644 index 00000000000..7aa844fe187 --- /dev/null +++ b/src/main/java/forge/gui/skin/FRoundedPanel.java @@ -0,0 +1,230 @@ +package forge.gui.skin; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.LayoutManager; +import java.awt.RenderingHints; + +import javax.swing.JPanel; + +import forge.AllZone; + +/**

FRoundedPanel.

+ * A subclass of JPanel with optional rounded corners and + * optional drop shadow, for special cases only. FPanel recommended for regular use. + * Limitations - cannot use background image, and single line border only. + * + * Default values provided, later updated from skin settings, and can be + * set dynamically. + * + */ +@SuppressWarnings("serial") +public class FRoundedPanel extends JPanel { + private FSkin skin; + private Color shadowColor = new Color(150,150,150,150); + private Color borderColor = Color.black; + private Dimension shadowDistance = new Dimension(5,5); + private int shadowThickness = 5; + private int cornerRadius = 20; // Note: this number is actually diameter. + + /** + *

FRoundedPanel.

+ * + * Constructor, null layout manager. + */ + public FRoundedPanel() { + super(); + this.setOpaque(false); + skin = AllZone.getSkin(); + + Color tempC; + Dimension tempD; + String tempS; + + tempC = parseColorString(skin.getSetting("shadowColor")); + if(tempC != null) { shadowColor = tempC; } + + tempC = parseColorString(skin.getSetting("borderColor")); + if(tempC != null) { borderColor = tempC; } + + tempD = parseDimensionString(skin.getSetting("shadowDistance")); + if(tempD != null) { shadowDistance = tempD; } + + tempS = skin.getSetting("shadowThickness"); + if(tempS != null) { shadowThickness = Integer.parseInt(tempS); } + + tempS = skin.getSetting("cornerRadius"); + if(tempS != null) { cornerRadius = Integer.parseInt(tempS); } + } + + /** + *

FRoundedPanel.

+ * + * Constructor. + * @param {@link java.awt.LayoutManager} + */ + public FRoundedPanel(LayoutManager lm) { + this(); + this.setLayout(lm); + } + + /** + *

FRoundedPanel.

+ * + * Constructor. + * @param {@link java.awt.Graphics} + */ + protected void paintComponent(Graphics g) { + super.paintComponent(g); + int w = getWidth(); + int h = getHeight(); + + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + // Draw shadow + g2d.setColor(shadowColor); + g2d.setStroke(new BasicStroke(shadowThickness)); + g2d.drawRoundRect( + 0 + (int)shadowDistance.getWidth() + (shadowThickness/2), + 0 + (int)shadowDistance.getHeight() + (shadowThickness/2), + w - (int)shadowDistance.getWidth() - shadowThickness, + h - (int)shadowDistance.getHeight() - shadowThickness, + cornerRadius, cornerRadius); + + // Draw content rectangle (on top of shadow) + g2d.setColor(this.getBackground()); + g2d.fillRoundRect( + 0, 0, + w - shadowThickness, + h - shadowThickness, + cornerRadius, cornerRadius); + + // Stroke border + g2d.setColor(this.borderColor); + g2d.setStroke(new BasicStroke(1)); + g2d.drawRoundRect( + 0,0, + w - shadowThickness, + h - shadowThickness, + cornerRadius, cornerRadius); + } + + /** + *

setShadowColor.

+ * Sets color of shadow behind rounded panel. + * + * @param {@link java.awt.Color} + */ + public void setShadowColor(Color c) { + this.shadowColor = c; + } + + /** + *

setBorderColor.

+ * Sets color of border around rounded panel. + * + * @param {@link java.awt.Color} + */ + public void setBorderColor(Color c) { + this.borderColor = c; + } + + /** + *

setShadowDistance.

+ * Sets distance of shadow from rounded panel. + * + * @param {@link java.lang.Integer} side + */ + public void setShadowDistance(int side) { + this.shadowDistance = new Dimension(side,side); + } + + /** + *

setShadowDistance.

+ * Sets distance of shadow from rounded panel. + * + * @param {@link java.lang.Integer} x + * @param {@link java.lang.Integer} y + */ + public void setShadowDistance(int x, int y) { + this.shadowDistance = new Dimension(x,y); + } + + /** + *

setShadowDistance.

+ * Sets thickness of rounded panel shadow. + * + * @param {@link java.lang.Integer} t + */ + public void setShadowThickness(int t) { + this.shadowThickness = t; + } + + /** + *

setCornerRadius.

+ * Sets radius of each corner on rounded panel. + * + * @param {@link java.lang.Integer} r + */ + public void setCornerRadius(int r) { + if(r < 0) { + r = 0; + } + + this.cornerRadius = r*2; + } + + /** + *

parseColorString.

+ * Uses string from settings file to make a new rgba color instance. + * + * @param {@link java.lang.String} s + */ + private Color parseColorString(String s) { + Color c = null; + int r,g,b,a = 0; + String[] temp = s.split(","); + + if(temp.length==3 || temp.length==4) { + r = Integer.parseInt(temp[0]); + g = Integer.parseInt(temp[1]); + b = Integer.parseInt(temp[2]); + if(temp.length==4) { + a = Integer.parseInt(temp[3]); + } + c = new Color(r,g,b,a); + } + + return c; + } + + /** + *

parseDimensionString.

+ * Uses string from settings file to make a new dimension instance. + * + * @param {@link java.lang.String} s + */ + private Dimension parseDimensionString(String s) { + Dimension d = null; + int w,h = 0; + String[] temp = s.split(","); + + if(temp.length==2) { + w = Integer.parseInt(temp[0]); + h = Integer.parseInt(temp[0]); + d = new Dimension(w,h); + } + else if(temp.length==1 && !temp[0].equals("")) { + w = Integer.parseInt(temp[0]); + h = w; + d = new Dimension(w,h); + } + + return d; + } +} diff --git a/src/main/java/forge/gui/skin/FSkin.java b/src/main/java/forge/gui/skin/FSkin.java new file mode 100644 index 00000000000..8e0b8f4c7d3 --- /dev/null +++ b/src/main/java/forge/gui/skin/FSkin.java @@ -0,0 +1,268 @@ +package forge.gui.skin; + +import java.awt.Color; +import java.awt.Font; +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Hashtable; + +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; + +import forge.gui.GuiUtils; + +/** + * Assembles settings from selected or default theme as appropriate. + * Saves in a hashtable, access using .get(settingName) method. + * + */ + +public class FSkin { + //===== Public fields + public Font font1 = null; + public Font font2 = null; + public ImageIcon texture1 = null; + public ImageIcon texture2 = null; + public ImageIcon texture3 = null; + public ImageIcon btnLup = null; + public ImageIcon btnMup = null; + public ImageIcon btnRup = null; + public ImageIcon btnLover = null; + public ImageIcon btnMover = null; + public ImageIcon btnRover = null; + public ImageIcon btnLdown = null; + public ImageIcon btnMdown = null; + public ImageIcon btnRdown = null; + + public Color bg1a = Color.red; + public Color bg1b = Color.red; + public Color bg2a = Color.red; + public Color bg2b = Color.red; + public Color bg3a = Color.red; + public Color bg3b = Color.red; + + public Color txt1a = Color.red; + public Color txt1b = Color.red; + public Color txt2a = Color.red; + public Color txt2b = Color.red; + public Color txt3a = Color.red; + public Color txt3b = Color.red; + + //===== Private fields + private final String settingsfile = "settings.txt"; + private final String paletteFile = "palette.jpg"; + private final String font1file = "font1.ttf"; + private final String font2file = "font2.ttf"; + private final String texture1file = "texture1.jpg"; + private final String texture2file = "texture2.jpg"; + private final String texture3file = "texture3.jpg"; + private final String btnLupfile = "btnLup.png"; + private final String btnMupfile = "btnMup.png"; + private final String btnRupfile = "btnRup.png"; + private final String btnLoverfile = "btnLover.png"; + private final String btnMoverfile = "btnMover.png"; + private final String btnRoverfile = "btnRover.png"; + private final String btnLdownfile = "btnLdown.png"; + private final String btnMdownfile = "btnMdown.png"; + private final String btnRdownfile = "btnRdown.png"; + + private ImageIcon tempImg; + private Font tempFont; + private String skin; + private String notfound = "FSkin.java: \""+skin+ + "\" skin can't find "; + private Hashtable customSettings = + new Hashtable(); + private Hashtable defaultSettings = + new Hashtable(); + + /** + * FSkin constructor. No arguments, will generate default skin settings, + * fonts, and backgrounds. + * + * @throws Exception + */ + public FSkin() throws Exception { + this("default"); + } + + /** + * FSkin constructor, using skin name. Generates custom skin settings, + * fonts, and backgrounds. + * + * @param themeName + * @throws Exception + */ + public FSkin(String skinName) throws Exception { + defaultSettings = loadSettings("default"); + loadFontAndImages("default"); + + if(!skinName.equals("default")) { + customSettings = loadSettings(skinName); + loadFontAndImages(skinName); + } + } + + /** + * Retrieves skin settings from file, returns in hashtable. + * + * @param skinName + * @return settings hashtable + * @throws Exception + */ + private Hashtable loadSettings(String skinName) throws Exception { + String filename = "res/images/skins/"+skinName+"/"+settingsfile; + + String notfound = "FSkin > load: Can't find \"" + filename + "\"."; + Hashtable settings = new Hashtable(); + + File f = new File(filename); + customSettings.put("name",skinName); + + if (!f.exists()) { + throw new RuntimeException(notfound); + } + + BufferedReader input = new BufferedReader(new FileReader(f)); + String line = null; + while ((line = input.readLine()) != null) { + String[] data = line.split("="); + if (line.startsWith("#") || line.length() == 0 || data.length != 2) { + continue; + } + + settings.put(data[0],data[1]); + } + + return settings; + } + + /** + * Loads objects from skin folder, prints brief error if not found. + * + * @param skinName + */ + private void loadFontAndImages(String skinName) { + String dirName = "res/images/skins/"+skinName+"/"; + + // Fonts + font1 = retrieveFont(dirName + font1file); + font2 = retrieveFont(dirName + font2file); + + // Images + texture1 = retrieveImage(dirName + texture1file); + texture2 = retrieveImage(dirName + texture2file); + texture3 = retrieveImage(dirName + texture3file); + btnLup = retrieveImage(dirName + btnLupfile); + btnMup = retrieveImage(dirName + btnMupfile); + btnRup = retrieveImage(dirName + btnRupfile); + btnLover = retrieveImage(dirName + btnLoverfile); + btnMover = retrieveImage(dirName + btnMoverfile); + btnRover = retrieveImage(dirName + btnRoverfile); + btnLdown = retrieveImage(dirName + btnLdownfile); + btnMdown = retrieveImage(dirName + btnMdownfile); + btnRdown = retrieveImage(dirName + btnRdownfile); + + // Color palette + File file= new File(dirName + paletteFile); + BufferedImage image; + try { + image = ImageIO.read(file); + bg1a = getColorFromPixel(image.getRGB(10,30)); + bg1b = getColorFromPixel(image.getRGB(30,30)); + bg2a = getColorFromPixel(image.getRGB(50,30)); + bg2b = getColorFromPixel(image.getRGB(70,30)); + bg3a = getColorFromPixel(image.getRGB(90,30)); + bg3b = getColorFromPixel(image.getRGB(110,30)); + + txt1a = getColorFromPixel(image.getRGB(10,70)); + txt1b = getColorFromPixel(image.getRGB(30,70)); + txt2a = getColorFromPixel(image.getRGB(50,70)); + txt2b = getColorFromPixel(image.getRGB(70,70)); + txt3a = getColorFromPixel(image.getRGB(90,70)); + txt3b = getColorFromPixel(image.getRGB(110,70)); + } catch (IOException e) { + System.err.println(notfound + paletteFile); + } + + } + + /** + *

retrieveImage.

+ * Tries to instantiate an image icon from a filename. + * Error reported if not found. + * + * @param {@link java.lang.String} address + * @return a ImageIcon + */ + private ImageIcon retrieveImage(String address) { + tempImg = new ImageIcon(address); + if(tempImg.getIconWidth()==-1) { + System.err.println(notfound + address); + } + + return tempImg; + } + + /** + *

retrieveFont.

+ * Uses GuiUtils to grab a font file at an address. + * Error will be reported by GuiUtils if not found. + * Error also reported by this method if not found. + * + * @param {@link java.lang.String} address + * @return a Font + */ + private Font retrieveFont(String address) { + tempFont = GuiUtils.newFont(address); + + return tempFont; + } + + /** + *

getColorFromPixel.

+ * + * @param {@link java.lang.Integer} pixel information + */ + private Color getColorFromPixel(int pixel) { + return new Color( + (pixel & 0x00ff0000) >> 16, + (pixel & 0x0000ff00) >> 8, + (pixel & 0x000000ff) + ); + } + + /** + *

getSetting.

+ * Retrieves a specific skin setting. If skin setting is not defined, + * will attempt to use default value. + * + * @param key a {@link java.lang.String} object. + * @return a {@link java.lang.String} object. + */ + public String getSetting(String key) { + String val = null; + + if(customSettings.size() > 1) { + val = customSettings.get(key); + if(val==null) { + System.err.println("FSkin > getSetting: Could not find "+key+ + " setting for "+customSettings.get("name")+" skin!"); + } + } + + if(val==null) { + val = defaultSettings.get(key); + } + + if(val==null) { + System.err.println("FSkin > getSetting: Could not find "+key+ + " in default settings!"); + } + + return val; + } +} diff --git a/src/main/java/forge/properties/ForgePreferences.java b/src/main/java/forge/properties/ForgePreferences.java index 30740833f69..7249cc2379b 100644 --- a/src/main/java/forge/properties/ForgePreferences.java +++ b/src/main/java/forge/properties/ForgePreferences.java @@ -18,6 +18,7 @@ public class ForgePreferences extends Preferences { public boolean uploadDraftAI; public boolean randCFoil; + public String skin; public String laf; public boolean lafFonts; public StackOffsetType stackOffset; @@ -80,6 +81,7 @@ public class ForgePreferences extends Preferences { laf = get("gui.laf", ""); lafFonts = getBoolean("gui.laf.fonts", false); + skin = get("gui.skin","default"); cardOverlay = getBoolean("card.overlay", true); cardSize = CardSizeType.valueOf(get("card.images.size", "medium")); @@ -122,6 +124,7 @@ public class ForgePreferences extends Preferences { set("rand.C.Foil", randCFoil); + set("gui.skin", skin); set("gui.laf", laf); set("gui.laf.fonts", lafFonts); diff --git a/src/main/java/forge/quest/gui/QuestWinLoseHandler.java b/src/main/java/forge/quest/gui/QuestWinLoseHandler.java index c110f62675d..e97baecaace 100644 --- a/src/main/java/forge/quest/gui/QuestWinLoseHandler.java +++ b/src/main/java/forge/quest/gui/QuestWinLoseHandler.java @@ -112,6 +112,15 @@ public class QuestWinLoseHandler extends WinLoseModeHandler { view.btnQuit.setText("Surrender (15 Credits)"); return false; } + else { + view.btnContinue.setVisible(false); + if(wonMatch) { + view.btnQuit.setText("Great!"); + } + else { + view.btnQuit.setText("OK"); + } + } // Win case if(wonMatch) { @@ -145,8 +154,8 @@ public class QuestWinLoseHandler extends WinLoseModeHandler { } // Win or lose, still a chance to win a booster, frequency set in preferences - int cntOutcomes = wonMatch ? model.qData.getWin() : model.qData.getLost(); - if (cntOutcomes % QuestPreferences.getWinsForBooster(model.qData.getDifficultyIndex()) == 0) { + int outcome = wonMatch ? model.qData.getWin() : model.qData.getLost(); + if (outcome % QuestPreferences.getWinsForBooster(model.qData.getDifficultyIndex()) == 0) { awardBooster(); } @@ -344,7 +353,7 @@ public class QuestWinLoseHandler extends WinLoseModeHandler { lblTemp2 = new JLabel(sb.toString()); lblTemp2.setHorizontalAlignment(SwingConstants.CENTER); - lblTemp2.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblTemp2.setFont(AllZone.getSkin().font2.deriveFont(Font.PLAIN,14)); lblTemp2.setForeground(Color.white); lblTemp2.setIcon(icoTemp); lblTemp2.setIconTextGap(50); @@ -441,7 +450,7 @@ public class QuestWinLoseHandler extends WinLoseModeHandler { ((QuestChallenge)model.qEvent).getTitle() + "\""); lblTemp2 = new JLabel(sb.toString()); - lblTemp2.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblTemp2.setFont(AllZone.getSkin().font2.deriveFont(Font.PLAIN,14)); lblTemp2.setForeground(Color.white); lblTemp2.setHorizontalAlignment(SwingConstants.CENTER); lblTemp2.setIconTextGap(50); @@ -464,7 +473,7 @@ public class QuestWinLoseHandler extends WinLoseModeHandler { lblTemp1 = new TitleLabel("Gameplay Results"); lblTemp2 = new JLabel("You lose! You have lost 15 credits."); - lblTemp2.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblTemp2.setFont(AllZone.getSkin().font2.deriveFont(Font.PLAIN,14)); lblTemp2.setForeground(Color.white); lblTemp2.setHorizontalAlignment(SwingConstants.CENTER); lblTemp2.setIconTextGap(50); @@ -530,11 +539,15 @@ public class QuestWinLoseHandler extends WinLoseModeHandler { return credits; } + /** + * JLabel header between reward sections. + * + */ @SuppressWarnings("serial") private class TitleLabel extends JLabel { TitleLabel(String msg) { super(msg); - this.setFont(new Font("Tahoma", Font.ITALIC, 16)); + this.setFont(AllZone.getSkin().font2.deriveFont(Font.ITALIC,16)); this.setPreferredSize(new Dimension(200,40)); this.setHorizontalAlignment(SwingConstants.CENTER); this.setForeground(Color.white); diff --git a/src/main/java/forge/view/swing/ApplicationView.java b/src/main/java/forge/view/swing/ApplicationView.java index fc1bd419e52..be54c774013 100644 --- a/src/main/java/forge/view/swing/ApplicationView.java +++ b/src/main/java/forge/view/swing/ApplicationView.java @@ -17,6 +17,7 @@ import forge.Constant; import forge.ImageCache; import forge.error.ErrorViewer; import forge.game.GameType; +import forge.gui.skin.FSkin; import forge.model.FModel; import forge.properties.ForgePreferences; import forge.view.FView; @@ -42,7 +43,7 @@ public class ApplicationView implements FView { // contract. UtilFunctions.invokeInEventDispatchThreadAndWait(new Runnable() { // NOPMD by Braids on 8/18/11 11:37 PM - public void run() { + public void run() { splashFrame = new SplashFrame(); } }); @@ -77,7 +78,7 @@ public class ApplicationView implements FView { */ @Override - public final void setModel(final FModel model) { + public final void setModel(final FModel model) { try { final ForgePreferences preferences = model.getPreferences(); @@ -97,6 +98,8 @@ public class ApplicationView implements FView { CardSizesAction.set(preferences.cardSize); OldGuiNewGame.upldDrftCheckBox.setSelected(preferences.uploadDraftAI); OldGuiNewGame.foilRandomCheckBox.setSelected(preferences.randCFoil); + + AllZone.setSkin(new FSkin(preferences.skin)); } catch (Exception exn) { Log.error("Error loading preferences: " + exn); diff --git a/src/main/java/forge/view/swing/WinLoseFrame.java b/src/main/java/forge/view/swing/WinLoseFrame.java index 3493aaedeed..942ffb003bb 100644 --- a/src/main/java/forge/view/swing/WinLoseFrame.java +++ b/src/main/java/forge/view/swing/WinLoseFrame.java @@ -1,22 +1,25 @@ package forge.view.swing; import java.awt.Color; -import java.awt.Container; +import java.awt.Component; import java.awt.Dimension; import java.awt.Font; +import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.ActionEvent; -import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SwingConstants; +import javax.swing.border.AbstractBorder; import forge.AllZone; import forge.Phase; import forge.Player; +import forge.gui.skin.FButton; +import forge.gui.skin.FPanel; import forge.properties.ForgeProps; import forge.properties.NewConstants.LANG.WinLoseFrame.WINLOSETEXT; import forge.quest.data.QuestMatchState; @@ -24,7 +27,7 @@ import forge.quest.data.QuestMatchState; import net.miginfocom.swing.MigLayout; /**

WinLoseFrame.

- * Core display for win/lose UI shown after completing a game. + * VIEW - Core display for win/lose UI shown after completing a game. * Uses handlers to customize central panel for various game modes. * */ @@ -34,9 +37,9 @@ public class WinLoseFrame extends JFrame { private QuestMatchState matchState; private WinLoseModeHandler modeHandler; - public JButton btnContinue; - public JButton btnQuit; - public JButton btnRestart; + public FButton btnContinue; + public FButton btnQuit; + public FButton btnRestart; public JLabel lblTitle; public JLabel lblStats; @@ -66,11 +69,14 @@ public class WinLoseFrame extends JFrame { modeHandler = mh; modeHandler.setView(this); matchState = AllZone.getMatchState(); - Container contentPane = this.getContentPane(); - contentPane.setLayout(new MigLayout("wrap, fill")); - contentPane.setBackground(new Color(16,28,50)); + + // Place all content in FPanel + FPanel contentPanel = new FPanel(new MigLayout("wrap, fill, insets 20 0 10 10")); + contentPanel.setBGImg(AllZone.getSkin().texture1); + contentPanel.setBorder(new WinLoseBorder()); + getContentPane().add(contentPanel); - //This needs to be at least 150, or the quit button is off the pane on Mac OS X + //Footer should be at least 150 to keep buttons in-pane on Mac OS X int HEAD_HEIGHT = 150; int FOOT_HEIGHT = 150; int FRAME_WIDTH_SMALL = 300; @@ -79,17 +85,17 @@ public class WinLoseFrame extends JFrame { // Head panel JPanel pnlHead = new JPanel(new MigLayout("wrap, fill")); pnlHead.setOpaque(false); - this.add(pnlHead,"width " + FRAME_WIDTH_SMALL + "!, align center"); + contentPanel.add(pnlHead,"width " + FRAME_WIDTH_SMALL + "!, align center"); lblTitle = new JLabel("WinLoseFrame > lblTitle is broken."); lblTitle.setForeground(Color.white); lblTitle.setHorizontalAlignment(SwingConstants.CENTER); - lblTitle.setFont(new Font("Tahoma", Font.PLAIN, 26)); + lblTitle.setFont(AllZone.getSkin().font1.deriveFont(Font.PLAIN,26)); lblStats = new JLabel("WinLoseFrame > lblStats is broken."); lblStats.setForeground(Color.white); lblStats.setHorizontalAlignment(SwingConstants.CENTER); - lblStats.setFont(new Font("Tahoma", Font.ITALIC, 21)); + lblStats.setFont(AllZone.getSkin().font1.deriveFont(Font.PLAIN,26)); pnlHead.add(lblTitle, "growx"); pnlHead.add(lblStats, "growx"); @@ -99,21 +105,21 @@ public class WinLoseFrame extends JFrame { pnlCustom = new JPanel(new MigLayout("wrap, fillx")); pnlCustom.setBackground(new Color(111,87,59)); pnlCustom.setForeground(Color.white); - this.add(scroller); + contentPanel.add(scroller,"w 96%!, align center, gapleft 2%"); scroller.getViewport().add(pnlCustom); // Foot panel JPanel pnlFoot = new JPanel(new MigLayout("wrap, fill, hidemode 3")); pnlFoot.setOpaque(false); - this.add(pnlFoot,"width " + FRAME_WIDTH_SMALL + "!, align center"); + contentPanel.add(pnlFoot,"width " + FRAME_WIDTH_SMALL + "!, align center"); - this.btnContinue = new WinLoseButton("Continue"); - this.btnRestart = new WinLoseButton("Restart"); - this.btnQuit = new WinLoseButton("Quit"); + this.btnContinue = new FButton("Continue"); + this.btnRestart = new FButton("Restart"); + this.btnQuit = new FButton("Quit"); - pnlFoot.add(btnContinue,"height 30!, gap 0 0 5 5, align center"); - pnlFoot.add(btnRestart,"height 30!, gap 0 0 5 5, align center"); - pnlFoot.add(btnQuit,"height 30!, gap 0 0 5 5, align center"); + pnlFoot.add(btnContinue,"h 36:36, w 150, gap 0 0 5 5, align center"); + pnlFoot.add(btnRestart,"h 36:36, w 150, gap 0 0 5 5, align center"); + pnlFoot.add(btnQuit,"h 36:36, w 150, gap 0 0 5 5, align center"); // Button actions btnQuit.addActionListener(new java.awt.event.ActionListener() { @@ -152,14 +158,14 @@ public class WinLoseFrame extends JFrame { } // Populate custom panel, if necessary. - boolean hasStuff = modeHandler.populateCustomPanel(); - if(!hasStuff) { scroller.setVisible(false); } + boolean hasContents = modeHandler.populateCustomPanel(); + if(!hasContents) { scroller.setVisible(false); } // Size and show frame Dimension screen = this.getToolkit().getScreenSize(); Rectangle bounds = this.getBounds(); - if(hasStuff) { + if(hasContents) { bounds.height = screen.height - 150; scroller.setPreferredSize(new Dimension(FRAME_WIDTH_BIG, screen.height - HEAD_HEIGHT - FOOT_HEIGHT)); @@ -174,7 +180,8 @@ public class WinLoseFrame extends JFrame { bounds.y = (screen.height - bounds.height)/2; } - this.setBounds(bounds); + this.setBackground(AllZone.getSkin().bg1a); + this.setBounds(bounds); this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setUndecorated(true); this.setVisible(true); @@ -226,7 +233,7 @@ public class WinLoseFrame extends JFrame { * @return {@link javax.swing.JFrame} display frame */ final JFrame closeWinLoseFrame() { - // issue 147 - keep battlefield up following win/loss + // Issue 147 - keep battlefield up following win/loss JFrame frame = (JFrame) AllZone.getDisplay(); frame.dispose(); frame.setEnabled(true); @@ -234,17 +241,14 @@ public class WinLoseFrame extends JFrame { return frame; } - /** - *

WinLoseButton.

- * Private button class to standardize buttons. - * - */ - private class WinLoseButton extends JButton { - WinLoseButton(String msg) { - super(msg); - this.setFont(new Font("Tahoma", Font.PLAIN, 14)); - this.setOpaque(false); - this.setPreferredSize(new Dimension(125,30)); - } + private class WinLoseBorder extends AbstractBorder { + public void paintBorder(Component c, + Graphics g, int x, int y, int width, + int height) { + g.setColor(AllZone.getSkin().txt1a); + g.drawRect(x+1, y+1, width-3, height-3); + g.setColor(AllZone.getSkin().bg1a); + g.drawRect(x+3, y+3, width-7, height-7); + } } }