/* * $Id$ * * Copyright (c) 2005 by Rodney Kinney, Brent Easton * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Library General Public License (LGPL) as published by * the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more * details. * * You should have received a copy of the GNU Library General Public License * along with this library; if not, copies are available at * http://www.opensource.org. */ package VASSAL.build.module.gamepieceimage; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import VASSAL.build.AbstractConfigurable; import VASSAL.build.AutoConfigurable; import VASSAL.build.Buildable; import VASSAL.build.module.documentation.HelpFile; import VASSAL.configure.Configurer; import VASSAL.configure.ConfigurerFactory; import VASSAL.configure.StringEnum; import VASSAL.tools.SequenceEncoder; import VASSAL.tools.image.ImageUtils; public class GamePieceLayout extends AbstractConfigurable implements Visualizable { protected static final String NAME = "name"; //$NON-NLS-1$ protected static final String WIDTH = "width"; //$NON-NLS-1$ protected static final String HEIGHT = "height"; //$NON-NLS-1$ protected static final String BORDER = "border"; //$NON-NLS-1$ protected static final String ITEMS = "layout"; //$NON-NLS-1$ protected static final String N = "Top"; protected static final String S = "Bottom"; protected static final String E = "Right"; protected static final String W = "Left"; protected static final String NE = "Top Right"; protected static final String NW = "Top Left"; protected static final String SE = "Bottom Right"; protected static final String SW = "Bottom Left"; protected static final String CENTER = "Center"; protected static final int POS_L = 15; protected static final int POS_R = 85; protected static final int POS_T = 15; protected static final int POS_B = 85; protected static final int POS_C = 50; protected static final String BORDER_PLAIN = "Plain"; protected static final String BORDER_FANCY = "Fancy"; protected static final String BORDER_3D = "3D"; protected static final String BORDER_NONE = "None"; public static final String[] LOCATIONS = new String[]{CENTER, N, S, E, W, NE, NW, SE, SW}; public static final int[] X_POS = new int[]{POS_C, POS_C, POS_C, POS_R, POS_L, POS_R, POS_L, POS_R, POS_L}; public static final int[] Y_POS = new int[]{POS_C, POS_T, POS_B, POS_C, POS_C, POS_T, POS_T, POS_B, POS_B}; protected static Map<String,String> compass = new HashMap<String,String>(); static { compass.put(N,"N"); compass.put(S,"S"); compass.put(E,"E"); compass.put(W,"W"); compass.put(NE,"NE"); compass.put(NW,"NW"); compass.put(SE,"SE"); compass.put(SW,"SW"); compass.put(CENTER,"CENTER"); } public static String getCompassPoint(String location) { return compass.get(location); } public Point getPosition(Item item) { final String s = getCompassPoint(item.getLocation()); int x,y; final Dimension d = item.getSize(); switch (s.charAt(s.length() - 1)) { case 'E': x = getLayoutWidth() - d.width; break; case 'W': x = 0; break; default: x = getLayoutWidth() / 2 - d.width / 2; } switch (s.charAt(0)) { case 'N': y = 0; break; case 'S': y = getLayoutHeight() - d.height; break; default: y = getLayoutHeight() / 2 - d.height / 2; } return new Point(x + item.getXoffset(), y + item.getYoffset()); } protected int width = 54; protected int height = 54; protected String border = BORDER_3D; protected GamePieceImage imageDefn; protected Image visImage; protected List<Item> items = new ArrayList<Item>(); public GamePieceLayout() { super(); name = ""; //$NON-NLS-1$ imageDefn = new GamePieceImage(this); } public String[] getAttributeDescriptions() { return new String[]{ "Name: ", "Counter Width: ", "Counter Height: ", "Border Style: ", "" //$NON-NLS-1$ }; } public Class<?>[] getAttributeTypes() { return new Class<?>[]{ String.class, Integer.class, Integer.class, BorderConfig.class, LayoutConfig.class }; } public static class LayoutConfig implements ConfigurerFactory { protected static LayoutConfigurer configurer; public Configurer getConfigurer(AutoConfigurable c, String key, String name) { configurer = new LayoutConfigurer(key, name, (GamePieceLayout) c); return configurer; } public static void refresh() { if (configurer != null) { configurer.repack(); } } } public static class BorderConfig extends StringEnum { public String[] getValidValues(AutoConfigurable target) { return new String[]{BORDER_PLAIN, BORDER_FANCY, BORDER_3D, BORDER_NONE}; } } public boolean isColoredBorder() { return border.equals(BORDER_PLAIN) || border.equals(BORDER_FANCY); } public String[] getAttributeNames() { return new String[]{NAME, WIDTH, HEIGHT, BORDER, ITEMS}; } public void setAttribute(String key, Object value) { if (NAME.equals(key)) { setConfigureName((String) value); } else if (WIDTH.equals(key)) { if (value instanceof String) { value = Integer.valueOf((String) value); } setWidth(((Integer) value).intValue()); } else if (HEIGHT.equals(key)) { if (value instanceof String) { value = Integer.valueOf((String) value); } setHeight(((Integer) value).intValue()); } else if (BORDER.equals(key)) { border = (String) value; } else if (ITEMS.equals(key)) { decodeItemList((String) value); } invalidate(); LayoutConfig.refresh(); } public String getAttributeValueString(String key) { if (NAME.equals(key)) { return getConfigureName(); } else if (WIDTH.equals(key)) { return getLayoutWidth() + ""; //$NON-NLS-1$ } else if (HEIGHT.equals(key)) { return getLayoutHeight() + ""; //$NON-NLS-1$ } else if (BORDER.equals(key)) { return border + ""; //$NON-NLS-1$ } else if (ITEMS.equals(key)) { return encodeItemList(); } else return null; } public void removeFrom(Buildable parent) { } public HelpFile getHelpFile() { return HelpFile.getReferenceManualPage("GamePieceLayouts.htm"); //$NON-NLS-1$ } public Class<?>[] getAllowableConfigureComponents() { return new Class<?>[]{GamePieceImage.class}; } public void addTo(Buildable parent) { setAllAttributesUntranslatable(); } public static String getConfigureTypeName() { return "Game Piece Layout"; //$NON-NLS-1$ } public void setWidth(int width) { this.width = width; } public int getLayoutWidth() { return width; } public void setHeight(int height) { this.height = height; } public int getLayoutHeight() { return height; } public String getBorder() { return border; } public List<Item> getItems() { return items; } protected int getItemCount() { return items.size(); } protected Item getItem(int n) { return items.get(n); } protected Item getItem(String name) { for (Item item : items) { if (item.getConfigureName().equals(name)) { return item; } } return null; } protected void removeItem(int n) { items.remove(n); } public void addItem(Item i) { items.add(i); } public void moveItem(int from, int to) { Item temp = items.get(to); items.set(to, items.get(from)); items.set(from, temp); } public void add(Buildable b) { super.add(b); } public void remove(Buildable b) { super.remove(b); } public Image getVisualizerImage() { if (visImage == null) { rebuildVisualizerImage(); } return visImage; } public Image buildImage(GamePieceImage defn) { // Create our base image final BufferedImage image = ImageUtils.createCompatibleTranslucentImage( Math.max(width,1), Math.max(height,1) ); final Graphics2D g = image.createGraphics(); // Fill in the sample Background color Color bgColor = defn.getBgColor().getColor(); g.setColor(bgColor); if (getBorder().equals(BORDER_3D)) { if (bgColor != null) g.fill3DRect(0, 0, width, height, true); } else { if (bgColor != null) g.fillRect(0, 0, width, height); // Add Border if (getBorder().equals(BORDER_PLAIN) || getBorder().equals(BORDER_FANCY)) { Color bg = bgColor == null ? Color.WHITE : bgColor; g.setColor(defn.getBorderColor().getColor()); g.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g.drawRect(0, 0, width - 1, height - 1); if (getBorder().equals(BORDER_FANCY)) { Color lt = new Color(bg.getRed() / 2, bg.getGreen() / 2, bg.getBlue() / 2); Color dk = new Color(bg.getRed() + (255 - bg.getRed()) / 2, bg.getGreen() + (255 - bg.getGreen()) / 2, bg.getBlue() + (255 - bg.getBlue()) / 2); g.setColor(dk); g.drawLine(1, 1, width - 3, 1); g.drawLine(1, 2, 1, height - 3); g.setColor(lt); g.drawLine(width - 2, 2, width - 2, height - 2); g.drawLine(2, height - 2, width - 3, height - 2); } } } // layer each item over the top for (Item item : items) { if (item != null) { item.draw(g, defn); } } g.dispose(); return image; } public void refresh() { invalidate(); LayoutConfig.refresh(); } protected void invalidate() { for (GamePieceImage i : getComponentsOf(GamePieceImage.class)) { i.rebuildVisualizerImage(); } } protected void decodeItemList(String string) { items.clear(); if (string.length() > 0) { SequenceEncoder.Decoder sd = new SequenceEncoder.Decoder(string, ','); while (sd.hasMoreTokens()) { Item item = Item.decode(this, sd.nextToken()); addItem(item); } } } protected String encodeItemList() { String[] list = new String[getItemCount()]; int i = 0; for (Item item : items) { list[i++] = item.encode(); } SequenceEncoder se = new SequenceEncoder('#'); se.append(list); return se.getValue(); } public int getVisualizerHeight() { return getLayoutHeight(); } public int getVisualizerWidth() { return getLayoutWidth(); } public void rebuildVisualizerImage() { visImage = buildImage(imageDefn); } public void setImageDefn(GamePieceImage d) { imageDefn = d; } public GamePieceImage getGenericDefn(String defnName) { for (Buildable b : getBuildables()) { if (b instanceof GamePieceImage) { GamePieceImage gpi = (GamePieceImage) b; if (gpi.getConfigureName().equals(defnName)) { return gpi; } } } return null; } }