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="https://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         }