forked from AuroraMiddleware/gtk
stack: Implement snapshot()
This uses the new push()/pop() mechanism to its fullest extent when implementing transitions. It's fun to inspect the results in the inspector. Crossfades don't work yet, they continue using a Cairo fallback. A side effect of the stack conversion is that widget-factory now uses snapshots for a lot more things.
This commit is contained in:
parent
1137483d15
commit
b0175421f2
153
gtk/gtkstack.c
153
gtk/gtkstack.c
@ -145,7 +145,7 @@ typedef struct {
|
||||
guint transition_duration;
|
||||
|
||||
GtkStackChildInfo *last_visible_child;
|
||||
cairo_surface_t *last_visible_surface;
|
||||
GskRenderNode *last_visible_node;
|
||||
GtkAllocation last_visible_surface_allocation;
|
||||
guint tick_id;
|
||||
GtkProgressTracker tracker;
|
||||
@ -176,8 +176,8 @@ static void gtk_stack_compute_expand (GtkWidget *widget,
|
||||
gboolean *vexpand);
|
||||
static void gtk_stack_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation);
|
||||
static gboolean gtk_stack_draw (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
static void gtk_stack_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot);
|
||||
static void gtk_stack_measure_ (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
@ -220,8 +220,7 @@ gtk_stack_finalize (GObject *obj)
|
||||
|
||||
gtk_stack_unschedule_ticks (stack);
|
||||
|
||||
if (priv->last_visible_surface != NULL)
|
||||
cairo_surface_destroy (priv->last_visible_surface);
|
||||
g_clear_pointer (&priv->last_visible_node, gsk_render_node_unref);
|
||||
|
||||
g_clear_object (&priv->gadget);
|
||||
|
||||
@ -408,7 +407,7 @@ gtk_stack_class_init (GtkStackClass *klass)
|
||||
object_class->finalize = gtk_stack_finalize;
|
||||
|
||||
widget_class->size_allocate = gtk_stack_size_allocate;
|
||||
widget_class->draw = gtk_stack_draw;
|
||||
widget_class->snapshot = gtk_stack_snapshot;
|
||||
widget_class->realize = gtk_stack_realize;
|
||||
widget_class->unrealize = gtk_stack_unrealize;
|
||||
widget_class->map = gtk_stack_map;
|
||||
@ -874,11 +873,7 @@ gtk_stack_progress_updated (GtkStack *stack)
|
||||
|
||||
if (gtk_progress_tracker_get_state (&priv->tracker) == GTK_PROGRESS_STATE_AFTER)
|
||||
{
|
||||
if (priv->last_visible_surface != NULL)
|
||||
{
|
||||
cairo_surface_destroy (priv->last_visible_surface);
|
||||
priv->last_visible_surface = NULL;
|
||||
}
|
||||
g_clear_pointer (&priv->last_visible_node, gsk_render_node_unref);
|
||||
|
||||
if (priv->last_visible_child != NULL)
|
||||
{
|
||||
@ -1065,9 +1060,7 @@ set_visible_child (GtkStack *stack,
|
||||
gtk_widget_set_child_visible (priv->last_visible_child->widget, FALSE);
|
||||
priv->last_visible_child = NULL;
|
||||
|
||||
if (priv->last_visible_surface != NULL)
|
||||
cairo_surface_destroy (priv->last_visible_surface);
|
||||
priv->last_visible_surface = NULL;
|
||||
g_clear_pointer (&priv->last_visible_node, gsk_render_node_unref);
|
||||
|
||||
if (priv->visible_child && priv->visible_child->widget)
|
||||
{
|
||||
@ -1877,6 +1870,7 @@ gtk_stack_forall (GtkContainer *container,
|
||||
}
|
||||
}
|
||||
|
||||
#include <gsk/gskrendernodeprivate.h>
|
||||
static void
|
||||
gtk_stack_compute_expand (GtkWidget *widget,
|
||||
gboolean *hexpand_p,
|
||||
@ -1913,43 +1907,48 @@ gtk_stack_compute_expand (GtkWidget *widget,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_stack_draw_crossfade (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
gtk_stack_snapshot_crossfade (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GtkStack *stack = GTK_STACK (widget);
|
||||
GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
|
||||
gdouble progress = gtk_progress_tracker_get_progress (&priv->tracker, FALSE);
|
||||
cairo_t *cr;
|
||||
|
||||
cr = gtk_snapshot_append_cairo_node (snapshot,
|
||||
&GRAPHENE_RECT_INIT(
|
||||
0, 0,
|
||||
gtk_widget_get_allocated_width (widget),
|
||||
gtk_widget_get_allocated_height (widget)
|
||||
),
|
||||
"GtkStackCrossfade");
|
||||
|
||||
cairo_push_group (cr);
|
||||
gtk_container_propagate_draw (GTK_CONTAINER (stack),
|
||||
priv->visible_child->widget,
|
||||
cr);
|
||||
cairo_save (cr);
|
||||
|
||||
/* Multiply alpha by progress */
|
||||
cairo_set_source_rgba (cr, 1, 1, 1, progress);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN);
|
||||
cairo_paint (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
|
||||
if (priv->last_visible_surface)
|
||||
if (priv->last_visible_node)
|
||||
{
|
||||
cairo_set_source_surface (cr, priv->last_visible_surface,
|
||||
priv->last_visible_surface_allocation.x,
|
||||
priv->last_visible_surface_allocation.y);
|
||||
cairo_push_group (cr);
|
||||
cairo_translate (cr, priv->last_visible_surface_allocation.x, priv->last_visible_surface_allocation.y);
|
||||
gsk_render_node_draw (priv->last_visible_node, cr);
|
||||
cairo_pop_group_to_source (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
|
||||
cairo_paint_with_alpha (cr, MAX (1.0 - progress, 0));
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
|
||||
cairo_pop_group_to_source (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_stack_draw_under (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
gtk_stack_snapshot_under (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GtkStack *stack = GTK_STACK (widget);
|
||||
GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
|
||||
@ -1988,33 +1987,39 @@ gtk_stack_draw_under (GtkWidget *widget,
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_rectangle (cr, x, y, width, height);
|
||||
cairo_clip (cr);
|
||||
gtk_snapshot_push_clip (snapshot,
|
||||
&GRAPHENE_RECT_INIT(x, y, width, height),
|
||||
"StackUnder");
|
||||
|
||||
gtk_container_propagate_draw (GTK_CONTAINER (stack),
|
||||
gtk_container_snapshot_child (GTK_CONTAINER (stack),
|
||||
priv->visible_child->widget,
|
||||
cr);
|
||||
snapshot);
|
||||
|
||||
cairo_restore (cr);
|
||||
gtk_snapshot_pop_and_append (snapshot);
|
||||
|
||||
if (priv->last_visible_surface)
|
||||
if (priv->last_visible_node)
|
||||
{
|
||||
cairo_set_source_surface (cr, priv->last_visible_surface, pos_x, pos_y);
|
||||
cairo_paint (cr);
|
||||
graphene_matrix_t matrix;
|
||||
|
||||
graphene_matrix_init_translate (&matrix, &GRAPHENE_POINT3D_INIT (pos_x, pos_y, 0));
|
||||
|
||||
gtk_snapshot_push_transform (snapshot, &matrix, "StackUnder");
|
||||
gtk_snapshot_append_node (snapshot, priv->last_visible_node);
|
||||
gtk_snapshot_pop_and_append (snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_stack_draw_slide (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
gtk_stack_snapshot_slide (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GtkStack *stack = GTK_STACK (widget);
|
||||
GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
|
||||
|
||||
if (priv->last_visible_surface)
|
||||
if (priv->last_visible_node)
|
||||
{
|
||||
GtkAllocation allocation;
|
||||
graphene_matrix_t matrix;
|
||||
int x, y;
|
||||
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
@ -2052,39 +2057,36 @@ gtk_stack_draw_slide (GtkWidget *widget,
|
||||
x += priv->last_visible_surface_allocation.x;
|
||||
y += priv->last_visible_surface_allocation.y;
|
||||
|
||||
|
||||
if (gtk_widget_get_valign (priv->last_visible_child->widget) == GTK_ALIGN_END &&
|
||||
priv->last_visible_widget_height > allocation.height)
|
||||
y -= priv->last_visible_widget_height - allocation.height;
|
||||
else if (gtk_widget_get_valign (priv->last_visible_child->widget) == GTK_ALIGN_CENTER)
|
||||
y -= (priv->last_visible_widget_height - allocation.height) / 2;
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_set_source_surface (cr, priv->last_visible_surface, x, y);
|
||||
cairo_paint (cr);
|
||||
cairo_restore (cr);
|
||||
graphene_matrix_init_translate (&matrix, &GRAPHENE_POINT3D_INIT (x, y, 0));
|
||||
gtk_snapshot_push_transform (snapshot, &matrix, "StackSlide");
|
||||
gtk_snapshot_append_node (snapshot, priv->last_visible_node);
|
||||
gtk_snapshot_pop_and_append (snapshot);
|
||||
}
|
||||
|
||||
gtk_container_propagate_draw (GTK_CONTAINER (stack),
|
||||
gtk_container_snapshot_child (GTK_CONTAINER (stack),
|
||||
priv->visible_child->widget,
|
||||
cr);
|
||||
snapshot);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_stack_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static void
|
||||
gtk_stack_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GtkStack *stack = GTK_STACK (widget);
|
||||
GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
|
||||
|
||||
gtk_css_gadget_draw (priv->gadget, cr);
|
||||
|
||||
return FALSE;
|
||||
gtk_css_gadget_snapshot (priv->gadget, snapshot);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_stack_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
GtkSnapshot *snapshot,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
@ -2094,40 +2096,33 @@ gtk_stack_render (GtkCssGadget *gadget,
|
||||
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
|
||||
GtkStack *stack = GTK_STACK (widget);
|
||||
GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
|
||||
cairo_t *pattern_cr;
|
||||
|
||||
if (priv->visible_child)
|
||||
{
|
||||
if (gtk_progress_tracker_get_state (&priv->tracker) != GTK_PROGRESS_STATE_AFTER)
|
||||
{
|
||||
if (priv->last_visible_surface == NULL &&
|
||||
if (priv->last_visible_node == NULL &&
|
||||
priv->last_visible_child != NULL)
|
||||
{
|
||||
gtk_widget_get_allocation (priv->last_visible_child->widget,
|
||||
&priv->last_visible_surface_allocation);
|
||||
priv->last_visible_surface =
|
||||
gdk_window_create_similar_surface (gtk_widget_get_window (widget),
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
priv->last_visible_surface_allocation.width,
|
||||
priv->last_visible_surface_allocation.height);
|
||||
pattern_cr = cairo_create (priv->last_visible_surface);
|
||||
/* We don't use propagate_draw here, because we don't want to apply
|
||||
* the bin_window offset
|
||||
*/
|
||||
gtk_widget_draw (priv->last_visible_child->widget, pattern_cr);
|
||||
cairo_destroy (pattern_cr);
|
||||
gtk_snapshot_push (snapshot, FALSE, "StackCaptureLastVisibleChild");
|
||||
gtk_widget_snapshot (priv->last_visible_child->widget, snapshot);
|
||||
priv->last_visible_node = gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
|
||||
cairo_rectangle (cr,
|
||||
gtk_snapshot_push_clip (snapshot,
|
||||
&GRAPHENE_RECT_INIT(
|
||||
0, 0,
|
||||
gtk_widget_get_allocated_width (widget),
|
||||
gtk_widget_get_allocated_height (widget));
|
||||
cairo_clip (cr);
|
||||
gtk_widget_get_allocated_height (widget)
|
||||
),
|
||||
"StackAnimationClip");
|
||||
|
||||
switch (priv->active_transition_type)
|
||||
{
|
||||
case GTK_STACK_TRANSITION_TYPE_CROSSFADE:
|
||||
gtk_stack_draw_crossfade (widget, cr);
|
||||
gtk_stack_snapshot_crossfade (widget, snapshot);
|
||||
break;
|
||||
case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT:
|
||||
case GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT:
|
||||
@ -2137,23 +2132,24 @@ gtk_stack_render (GtkCssGadget *gadget,
|
||||
case GTK_STACK_TRANSITION_TYPE_OVER_DOWN:
|
||||
case GTK_STACK_TRANSITION_TYPE_OVER_LEFT:
|
||||
case GTK_STACK_TRANSITION_TYPE_OVER_RIGHT:
|
||||
gtk_stack_draw_slide (widget, cr);
|
||||
gtk_stack_snapshot_slide (widget, snapshot);
|
||||
break;
|
||||
case GTK_STACK_TRANSITION_TYPE_UNDER_UP:
|
||||
case GTK_STACK_TRANSITION_TYPE_UNDER_DOWN:
|
||||
case GTK_STACK_TRANSITION_TYPE_UNDER_LEFT:
|
||||
case GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT:
|
||||
gtk_stack_draw_under (widget, cr);
|
||||
gtk_stack_snapshot_under (widget, snapshot);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
gtk_snapshot_pop_and_append (snapshot);
|
||||
}
|
||||
else
|
||||
gtk_container_propagate_draw (GTK_CONTAINER (stack),
|
||||
gtk_container_snapshot_child (GTK_CONTAINER (stack),
|
||||
priv->visible_child->widget,
|
||||
cr);
|
||||
snapshot);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
@ -2226,8 +2222,7 @@ gtk_stack_allocate (GtkCssGadget *gadget,
|
||||
if (!gdk_rectangle_equal (&priv->last_visible_surface_allocation,
|
||||
&child_allocation))
|
||||
{
|
||||
cairo_surface_destroy (priv->last_visible_surface);
|
||||
priv->last_visible_surface = NULL;
|
||||
g_clear_pointer (&priv->last_visible_node, gsk_render_node_unref);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2364,8 +2359,8 @@ gtk_stack_init (GtkStack *stack)
|
||||
GTK_WIDGET (stack),
|
||||
gtk_stack_measure,
|
||||
gtk_stack_allocate,
|
||||
gtk_stack_render,
|
||||
NULL,
|
||||
gtk_stack_render,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user