1 /***
2 * Redistribution and use in source and binary forms, with or without
3 * modification, are permitted provided that the following conditions are
4 * met :
5 *
6 * . Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 *
9 * . Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * . The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $Id: HexagonCanvas.java,v 1.4 2005/09/10 14:06:22 mat007 Exp $
29 */
30
31 package jtge.sample.grid;
32
33 import java.awt.Color;
34 import java.awt.Dimension;
35 import java.awt.Graphics;
36 import java.awt.Graphics2D;
37 import java.awt.Image;
38 import java.awt.Point;
39 import java.awt.Polygon;
40 import java.awt.font.FontRenderContext;
41 import java.awt.geom.Rectangle2D;
42 import java.util.Iterator;
43 import javax.swing.JComponent;
44 import jtge.util.grid.Coordinate;
45 import jtge.util.grid.IGrid;
46 import jtge.util.grid.builder.IHexagonBuilder;
47
48 /***
49 * Displays a grid.
50 *
51 * @author Jean-Laurent
52 * @version $Id: HexagonCanvas.java,v 1.4 2005/09/10 14:06:22 mat007 Exp $
53 */
54 public class HexagonCanvas extends JComponent
55 {
56 private static final long serialVersionUID = -8171784620344147733L;
57 /***
58 * The displayed grid.
59 */
60 private final IGrid grid;
61 /***
62 * The associated builder.
63 */
64 private final IHexagonBuilder builder;
65 /***
66 * The canvas size in pixels.
67 */
68 private final int width, height;
69 /***
70 * The offscreen buffer.
71 */
72 private Image offscreen;
73 /***
74 * The current selected coordinate.
75 */
76 private Coordinate highlight;
77 /***
78 * The border size in pixels.
79 */
80 private final int border;
81
82 /***
83 * Create an hexagon canvas.
84 *
85 * @param grid the grid
86 * @param builder the builder
87 * @param border the border size in pixels
88 */
89 public HexagonCanvas( final IGrid grid, final IHexagonBuilder builder, final int border )
90 {
91 this.grid = grid;
92 this.builder = builder;
93 this.border = border;
94 width = builder.computeWidth( grid.getWidth() ) + border * 2;
95 height = builder.computeHeight( grid.getHeight() ) + border * 2;
96 setPreferredSize( new Dimension( width, height ) );
97 }
98
99 /***
100 * Convert a point to a coordinate.
101 *
102 * @param point the point to convert
103 * @return the converted coordinate or null if out of the map
104 */
105 public final Coordinate fromPixel( final Point point )
106 {
107 final Point translated = (Point)point.clone();
108 translated.translate( -border, -border );
109 return builder.fromPixel( translated, grid );
110 }
111
112 private void drawHighlight( final Graphics gc )
113 {
114 if( highlight != null )
115 {
116 gc.setColor( Color.RED );
117 final Polygon polygon = builder.buildHexagon( highlight );
118 polygon.translate( border, border );
119 gc.drawPolygon( polygon );
120 }
121 }
122
123 /***
124 * {@inheritDoc}
125 */
126 protected final void paintComponent( final Graphics gc )
127 {
128 if( offscreen == null )
129 offscreen = createOffscreen();
130 gc.drawImage( offscreen, 0, 0, this );
131 drawHighlight( gc );
132 }
133
134 private Image createOffscreen()
135 {
136 final Image image = createImage( width, height );
137 final Graphics gc = image.getGraphics();
138 drawBackground( gc );
139 drawGrid( gc );
140 gc.dispose();
141 image.flush();
142 return image;
143 }
144
145 private void drawGrid( final Graphics gc )
146 {
147 final Iterator iterator = grid.linearIterator();
148 while( iterator.hasNext() )
149 {
150 final Coordinate coordinate = (Coordinate)iterator.next();
151 final Polygon polygon = builder.buildHexagon( coordinate );
152 polygon.translate( border, border );
153 gc.setColor( Color.LIGHT_GRAY );
154 gc.fillPolygon( polygon );
155 gc.setColor( Color.BLACK );
156 gc.drawPolygon( polygon );
157 drawCoordinate( gc, coordinate, polygon );
158 }
159 }
160
161 private void drawBackground( final Graphics gc )
162 {
163 gc.setColor( Color.WHITE );
164 gc.fillRect( 0, 0, width, height );
165 }
166
167 private void drawCoordinate( final Graphics gc, final Coordinate coordinate, final Polygon polygon )
168 {
169 final FontRenderContext context = ((Graphics2D)gc).getFontRenderContext();
170 final Rectangle2D bounds = getFont().getStringBounds( coordinate.toString(), context );
171 final Rectangle2D bounds2 = polygon.getBounds2D();
172 final double x = bounds2.getX() + bounds2.getWidth() / 2 - bounds.getX() - bounds.getWidth() / 2;
173 final double y = bounds2.getY() + bounds2.getHeight() / 2 - bounds.getY() - bounds.getHeight() / 2;
174 gc.drawString( coordinate.toString(), (int)x, (int)y );
175 }
176
177 /***
178 * Highlight the given coordinate.
179 *
180 * @param coordinate the coordinate to highlight
181 */
182 public final void select( final Coordinate coordinate )
183 {
184 highlight = coordinate;
185 repaint();
186 }
187 }