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