]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssanimation.c
csscomputedvalues: Store animated values here
[~andy/gtk] / gtk / gtkcssanimation.c
1 /*
2  * Copyright © 2012 Red Hat Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Authors: Benjamin Otte <otte@gnome.org>
18  */
19
20 #include "config.h"
21
22 #include "gtkcssanimationprivate.h"
23
24 #include "gtkcsseasevalueprivate.h"
25
26 #include <math.h>
27
28 G_DEFINE_TYPE (GtkCssAnimation, _gtk_css_animation, GTK_TYPE_STYLE_ANIMATION)
29
30 /* NB: Return value can be negative and +-Inf */
31 static double
32 gtk_css_animation_get_iteration (GtkCssAnimation *animation,
33                                  gint64           for_time_us)
34 {
35   gint64 elapsed;
36   double iterations;
37
38   elapsed = for_time_us - animation->timestamp;
39   iterations = (double) elapsed / animation->duration;
40
41   return iterations;
42 }
43
44 static gboolean
45 gtk_css_animation_is_executing_at_iteration (GtkCssAnimation *animation,
46                                              double           iteration)
47 {
48   switch (animation->fill_mode)
49     {
50     case GTK_CSS_FILL_NONE:
51       return iteration >= 0 && iteration <= animation->iteration_count;
52     case GTK_CSS_FILL_FORWARDS:
53       return iteration >= 0;
54     case GTK_CSS_FILL_BACKWARDS:
55       return iteration <= animation->iteration_count;
56     case GTK_CSS_FILL_BOTH:
57       return TRUE;
58     default:
59       g_return_val_if_reached (FALSE);
60     }
61 }
62
63 static double
64 gtk_css_animation_get_progress_from_iteration (GtkCssAnimation *animation,
65                                                double           iteration)
66 {
67   double d;
68
69   iteration = CLAMP (iteration, 0, animation->iteration_count);
70
71   switch (animation->direction)
72     {
73     case GTK_CSS_DIRECTION_NORMAL:
74       if (iteration == animation->iteration_count)
75         return 1;
76       else
77         return iteration - floor (iteration);
78     case GTK_CSS_DIRECTION_REVERSE:
79       if (iteration == animation->iteration_count)
80         return 1;
81       else
82         return ceil (iteration) - iteration;
83     case GTK_CSS_DIRECTION_ALTERNATE:
84       d = floor (iteration);
85       if (fmod (d, 2))
86         return iteration - d;
87       else
88         return 1 + d - iteration;
89     case GTK_CSS_DIRECTION_ALTERNATE_REVERSE:
90       d = floor (iteration);
91       if (fmod (d, 2))
92         return 1 + d - iteration;
93       else
94         return iteration - d;
95     default:
96       g_return_val_if_reached (0);
97     }
98 }
99
100 static GtkBitmask *
101 gtk_css_animation_set_values (GtkStyleAnimation    *style_animation,
102                               GtkBitmask           *changed,
103                               gint64                for_time_us,
104                               GtkCssComputedValues *values)
105 {
106   GtkCssAnimation *animation = GTK_CSS_ANIMATION (style_animation);
107   double iteration, progress;
108   guint i;
109
110   iteration = gtk_css_animation_get_iteration (animation, for_time_us);
111
112   if (!gtk_css_animation_is_executing_at_iteration (animation, iteration))
113     return changed;
114
115   progress = gtk_css_animation_get_progress_from_iteration (animation, iteration);
116   progress = _gtk_css_ease_value_transform (animation->ease, progress);
117   
118   for (i = 0; i < _gtk_css_keyframes_get_n_properties (animation->keyframes); i++)
119     {
120       GtkCssValue *value;
121       guint property_id;
122       
123       property_id = _gtk_css_keyframes_get_property_id (animation->keyframes, i);
124
125       value = _gtk_css_keyframes_get_value (animation->keyframes,
126                                             i,
127                                             progress,
128                                             _gtk_css_computed_values_get_intrinsic_value (values, i));
129       _gtk_css_computed_values_set_animated_value (values, property_id, value);
130       _gtk_css_value_unref (value);
131       
132       changed = _gtk_bitmask_set (changed, property_id, TRUE);
133     }
134
135   return changed;
136 }
137
138 static gboolean
139 gtk_css_animation_is_finished (GtkStyleAnimation *style_animation,
140                                gint64             at_time_us)
141 {
142   return FALSE;
143 }
144
145 static gboolean
146 gtk_css_animation_is_static (GtkStyleAnimation *style_animation,
147                              gint64             at_time_us)
148 {
149   GtkCssAnimation *animation = GTK_CSS_ANIMATION (style_animation);
150   double iteration;
151
152   iteration = gtk_css_animation_get_iteration (animation, at_time_us);
153
154   return iteration >= animation->iteration_count;
155 }
156
157 static void
158 gtk_css_animation_finalize (GObject *object)
159 {
160   GtkCssAnimation *animation = GTK_CSS_ANIMATION (object);
161
162   g_free (animation->name);
163   _gtk_css_keyframes_unref (animation->keyframes);
164   _gtk_css_value_unref (animation->ease);
165
166   G_OBJECT_CLASS (_gtk_css_animation_parent_class)->finalize (object);
167 }
168
169 static void
170 _gtk_css_animation_class_init (GtkCssAnimationClass *klass)
171 {
172   GObjectClass *object_class = G_OBJECT_CLASS (klass);
173   GtkStyleAnimationClass *animation_class = GTK_STYLE_ANIMATION_CLASS (klass);
174
175   object_class->finalize = gtk_css_animation_finalize;
176
177   animation_class->set_values = gtk_css_animation_set_values;
178   animation_class->is_finished = gtk_css_animation_is_finished;
179   animation_class->is_static = gtk_css_animation_is_static;
180 }
181
182 static void
183 _gtk_css_animation_init (GtkCssAnimation *animation)
184 {
185 }
186
187 GtkStyleAnimation *
188 _gtk_css_animation_new (const char      *name,
189                         GtkCssKeyframes *keyframes,
190                         gint64           start_time_us,
191                         gint64           duration_us,
192                         GtkCssValue     *ease,
193                         GtkCssDirection  direction,
194                         GtkCssPlayState  play_state,
195                         GtkCssFillMode   fill_mode,
196                         double           iteration_count)
197 {
198   GtkCssAnimation *animation;
199
200   g_return_val_if_fail (name != NULL, NULL);
201   g_return_val_if_fail (keyframes != NULL, NULL);
202   g_return_val_if_fail (ease != NULL, NULL);
203   g_return_val_if_fail (iteration_count >= 0, NULL);
204
205   animation = g_object_new (GTK_TYPE_CSS_ANIMATION, NULL);
206
207   animation->name = g_strdup (name);
208   animation->keyframes = _gtk_css_keyframes_ref (keyframes);
209   animation->timestamp = start_time_us;
210   animation->duration = duration_us;
211   animation->ease = _gtk_css_value_ref (ease);
212   animation->direction = direction;
213   animation->play_state = play_state;
214   animation->fill_mode = fill_mode;
215   animation->iteration_count = iteration_count;
216
217   return GTK_STYLE_ANIMATION (animation);
218 }
219
220 const char *
221 _gtk_css_animation_get_name (GtkCssAnimation *animation)
222 {
223   g_return_val_if_fail (GTK_IS_CSS_ANIMATION (animation), NULL);
224
225   return animation->name;
226 }