]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssanimation.c
stylecontext: Do invalidation on first resize container
[~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 (if animation hasn't started yet) */
31 static gint64
32 gtk_css_animation_get_elapsed (GtkCssAnimation *animation,
33                                gint64           for_time_us)
34 {
35   if (animation->play_state == GTK_CSS_PLAY_STATE_PAUSED)
36     return animation->timestamp;
37   else
38     return for_time_us - animation->timestamp;
39 }
40 /* NB: Return value can be negative and +-Inf */
41 static double
42 gtk_css_animation_get_iteration (GtkCssAnimation *animation,
43                                  gint64           for_time_us)
44 {
45   return (double) gtk_css_animation_get_elapsed (animation, for_time_us) / animation->duration;
46 }
47
48 static gboolean
49 gtk_css_animation_is_executing_at_iteration (GtkCssAnimation *animation,
50                                              double           iteration)
51 {
52   switch (animation->fill_mode)
53     {
54     case GTK_CSS_FILL_NONE:
55       return iteration >= 0 && iteration <= animation->iteration_count;
56     case GTK_CSS_FILL_FORWARDS:
57       return iteration >= 0;
58     case GTK_CSS_FILL_BACKWARDS:
59       return iteration <= animation->iteration_count;
60     case GTK_CSS_FILL_BOTH:
61       return TRUE;
62     default:
63       g_return_val_if_reached (FALSE);
64     }
65 }
66
67 static double
68 gtk_css_animation_get_progress_from_iteration (GtkCssAnimation *animation,
69                                                double           iteration)
70 {
71   double d;
72
73   iteration = CLAMP (iteration, 0, animation->iteration_count);
74
75   switch (animation->direction)
76     {
77     case GTK_CSS_DIRECTION_NORMAL:
78       if (iteration == animation->iteration_count)
79         return 1;
80       else
81         return iteration - floor (iteration);
82     case GTK_CSS_DIRECTION_REVERSE:
83       if (iteration == animation->iteration_count)
84         return 1;
85       else
86         return ceil (iteration) - iteration;
87     case GTK_CSS_DIRECTION_ALTERNATE:
88       d = floor (iteration);
89       if (fmod (d, 2))
90         return iteration - d;
91       else
92         return 1 + d - iteration;
93     case GTK_CSS_DIRECTION_ALTERNATE_REVERSE:
94       d = floor (iteration);
95       if (fmod (d, 2))
96         return 1 + d - iteration;
97       else
98         return iteration - d;
99     default:
100       g_return_val_if_reached (0);
101     }
102 }
103
104 static void
105 gtk_css_animation_set_values (GtkStyleAnimation    *style_animation,
106                               gint64                for_time_us,
107                               GtkCssComputedValues *values)
108 {
109   GtkCssAnimation *animation = GTK_CSS_ANIMATION (style_animation);
110   double iteration, progress;
111   guint i;
112
113   iteration = gtk_css_animation_get_iteration (animation, for_time_us);
114
115   if (!gtk_css_animation_is_executing_at_iteration (animation, iteration))
116     return;
117
118   progress = gtk_css_animation_get_progress_from_iteration (animation, iteration);
119   progress = _gtk_css_ease_value_transform (animation->ease, progress);
120   
121   for (i = 0; i < _gtk_css_keyframes_get_n_properties (animation->keyframes); i++)
122     {
123       GtkCssValue *value;
124       guint property_id;
125       
126       property_id = _gtk_css_keyframes_get_property_id (animation->keyframes, i);
127
128       value = _gtk_css_keyframes_get_value (animation->keyframes,
129                                             i,
130                                             progress,
131                                             _gtk_css_computed_values_get_intrinsic_value (values, i));
132       _gtk_css_computed_values_set_animated_value (values, property_id, value);
133       _gtk_css_value_unref (value);
134     }
135 }
136
137 static gboolean
138 gtk_css_animation_is_finished (GtkStyleAnimation *style_animation,
139                                gint64             at_time_us)
140 {
141   return FALSE;
142 }
143
144 static gboolean
145 gtk_css_animation_is_static (GtkStyleAnimation *style_animation,
146                              gint64             at_time_us)
147 {
148   GtkCssAnimation *animation = GTK_CSS_ANIMATION (style_animation);
149   double iteration;
150
151   if (animation->play_state == GTK_CSS_PLAY_STATE_PAUSED)
152     return TRUE;
153
154   iteration = gtk_css_animation_get_iteration (animation, at_time_us);
155
156   return iteration >= animation->iteration_count;
157 }
158
159 static void
160 gtk_css_animation_finalize (GObject *object)
161 {
162   GtkCssAnimation *animation = GTK_CSS_ANIMATION (object);
163
164   g_free (animation->name);
165   _gtk_css_keyframes_unref (animation->keyframes);
166   _gtk_css_value_unref (animation->ease);
167
168   G_OBJECT_CLASS (_gtk_css_animation_parent_class)->finalize (object);
169 }
170
171 static void
172 _gtk_css_animation_class_init (GtkCssAnimationClass *klass)
173 {
174   GObjectClass *object_class = G_OBJECT_CLASS (klass);
175   GtkStyleAnimationClass *animation_class = GTK_STYLE_ANIMATION_CLASS (klass);
176
177   object_class->finalize = gtk_css_animation_finalize;
178
179   animation_class->set_values = gtk_css_animation_set_values;
180   animation_class->is_finished = gtk_css_animation_is_finished;
181   animation_class->is_static = gtk_css_animation_is_static;
182 }
183
184 static void
185 _gtk_css_animation_init (GtkCssAnimation *animation)
186 {
187 }
188
189 GtkStyleAnimation *
190 _gtk_css_animation_new (const char      *name,
191                         GtkCssKeyframes *keyframes,
192                         gint64           timestamp,
193                         gint64           delay_us,
194                         gint64           duration_us,
195                         GtkCssValue     *ease,
196                         GtkCssDirection  direction,
197                         GtkCssPlayState  play_state,
198                         GtkCssFillMode   fill_mode,
199                         double           iteration_count)
200 {
201   GtkCssAnimation *animation;
202
203   g_return_val_if_fail (name != NULL, NULL);
204   g_return_val_if_fail (keyframes != NULL, NULL);
205   g_return_val_if_fail (ease != NULL, NULL);
206   g_return_val_if_fail (iteration_count >= 0, NULL);
207
208   animation = g_object_new (GTK_TYPE_CSS_ANIMATION, NULL);
209
210   animation->name = g_strdup (name);
211   animation->keyframes = _gtk_css_keyframes_ref (keyframes);
212   if (play_state == GTK_CSS_PLAY_STATE_PAUSED)
213     animation->timestamp = - delay_us;
214   else
215     animation->timestamp = timestamp + delay_us;
216
217   animation->duration = duration_us;
218   animation->ease = _gtk_css_value_ref (ease);
219   animation->direction = direction;
220   animation->play_state = play_state;
221   animation->fill_mode = fill_mode;
222   animation->iteration_count = iteration_count;
223
224   return GTK_STYLE_ANIMATION (animation);
225 }
226
227 const char *
228 _gtk_css_animation_get_name (GtkCssAnimation *animation)
229 {
230   g_return_val_if_fail (GTK_IS_CSS_ANIMATION (animation), NULL);
231
232   return animation->name;
233 }
234
235 GtkStyleAnimation *
236 _gtk_css_animation_copy (GtkCssAnimation *animation,
237                          gint64           at_time_us,
238                          GtkCssPlayState  play_state)
239 {
240   g_return_val_if_fail (GTK_IS_CSS_ANIMATION (animation), NULL);
241
242   if (animation->play_state == play_state)
243     return g_object_ref (animation);
244
245   return _gtk_css_animation_new (animation->name,
246                                  animation->keyframes,
247                                  at_time_us,
248                                  - gtk_css_animation_get_elapsed (animation, at_time_us),
249                                  animation->duration,
250                                  animation->ease,
251                                  animation->direction,
252                                  play_state,
253                                  animation->fill_mode,
254                                  animation->iteration_count);
255 }
256