aboutsummaryrefslogtreecommitdiff
path: root/src/animate-timer.vala
blob: 9f924485187e3c42b7fe03a64d3184985e3905d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 4 -*-
 *
 * Copyright (C) 2011,2012 Canonical Ltd
 * Copyright (C) 2015 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors: Robert Ancell <robert.ancell@canonical.com>
 *          Michael Terry <michael.terry@canonical.com>
 *          Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
 */

private class AnimateTimer : Object
{
    /* x and y are 0.0 to 1.0 */
    public delegate double EasingFunc (double x);

    /* The following are the same intervals that Unity uses */
    public const int INSTANT = 150; /* Good for animations that don't convey any information */
    public const int FAST =    250; /* Good for animations that convey duplicated information */
    public const int NORMAL =  500;
    public const int SLOW =   1000; /* Good for animations that convey information that is only presented in the animation */

    /* speed is in milliseconds */
    public unowned EasingFunc easing_func { get; private set; }
    public int speed { get; set; }
    public bool is_running { get { return timeout != 0; } }
    public double progress { get; private set; }

    /* progress is from 0.0 to 1.0 */
    public signal void animate (double progress);

    /* AnimateTimer requires two things: an easing function and a speed.

       The speed is just the duration of the animation in milliseconds.

       The easing function describes how fast the animation occurs at different
       parts of the duration.

       See http://hosted.zeh.com.br/tweener/docs/en-us/misc/transitions.html
       for examples of various easing functions.

       A few are provided with this class, notably ease_in_out and
       ease_out_quint.
    */
    /* speed is in milliseconds */
    public AnimateTimer (EasingFunc func, int speed)
    {
        Object (speed: speed);
        this.easing_func = func;
    }

    ~AnimateTimer ()
    {
        stop ();
    }

    /* temp_speed is in milliseconds */
    public void reset (int temp_speed = -1)
    {
        stop ();

        timeout = Timeout.add (16, animate_cb);
        progress = 0;
        start_time = 0;
        extra_time = 0;
        extra_progress = 0;

        if (temp_speed == -1)
            temp_speed = speed;

        length = temp_speed * TimeSpan.MILLISECOND;
    }

    public void stop ()
    {
        if (timeout != 0)
            Source.remove (timeout);
        timeout = 0;
    }

    private uint timeout = 0;
    private TimeSpan start_time = 0;
    private TimeSpan length = 0;
    private TimeSpan extra_time = 0;
    private double extra_progress = 0.0;

    private bool animate_cb ()
    {
        if (start_time == 0)
            start_time = GLib.get_monotonic_time ();

        var time_progress = normalize_time (GLib.get_monotonic_time ());
        progress = calculate_progress (time_progress);
        animate (progress);

        if (time_progress >= 1.0)
        {
            timeout = 0;
            return false;
        }
        else
            return true;
    }

    /* Returns 0.0 to 1.0 where 1.0 is at or past end_time */
    private double normalize_time (TimeSpan now)
    {
        if (length == 0)
            return 1.0f;

        return (((double)(now - start_time)) / length).clamp (0.0, 1.0);
    }

    /* Returns 0.0 to 1.0 where 1.0 is done.
       time is not normalized yet! */
    private double calculate_progress (double time_progress)
    {
        var y = easing_func (time_progress);
        return y.clamp (0.0, 1.0);
    }

    public static double ease_in_out (double x)
    {
        return (1 - Math.cos (Math.PI * x)) / 2;
    }

    /*public static double ease_in_quad (double x)
    {
        return Math.pow (x, 2);
    }*/
    /*public static double ease_out_quad (double x)
    {
        return -1 * Math.pow (x - 1, 2) + 1;
    }*/

    /*public static double ease_in_quint (double x)
    {
        return Math.pow (x, 5);
    }*/
    public static double ease_out_quint (double x)
    {
        return Math.pow (x - 1, 5) + 1;
    }
}