/* * $Id$ * * Copyright (c) 2000-2006 by Brent Easton, Rodney Kinney * * 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.map.boardPicker.board.mapgrid; import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Component; import java.awt.Composite; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Paint; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.Stroke; import java.awt.TexturePaint; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.Hashtable; import javax.swing.Icon; import javax.swing.JLabel; import javax.swing.JSlider; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import VASSAL.build.AbstractConfigurable; import VASSAL.build.AutoConfigurable; import VASSAL.build.Buildable; import VASSAL.build.module.documentation.HelpFile; import VASSAL.configure.ColorConfigurer; import VASSAL.configure.Configurer; import VASSAL.configure.ConfigurerFactory; import VASSAL.configure.StringEnum; import VASSAL.configure.VisibilityCondition; import VASSAL.tools.image.ImageUtils; import VASSAL.tools.imageop.Op; import VASSAL.tools.imageop.SourceOp; /** * A Class that defines a method of highlighting the a zone in * a multi-zoned grid. * * @author Brent Easton */ public class ZoneHighlight extends AbstractConfigurable { public static final String NAME = "name"; public static final String COLOR = "color"; public static final String COVERAGE = "coverage"; public static final String WIDTH = "width"; public static final String STYLE = "style"; public static final String IMAGE = "image"; public static final String OPACITY = "opacity"; public static final String COVERAGE_FULL = "Entire Zone"; public static final String COVERAGE_BORDER = "Zone Border"; public static final String STYLE_PLAIN = "Plain"; public static final String STYLE_STRIPES = "Striped"; public static final String STYLE_CROSS = "Crosshatched"; public static final String STYLE_IMAGE = "Tiled Image"; protected Color color = null; protected String coverage = COVERAGE_FULL; protected int width = 1; protected String style = STYLE_PLAIN; protected String imageName = null; protected SourceOp srcOp; protected int opacity = 100; protected TexturePaint paint; public ZoneHighlight() { setConfigureName(""); } /* * Stage 1 - Only Plain Style and Border Coverage is implemented */ public void draw(Graphics2D g2d, Shape s, double scale) { if ((color != null && opacity > 0 ) || STYLE_IMAGE.equals(style)) { final Stroke oldStroke = g2d.getStroke(); final Color oldColor = g2d.getColor(); final Composite oldComposite = g2d.getComposite(); final Paint oldPaint = g2d.getPaint(); if (!STYLE_PLAIN.equals(style)) { g2d.setPaint(getPaint()); } else { g2d.setColor(color); } g2d.setComposite(AlphaComposite.getInstance( AlphaComposite.SRC_OVER, opacity/100.0f)); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); if (COVERAGE_FULL.equals(coverage)) { g2d.fill(s); } else { final Stroke stroke = new BasicStroke((float)(width*scale), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); g2d.setStroke(stroke); g2d.draw(s); } g2d.setColor(oldColor); g2d.setStroke(oldStroke); g2d.setComposite(oldComposite); g2d.setPaint(oldPaint); } } protected Paint getPaint() { if (paint == null) { if (style.equals(STYLE_IMAGE)) { final Image im = srcOp.getImage(); if (im != null) { paint = new TexturePaint(ImageUtils.toBufferedImage(im), new Rectangle(srcOp.getSize())); } } else { // FIXME: Make this an ImageOp? final BufferedImage img = ImageUtils.createCompatibleTranslucentImage(6, 6); final Graphics2D g = img.createGraphics(); g.setColor(color); if (style.equals(STYLE_STRIPES)) { g.drawLine(0, 5, 5, 0); } else if (style.equals(STYLE_CROSS)) { g.drawLine(0, 5, 5, 0); g.drawLine(1, 0, 5, 4); } g.dispose(); paint = new TexturePaint(img, new Rectangle(0,0,6,6)); } } return paint; } public String getName() { return getConfigureName(); } public Color getColor() { return color; } public void setOpacity(int o) { opacity = o; } public String[] getAttributeNames() { return new String[]{ NAME, COLOR, COVERAGE, WIDTH, STYLE, IMAGE, OPACITY }; } public String[] getAttributeDescriptions() { return new String[]{ "Name: ", "Color: ", "Coverage: ", "Width: ", "Style: ", "Image: ", "Opacity(%): " }; } public Class<?>[] getAttributeTypes() { return new Class<?>[]{ String.class, Color.class, Coverage.class, Integer.class, Style.class, Icon.class, OpacityConfig.class }; } public static class Coverage extends StringEnum { public String[] getValidValues(AutoConfigurable target) { return new String[]{ COVERAGE_FULL, COVERAGE_BORDER }; } } public static class Style extends StringEnum { public String[] getValidValues(AutoConfigurable target) { return new String[]{ STYLE_PLAIN, STYLE_STRIPES, STYLE_CROSS, STYLE_IMAGE }; } } public static class OpacityConfig implements ConfigurerFactory { public Configurer getConfigurer(AutoConfigurable c, String key, String name) { final ZoneHighlight zh = (ZoneHighlight) c; return zh.new PercentageConfigurer(key, name, zh.opacity); } } public void addTo(Buildable b) { ((ZonedGridHighlighter) b).addHighlight(this); } public void removeFrom(Buildable b) { ((ZonedGridHighlighter) b).removeHighlight(this); } public static String getConfigureTypeName() { return "Zone Highlight"; } public VASSAL.build.module.documentation.HelpFile getHelpFile() { return HelpFile.getReferenceManualPage("ZonedGrid.htm","ZoneHighlighter"); } public String getAttributeValueString(String key) { if (NAME.equals(key)) { return getConfigureName(); } else if (COLOR.equals(key)) { return ColorConfigurer.colorToString(color); } else if (COVERAGE.equals(key)) { return coverage; } else if (WIDTH.equals(key)) { return String.valueOf(width); } else if (STYLE.equals(key)) { return style; } else if (OPACITY.equals(key)) { return String.valueOf(opacity); } else if (IMAGE.equals(key)) { return imageName; } return null; } public void setAttribute(String key, Object val) { if (val == null) return; if (NAME.equals(key)) { setConfigureName((String) val); } else if (COLOR.equals(key)) { if (val instanceof String) { val = ColorConfigurer.stringToColor((String) val); } if (val != null) { color = (Color) val; } } else if (COVERAGE.equals(key)) { coverage = (String) val; } else if (WIDTH.equals(key)) { if (val instanceof String) { val = Integer.valueOf((String) val); } width = ((Integer) val).intValue(); } else if (STYLE.equals(key)) { style = (String) val; paint = null; } else if (OPACITY.equals(key)) { if (val instanceof String) { val = Integer.valueOf((String) val); } opacity = ((Integer) val).intValue(); } else if (IMAGE.equals(key)) { imageName = (String) val; srcOp = imageName == null || imageName.trim().length() == 0 ? null : Op.load(imageName); } } public Class<?>[] getAllowableConfigureComponents() { return new Class<?>[0]; } public VisibilityCondition getAttributeVisibility(String name) { if (IMAGE.equals(name)) { return new VisibilityCondition() { public boolean shouldBeVisible() { return STYLE_IMAGE.equals(style); } }; } else if (WIDTH.equals(name)) { return new VisibilityCondition() { public boolean shouldBeVisible() { return COVERAGE_BORDER.equals(coverage); } }; } else { return super.getAttributeVisibility(name); } } public class PercentageConfigurer extends Configurer { public PercentageConfigurer(String key, String name, Object val) { super(key, name, val); opacity = ((Integer) val).intValue(); } public String getValueString() { return String.valueOf(opacity); } public void setValue(String s) { opacity = Integer.parseInt(s); } public Component getControls() { final JSlider slider = new JSlider(JSlider.HORIZONTAL,0,100,opacity); final HashMap<Integer,JLabel> labelTable = new HashMap<Integer,JLabel>(); labelTable.put(0, new JLabel("Transparent")); labelTable.put(100, new JLabel("Opaque")); slider.setMajorTickSpacing(10); slider.setPaintTicks(true); // Note: JSlider uses the outdated Hashtable. Eventually Hashtable // will be deprecated and we'll be able to use the HashMap directly. slider.setLabelTable(new Hashtable<Integer,JLabel>(labelTable)); slider.setPaintLabels(true); slider.setBorder(javax.swing.BorderFactory.createTitledBorder(name)); slider.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { final JSlider source = (JSlider) e.getSource(); if (!source.getValueIsAdjusting()) { opacity = source.getValue(); } }}); return slider; } } }