/* * Copyright © 2012 Red Hat Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: Benjamin Otte */ #include "config.h" #include "gtkcssanimationprivate.h" #include "gtkcsseasevalueprivate.h" #include "gtkprogresstrackerprivate.h" #include static gboolean gtk_css_animation_is_executing (GtkCssAnimation *animation) { GtkProgressState state = gtk_progress_tracker_get_state (&animation->tracker); switch (animation->fill_mode) { case GTK_CSS_FILL_NONE: return state == GTK_PROGRESS_STATE_DURING; case GTK_CSS_FILL_FORWARDS: return state != GTK_PROGRESS_STATE_BEFORE; case GTK_CSS_FILL_BACKWARDS: return state != GTK_PROGRESS_STATE_AFTER; case GTK_CSS_FILL_BOTH: return TRUE; default: g_return_val_if_reached (FALSE); } } static double gtk_css_animation_get_progress (GtkCssAnimation *animation) { gboolean reverse, odd_iteration; int cycle = gtk_progress_tracker_get_iteration_cycle (&animation->tracker); odd_iteration = cycle % 2 > 0; switch (animation->direction) { case GTK_CSS_DIRECTION_NORMAL: reverse = FALSE; break; case GTK_CSS_DIRECTION_REVERSE: reverse = TRUE; break; case GTK_CSS_DIRECTION_ALTERNATE: reverse = odd_iteration; break; case GTK_CSS_DIRECTION_ALTERNATE_REVERSE: reverse = !odd_iteration; break; default: g_return_val_if_reached (0.0); } return gtk_progress_tracker_get_progress (&animation->tracker, reverse); } static GtkStyleAnimation * gtk_css_animation_advance (GtkStyleAnimation *style_animation, gint64 timestamp) { GtkCssAnimation *animation = (GtkCssAnimation *)style_animation; return _gtk_css_animation_advance_with_play_state (animation, timestamp, animation->play_state); } static void gtk_css_animation_apply_values (GtkStyleAnimation *style_animation, GtkCssAnimatedStyle *style) { GtkCssAnimation *animation = (GtkCssAnimation *)style_animation; double progress; guint i; if (!gtk_css_animation_is_executing (animation)) return; progress = gtk_css_animation_get_progress (animation); progress = _gtk_css_ease_value_transform (animation->ease, progress); for (i = 0; i < _gtk_css_keyframes_get_n_properties (animation->keyframes); i++) { GtkCssValue *value; guint property_id; property_id = _gtk_css_keyframes_get_property_id (animation->keyframes, i); value = _gtk_css_keyframes_get_value (animation->keyframes, i, progress, gtk_css_animated_style_get_intrinsic_value (style, property_id)); gtk_css_animated_style_set_animated_value (style, property_id, value); } } static gboolean gtk_css_animation_is_finished (GtkStyleAnimation *style_animation) { return FALSE; } static gboolean gtk_css_animation_is_static (GtkStyleAnimation *style_animation) { GtkCssAnimation *animation = (GtkCssAnimation *)style_animation; if (animation->play_state == GTK_CSS_PLAY_STATE_PAUSED) return TRUE; return gtk_progress_tracker_get_state (&animation->tracker) == GTK_PROGRESS_STATE_AFTER; } static void gtk_css_animation_free (GtkStyleAnimation *animation) { GtkCssAnimation *self = (GtkCssAnimation *)animation; g_free (self->name); _gtk_css_keyframes_unref (self->keyframes); _gtk_css_value_unref (self->ease); g_free (self); } static const GtkStyleAnimationClass GTK_CSS_ANIMATION_CLASS = { "GtkCssAnimation", gtk_css_animation_free, gtk_css_animation_is_finished, gtk_css_animation_is_static, gtk_css_animation_apply_values, gtk_css_animation_advance, }; 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) { GtkCssAnimation *animation; g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (keyframes != NULL, NULL); g_return_val_if_fail (ease != NULL, NULL); g_return_val_if_fail (iteration_count >= 0, NULL); animation = g_new (GtkCssAnimation, 1); animation->parent.class = >K_CSS_ANIMATION_CLASS; animation->parent.ref_count = 1; animation->name = g_strdup (name); animation->keyframes = _gtk_css_keyframes_ref (keyframes); animation->ease = _gtk_css_value_ref (ease); animation->direction = direction; animation->play_state = play_state; animation->fill_mode = fill_mode; gtk_progress_tracker_start (&animation->tracker, duration_us, delay_us, iteration_count); if (animation->play_state == GTK_CSS_PLAY_STATE_PAUSED) gtk_progress_tracker_skip_frame (&animation->tracker, timestamp); else gtk_progress_tracker_advance_frame (&animation->tracker, timestamp); return (GtkStyleAnimation *)animation; } const char * _gtk_css_animation_get_name (GtkCssAnimation *animation) { return animation->name; } GtkStyleAnimation * _gtk_css_animation_advance_with_play_state (GtkCssAnimation *source, gint64 timestamp, GtkCssPlayState play_state) { GtkCssAnimation *animation = g_new (GtkCssAnimation, 1); animation->parent.class = >K_CSS_ANIMATION_CLASS; animation->parent.ref_count = 1; animation->name = g_strdup (source->name); animation->keyframes = _gtk_css_keyframes_ref (source->keyframes); animation->ease = _gtk_css_value_ref (source->ease); animation->direction = source->direction; animation->play_state = play_state; animation->fill_mode = source->fill_mode; gtk_progress_tracker_init_copy (&source->tracker, &animation->tracker); if (animation->play_state == GTK_CSS_PLAY_STATE_PAUSED) gtk_progress_tracker_skip_frame (&animation->tracker, timestamp); else gtk_progress_tracker_advance_frame (&animation->tracker, timestamp); return (GtkStyleAnimation *)animation; } gboolean _gtk_css_animation_is_animation (GtkStyleAnimation *animation) { return animation->class == >K_CSS_ANIMATION_CLASS; }