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 }