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 | |
29 | static gboolean |
30 | gtk_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 | |
49 | static double |
50 | gtk_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 | |
77 | static GtkStyleAnimation * |
78 | gtk_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 | |
88 | static void |
89 | gtk_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 | |
117 | static gboolean |
118 | gtk_css_animation_is_finished (GtkStyleAnimation *style_animation) |
119 | { |
120 | return FALSE; |
121 | } |
122 | |
123 | static gboolean |
124 | gtk_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 | |
134 | static void |
135 | gtk_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 | |
146 | static 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 | |
156 | GtkStyleAnimation * |
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 = >K_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 | |
195 | const char * |
196 | _gtk_css_animation_get_name (GtkCssAnimation *animation) |
197 | { |
198 | return animation->name; |
199 | } |
200 | |
201 | GtkStyleAnimation * |
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 = >K_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 | |
226 | gboolean |
227 | _gtk_css_animation_is_animation (GtkStyleAnimation *animation) |
228 | { |
229 | return animation->class == >K_CSS_ANIMATION_CLASS; |
230 | } |
231 | |