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 #include "gtkprogresstrackerprivate.h"
26
27 #include <math.h>
28
G_DEFINE_TYPE(GtkCssAnimation,_gtk_css_animation,GTK_TYPE_STYLE_ANIMATION)29 G_DEFINE_TYPE (GtkCssAnimation, _gtk_css_animation, GTK_TYPE_STYLE_ANIMATION)
30
31 static gboolean
32 gtk_css_animation_is_executing (GtkCssAnimation *animation)
33 {
34 GtkProgressState state = gtk_progress_tracker_get_state (&animation->tracker);
35
36 switch (animation->fill_mode)
37 {
38 case GTK_CSS_FILL_NONE:
39 return state == GTK_PROGRESS_STATE_DURING;
40 case GTK_CSS_FILL_FORWARDS:
41 return state != GTK_PROGRESS_STATE_BEFORE;
42 case GTK_CSS_FILL_BACKWARDS:
43 return state != GTK_PROGRESS_STATE_AFTER;
44 case GTK_CSS_FILL_BOTH:
45 return TRUE;
46 default:
47 g_return_val_if_reached (FALSE);
48 }
49 }
50
51 static double
gtk_css_animation_get_progress(GtkCssAnimation * animation)52 gtk_css_animation_get_progress (GtkCssAnimation *animation)
53 {
54 gboolean reverse, odd_iteration;
55 gint cycle = gtk_progress_tracker_get_iteration_cycle (&animation->tracker);
56 odd_iteration = cycle % 2 > 0;
57
58 switch (animation->direction)
59 {
60 case GTK_CSS_DIRECTION_NORMAL:
61 reverse = FALSE;
62 break;
63 case GTK_CSS_DIRECTION_REVERSE:
64 reverse = TRUE;
65 break;
66 case GTK_CSS_DIRECTION_ALTERNATE:
67 reverse = odd_iteration;
68 break;
69 case GTK_CSS_DIRECTION_ALTERNATE_REVERSE:
70 reverse = !odd_iteration;
71 break;
72 default:
73 g_return_val_if_reached (0.0);
74 }
75
76 return gtk_progress_tracker_get_progress (&animation->tracker, reverse);
77 }
78
79 GtkStyleAnimation *
gtk_css_animation_advance(GtkStyleAnimation * style_animation,gint64 timestamp)80 gtk_css_animation_advance (GtkStyleAnimation *style_animation,
81 gint64 timestamp)
82 {
83 GtkCssAnimation *animation = GTK_CSS_ANIMATION (style_animation);
84
85 return _gtk_css_animation_advance_with_play_state (animation,
86 timestamp,
87 animation->play_state);
88 }
89
90 static void
gtk_css_animation_apply_values(GtkStyleAnimation * style_animation,GtkCssAnimatedStyle * style)91 gtk_css_animation_apply_values (GtkStyleAnimation *style_animation,
92 GtkCssAnimatedStyle *style)
93 {
94 GtkCssAnimation *animation = GTK_CSS_ANIMATION (style_animation);
95 double progress;
96 guint i;
97
98 if (!gtk_css_animation_is_executing (animation))
99 return;
100
101 progress = gtk_css_animation_get_progress (animation);
102 progress = _gtk_css_ease_value_transform (animation->ease, progress);
103
104 for (i = 0; i < _gtk_css_keyframes_get_n_properties (animation->keyframes); i++)
105 {
106 GtkCssValue *value;
107 guint property_id;
108
109 property_id = _gtk_css_keyframes_get_property_id (animation->keyframes, i);
110
111 value = _gtk_css_keyframes_get_value (animation->keyframes,
112 i,
113 progress,
114 gtk_css_animated_style_get_intrinsic_value (style, property_id));
115 gtk_css_animated_style_set_animated_value (style, property_id, value);
116 _gtk_css_value_unref (value);
117 }
118 }
119
120 static gboolean
gtk_css_animation_is_finished(GtkStyleAnimation * style_animation)121 gtk_css_animation_is_finished (GtkStyleAnimation *style_animation)
122 {
123 return FALSE;
124 }
125
126 static gboolean
gtk_css_animation_is_static(GtkStyleAnimation * style_animation)127 gtk_css_animation_is_static (GtkStyleAnimation *style_animation)
128 {
129 GtkCssAnimation *animation = GTK_CSS_ANIMATION (style_animation);
130
131 if (animation->play_state == GTK_CSS_PLAY_STATE_PAUSED)
132 return TRUE;
133
134 return gtk_progress_tracker_get_state (&animation->tracker) == GTK_PROGRESS_STATE_AFTER;
135 }
136
137 static void
gtk_css_animation_finalize(GObject * object)138 gtk_css_animation_finalize (GObject *object)
139 {
140 GtkCssAnimation *animation = GTK_CSS_ANIMATION (object);
141
142 g_free (animation->name);
143 _gtk_css_keyframes_unref (animation->keyframes);
144 _gtk_css_value_unref (animation->ease);
145
146 G_OBJECT_CLASS (_gtk_css_animation_parent_class)->finalize (object);
147 }
148
149 static void
_gtk_css_animation_class_init(GtkCssAnimationClass * klass)150 _gtk_css_animation_class_init (GtkCssAnimationClass *klass)
151 {
152 GObjectClass *object_class = G_OBJECT_CLASS (klass);
153 GtkStyleAnimationClass *animation_class = GTK_STYLE_ANIMATION_CLASS (klass);
154
155 object_class->finalize = gtk_css_animation_finalize;
156
157 animation_class->advance = gtk_css_animation_advance;
158 animation_class->apply_values = gtk_css_animation_apply_values;
159 animation_class->is_finished = gtk_css_animation_is_finished;
160 animation_class->is_static = gtk_css_animation_is_static;
161 }
162
163 static void
_gtk_css_animation_init(GtkCssAnimation * animation)164 _gtk_css_animation_init (GtkCssAnimation *animation)
165 {
166 }
167
168 GtkStyleAnimation *
_gtk_css_animation_new(const char * name,GtkCssKeyframes * keyframes,gint64 timestamp,gint64 delay_us,gint64 duration_us,GtkCssValue * ease,GtkCssDirection direction,GtkCssPlayState play_state,GtkCssFillMode fill_mode,double iteration_count)169 _gtk_css_animation_new (const char *name,
170 GtkCssKeyframes *keyframes,
171 gint64 timestamp,
172 gint64 delay_us,
173 gint64 duration_us,
174 GtkCssValue *ease,
175 GtkCssDirection direction,
176 GtkCssPlayState play_state,
177 GtkCssFillMode fill_mode,
178 double iteration_count)
179 {
180 GtkCssAnimation *animation;
181
182 g_return_val_if_fail (name != NULL, NULL);
183 g_return_val_if_fail (keyframes != NULL, NULL);
184 g_return_val_if_fail (ease != NULL, NULL);
185 g_return_val_if_fail (iteration_count >= 0, NULL);
186
187 animation = g_object_new (GTK_TYPE_CSS_ANIMATION, NULL);
188
189 animation->name = g_strdup (name);
190 animation->keyframes = _gtk_css_keyframes_ref (keyframes);
191 animation->ease = _gtk_css_value_ref (ease);
192 animation->direction = direction;
193 animation->play_state = play_state;
194 animation->fill_mode = fill_mode;
195
196 gtk_progress_tracker_start (&animation->tracker, duration_us, delay_us, iteration_count);
197 if (animation->play_state == GTK_CSS_PLAY_STATE_PAUSED)
198 gtk_progress_tracker_skip_frame (&animation->tracker, timestamp);
199 else
200 gtk_progress_tracker_advance_frame (&animation->tracker, timestamp);
201
202 return GTK_STYLE_ANIMATION (animation);
203 }
204
205 const char *
_gtk_css_animation_get_name(GtkCssAnimation * animation)206 _gtk_css_animation_get_name (GtkCssAnimation *animation)
207 {
208 g_return_val_if_fail (GTK_IS_CSS_ANIMATION (animation), NULL);
209
210 return animation->name;
211 }
212
213 GtkStyleAnimation *
_gtk_css_animation_advance_with_play_state(GtkCssAnimation * source,gint64 timestamp,GtkCssPlayState play_state)214 _gtk_css_animation_advance_with_play_state (GtkCssAnimation *source,
215 gint64 timestamp,
216 GtkCssPlayState play_state)
217 {
218 GtkCssAnimation *animation;
219
220 g_return_val_if_fail (GTK_IS_CSS_ANIMATION (source), NULL);
221
222 animation = g_object_new (GTK_TYPE_CSS_ANIMATION, NULL);
223
224 animation->name = g_strdup (source->name);
225 animation->keyframes = _gtk_css_keyframes_ref (source->keyframes);
226 animation->ease = _gtk_css_value_ref (source->ease);
227 animation->direction = source->direction;
228 animation->play_state = play_state;
229 animation->fill_mode = source->fill_mode;
230
231 gtk_progress_tracker_init_copy (&source->tracker, &animation->tracker);
232 if (animation->play_state == GTK_CSS_PLAY_STATE_PAUSED)
233 gtk_progress_tracker_skip_frame (&animation->tracker, timestamp);
234 else
235 gtk_progress_tracker_advance_frame (&animation->tracker, timestamp);
236
237 return GTK_STYLE_ANIMATION (animation);
238 }
239