[StWidget] Support style transitions

It is sometimes desirable to fade smoothly between two styles
instead of changing it abruptly.
Add transitions controlled by the transition-duration CSS property.

https://bugzilla.gnome.org/show_bug.cgi?id=619025
This commit is contained in:
Florian Müllner 2010-05-25 20:07:39 +02:00
parent d4a8c64d22
commit db45c0920b

View File

@ -41,6 +41,7 @@
#include "st-texture-cache.h" #include "st-texture-cache.h"
#include "st-theme-context.h" #include "st-theme-context.h"
#include "st-tooltip.h" #include "st-tooltip.h"
#include "st-theme-node-transition.h"
/* /*
* Forward declaration for sake of StWidgetChild * Forward declaration for sake of StWidgetChild
@ -53,6 +54,8 @@ struct _StWidgetPrivate
gchar *style_class; gchar *style_class;
gchar *inline_style; gchar *inline_style;
StThemeNodeTransition *transition_animation;
gboolean is_stylable : 1; gboolean is_stylable : 1;
gboolean has_tooltip : 1; gboolean has_tooltip : 1;
gboolean is_style_dirty : 1; gboolean is_style_dirty : 1;
@ -236,6 +239,13 @@ st_widget_dispose (GObject *gobject)
priv->theme_node = NULL; priv->theme_node = NULL;
} }
if (priv->transition_animation)
{
g_object_run_dispose (G_OBJECT (priv->transition_animation));
g_object_unref (priv->transition_animation);
priv->transition_animation = NULL;
}
if (priv->tooltip) if (priv->tooltip)
{ {
ClutterContainer *parent; ClutterContainer *parent;
@ -349,12 +359,20 @@ st_widget_paint (ClutterActor *actor)
StWidget *self = ST_WIDGET (actor); StWidget *self = ST_WIDGET (actor);
StThemeNode *theme_node; StThemeNode *theme_node;
ClutterActorBox allocation; ClutterActorBox allocation;
guint8 opacity;
theme_node = st_widget_get_theme_node (self); theme_node = st_widget_get_theme_node (self);
clutter_actor_get_allocation_box (actor, &allocation); clutter_actor_get_allocation_box (actor, &allocation);
st_theme_node_paint (theme_node, &allocation, clutter_actor_get_paint_opacity (actor)); opacity = clutter_actor_get_paint_opacity (actor);
if (self->priv->transition_animation)
st_theme_node_transition_paint (self->priv->transition_animation,
&allocation,
opacity);
else
st_theme_node_paint (theme_node, &allocation, opacity);
} }
static void static void
@ -1185,21 +1203,57 @@ st_widget_init (StWidget *actor)
actor->priv = priv = ST_WIDGET_GET_PRIVATE (actor); actor->priv = priv = ST_WIDGET_GET_PRIVATE (actor);
priv->is_stylable = TRUE; priv->is_stylable = TRUE;
priv->transition_animation = NULL;
/* connect style changed */ /* connect style changed */
g_signal_connect (actor, "notify::name", G_CALLBACK (st_widget_name_notify), NULL); g_signal_connect (actor, "notify::name", G_CALLBACK (st_widget_name_notify), NULL);
} }
static void
on_transition_completed (StThemeNodeTransition *transition,
StWidget *widget)
{
g_object_run_dispose (G_OBJECT (widget->priv->transition_animation));
g_object_unref (widget->priv->transition_animation);
widget->priv->transition_animation = NULL;
}
static void static void
st_widget_recompute_style (StWidget *widget, st_widget_recompute_style (StWidget *widget,
StThemeNode *old_theme_node) StThemeNode *old_theme_node)
{ {
StThemeNode *new_theme_node = st_widget_get_theme_node (widget); StThemeNode *new_theme_node = st_widget_get_theme_node (widget);
int transition_duration;
if (!old_theme_node || if (!old_theme_node ||
!st_theme_node_geometry_equal (old_theme_node, new_theme_node)) !st_theme_node_geometry_equal (old_theme_node, new_theme_node))
clutter_actor_queue_relayout ((ClutterActor *) widget); clutter_actor_queue_relayout ((ClutterActor *) widget);
transition_duration = st_theme_node_get_transition_duration (new_theme_node);
if (transition_duration > 0)
{
if (widget->priv->transition_animation != NULL)
{
st_theme_node_transition_update (widget->priv->transition_animation,
new_theme_node);
}
else if (old_theme_node)
{
widget->priv->transition_animation =
st_theme_node_transition_new (old_theme_node,
new_theme_node,
transition_duration);
g_signal_connect (widget->priv->transition_animation, "completed",
G_CALLBACK (on_transition_completed), widget);
g_signal_connect_swapped (widget->priv->transition_animation,
"new-frame",
G_CALLBACK (clutter_actor_queue_redraw),
widget);
}
}
g_signal_emit (widget, signals[STYLE_CHANGED], 0); g_signal_emit (widget, signals[STYLE_CHANGED], 0);
widget->priv->is_style_dirty = FALSE; widget->priv->is_style_dirty = FALSE;
} }