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

source code of gtk/gtk/gtkcssanimation.c