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

« back to all changes in this revision

Viewing changes to src/core/MonoDevelop.Ide/MonoDevelop.Components/Tweener.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
// Tweener.cs
 
3
//
 
4
// Author:
 
5
//       Jason Smith <jason.smith@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 System.Diagnostics;
 
30
 
 
31
namespace MonoDevelop.Components
 
32
{
 
33
 
 
34
        public static class Easing
 
35
        {
 
36
                public static readonly Func<float, float> Linear = x => x;
 
37
 
 
38
                public static readonly Func<float, float> SinOut = x => (float)Math.Sin (x * Math.PI * 0.5f);
 
39
                public static readonly Func<float, float> SinIn = x => 1.0f - (float)Math.Cos (x * Math.PI * 0.5f);
 
40
                public static readonly Func<float, float> SinInOut = x => -(float)Math.Cos (Math.PI * x) / 2.0f + 0.5f;
 
41
 
 
42
                public static readonly Func<float, float> CubicIn = x => x * x * x;
 
43
                public static readonly Func<float, float> CubicOut = x => (float)Math.Pow (x - 1.0f, 3.0f) + 1.0f;
 
44
                public static readonly Func<float, float> CubicInOut = x => x < 0.5f ? (float)Math.Pow (x * 2.0f, 3.0f) / 2.0f :
 
45
                                                                                                                                                           (float)(Math.Pow ((x-1)*2.0f, 3.0f) + 2.0f) / 2.0f;
 
46
 
 
47
                public static readonly Func<float, float> BounceOut;
 
48
                public static readonly Func<float, float> BounceIn;
 
49
 
 
50
                public static readonly Func<float, float> SpringIn = x => x * x * ((1.70158f + 1) * x - 1.70158f);
 
51
                public static readonly Func<float, float> SpringOut = x => (x - 1) * (x - 1) * ((1.70158f + 1) * (x - 1) + 1.70158f) + 1;
 
52
 
 
53
                static Easing ()
 
54
                {
 
55
                        BounceOut = p => {
 
56
                                if (p < (1 / 2.75f))
 
57
                                {
 
58
                                        return 7.5625f * p * p;
 
59
                                }
 
60
                                else if (p < (2 / 2.75f))
 
61
                                {
 
62
                                        p -= (1.5f / 2.75f);
 
63
 
 
64
                                        return 7.5625f * p * p + .75f;
 
65
                                }
 
66
                                else if (p < (2.5f / 2.75f))
 
67
                                {
 
68
                                        p -= (2.25f / 2.75f);
 
69
 
 
70
                                        return 7.5625f * p * p + .9375f;
 
71
                                }
 
72
                                else
 
73
                                {
 
74
                                        p -= (2.625f / 2.75f);
 
75
 
 
76
                                        return 7.5625f * p * p + .984375f;
 
77
                                }
 
78
                        };
 
79
 
 
80
                        BounceIn = p => 1.0f - BounceOut (p);
 
81
                }
 
82
        }
 
83
 
 
84
        public interface Animatable
 
85
        {
 
86
                void QueueDraw ();
 
87
        }
 
88
 
 
89
        public class Animation : System.Collections.IEnumerable
 
90
        {
 
91
                float beginAt;
 
92
                float finishAt;
 
93
                Func<float, float> easing;
 
94
                Action<float> step;
 
95
                List<Animation> children;
 
96
                Action finished;
 
97
                bool finishedTriggered;
 
98
 
 
99
                public Animation ()
 
100
                {
 
101
                        children = new List<Animation> ();
 
102
                        easing = Easing.Linear;
 
103
                        step = f => {};
 
104
                }
 
105
 
 
106
                public Animation (Action<float> callback, float start = 0.0f, float end = 1.0f, Func<float, float> easing = null, Action finished = null)
 
107
                {
 
108
                        children = new List<Animation> ();
 
109
                        this.easing = easing ?? Components.Easing.Linear;
 
110
                        this.finished = finished;
 
111
 
 
112
                        var transform = AnimationExtensions.Interpolate (start, end);
 
113
                        step = f => callback (transform (f));
 
114
                }
 
115
 
 
116
                public System.Collections.IEnumerator GetEnumerator ()
 
117
                {
 
118
                        return children.GetEnumerator ();
 
119
                }
 
120
 
 
121
                public Animation Insert (float beginAt, float finishAt, Animation animation)
 
122
                {
 
123
                        Add (beginAt, finishAt, animation);
 
124
                        return this;
 
125
                }
 
126
 
 
127
                public void Commit (Animatable owner, string name, uint rate = 16, uint length = 250, 
 
128
                                    Func<float, float> easing = null, Action<float, bool> finished = null, Func<bool> repeat = null)
 
129
                {
 
130
                        owner.Animate (name, this, rate, length, easing, finished, repeat);
 
131
                }
 
132
 
 
133
                public void Add (float beginAt, float finishAt, Animation animation)
 
134
                {
 
135
                        if (beginAt < 0 || beginAt > 1)
 
136
                                throw new ArgumentOutOfRangeException ("beginAt");
 
137
 
 
138
                        if (finishAt < 0 || finishAt > 1)
 
139
                                throw new ArgumentOutOfRangeException ("finishAt");
 
140
 
 
141
                        if (finishAt <= beginAt)
 
142
                                throw new ArgumentException ("finishAt must be greater than beginAt");
 
143
 
 
144
                        animation.beginAt = beginAt;
 
145
                        animation.finishAt = finishAt;
 
146
                        children.Add (animation);
 
147
                }
 
148
 
 
149
                public Animation WithConcurrent (Animation animation, float beginAt = 0.0f, float finishAt = 1.0f)
 
150
                {
 
151
                        animation.beginAt = beginAt;
 
152
                        animation.finishAt = finishAt;
 
153
                        children.Add (animation);
 
154
                        return this;
 
155
                }
 
156
 
 
157
                public Animation WithConcurrent (Action<float> callback, float start = 0.0f, float end = 1.0f, Func<float, float> easing = null, float beginAt = 0.0f, float finishAt = 1.0f)
 
158
                {
 
159
                        Animation child = new Animation (callback, start, end, easing);
 
160
                        child.beginAt = beginAt;
 
161
                        child.finishAt = finishAt;
 
162
                        children.Add (child);
 
163
                        return this;
 
164
                }
 
165
 
 
166
                public Action<float> GetCallback ()
 
167
                {
 
168
                        Action<float> result = f => {
 
169
                                step (easing (f));
 
170
                                foreach (var animation in children) {
 
171
                                        if (animation.finishedTriggered)
 
172
                                                continue;
 
173
 
 
174
                                        float val = Math.Max (0.0f, Math.Min (1.0f, (f - animation.beginAt) / (animation.finishAt - animation.beginAt)));
 
175
 
 
176
                                        if (val <= 0.0f) // not ready to process yet
 
177
                                                continue;
 
178
 
 
179
                                        var callback = animation.GetCallback ();
 
180
                                        callback (val);
 
181
 
 
182
                                        if (val >= 1.0f) {
 
183
                                                animation.finishedTriggered = true;
 
184
                                                if (animation.finished != null)
 
185
                                                        animation.finished ();
 
186
                                        }
 
187
                                }
 
188
                        };
 
189
                        return result;
 
190
                }
 
191
        }
 
192
 
 
193
        public static class AnimationExtensions
 
194
        {
 
195
                class Info
 
196
                {
 
197
                        public Func<float, float> Easing { get; set; }
 
198
                        public uint Rate { get; set; }
 
199
                        public uint Length { get; set; }
 
200
                        public Animatable Owner { get; set; }
 
201
                        public Action<float> callback;
 
202
                        public Action<float, bool> finished;
 
203
                        public Func<bool> repeat;
 
204
                        public Tweener tweener;
 
205
                }
 
206
 
 
207
                static Dictionary<string, Info> animations;
 
208
 
 
209
                static AnimationExtensions ()
 
210
                {
 
211
                        animations = new Dictionary<string, Info> ();
 
212
                }
 
213
 
 
214
                public static void Animate (this Animatable self, string name, Animation animation, uint rate = 16, uint length = 250, 
 
215
                                            Func<float, float> easing = null, Action<float, bool> finished = null, Func<bool> repeat = null)
 
216
                {
 
217
                        self.Animate (name, animation.GetCallback (), rate, length, easing, finished, repeat);
 
218
                }
 
219
 
 
220
                public static Func<float, float> Interpolate (float start, float end = 1.0f, float reverseVal = 0.0f, bool reverse = false)
 
221
                {
 
222
                        float target = (reverse ? reverseVal : end);
 
223
                        return x => start + (target - start) * x;
 
224
                }
 
225
 
 
226
                public static void Animate (this Animatable self, string name, Action<float> callback, float start, float end, uint rate = 16, uint length = 250, 
 
227
                                            Func<float, float> easing = null, Action<float, bool> finished = null, Func<bool> repeat = null)
 
228
                {
 
229
                        self.Animate<float> (name, Interpolate (start, end), callback, rate, length, easing, finished, repeat);
 
230
                }
 
231
 
 
232
                public static void Animate (this Animatable self, string name, Action<float> callback, uint rate = 16, uint length = 250, 
 
233
                                            Func<float, float> easing = null, Action<float, bool> finished = null, Func<bool> repeat = null)
 
234
                {
 
235
                        self.Animate<float> (name, x => x, callback, rate, length, easing, finished, repeat);
 
236
                }
 
237
 
 
238
                public static void Animate<T> (this Animatable self, string name, Func<float, T> transform, Action<T> callback, uint rate = 16, uint length = 250, 
 
239
                                               Func<float, float> easing = null, Action<T, bool> finished = null, Func<bool> repeat = null) 
 
240
                {
 
241
                        if (transform == null)
 
242
                                throw new ArgumentNullException ("transform");
 
243
                        if (callback == null)
 
244
                                throw new ArgumentNullException ("callback");
 
245
                        if (self == null)
 
246
                                throw new ArgumentNullException ("widget");
 
247
 
 
248
                        self.AbortAnimation (name);
 
249
                        name += self.GetHashCode ().ToString ();
 
250
 
 
251
                        Action<float> step = f => callback (transform(f));
 
252
                        Action<float, bool> final = null;
 
253
                        if (finished != null)
 
254
                                final = (f, b) => finished (transform(f), b);
 
255
 
 
256
                        var info = new Info {
 
257
                                Rate = rate,
 
258
                                Length = length,
 
259
                                Easing = easing ?? Easing.Linear
 
260
                        };
 
261
 
 
262
                        Tweener tweener = new Tweener (info.Length, info.Rate);
 
263
                        tweener.Easing = info.Easing;
 
264
                        tweener.Handle = name;
 
265
                        tweener.ValueUpdated += HandleTweenerUpdated;
 
266
                        tweener.Finished += HandleTweenerFinished;
 
267
 
 
268
                        info.tweener = tweener;
 
269
                        info.callback = step;
 
270
                        info.finished = final;
 
271
                        info.repeat = repeat ?? (() => false);
 
272
                        info.Owner = self;
 
273
 
 
274
                        animations[name] = info;
 
275
                        tweener.Start ();
 
276
 
 
277
                        info.callback (0.0f);
 
278
                }
 
279
 
 
280
                public static bool AbortAnimation (this Animatable self, string handle)
 
281
                {
 
282
                        handle += self.GetHashCode ().ToString ();
 
283
                        if (!animations.ContainsKey (handle))
 
284
                                return false;
 
285
 
 
286
                        Info info = animations[handle];
 
287
                        info.tweener.ValueUpdated -= HandleTweenerUpdated;
 
288
                        info.tweener.Finished -= HandleTweenerFinished;
 
289
                        info.tweener.Stop ();
 
290
 
 
291
                        animations.Remove (handle);
 
292
                        if (info.finished != null)
 
293
                                info.finished (1.0f, true);
 
294
                        return true;
 
295
                }
 
296
 
 
297
                public static bool AnimationIsRunning (this Animatable self, string handle)
 
298
                {
 
299
                        handle += self.GetHashCode ().ToString ();
 
300
                        return animations.ContainsKey (handle);
 
301
                }
 
302
 
 
303
                static void HandleTweenerUpdated (object o, EventArgs args)
 
304
                {
 
305
                        Tweener tweener = o as Tweener;
 
306
                        Info info = animations[tweener.Handle];
 
307
 
 
308
                        info.callback (tweener.Value);
 
309
                        info.Owner.QueueDraw ();
 
310
                }
 
311
 
 
312
                static void HandleTweenerFinished (object o, EventArgs args)
 
313
                {
 
314
                        Tweener tweener = o as Tweener;
 
315
                        Info info = animations[tweener.Handle];
 
316
 
 
317
                        bool repeat = info.repeat ();
 
318
 
 
319
                        info.callback (tweener.Value);
 
320
 
 
321
                        if (!repeat) {
 
322
                                animations.Remove (tweener.Handle);
 
323
                                tweener.ValueUpdated -= HandleTweenerUpdated;
 
324
                                tweener.Finished -= HandleTweenerFinished;
 
325
                        }
 
326
 
 
327
                        if (info.finished != null)
 
328
                                info.finished (tweener.Value, false);
 
329
                        info.Owner.QueueDraw ();
 
330
 
 
331
                        if (repeat) {
 
332
                                tweener.Start ();
 
333
                        }
 
334
                }
 
335
        }
 
336
 
 
337
        class Tweener
 
338
        {
 
339
                public uint Length { get; private set; }
 
340
                public uint Rate { get; private set; }
 
341
                public float Value { get; private set; }
 
342
                public Func<float, float> Easing { get; set; }
 
343
                public bool Loop { get; set; }
 
344
                public string Handle { get; set; }
 
345
 
 
346
                public bool IsRunning {
 
347
                        get { return runningTime.IsRunning; }
 
348
                }
 
349
 
 
350
                public event EventHandler ValueUpdated;
 
351
                public event EventHandler Finished;
 
352
 
 
353
                Stopwatch runningTime;
 
354
                uint timeoutHandle;
 
355
 
 
356
                public Tweener (uint length, uint rate)
 
357
                {
 
358
                        Value = 0.0f;
 
359
                        Length = length;
 
360
                        Loop = false;
 
361
                        Rate = rate;
 
362
                        runningTime = new Stopwatch ();
 
363
                        Easing = Components.Easing.Linear;
 
364
                }
 
365
 
 
366
                ~Tweener ()
 
367
                {
 
368
                        if (timeoutHandle > 0)
 
369
                                GLib.Source.Remove (timeoutHandle);
 
370
                }
 
371
 
 
372
                public void Start ()
 
373
                {
 
374
                        Pause ();
 
375
 
 
376
                        runningTime.Start ();
 
377
                        timeoutHandle = GLib.Timeout.Add (Rate, () => { 
 
378
                                float rawValue = Math.Min (1.0f, runningTime.ElapsedMilliseconds / (float) Length);
 
379
                                Value = Easing (rawValue);
 
380
                                if (ValueUpdated != null)
 
381
                                        ValueUpdated (this, EventArgs.Empty);
 
382
 
 
383
                                if (rawValue >= 1.0f)
 
384
                                {
 
385
                                        if (Loop) {
 
386
                                                Value = 0.0f;
 
387
                                                runningTime.Reset ();
 
388
                                                runningTime.Start ();
 
389
                                                return true;
 
390
                                        }
 
391
 
 
392
                                        runningTime.Stop ();
 
393
                                        runningTime.Reset ();
 
394
                                        timeoutHandle = 0;
 
395
                                        if (Finished != null)
 
396
                                                Finished (this, EventArgs.Empty);
 
397
                                        Value = 0.0f;
 
398
                                        return false;
 
399
                                }
 
400
                                return true;
 
401
                        });
 
402
                }
 
403
 
 
404
                public void Stop ()
 
405
                {
 
406
                        Pause ();
 
407
                        runningTime.Reset ();
 
408
                        Value = 1.0f;
 
409
                        if (Finished != null)
 
410
                                Finished (this, EventArgs.Empty);
 
411
                        Value = 0.0f;
 
412
                }
 
413
 
 
414
                public void Reset ()
 
415
                {
 
416
                        runningTime.Reset ();
 
417
                        runningTime.Start ();
 
418
                }
 
419
 
 
420
                public void Pause ()
 
421
                {
 
422
                        runningTime.Stop ();
 
423
 
 
424
                        if (timeoutHandle > 0) {
 
425
                                GLib.Source.Remove (timeoutHandle);
 
426
                                timeoutHandle = 0;
 
427
                        }
 
428
                }
 
429
        }
 
430
}