~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/AnimatedIcon.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// AnimatedIcon.cs
 
3
//
 
4
// Author:
 
5
//       Lluis Sanchez <lluis@xamarin.com>
 
6
//
 
7
// Copyright (c) 2012 Xamarin Inc
 
8
//
 
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
 
10
// of this software and associated documentation files (the "Software"), to deal
 
11
// in the Software without restriction, including without limitation the rights
 
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
13
// copies of the Software, and to permit persons to whom the Software is
 
14
// furnished to do so, subject to the following conditions:
 
15
//
 
16
// The above copyright notice and this permission notice shall be included in
 
17
// all copies or substantial portions of the Software.
 
18
//
 
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
25
// THE SOFTWARE.
 
26
 
 
27
using System;
 
28
using System.Collections.Generic;
 
29
using Mono.Addins;
 
30
using System.IO;
 
31
using MonoDevelop.Ide.Extensions;
 
32
using MonoDevelop.Core;
 
33
using MonoDevelop.Components;
 
34
using System.Text;
 
35
using System.Linq;
 
36
 
 
37
namespace MonoDevelop.Ide.Gui.Components
 
38
{
 
39
 
 
40
        public class AnimatedIcon
 
41
        {
 
42
                /* An animation spec is a sequence of animation frames. Frames are separated using semicolons.
 
43
                 * Each frame can be an image (using a regular image spec), an effect, or a pause. For example:
 
44
                 * 
 
45
                 * res:build1.png;morph;res:build2.png;morph
 
46
                 * 
 
47
                 * Supported effects are:
 
48
                 * fade-out, fade-in, morph
 
49
                 * 
 
50
                 */
 
51
 
 
52
                string animationSpec;
 
53
                RuntimeAddin addin;
 
54
                Gtk.IconSize size;
 
55
 
 
56
                const int defaultPause = 200;
 
57
                List<Gdk.Pixbuf> images;
 
58
                List<int> pauses;
 
59
 
 
60
                static Dictionary<string,Type> animationItems = new Dictionary<string, Type> ();
 
61
 
 
62
                static AnimatedIcon ()
 
63
                {
 
64
                        animationItems ["morph"] = typeof(MorphEffect);
 
65
                        animationItems ["fade-in"] = typeof(FadeInEffect);
 
66
                        animationItems ["fade-out"] = typeof(FadeOutEffect);
 
67
                }
 
68
 
 
69
                public AnimatedIcon (RuntimeAddin addin, string animationSpec, Gtk.IconSize size)
 
70
                {
 
71
                        this.addin = addin;
 
72
                        this.size = size;
 
73
                        this.animationSpec = animationSpec;
 
74
                        Parse (animationSpec);
 
75
                }
 
76
 
 
77
                void Parse (string animationSpec)
 
78
                {
 
79
                        List<AnimationItem> parsedItems = new List<AnimationItem> ();
 
80
                        string[] items = animationSpec.Split (';');
 
81
                        AnimationItem last = null;
 
82
 
 
83
                        foreach (var item in items) {
 
84
                                int i = item.IndexOf (':');
 
85
                                var tname = i != -1 ? item.Substring (0, i) : item;
 
86
                                int pause;
 
87
                                Type type;
 
88
                                AnimationItem aitem = null;
 
89
 
 
90
                                if (animationItems.TryGetValue (tname, out type)) {
 
91
                                        aitem = (AnimationItem) Activator.CreateInstance (type);
 
92
                                        aitem.Parse (item);
 
93
                                }
 
94
                                else if (int.TryParse (item, out pause)) {
 
95
                                        aitem = new PauseItem () { Pause = pause };
 
96
                                }
 
97
                                else {
 
98
                                        // It must be an image
 
99
                                        var id = ImageService.GetStockId (addin, item, size);
 
100
                                        var img = ImageService.GetPixbuf (id, size);
 
101
                                        if (img == null)
 
102
                                                continue;
 
103
                                        aitem = new ImageItem () { Image = img };
 
104
                                }
 
105
                                if (last != null)
 
106
                                        last.NextItem = aitem;
 
107
                                aitem.PreviousItem = last;
 
108
                                parsedItems.Add (aitem);
 
109
                                last = aitem;
 
110
                        }
 
111
 
 
112
                        if (parsedItems.Count > 0) {
 
113
                                // Close the chain
 
114
                                parsedItems[0].PreviousItem = parsedItems [parsedItems.Count - 1];
 
115
                                parsedItems [parsedItems.Count - 1].NextItem = parsedItems [0];
 
116
                        }
 
117
 
 
118
                        images = new List<Gdk.Pixbuf> ();
 
119
                        pauses = new List<int> ();
 
120
                        bool lastWasImage = false;
 
121
 
 
122
                        foreach (var aitem in parsedItems) {
 
123
                                foreach (var frame in aitem.GetFrames ()) {
 
124
                                        if (frame is Gdk.Pixbuf) {
 
125
                                                if (lastWasImage)
 
126
                                                        pauses.Add (defaultPause);
 
127
                                                images.Add ((Gdk.Pixbuf)frame);
 
128
                                                lastWasImage = true;
 
129
                                        }
 
130
                                        else {
 
131
                                                if (!lastWasImage) {
 
132
                                                        if (pauses.Count > 0)
 
133
                                                                pauses [pauses.Count - 1] = pauses [pauses.Count - 1] + (int) frame;
 
134
                                                        else {
 
135
                                                                // Pause before any image. Add a dummy image
 
136
                                                                images.Add (ImageService.GetPixbuf ("md-empty"));
 
137
                                                                pauses.Add ((int) frame);
 
138
                                                        }
 
139
                                                } else
 
140
                                                        pauses.Add ((int)frame);
 
141
                                                lastWasImage = false;
 
142
                                        }
 
143
                                }
 
144
                        }
 
145
                        if (pauses.Count < images.Count)
 
146
                                pauses.Add (defaultPause);
 
147
                }
 
148
 
 
149
                public Gdk.Pixbuf FirstFrame {
 
150
                        get {
 
151
                                return images.Count > 0 ? images [0] : ImageService.GetPixbuf ("md-empty");
 
152
                        }
 
153
                }
 
154
 
 
155
                public string AnimationSpec {
 
156
                        get { return animationSpec; }
 
157
                }
 
158
 
 
159
                public IDisposable StartAnimation (Action<Gdk.Pixbuf> renderer)
 
160
                {
 
161
                        int currentFrame = 0;
 
162
                        return DispatchService.RunAnimation (delegate {
 
163
                                renderer (images [currentFrame]);
 
164
                                var res = pauses [currentFrame];
 
165
                                currentFrame = (currentFrame + 1) % images.Count;
 
166
                                return res;
 
167
                        });
 
168
                }
 
169
 
 
170
                abstract class AnimationItem
 
171
                {
 
172
                        List<object> frames;
 
173
 
 
174
                        internal AnimationItem NextItem;
 
175
                        internal AnimationItem PreviousItem;
 
176
                        bool renderingFrames;
 
177
 
 
178
                        public virtual void Parse (string spec)
 
179
                        {
 
180
                        }
 
181
 
 
182
                        internal List<object> GetFrames ()
 
183
                        {
 
184
                                RenderFrames ();
 
185
                                return frames;
 
186
                        }
 
187
 
 
188
                        public Gdk.Pixbuf PreviousFrame {
 
189
                                get {
 
190
                                        PreviousItem.RenderFrames ();
 
191
                                        var last = (Gdk.Pixbuf) PreviousItem.frames.LastOrDefault (f => f is Gdk.Pixbuf);
 
192
                                        if (last != null)
 
193
                                                return last;
 
194
                                        else
 
195
                                                return PreviousItem.PreviousFrame;
 
196
                                }
 
197
                        }
 
198
 
 
199
                        public Gdk.Pixbuf NextFrame {
 
200
                                get {
 
201
                                        NextItem.RenderFrames ();
 
202
                                        var first = (Gdk.Pixbuf) NextItem.frames.FirstOrDefault (f => f is Gdk.Pixbuf);
 
203
                                        if (first != null)
 
204
                                                return first;
 
205
                                        else
 
206
                                                return NextItem.NextFrame;
 
207
                                }
 
208
                        }
 
209
 
 
210
                        void RenderFrames ()
 
211
                        {
 
212
                                if (renderingFrames)
 
213
                                        throw new Exception ("Invalid animation sequence");
 
214
                                if (frames == null) {
 
215
                                        renderingFrames = true;
 
216
                                        frames = new List<object> ();
 
217
                                        OnRenderFrames ();
 
218
                                        renderingFrames = false;
 
219
                                }
 
220
                        }
 
221
                        
 
222
                        public abstract void OnRenderFrames ();
 
223
 
 
224
                        protected void AddImage (Gdk.Pixbuf image)
 
225
                        {
 
226
                                frames.Add (image);
 
227
                        }
 
228
 
 
229
                        protected void AddPause (int ms)
 
230
                        {
 
231
                                frames.Add (ms);
 
232
                        }
 
233
                }
 
234
 
 
235
                class ImageItem: AnimationItem
 
236
                {
 
237
                        public Gdk.Pixbuf Image { get; set; }
 
238
 
 
239
                        public override void OnRenderFrames ()
 
240
                        {
 
241
                                AddImage (Image);
 
242
                        }
 
243
                }
 
244
 
 
245
                class PauseItem: AnimationItem
 
246
                {
 
247
                        public int Pause { get; set; }
 
248
                        
 
249
                        public override void OnRenderFrames ()
 
250
                        {
 
251
                                AddPause (Pause);
 
252
                        }
 
253
                }
 
254
                
 
255
                class FadeOutEffect: AnimationItem
 
256
                {
 
257
                        public override void OnRenderFrames ()
 
258
                        {
 
259
                                var icon = PreviousFrame;
 
260
                                for (int n=0; n<10; n++) {
 
261
                                        AddImage (ImageService.MakeTransparent (icon, ((double)(9-n))/10.0));
 
262
                                        AddPause (60);
 
263
                                }
 
264
                        }
 
265
                }
 
266
 
 
267
                class FadeInEffect: AnimationItem
 
268
                {
 
269
                        public override void OnRenderFrames ()
 
270
                        {
 
271
                                var icon = NextFrame;
 
272
                                for (int n=0; n<10; n++) {
 
273
                                        AddImage (ImageService.MakeTransparent (icon, ((double)(n))/10.0));
 
274
                                        AddPause (60);
 
275
                                }
 
276
                        }
 
277
                }
 
278
                
 
279
                class MorphEffect: AnimationItem
 
280
                {
 
281
                        public override void OnRenderFrames ()
 
282
                        {
 
283
                                var prev = PreviousFrame;
 
284
                                var next = NextFrame;
 
285
                                for (int n=0; n<10; n++) {
 
286
                                        var img1 = ImageService.MakeTransparent (next, ((double)(n))/10.0);
 
287
                                        var img2 = ImageService.MakeTransparent (prev, ((double)(9-n))/10.0);
 
288
                                        img1.Composite (img2,
 
289
                                                        0,  0,
 
290
                                                        img2.Width, img2.Width,
 
291
                                                        0, 0,
 
292
                                                        1, 1, Gdk.InterpType.Bilinear, 255); 
 
293
                                        AddImage (img2);
 
294
                                        AddPause (60);
 
295
                                }
 
296
                        }
 
297
                }
 
298
        }
 
299
}