001 package com.croftsoft.core.animation.sprite; 002 003 import java.awt.Color; 004 import java.awt.Component; 005 import java.awt.Font; 006 import java.awt.Graphics; 007 import java.awt.Graphics2D; 008 import java.awt.Rectangle; 009 import java.awt.Shape; 010 import java.awt.geom.Rectangle2D; 011 import java.awt.font.FontRenderContext; 012 import java.awt.font.TextLayout; 013 import javax.swing.JComponent; 014 015 import com.croftsoft.core.animation.ComponentUpdater; 016 import com.croftsoft.core.animation.painter.NullComponentPainter; 017 import com.croftsoft.core.animation.sprite.AbstractSprite; 018 import com.croftsoft.core.animation.updater.NullComponentUpdater; 019 import com.croftsoft.core.lang.NullArgumentException; 020 import com.croftsoft.core.lang.ObjectLib; 021 022 /********************************************************************* 023 * A Sprite implementation that paints text. 024 * 025 * @version 026 * 2003-07-11 027 * @since 028 * 2002-03-07 029 * @author 030 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 031 *********************************************************************/ 032 033 public class TextSprite 034 extends AbstractSprite 035 ////////////////////////////////////////////////////////////////////// 036 ////////////////////////////////////////////////////////////////////// 037 { 038 039 private String text; 040 041 private Font font; 042 043 private Color color; 044 045 private Color backgroundColor; 046 047 private Rectangle2D textLayoutBounds; 048 049 private Component component; 050 051 private String oldText; 052 053 private Font oldFont; 054 055 private Rectangle backgroundArea; 056 057 ////////////////////////////////////////////////////////////////////// 058 // constructor methods 059 ////////////////////////////////////////////////////////////////////// 060 061 public TextSprite ( 062 double x, 063 double y, 064 double z, 065 double heading, 066 double velocity, 067 ComponentUpdater componentUpdater, 068 String text, 069 Font font, 070 Color color ) 071 ////////////////////////////////////////////////////////////////////// 072 { 073 super ( x, y, z, heading, velocity, componentUpdater, 074 NullComponentPainter.INSTANCE ); 075 076 setText ( text ); 077 078 setFont ( font ); 079 080 setColor ( color ); 081 082 backgroundArea = new Rectangle ( ); 083 } 084 085 public TextSprite ( String text ) 086 ////////////////////////////////////////////////////////////////////// 087 { 088 this ( 0.0, 0.0, 0.0, 0.0, 0.0, NullComponentUpdater.INSTANCE, 089 text, null, null ); 090 } 091 092 ////////////////////////////////////////////////////////////////////// 093 // accessor methods 094 ////////////////////////////////////////////////////////////////////// 095 096 public Shape getCollisionShape ( ) 097 ////////////////////////////////////////////////////////////////////// 098 { 099 // this is nasty inefficient 100 101 Rectangle paintBounds = new Rectangle ( ); 102 103 getPaintBounds ( paintBounds ); 104 105 return paintBounds; 106 } 107 108 public void getPaintBounds ( Rectangle paintBounds ) 109 ////////////////////////////////////////////////////////////////////// 110 { 111 if ( paintBounds == null ) 112 { 113 return; 114 } 115 116 Rectangle2D textLayoutBounds = this.textLayoutBounds; 117 118 if ( textLayoutBounds == null ) 119 { 120 Component component = this.component; 121 122 if ( component != null ) 123 { 124 Graphics2D graphics2D 125 = ( Graphics2D ) component.getGraphics ( ); 126 127 FontRenderContext fontRenderContext 128 = graphics2D.getFontRenderContext ( ); 129 130 Font font = this.font; 131 132 if ( font == null ) 133 { 134 font = component.getFont ( ); 135 } 136 137 TextLayout textLayout = new TextLayout ( 138 text, font, fontRenderContext ); 139 140 textLayoutBounds = textLayout.getBounds ( ); 141 142 graphics2D.dispose ( ); 143 } 144 } 145 146 double x = getX ( ); 147 148 double y = getY ( ); 149 150 if ( textLayoutBounds != null ) 151 { 152 // I added the -1/+2 as a fudge. Need to figure out how it works. 153 154 paintBounds.setBounds ( 155 ( int ) Math.round ( x ) 156 + ( int ) Math.floor ( textLayoutBounds.getX ( ) ) - 1, 157 ( int ) Math.round ( y ) 158 + ( int ) Math.floor ( textLayoutBounds.getY ( ) ) - 1, 159 ( int ) Math.ceil ( textLayoutBounds.getWidth ( ) ) + 2, 160 ( int ) Math.ceil ( textLayoutBounds.getHeight ( ) ) + 2 ); 161 } 162 else 163 { 164 paintBounds.x = 0; 165 166 paintBounds.y = 0; 167 168 paintBounds.width = 0; 169 170 paintBounds.height = 0; 171 } 172 } 173 174 // 175 176 public String getText ( ) { return text; } 177 178 public Font getFont ( ) { return font; } 179 180 public Color getColor ( ) { return color; } 181 182 ////////////////////////////////////////////////////////////////////// 183 // mutator methods 184 ////////////////////////////////////////////////////////////////////// 185 186 public void setBackgroundColor ( Color backgroundColor ) 187 ////////////////////////////////////////////////////////////////////// 188 { 189 this.backgroundColor = backgroundColor; 190 } 191 192 public void setText ( String text ) 193 ////////////////////////////////////////////////////////////////////// 194 { 195 NullArgumentException.check ( this.text = text ); 196 197 if ( !text.equals ( oldText ) ) 198 { 199 textLayoutBounds = null; 200 } 201 202 oldText = text; 203 } 204 205 public void setFont ( Font font ) 206 ////////////////////////////////////////////////////////////////////// 207 { 208 this.font = font; 209 210 if ( !ObjectLib.equivalent ( font, oldFont ) ) 211 { 212 textLayoutBounds = null; 213 } 214 215 oldFont = font; 216 } 217 218 public void setColor ( Color color ) 219 ////////////////////////////////////////////////////////////////////// 220 { 221 this.color = color; 222 } 223 224 ////////////////////////////////////////////////////////////////////// 225 ////////////////////////////////////////////////////////////////////// 226 227 /* 228 public boolean contains ( 229 double x, 230 double y ) 231 ////////////////////////////////////////////////////////////////////// 232 { 233 getPaintBounds ( backgroundArea ); 234 235 return backgroundArea.contains ( x, y ); 236 } 237 238 public boolean intersects ( 239 double x, 240 double y, 241 double width, 242 double height ) 243 ////////////////////////////////////////////////////////////////////// 244 { 245 getPaintBounds ( backgroundArea ); 246 247 return backgroundArea.contains ( x, y, width, height ); 248 } 249 */ 250 251 ////////////////////////////////////////////////////////////////////// 252 // interface ComponentAnimator methods 253 ////////////////////////////////////////////////////////////////////// 254 255 public void paint ( 256 JComponent component, 257 Graphics2D graphics ) 258 ////////////////////////////////////////////////////////////////////// 259 { 260 this.component = component; 261 262 if ( backgroundColor != null ) 263 { 264 graphics.setColor ( backgroundColor ); 265 266 getPaintBounds ( backgroundArea ); 267 268 graphics.fillRect ( 269 backgroundArea.x, 270 backgroundArea.y, 271 backgroundArea.width, 272 backgroundArea.height ); 273 } 274 275 Color color = this.color; 276 277 if ( color == null ) 278 { 279 color = component.getForeground ( ); 280 } 281 282 graphics.setColor ( color ); 283 284 // 285 286 Font font = this.font; 287 288 if ( font == null ) 289 { 290 font = component.getFont ( ); 291 } 292 293 graphics.setFont ( font ); 294 295 // 296 297 graphics.drawString ( 298 text, 299 ( int ) Math.round ( getX ( ) ), 300 ( int ) Math.round ( getY ( ) ) ); 301 } 302 303 ////////////////////////////////////////////////////////////////////// 304 ////////////////////////////////////////////////////////////////////// 305 }