New test.
[mono.git] / mcs / class / System.Drawing / System.Drawing / ImageAnimator.cs
1 //
2 // System.Drawing.ImageAnimator.cs
3 //
4 // Author:
5 //   Dennis Hayes (dennish@Raytek.com)
6 //   Sanjay Gupta (gsanjay@novell.com)
7 //
8 // (C) 2002 Ximian, Inc
9 // Copyright (C) 2004,2006 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.Drawing.Imaging;
32 using System.Threading;
33 using System.Collections;
34
35 namespace System.Drawing
36 {
37         //AnimateEventArgs class
38         class AnimateEventArgs : EventArgs 
39         {  
40                 private int frameCount;
41                 private int activeFrameCount = 0;
42                 private Thread thread;
43       
44                 //Constructor.
45                 //
46                 public AnimateEventArgs(Image img)
47                 {
48                         Guid[] dimensionList = img.FrameDimensionsList;
49                         int length = dimensionList.Length;
50                         for (int i=0; i<length; i++) {
51                                 if (dimensionList [i].Equals(FrameDimension.Time.Guid))
52                                         this.frameCount = img.GetFrameCount (FrameDimension.Time);
53                         }                       
54                 }
55       
56                 public int FrameCount {     
57                         get { 
58                                 return frameCount;
59                         }      
60                 }
61       
62                 public int ActiveFrameCount {
63                         get {
64                                 return activeFrameCount;
65                         }
66
67                         set {
68                                 activeFrameCount = value;
69                         }
70                 }
71
72                 public Thread RunThread{
73                         get {
74                                 return thread;
75                         }
76
77                         set {
78                                 thread = value;
79                         }
80                 }
81         }
82
83         /// <summary>
84         /// Summary description for ImageAnimator.
85         /// </summary>
86         /// 
87         [MonoTODO]
88         public sealed class ImageAnimator
89         {
90                 static Hashtable ht = new Hashtable (); 
91                 
92                 private ImageAnimator ()
93                 {
94                         //
95                         // TODO: Add constructor logic here
96                         //
97                 }
98
99                 public static void Animate (Image img, EventHandler onFrameChangeHandler)
100                 {
101                         if (img == null)
102                                 throw new System.NullReferenceException ("Object reference not set to an instance of an object.");
103                         
104                         if (!ht.ContainsKey (img)) {
105                                 AnimateEventArgs evtArgs = new AnimateEventArgs (img);
106                                 int delay;
107                                 try {
108                                         PropertyItem item = img.GetPropertyItem (0x5100); // FrameDelay in libgdiplus
109                                         // Time is in 1/100th of a second
110                                         delay = (item.Value [0] + item.Value [1] * 256) * 10;
111                                 } catch {
112                                         delay = 200;
113                                 }
114
115                                 WorkerThread WT = new WorkerThread (onFrameChangeHandler, evtArgs, delay);
116                                 ThreadStart TS = new ThreadStart(WT.LoopHandler);       
117                                 Thread thread = new Thread(TS);
118                                 thread.IsBackground = true;
119                                 evtArgs.RunThread = thread;
120                                 ht.Add (img, evtArgs);
121                                 
122                                 thread.Start();                         
123                         }
124                 }
125
126                 public static bool CanAnimate (Image img)
127                 {
128                         //An image can animate if it has multiple frame in
129                         //time based FrameDimension else return false
130                         //Doubt what if the image has multiple frame in page
131                         //based FrameDimension
132                         if (img == null)
133                                 return false;
134
135                         //Need to check whether i can do this without iterating
136                         //within the FrameDimensionsList, ie just call GetFrameCount
137                         //with parameter FrameDimension.Time
138                         Guid[] dimensionList = img.FrameDimensionsList;
139                         int length = dimensionList.Length;
140                         int frameCount;
141                         for (int i=0; i<length; i++) 
142                         {
143                                 if (dimensionList [i].Equals(FrameDimension.Time.Guid)) 
144                                 {
145                                         frameCount = img.GetFrameCount (FrameDimension.Time);
146                                         if (frameCount > 1)
147                                                 return true;
148                                 }
149                         }                       
150
151                         return false;           
152                 }
153
154                 public static void StopAnimate (Image img, EventHandler onFrameChangeHandler)
155                 {
156                         if (img == null)
157                                 throw new System.NullReferenceException ("Object reference not set to an instance of an object.");                      
158
159                         if (ht.ContainsKey (img)) {
160                                 AnimateEventArgs evtArgs = (AnimateEventArgs) ht [img];
161                                 evtArgs.RunThread.Abort ();
162                                 ht.Remove (img);
163                         }                               
164                 }
165
166                 public static void UpdateFrames ()
167                 {
168                         foreach (Image img in ht.Keys) {
169                                 UpdateFrames (img);
170                         }
171                 }
172                 
173                 public static void UpdateFrames (Image img)
174                 {
175                         if (img == null)
176                                 throw new System.NullReferenceException ("Object reference not set to an instance of an object.");
177
178                         if (ht.ContainsKey (img)){
179                                 //Need a way to get the delay during animation
180                                 AnimateEventArgs evtArgs = (AnimateEventArgs) ht [img];
181                                 if (evtArgs.ActiveFrameCount < evtArgs.FrameCount-1){
182                                         evtArgs.ActiveFrameCount ++;
183                                         img.SelectActiveFrame (FrameDimension.Time, evtArgs.ActiveFrameCount);
184                                 } 
185                                 else
186                                         evtArgs.ActiveFrameCount = 0;
187                                 ht [img] = evtArgs;
188                         }                       
189                 }
190         }
191
192         class WorkerThread
193         {
194                 EventHandler frameChangeHandler;
195                 AnimateEventArgs animateEventArgs;
196                 int delay;
197                                 
198                 public WorkerThread (EventHandler frmChgHandler, AnimateEventArgs aniEvtArgs, int delay)
199                 {
200                         frameChangeHandler = frmChgHandler;
201                         animateEventArgs = aniEvtArgs;
202                         this.delay = delay;
203                 }
204     
205                 public void LoopHandler()
206                 {
207                         try {
208                                 while (true) {
209                                         Thread.Sleep (delay);
210                                         frameChangeHandler (null, animateEventArgs);
211                                 }                               
212                         } catch (ThreadAbortException) { 
213                                 Thread.ResetAbort (); // we're going to finish anyway
214                         }
215                 }
216         }
217 }
218