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 }