001 package com.croftsoft.core.animation.animator;
002
003 import java.awt.*;
004 import java.awt.event.*;
005 import java.awt.geom.*;
006 import javax.swing.*;
007
008 import com.croftsoft.core.animation.ComponentAnimator;
009 import com.croftsoft.core.lang.NullArgumentException;
010
011 /*********************************************************************
012 * Displays a quantity as a row of icons.
013 *
014 * <p>
015 * Useful for display number of remaining lives, ammo, population, etc.
016 * If the area to display the icons is too small, the icon spacing
017 * will be adjusted so that icons overlap each other to fit.
018 * </p>
019 *
020 * @version
021 * 2003-03-28
022 * @since
023 * 2003-03-28
024 * @author
025 * <a href="http://www.CroftSoft.com/">David Wallace Croft</a>
026 *********************************************************************/
027
028 public final class IconRowAnimator
029 implements ComponentAnimator
030 //////////////////////////////////////////////////////////////////////
031 //////////////////////////////////////////////////////////////////////
032 {
033
034 private final AffineTransform affineTransform;
035
036 private final Rectangle newRectangle;
037
038 private final Rectangle repaintArea;
039
040 private final Rectangle componentBounds;
041
042 //
043
044 private boolean rectangleIsRelative;
045
046 private Rectangle oldPaintArea;
047
048 private Rectangle newPaintArea;
049
050 private Icon icon;
051
052 private int count;
053
054 private double iconSpacing;
055
056 private boolean updateRequired;
057
058 private int x;
059
060 private int y;
061
062 private int width;
063
064 private int height;
065
066 private int newCount;
067
068 private Icon newIcon;
069
070 //////////////////////////////////////////////////////////////////////
071 // constructor methods
072 //////////////////////////////////////////////////////////////////////
073
074 private IconRowAnimator (
075 Icon icon,
076 int count,
077 Rectangle rectangle,
078 JComponent component )
079 //////////////////////////////////////////////////////////////////////
080 {
081 affineTransform = new AffineTransform ( );
082
083 componentBounds = new Rectangle ( );
084
085 oldPaintArea = new Rectangle ( );
086
087 newPaintArea = new Rectangle ( );
088
089 repaintArea = new Rectangle ( );
090
091 newRectangle = new Rectangle ( );
092
093 setIcon ( icon );
094
095 setRectangle ( rectangle );
096
097 setCount ( count );
098
099 update ( component );
100
101 if ( ( rectangle == null )
102 && ( component != null ) )
103 {
104 component.addComponentListener (
105 new ComponentAdapter ( )
106 {
107 public void componentResized (
108 ComponentEvent componentEvent )
109 {
110 updateRequired = true;
111 }
112 } );
113 }
114 }
115
116 /*********************************************************************
117 * Draws the icon row in the rectangle.
118 *********************************************************************/
119 public IconRowAnimator (
120 Icon icon,
121 int count,
122 Rectangle rectangle )
123 //////////////////////////////////////////////////////////////////////
124 {
125 this ( icon, count, rectangle, null );
126
127 NullArgumentException.check ( rectangle );
128 }
129
130 /*********************************************************************
131 * Draws the icon row at the bottom left of the component.
132 *********************************************************************/
133 public IconRowAnimator (
134 Icon icon,
135 int count,
136 JComponent component )
137 //////////////////////////////////////////////////////////////////////
138 {
139 this ( icon, count, null, component );
140
141 NullArgumentException.check ( component );
142 }
143
144 //////////////////////////////////////////////////////////////////////
145 //////////////////////////////////////////////////////////////////////
146
147 public int getCount ( ) { return count; }
148
149 public Icon getIcon ( ) { return icon; }
150
151 public void getRectangle ( Rectangle rectangle )
152 //////////////////////////////////////////////////////////////////////
153 {
154 rectangle.setBounds ( x, y, width, height );
155 }
156
157 //////////////////////////////////////////////////////////////////////
158 //////////////////////////////////////////////////////////////////////
159
160 public void setCount ( int count )
161 //////////////////////////////////////////////////////////////////////
162 {
163 if ( count < 0 )
164 {
165 throw new IllegalArgumentException ( "count < 0" );
166 }
167
168 if ( this.count == count )
169 {
170 return;
171 }
172
173 newCount = count;
174
175 updateRequired = true;
176 }
177
178 public void setIcon ( Icon icon )
179 //////////////////////////////////////////////////////////////////////
180 {
181 NullArgumentException.check ( icon );
182
183 newIcon = icon;
184
185 updateRequired = true;
186 }
187
188 public void setRectangle ( Rectangle rectangle )
189 //////////////////////////////////////////////////////////////////////
190 {
191 rectangleIsRelative = rectangle == null;
192
193 if ( !rectangleIsRelative )
194 {
195 newRectangle.setBounds ( rectangle );
196 }
197
198 updateRequired = true;
199 }
200
201 //////////////////////////////////////////////////////////////////////
202 // interface ComponentAnimator methods
203 //////////////////////////////////////////////////////////////////////
204
205 public void update ( JComponent component )
206 //////////////////////////////////////////////////////////////////////
207 {
208 if ( !updateRequired )
209 {
210 return;
211 }
212
213 updateRequired = false;
214
215 icon = newIcon;
216
217 count = newCount;
218
219 int iconWidth = icon.getIconWidth ( );
220
221 int iconHeight = icon.getIconHeight ( );
222
223 if ( rectangleIsRelative && ( component != null ) )
224 {
225 component.getBounds ( componentBounds );
226
227 x = 1;
228
229 y = componentBounds.height - iconHeight - 1;
230
231 width = componentBounds.width / 3;
232
233 height = iconHeight;
234 }
235 else
236 {
237 x = newRectangle.x;
238
239 y = newRectangle.y;
240
241 width = newRectangle.width;
242
243 height = newRectangle.height;
244 }
245
246 if ( ( count > 0 )
247 && ( width > iconWidth ) )
248 {
249 iconSpacing = ( width - iconWidth ) / ( double ) count;
250
251 if ( iconSpacing > iconWidth )
252 {
253 iconSpacing = iconWidth;
254 }
255
256 newPaintArea.setBounds (
257 x, y,
258 ( int ) ( iconSpacing * ( count - 1 ) ) + iconWidth + 1,
259 iconHeight );
260 }
261 else
262 {
263 iconSpacing = 0.0;
264
265 newPaintArea.setBounds ( x, y, iconWidth, iconHeight );
266 }
267
268 if ( component != null )
269 {
270 Rectangle2D.union ( oldPaintArea, newPaintArea, repaintArea );
271
272 component.repaint ( repaintArea );
273
274 Rectangle swapRectangle = oldPaintArea;
275
276 oldPaintArea = newPaintArea;
277
278 newPaintArea = swapRectangle;
279 }
280 }
281
282 public void paint (
283 JComponent component,
284 Graphics2D graphics )
285 //////////////////////////////////////////////////////////////////////
286 {
287 /*
288 graphics.setColor ( Color.RED );
289
290 graphics.drawRect (
291 oldPaintArea.x,
292 oldPaintArea.y,
293 oldPaintArea.width,
294 oldPaintArea.height );
295
296 graphics.setColor ( Color.BLUE );
297
298 graphics.drawRect (
299 newPaintArea.x,
300 newPaintArea.y,
301 newPaintArea.width,
302 newPaintArea.height );
303
304 graphics.setColor ( Color.MAGENTA );
305
306 graphics.drawRect (
307 repaintArea.x,
308 repaintArea.y,
309 repaintArea.width,
310 repaintArea.height );
311 */
312
313 AffineTransform oldAffineTransform
314 = graphics.getTransform ( );
315
316 affineTransform.setToTranslation ( iconSpacing, 0.0 );
317
318 for ( int i = 0; i < count; i++ )
319 {
320 icon.paintIcon ( component, graphics, x, y );
321
322 graphics.transform ( affineTransform );
323 }
324
325 graphics.setTransform ( oldAffineTransform );
326 }
327
328 //////////////////////////////////////////////////////////////////////
329 //////////////////////////////////////////////////////////////////////
330 }