001         package com.croftsoft.core.animation;
002    
003         import java.awt.EventQueue;
004         import java.awt.Graphics;
005         import java.awt.Graphics2D;
006         import java.awt.Rectangle;
007         import java.lang.reflect.InvocationTargetException;
008         import javax.swing.JComponent;
009    
010         import com.croftsoft.core.animation.factory.DefaultAnimationFactory;
011         import com.croftsoft.core.lang.NullArgumentException;
012         import com.croftsoft.core.lang.lifecycle.Lifecycle;
013         import com.croftsoft.core.util.loop.LoopGovernor;
014    
015         /*********************************************************************
016         * Animated Swing component.
017         *
018         * @version
019         *   $Id: AnimatedComponent.java,v 1.3 2008/09/28 21:49:39 croft Exp $
020         * @since
021         *   2002-03-10
022         * @author
023         *   <a href="https://www.croftsoft.com/">David Wallace Croft</a>
024         *********************************************************************/
025    
026         public class  AnimatedComponent
027           extends JComponent
028           implements Lifecycle
029         //////////////////////////////////////////////////////////////////////
030         //////////////////////////////////////////////////////////////////////
031         {
032    
033         private static final long  serialVersionUID = 0L;
034    
035         public static final String  ANIMATION_THREAD_NAME = "Animation";
036    
037         //
038    
039         protected final Runnable  animationRunner;
040    
041         //
042    
043         protected ComponentAnimator  componentAnimator;
044    
045         protected RepaintCollector   repaintCollector;
046    
047         protected LoopGovernor       loopGovernor;
048    
049         protected Thread             animationThread;
050    
051         protected boolean            stopRequested;
052    
053         //////////////////////////////////////////////////////////////////////
054         // constructor methods
055         //////////////////////////////////////////////////////////////////////
056    
057         /*********************************************************************
058         * Main constructor.
059         *********************************************************************/
060         public  AnimatedComponent (
061           ComponentAnimator  componentAnimator,
062           RepaintCollector   repaintCollector,
063           LoopGovernor       loopGovernor )
064         //////////////////////////////////////////////////////////////////////
065         {
066           setComponentAnimator ( componentAnimator );
067    
068           setRepaintCollector ( repaintCollector );
069    
070           setLoopGovernor ( loopGovernor );
071    
072           setOpaque ( true );
073    
074           animationRunner =
075             new Runnable ( )
076             {
077               public void  run ( )
078               {
079                 animate ( );
080               }
081             };         
082         }
083    
084         /*********************************************************************
085         * Convenience constructor.
086         *
087         * @param  frequency
088         *
089         *   The targeted update frequency in loops per second.
090         *********************************************************************/
091         public  AnimatedComponent (
092           ComponentAnimator  componentAnimator,
093           AnimationFactory   animationFactory,
094           double             frequency )
095         //////////////////////////////////////////////////////////////////////
096         {
097           this (
098             componentAnimator,
099             animationFactory.createRepaintCollector ( ),
100             animationFactory.createLoopGovernor ( frequency ) );
101         }
102    
103         /*********************************************************************
104         * Convenience constructor.
105         *********************************************************************/
106         public  AnimatedComponent (
107           ComponentAnimator  componentAnimator,
108           AnimationFactory   animationFactory )
109         //////////////////////////////////////////////////////////////////////
110         {
111           this (
112             componentAnimator,
113             animationFactory.createRepaintCollector ( ),
114             animationFactory.createLoopGovernor ( ) );
115         }
116    
117         /*********************************************************************
118         * Convenience constructor.
119         *
120         * @param  frequency
121         *
122         *   The targeted update frequency in loops per second.
123         *********************************************************************/
124         public  AnimatedComponent (
125           ComponentAnimator  componentAnimator,
126           double             frequency )
127         //////////////////////////////////////////////////////////////////////
128         {
129           this (
130             componentAnimator,
131             DefaultAnimationFactory.INSTANCE,
132             frequency );
133         }
134    
135         /*********************************************************************
136         * Convenience constructor.
137         *********************************************************************/
138         public  AnimatedComponent ( ComponentAnimator  componentAnimator )
139         //////////////////////////////////////////////////////////////////////
140         {
141           this (
142             componentAnimator,
143             DefaultAnimationFactory.INSTANCE );
144         }
145    
146         //////////////////////////////////////////////////////////////////////
147         // mutator methods
148         //////////////////////////////////////////////////////////////////////
149    
150         public synchronized ComponentAnimator  setComponentAnimator (
151           ComponentAnimator  componentAnimator )
152         //////////////////////////////////////////////////////////////////////
153         {
154           NullArgumentException.check ( componentAnimator );
155    
156           ComponentAnimator  oldComponentAnimator = this.componentAnimator;
157    
158           this.componentAnimator = componentAnimator;
159    
160           return oldComponentAnimator;
161         }
162    
163         public synchronized RepaintCollector  setRepaintCollector (
164           RepaintCollector  repaintCollector )
165         //////////////////////////////////////////////////////////////////////
166         {
167           NullArgumentException.check ( repaintCollector );
168    
169           RepaintCollector  oldRepaintCollector = this.repaintCollector;
170    
171           this.repaintCollector = repaintCollector;
172    
173           return oldRepaintCollector;
174         }
175    
176         public synchronized LoopGovernor  setLoopGovernor (
177           LoopGovernor  loopGovernor )
178         //////////////////////////////////////////////////////////////////////
179         {
180           NullArgumentException.check ( loopGovernor );
181    
182           LoopGovernor  oldLoopGovernor = this.loopGovernor;
183    
184           this.loopGovernor = loopGovernor;
185    
186           return oldLoopGovernor;
187         }
188    
189         //////////////////////////////////////////////////////////////////////
190         // interface Lifecycle methods
191         //////////////////////////////////////////////////////////////////////
192    
193         public void  init ( )
194         //////////////////////////////////////////////////////////////////////
195         {
196           // empty
197         }
198    
199         public synchronized void  start ( )
200         //////////////////////////////////////////////////////////////////////
201         {
202           stopRequested = false;
203    
204           if ( animationThread == null )
205           {
206             animationThread = new Thread (
207               new Runnable ( )
208               {
209                 public void  run ( )
210                 {
211                   loop ( );
212                 }
213               },
214               ANIMATION_THREAD_NAME );
215    
216             animationThread.setPriority ( Thread.MIN_PRIORITY );
217    
218             animationThread.setDaemon ( true );
219    
220             animationThread.start ( );
221           }
222           else
223           {
224             notify ( );
225           }
226         }
227    
228         public synchronized void  stop ( )
229         //////////////////////////////////////////////////////////////////////
230         {
231           stopRequested = true;
232    
233           animationThread.interrupt ( );
234         }
235    
236         public synchronized void  destroy ( )
237         //////////////////////////////////////////////////////////////////////
238         {
239           animationThread = null;
240    
241           stopRequested = false;
242    
243           notify ( );
244         }
245    
246         //////////////////////////////////////////////////////////////////////
247         // overridden JComponent methods
248         //////////////////////////////////////////////////////////////////////
249    
250         @Override
251         public void  paintComponent ( Graphics  graphics )
252         //////////////////////////////////////////////////////////////////////
253         {
254           componentAnimator.paint ( this, ( Graphics2D ) graphics );
255         }
256    
257         @Override
258         public void  repaint ( )
259         //////////////////////////////////////////////////////////////////////
260         {
261           repaintCollector.repaint ( );
262         }
263    
264         @Override
265         public void  repaint ( long  tm )
266         //////////////////////////////////////////////////////////////////////
267         {
268           repaintCollector.repaint ( );
269         }
270    
271         @Override
272         public void  repaint (
273           int  x,
274           int  y,
275           int  width,
276           int  height )
277         //////////////////////////////////////////////////////////////////////
278         {
279           repaintCollector.repaint ( x, y, width, height );
280         }
281    
282         @Override
283         public void  repaint (
284           long  tm,
285           int   x,
286           int   y,
287           int   width,
288           int   height )
289         //////////////////////////////////////////////////////////////////////
290         {
291           repaintCollector.repaint ( x, y, width, height );
292         }
293    
294         @Override
295         public void  repaint ( Rectangle  r )
296         //////////////////////////////////////////////////////////////////////
297         {
298           repaintCollector.repaint ( r.x, r.y, r.width, r.height );
299         }
300    
301         //////////////////////////////////////////////////////////////////////
302         // protected methods
303         //////////////////////////////////////////////////////////////////////
304    
305         protected void  loop ( )
306         //////////////////////////////////////////////////////////////////////
307         {
308           while ( animationThread != null )
309           {
310             try
311             {
312               EventQueue.invokeAndWait ( animationRunner );
313    
314               loopGovernor.govern ( );
315    
316               if ( stopRequested )
317               {
318                 synchronized ( this )
319                 {
320                   while ( stopRequested )
321                   {
322                     wait ( );
323                   }
324                 }
325               }
326             }
327             catch ( InterruptedException  ex )
328             {
329               // ignore
330             }
331             catch ( InvocationTargetException  ex )
332             {
333               ex.getCause ( ).printStackTrace ( );
334             }
335           }
336         }
337    
338         protected void  animate ( )
339         //////////////////////////////////////////////////////////////////////
340         {
341           componentAnimator.update ( this );
342    
343           int  count = repaintCollector.getCount ( );
344    
345           Rectangle [ ]  repaintRegions
346             = repaintCollector.getRepaintRegions ( );
347    
348           for ( int  i = 0; i < count; i++ )
349           {
350             paintImmediately ( repaintRegions [ i ] );
351           }
352    
353           repaintCollector.reset ( );
354         }
355    
356         //////////////////////////////////////////////////////////////////////
357         //////////////////////////////////////////////////////////////////////
358         }