]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssanimation.c
animation: Don't set the changed properties anymore
[~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 void
101 gtk_css_animation_set_values (GtkStyleAnimation    *style_animation,
102                               gint64                for_time_us,
103                               GtkCssComputedValues *values)
104 {
105   GtkCssAnimation *animation = GTK_CSS_ANIMATION (style_animation);
106   double iteration, progress;
107   guint i;
108
109   iteration = gtk_css_animation_get_iteration (animation, for_time_us);
110
111   if (!gtk_css_animation_is_executing_at_iteration (animation, iteration))
112     return;
113
114   progress = gtk_css_animation_get_progress_from_iteration (animation, iteration);
115   progress = _gtk_css_ease_value_transform (animation->ease, progress);
116   
117   for (i = 0; i < _gtk_css_keyframes_get_n_properties (animation->keyframes); i++)
118     {
119       GtkCssValue *value;
120       guint property_id;
121       
122       property_id = _gtk_css_keyframes_get_property_id (animation->keyframes, i);
123
124       value = _gtk_css_keyframes_get_value (animation->keyframes,
125                                             i,
126                                             progress,
127                                             _gtk_css_computed_values_get_intrinsic_value (values, i));
128       _gtk_css_computed_values_set_animated_value (values, property_id, value);
129       _gtk_css_value_unref (value);
130     }
131 }
132
133 static gboolean
134 gtk_css_animation_is_finished (GtkStyleAnimation *style_animation,
135                                gint64             at_time_us)
136 {
137   return FALSE;
138 }
139
140 static gboolean
141 gtk_css_animation_is_static (GtkStyleAnimation *style_animation,
142                              gint64             at_time_us)
143 {
144   GtkCssAnimation *animation = GTK_CSS_ANIMATION (style_animation);
145   double iteration;
146
147   iteration = gtk_css_animation_get_iteration (animation, at_time_us);
148
149   return iteration >= animation->iteration_count;
150 }
151
152 static void
153 gtk_css_animation_finalize (GObject *object)
154 {
155   GtkCssAnimation *animation = GTK_CSS_ANIMATION (object);
156
157   g_free (animation->name);
158   _gtk_css_keyframes_unref (animation->keyframes);
159   _gtk_css_value_unref (animation->ease);
160
161   G_OBJECT_CLASS (_gtk_css_animation_parent_class)->finalize (object);
162 }
163
164 static void
165 _gtk_css_animation_class_init (GtkCssAnimationClass *klass)
166 {
167   GObjectClass *object_class = G_OBJECT_CLASS (klass);
168   GtkStyleAnimationClass *animation_class = GTK_STYLE_ANIMATION_CLASS (klass);
169
170   object_class->finalize = gtk_css_animation_finalize;
171
172   animation_class->set_values = gtk_css_animation_set_values;
173   animation_class->is_finished = gtk_css_animation_is_finished;
174   animation_class->is_static = gtk_css_animation_is_static;
175 }
176
177 static void
178 _gtk_css_animation_init (GtkCssAnimation *animation)
179 {
180 }
181
182 GtkStyleAnimation *
183 _gtk_css_animation_new (const char      *name,
184                         GtkCssKeyframes *keyframes,
185                         gint64           start_time_us,
186                         gint64           duration_us,
187                         GtkCssValue     *ease,
188                         GtkCssDirection  direction,
189                         GtkCssPlayState  play_state,
190                         GtkCssFillMode   fill_mode,
191                         double           iteration_count)
192 {
193   GtkCssAnimation *animation;
194
195   g_return_val_if_fail (name != NULL, NULL);
196   g_return_val_if_fail (keyframes != NULL, NULL);
197   g_return_val_if_fail (ease != NULL, NULL);
198   g_return_val_if_fail (iteration_count >= 0, NULL);
199
200   animation = g_object_new (GTK_TYPE_CSS_ANIMATION, NULL);
201
202   animation->name = g_strdup (name);
203   animation->keyframes = _gtk_css_keyframes_ref (keyframes);
204   animation->timestamp = start_time_us;
205   animation->duration = duration_us;
206   animation->ease = _gtk_css_value_ref (ease);
207   animation->direction = direction;
208   animation->play_state = play_state;
209   animation->fill_mode = fill_mode;
210   animation->iteration_count = iteration_count;
211
212   return GTK_STYLE_ANIMATION (animation);
213 }
214
215 const char *
216 _gtk_css_animation_get_name (GtkCssAnimation *animation)
217 {
218   g_return_val_if_fail (GTK_IS_CSS_ANIMATION (animation), NULL);
219
220   return animation->name;
221 }