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         }