From 5d8e439bc597159e3c9f0a8b65c0ae869dead3a8 Mon Sep 17 00:00:00 2001 From: Matthew Fennell Date: Sat, 27 Dec 2025 12:40:20 +0000 Subject: Import Upstream version 43.0 --- src/animation/gtd-property-transition.c | 359 ++++++++++++++++++++++++++++++++ 1 file changed, 359 insertions(+) create mode 100644 src/animation/gtd-property-transition.c (limited to 'src/animation/gtd-property-transition.c') diff --git a/src/animation/gtd-property-transition.c b/src/animation/gtd-property-transition.c new file mode 100644 index 0000000..f0ceb88 --- /dev/null +++ b/src/animation/gtd-property-transition.c @@ -0,0 +1,359 @@ +/* gtd-property-transition.c + * + * Copyright 2020 Georges Basile Stavracas Neto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + + +/** + * SECTION:gtd-property-transition + * @Title: GtdPropertyTransition + * @Short_Description: Property transitions + * + * #GtdPropertyTransition is a specialized #GtdTransition that + * can be used to tween a property of a #GtdAnimatable instance. + */ + +#include "gtd-property-transition.h" + +#include "gtd-animatable.h" +#include "gtd-debug.h" +#include "gtd-interval.h" +#include "gtd-transition.h" + +typedef struct +{ + gchar *property_name; + + GParamSpec *pspec; +} GtdPropertyTransitionPrivate; + +enum +{ + PROP_0, + PROP_PROPERTY_NAME, + PROP_LAST, +}; + +static GParamSpec *obj_props[PROP_LAST] = { NULL, }; + +G_DEFINE_TYPE_WITH_PRIVATE (GtdPropertyTransition, gtd_property_transition, GTD_TYPE_TRANSITION) + +static inline void +gtd_property_transition_ensure_interval (GtdPropertyTransition *self, + GtdAnimatable *animatable, + GtdInterval *interval) +{ + GtdPropertyTransitionPrivate *priv = gtd_property_transition_get_instance_private (self); + GValue *value_p; + + if (gtd_interval_is_valid (interval)) + return; + + /* if no initial value has been set, use the current value */ + value_p = gtd_interval_peek_initial_value (interval); + if (!G_IS_VALUE (value_p)) + { + g_value_init (value_p, gtd_interval_get_value_type (interval)); + gtd_animatable_get_initial_state (animatable, + priv->property_name, + value_p); + } + + /* if no final value has been set, use the current value */ + value_p = gtd_interval_peek_final_value (interval); + if (!G_IS_VALUE (value_p)) + { + g_value_init (value_p, gtd_interval_get_value_type (interval)); + gtd_animatable_get_initial_state (animatable, + priv->property_name, + value_p); + } +} + +static void +gtd_property_transition_attached (GtdTransition *transition, + GtdAnimatable *animatable) +{ + GtdPropertyTransition *self = GTD_PROPERTY_TRANSITION (transition); + GtdPropertyTransitionPrivate *priv = gtd_property_transition_get_instance_private (self); + GtdInterval *interval; + + if (priv->property_name == NULL) + return; + + priv->pspec = + gtd_animatable_find_property (animatable, priv->property_name); + + if (priv->pspec == NULL) + return; + + interval = gtd_transition_get_interval (transition); + if (interval == NULL) + return; + + gtd_property_transition_ensure_interval (self, animatable, interval); +} + +static void +gtd_property_transition_detached (GtdTransition *transition, + GtdAnimatable *animatable) +{ + GtdPropertyTransition *self = GTD_PROPERTY_TRANSITION (transition); + GtdPropertyTransitionPrivate *priv = gtd_property_transition_get_instance_private (self); + + priv->pspec = NULL; +} + +static void +gtd_property_transition_compute_value (GtdTransition *transition, + GtdAnimatable *animatable, + GtdInterval *interval, + gdouble progress) +{ + GtdPropertyTransition *self = GTD_PROPERTY_TRANSITION (transition); + GtdPropertyTransitionPrivate *priv = gtd_property_transition_get_instance_private (self); + GValue value = G_VALUE_INIT; + GType p_type, i_type; + gboolean res; + + /* if we have a GParamSpec we also have an animatable instance */ + if (priv->pspec == NULL) + return; + + gtd_property_transition_ensure_interval (self, animatable, interval); + + p_type = G_PARAM_SPEC_VALUE_TYPE (priv->pspec); + i_type = gtd_interval_get_value_type (interval); + + g_value_init (&value, i_type); + + res = gtd_animatable_interpolate_value (animatable, + priv->property_name, + interval, + progress, + &value); + + if (res) + { + if (i_type != p_type || g_type_is_a (i_type, p_type)) + { + if (g_value_type_transformable (i_type, p_type)) + { + GValue transform = G_VALUE_INIT; + + g_value_init (&transform, p_type); + + if (g_value_transform (&value, &transform)) + { + gtd_animatable_set_final_state (animatable, + priv->property_name, + &transform); + } + else + g_warning ("%s: Unable to convert a value of type '%s' from " + "the value type '%s' of the interval.", + G_STRLOC, + g_type_name (p_type), + g_type_name (i_type)); + + g_value_unset (&transform); + } + } + else + gtd_animatable_set_final_state (animatable, + priv->property_name, + &value); + } + + g_value_unset (&value); +} + +static void +gtd_property_transition_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtdPropertyTransition *self = GTD_PROPERTY_TRANSITION (gobject); + + switch (prop_id) + { + case PROP_PROPERTY_NAME: + gtd_property_transition_set_property_name (self, g_value_get_string (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + } +} + +static void +gtd_property_transition_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtdPropertyTransition *self = GTD_PROPERTY_TRANSITION (gobject); + GtdPropertyTransitionPrivate *priv = gtd_property_transition_get_instance_private (self); + + switch (prop_id) + { + case PROP_PROPERTY_NAME: + g_value_set_string (value, priv->property_name); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + } +} + +static void +gtd_property_transition_finalize (GObject *gobject) +{ + GtdPropertyTransition *self = GTD_PROPERTY_TRANSITION (gobject); + GtdPropertyTransitionPrivate *priv = gtd_property_transition_get_instance_private (self); + + g_free (priv->property_name); + + G_OBJECT_CLASS (gtd_property_transition_parent_class)->finalize (gobject); +} + +static void +gtd_property_transition_class_init (GtdPropertyTransitionClass *klass) +{ + GtdTransitionClass *transition_class = GTD_TRANSITION_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + transition_class->attached = gtd_property_transition_attached; + transition_class->detached = gtd_property_transition_detached; + transition_class->compute_value = gtd_property_transition_compute_value; + + gobject_class->set_property = gtd_property_transition_set_property; + gobject_class->get_property = gtd_property_transition_get_property; + gobject_class->finalize = gtd_property_transition_finalize; + + /** + * GtdPropertyTransition:property-name: + * + * The name of the property of a #GtdAnimatable to animate. + */ + obj_props[PROP_PROPERTY_NAME] = + g_param_spec_string ("property-name", + "Property Name", + "The name of the property to animate", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); +} + +static void +gtd_property_transition_init (GtdPropertyTransition *self) +{ +} + +/** + * gtd_property_transition_new_for_actor: + * @actor: a #GtdActor + * @property_name: (allow-none): a property of @animatable, or %NULL + * + * Creates a new #GtdPropertyTransition. + * + * Return value: (transfer full): the newly created #GtdPropertyTransition. + * Use g_object_unref() when done + */ +GtdTransition * +gtd_property_transition_new_for_actor (GtdWidget *widget, + const char *property_name) +{ + return g_object_new (GTD_TYPE_PROPERTY_TRANSITION, + "widget", widget, + "property-name", property_name, + NULL); +} + +/** + * gtd_property_transition_new: + * @property_name: (allow-none): a property of @animatable, or %NULL + * + * Creates a new #GtdPropertyTransition. + * + * Return value: (transfer full): the newly created #GtdPropertyTransition. + * Use g_object_unref() when done + */ +GtdTransition * +gtd_property_transition_new (const char *property_name) +{ + return g_object_new (GTD_TYPE_PROPERTY_TRANSITION, + "property-name", property_name, + NULL); +} + +/** + * gtd_property_transition_set_property_name: + * @transition: a #GtdPropertyTransition + * @property_name: (allow-none): a property name + * + * Sets the #GtdPropertyTransition:property-name property of @transition. + */ +void +gtd_property_transition_set_property_name (GtdPropertyTransition *self, + const gchar *property_name) +{ + GtdPropertyTransitionPrivate *priv; + GtdAnimatable *animatable; + + g_return_if_fail (GTD_IS_PROPERTY_TRANSITION (self)); + + priv = gtd_property_transition_get_instance_private (self); + + if (g_strcmp0 (priv->property_name, property_name) == 0) + return; + + g_free (priv->property_name); + priv->property_name = g_strdup (property_name); + priv->pspec = NULL; + + animatable = gtd_transition_get_animatable (GTD_TRANSITION (self)); + if (animatable) + priv->pspec = gtd_animatable_find_property (animatable, priv->property_name); + + g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PROPERTY_NAME]); +} + +/** + * gtd_property_transition_get_property_name: + * @transition: a #GtdPropertyTransition + * + * Retrieves the value of the #GtdPropertyTransition:property-name + * property. + * + * Return value: the name of the property being animated, or %NULL if + * none is set. The returned string is owned by the @transition and + * it should not be freed. + */ +const char * +gtd_property_transition_get_property_name (GtdPropertyTransition *self) +{ + GtdPropertyTransitionPrivate *priv; + + g_return_val_if_fail (GTD_IS_PROPERTY_TRANSITION (self), NULL); + + priv = gtd_property_transition_get_instance_private (self); + return priv->property_name; +} -- cgit v1.2.3