diff options
author | Timm Bäder <mail@baedert.org> | 2018-08-18 07:05:24 +0200 |
---|---|---|
committer | Timm Bäder <mail@baedert.org> | 2019-02-14 06:57:23 +0100 |
commit | 997e4381e14b41cb3d3d356ef25b254e7d932ba8 (patch) | |
tree | 1a26a8b3c15451b5f7c9be76c14140cf9ee8bf31 | |
parent | 13d9848da740e35fa3e66dcfe0b014c44d73f85e (diff) | |
download | gtk+-997e4381e14b41cb3d3d356ef25b254e7d932ba8.tar.gz |
widget: Handle position in transformation matrix
Most unoptimized version so far.
-rw-r--r-- | gtk/gtksizerequest.c | 97 | ||||
-rw-r--r-- | gtk/gtkwidget.c | 320 | ||||
-rw-r--r-- | gtk/gtkwidget.h | 6 | ||||
-rw-r--r-- | gtk/gtkwidgetprivate.h | 7 |
4 files changed, 246 insertions, 184 deletions
diff --git a/gtk/gtksizerequest.c b/gtk/gtksizerequest.c index 197d2413ea..8d3d5e90c8 100644 --- a/gtk/gtksizerequest.c +++ b/gtk/gtksizerequest.c @@ -120,6 +120,103 @@ get_box_padding (GtkCssStyle *style, border->right = get_number (style, GTK_CSS_PROPERTY_PADDING_RIGHT); } +/* translate initial/final into start/end */ +static GtkAlign +effective_align (GtkAlign align, + GtkTextDirection direction) +{ + switch (align) + { + case GTK_ALIGN_START: + return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START; + case GTK_ALIGN_END: + return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END; + case GTK_ALIGN_FILL: + case GTK_ALIGN_CENTER: + case GTK_ALIGN_BASELINE: + default: + return align; + } +} + +static void +adjust_for_align (GtkAlign align, + gint *natural_size, + gint *allocated_pos, + gint *allocated_size) +{ + switch (align) + { + case GTK_ALIGN_BASELINE: + case GTK_ALIGN_FILL: + default: + /* change nothing */ + break; + case GTK_ALIGN_START: + /* keep *allocated_pos where it is */ + *allocated_size = MIN (*allocated_size, *natural_size); + break; + case GTK_ALIGN_END: + if (*allocated_size > *natural_size) + { + *allocated_pos += (*allocated_size - *natural_size); + *allocated_size = *natural_size; + } + break; + case GTK_ALIGN_CENTER: + if (*allocated_size > *natural_size) + { + *allocated_pos += (*allocated_size - *natural_size) / 2; + *allocated_size = MIN (*allocated_size, *natural_size); + } + break; + } +} + +static void +adjust_for_margin(gint start_margin, + gint end_margin, + gint *minimum_size, + gint *natural_size, + gint *allocated_pos, + gint *allocated_size) +{ + *minimum_size -= (start_margin + end_margin); + *natural_size -= (start_margin + end_margin); + *allocated_pos += start_margin; + *allocated_size -= (start_margin + end_margin); +} + +static void +gtk_widget_adjust_size_allocation (GtkWidget *widget, + GtkOrientation orientation, + gint *minimum_size, + gint *natural_size, + gint *allocated_pos, + gint *allocated_size) +{ + GtkWidgetPrivate *priv = widget->priv; + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + adjust_for_margin (priv->margin.left, + priv->margin.right, + minimum_size, natural_size, + allocated_pos, allocated_size); + adjust_for_align (effective_align (priv->halign, _gtk_widget_get_direction (widget)), + natural_size, allocated_pos, allocated_size); + } + else + { + adjust_for_margin (priv->margin.top, + priv->margin.bottom, + minimum_size, natural_size, + allocated_pos, allocated_size); + adjust_for_align (effective_align (priv->valign, GTK_TEXT_DIR_NONE), + natural_size, allocated_pos, allocated_size); + } +} + static void gtk_widget_query_size_for_orientation (GtkWidget *widget, GtkOrientation orientation, diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index e3019b1606..8154cc3b7c 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -4098,22 +4098,110 @@ gtk_widget_size_allocate (GtkWidget *widget, const GtkAllocation *allocation, int baseline) { + graphene_matrix_t transform; + + graphene_matrix_init_translate (&transform, + &GRAPHENE_POINT3D_INIT (allocation->x, allocation->y, 0)); + + gtk_widget_size_allocate_transformed (widget, + allocation->width, + allocation->height, + baseline, + &transform); +} + +/* translate initial/final into start/end */ +static inline GtkAlign +effective_align (GtkAlign align, + GtkTextDirection direction) +{ + switch (align) + { + case GTK_ALIGN_START: + return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START; + case GTK_ALIGN_END: + return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END; + case GTK_ALIGN_FILL: + case GTK_ALIGN_CENTER: + case GTK_ALIGN_BASELINE: + default: + return align; + } +} + +static void +adjust_for_align (GtkAlign align, + GtkOrientation orientation, + graphene_matrix_t *transform, + int nat_size, + int *allocated_size) +{ + switch (align) + { + case GTK_ALIGN_BASELINE: + case GTK_ALIGN_FILL: + default: + /* change nothing */ + break; + case GTK_ALIGN_START: + /* keep *allocated_pos where it is */ + *allocated_size = MIN (*allocated_size, nat_size); + break; + case GTK_ALIGN_END: + if (*allocated_size > nat_size) + { + if (orientation == GTK_ORIENTATION_HORIZONTAL) + graphene_matrix_translate (transform, + &GRAPHENE_POINT3D_INIT (*allocated_size - nat_size, 0, 0)); + else + graphene_matrix_translate (transform, + &GRAPHENE_POINT3D_INIT (0, *allocated_size - nat_size, 0)); + + *allocated_size = nat_size; + } + + break; + case GTK_ALIGN_CENTER: + if (*allocated_size > nat_size) + { + if (orientation == GTK_ORIENTATION_HORIZONTAL) + graphene_matrix_translate (transform, + &GRAPHENE_POINT3D_INIT ((*allocated_size - nat_size) / 2, 0, 0)); + else + graphene_matrix_translate (transform, + &GRAPHENE_POINT3D_INIT (0, (*allocated_size - nat_size) / 2, 0)); + + *allocated_size = MIN (*allocated_size, nat_size); + } + break; + } +} + +void +gtk_widget_size_allocate_transformed (GtkWidget *widget, + int width, + int height, + int baseline, + const graphene_matrix_t *transform) +{ GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + graphene_matrix_t final_transform; GdkRectangle real_allocation; GdkRectangle adjusted_allocation; gboolean alloc_needed; gboolean size_changed; gboolean baseline_changed; - gboolean position_changed; - gint natural_width, natural_height, dummy = 0; - gint min_width, min_height; + gboolean transform_changed; + int min_width, min_height; + int nat_width, nat_height; GtkCssStyle *style; GtkBorder margin, border, padding; GdkDisplay *display; g_return_if_fail (GTK_IS_WIDGET (widget)); g_return_if_fail (baseline >= -1); - g_return_if_fail (allocation != NULL); + g_return_if_fail (width >= 0); + g_return_if_fail (height >= 0); gtk_widget_push_verify_invariants (widget); @@ -4134,37 +4222,16 @@ gtk_widget_size_allocate (GtkWidget *widget, "How does the code know the size to allocate?", gtk_widget_get_name (widget), widget); } - - if (GTK_DISPLAY_DEBUG_CHECK (display, GEOMETRY)) - { - gint depth; - GtkWidget *parent; - const gchar *name; - - depth = 0; - parent = widget; - while (parent) - { - depth++; - parent = _gtk_widget_get_parent (parent); - } - - name = g_type_name (G_OBJECT_TYPE (G_OBJECT (widget))); - g_message ("gtk_widget_size_allocate: %*s%s %d %d %d %d, baseline %d", - 2 * depth, " ", name, - allocation->x, allocation->y, - allocation->width, allocation->height, - baseline); - } #endif /* G_ENABLE_DEBUG */ alloc_needed = priv->alloc_needed; /* Preserve request/allocate ordering */ priv->alloc_needed = FALSE; - real_allocation = *allocation; + real_allocation = (GtkAllocation) {0, 0, width, height}; - priv->allocated_size = *allocation; + priv->allocated_transform = *transform; + priv->allocated_size = real_allocation; priv->allocated_size_baseline = baseline; adjusted_allocation = real_allocation; @@ -4175,9 +4242,9 @@ gtk_widget_size_allocate (GtkWidget *widget, * when aligning implicitly. */ gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1, - &min_width, &natural_width, NULL, NULL); + &min_width, &nat_width, NULL, NULL); gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, real_allocation.width, - &min_height, &natural_height, NULL, NULL); + &min_height, &nat_height, NULL, NULL); } else { @@ -4186,9 +4253,9 @@ gtk_widget_size_allocate (GtkWidget *widget, * when aligning implicitly. */ gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, -1, - &min_height, &natural_height, NULL, NULL); + &min_height, &nat_height, NULL, NULL); gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, real_allocation.height, - &min_width, &natural_width, NULL, NULL); + &min_width, &nat_width, NULL, NULL); } #ifdef G_ENABLE_CONSISTENCY_CHECKS @@ -4201,40 +4268,33 @@ gtk_widget_size_allocate (GtkWidget *widget, real_allocation.width, real_allocation.height, min_width, min_height); #endif - /* Now that we have the right natural height and width, go ahead and remove any margins from the - * allocated sizes and possibly limit them to the natural sizes */ - gtk_widget_adjust_size_allocation (widget, - GTK_ORIENTATION_HORIZONTAL, - &dummy, - &natural_width, - &adjusted_allocation.x, - &adjusted_allocation.width); - gtk_widget_adjust_size_allocation (widget, - GTK_ORIENTATION_VERTICAL, - &dummy, - &natural_height, - &adjusted_allocation.y, - &adjusted_allocation.height); + + final_transform = *transform; + /* Remove widget margins from the allocated size */ + graphene_matrix_translate (&final_transform, + &GRAPHENE_POINT3D_INIT (priv->margin.left, + priv->margin.top, 0)); + adjusted_allocation.width -= priv->margin.left + priv->margin.right; + adjusted_allocation.height -= priv->margin.top + priv->margin.bottom; + + nat_width -= priv->margin.left + priv->margin.right; + nat_height -= priv->margin.top + priv->margin.bottom; + + adjust_for_align (effective_align (priv->halign, _gtk_widget_get_direction (widget)), + GTK_ORIENTATION_HORIZONTAL, + &final_transform, + nat_width, + &adjusted_allocation.width); + adjust_for_align (effective_align (priv->valign, GTK_TEXT_DIR_NONE), + GTK_ORIENTATION_VERTICAL, + &final_transform, + nat_height, + &adjusted_allocation.height); + if (baseline >= 0) baseline -= priv->margin.top; - if (adjusted_allocation.x < real_allocation.x || - adjusted_allocation.y < real_allocation.y || - (adjusted_allocation.x + adjusted_allocation.width) > - (real_allocation.x + real_allocation.width) || - (adjusted_allocation.y + adjusted_allocation.height > - real_allocation.y + real_allocation.height)) - { - g_warning ("%s %p attempted to adjust its size allocation from %d,%d %dx%d to %d,%d %dx%d. adjust_size_allocation must keep allocation inside original bounds", - G_OBJECT_TYPE_NAME (widget), widget, - real_allocation.x, real_allocation.y, real_allocation.width, real_allocation.height, - adjusted_allocation.x, adjusted_allocation.y, adjusted_allocation.width, adjusted_allocation.height); - } - else - { - real_allocation = adjusted_allocation; - } - + real_allocation = adjusted_allocation; if (real_allocation.width < 0 || real_allocation.height < 0) { g_warning ("gtk_widget_size_allocate(): attempt to allocate %s %s %p with width %d and height %d", @@ -4255,12 +4315,14 @@ gtk_widget_size_allocate (GtkWidget *widget, baseline_changed = priv->allocated_baseline != baseline; size_changed = (priv->allocation.width != real_allocation.width || priv->allocation.height != real_allocation.height); - position_changed = (priv->allocation.x != real_allocation.x || - priv->allocation.y != real_allocation.y); + transform_changed = memcmp (&final_transform, + &priv->transform, + sizeof (graphene_matrix_t)) != 0; /* Set the widget allocation to real_allocation now, pass the smaller allocation to the vfunc */ priv->allocation = real_allocation; priv->allocated_baseline = baseline; + priv->transform = final_transform; if (!alloc_needed && !size_changed && !baseline_changed) { @@ -4325,7 +4387,7 @@ gtk_widget_size_allocate (GtkWidget *widget, check_clip: if (size_changed || baseline_changed) gtk_widget_queue_draw (widget); - else if (position_changed && priv->parent) + else if (transform_changed && priv->parent) gtk_widget_queue_draw (priv->parent); out: @@ -4587,103 +4649,6 @@ gtk_widget_real_size_allocate (GtkWidget *widget, } } -/* translate initial/final into start/end */ -static GtkAlign -effective_align (GtkAlign align, - GtkTextDirection direction) -{ - switch (align) - { - case GTK_ALIGN_START: - return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START; - case GTK_ALIGN_END: - return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END; - case GTK_ALIGN_FILL: - case GTK_ALIGN_CENTER: - case GTK_ALIGN_BASELINE: - default: - return align; - } -} - -static void -adjust_for_align (GtkAlign align, - gint *natural_size, - gint *allocated_pos, - gint *allocated_size) -{ - switch (align) - { - case GTK_ALIGN_BASELINE: - case GTK_ALIGN_FILL: - default: - /* change nothing */ - break; - case GTK_ALIGN_START: - /* keep *allocated_pos where it is */ - *allocated_size = MIN (*allocated_size, *natural_size); - break; - case GTK_ALIGN_END: - if (*allocated_size > *natural_size) - { - *allocated_pos += (*allocated_size - *natural_size); - *allocated_size = *natural_size; - } - break; - case GTK_ALIGN_CENTER: - if (*allocated_size > *natural_size) - { - *allocated_pos += (*allocated_size - *natural_size) / 2; - *allocated_size = MIN (*allocated_size, *natural_size); - } - break; - } -} - -static void -adjust_for_margin(gint start_margin, - gint end_margin, - gint *minimum_size, - gint *natural_size, - gint *allocated_pos, - gint *allocated_size) -{ - *minimum_size -= (start_margin + end_margin); - *natural_size -= (start_margin + end_margin); - *allocated_pos += start_margin; - *allocated_size -= (start_margin + end_margin); -} - -void -gtk_widget_adjust_size_allocation (GtkWidget *widget, - GtkOrientation orientation, - gint *minimum_size, - gint *natural_size, - gint *allocated_pos, - gint *allocated_size) -{ - GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - { - adjust_for_margin (priv->margin.left, - priv->margin.right, - minimum_size, natural_size, - allocated_pos, allocated_size); - adjust_for_align (effective_align (priv->halign, _gtk_widget_get_direction (widget)), - natural_size, allocated_pos, allocated_size); - } - else - { - adjust_for_margin (priv->margin.top, - priv->margin.bottom, - minimum_size, natural_size, - allocated_pos, allocated_size); - adjust_for_align (effective_align (priv->valign, GTK_TEXT_DIR_NONE), - natural_size, allocated_pos, allocated_size); - } -} - static gboolean gtk_widget_real_can_activate_accel (GtkWidget *widget, guint signal_id) @@ -11164,7 +11129,12 @@ gtk_widget_get_allocated_size (GtkWidget *widget, g_return_if_fail (GTK_IS_WIDGET (widget)); g_return_if_fail (allocation != NULL); - *allocation = priv->allocated_size; + *allocation = (GtkAllocation) { + (int)graphene_matrix_get_value (&priv->allocated_transform, 3, 0), + (int)graphene_matrix_get_value (&priv->allocated_transform, 3, 1), + priv->allocated_size.width, + priv->allocated_size.height + }; if (baseline) *baseline = priv->allocated_size_baseline; @@ -11198,7 +11168,12 @@ gtk_widget_get_allocation (GtkWidget *widget, g_return_if_fail (GTK_IS_WIDGET (widget)); g_return_if_fail (allocation != NULL); - *allocation = priv->allocation; + *allocation = (GtkAllocation) { + (int)graphene_matrix_get_value (&priv->transform, 0, 3), + (int)graphene_matrix_get_value (&priv->transform, 1, 3), + priv->allocation.width, + priv->allocation.height + }; } /** @@ -13143,7 +13118,6 @@ gtk_widget_create_render_node (GtkWidget *widget, { GtkWidgetClass *klass = GTK_WIDGET_GET_CLASS (widget); GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); - const gboolean needs_transform = !graphene_matrix_is_identity (&priv->transform); GtkCssValue *filter_value; double opacity; GtkCssStyle *style; @@ -13163,9 +13137,6 @@ gtk_widget_create_render_node (GtkWidget *widget, G_OBJECT_TYPE_NAME (widget), widget, allocation.width, allocation.height); - if (needs_transform) - gtk_snapshot_push_transform (snapshot, &priv->transform); - filter_value = _gtk_style_context_peek_property (_gtk_widget_get_style_context (widget), GTK_CSS_PROPERTY_FILTER); gtk_css_filter_value_push_snapshot (filter_value, snapshot); @@ -13225,9 +13196,6 @@ gtk_widget_create_render_node (GtkWidget *widget, gtk_widget_maybe_add_debug_render_nodes (widget, snapshot); #endif - if (needs_transform) - gtk_snapshot_pop (snapshot); - gtk_snapshot_pop (snapshot); /* Debug */ return gtk_snapshot_free_to_node (snapshot); @@ -13601,17 +13569,13 @@ gtk_widget_snapshot_child (GtkWidget *widget, GtkSnapshot *snapshot) { GtkWidgetPrivate *priv = gtk_widget_get_instance_private (child); - int x, y; g_return_if_fail (_gtk_widget_get_parent (child) == widget); g_return_if_fail (snapshot != NULL); - x = priv->allocation.x; - y = priv->allocation.y; - - gtk_snapshot_offset (snapshot, x, y); + gtk_snapshot_push_transform (snapshot, &priv->transform); gtk_widget_snapshot (child, snapshot); - gtk_snapshot_offset (snapshot, -x, -y); + gtk_snapshot_pop (snapshot); } /** diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 0b4a53f011..29f4ed8a1e 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -406,6 +406,12 @@ GDK_AVAILABLE_IN_ALL void gtk_widget_size_allocate (GtkWidget *widget, const GtkAllocation *allocation, int baseline); +GDK_AVAILABLE_IN_ALL +void gtk_widget_size_allocate_transformed (GtkWidget *widget, + int width, + int height, + int baseline, + const graphene_matrix_t *transform); GDK_AVAILABLE_IN_ALL GtkSizeRequestMode gtk_widget_get_request_mode (GtkWidget *widget); diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index 68091224a7..fca15f566d 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -144,6 +144,7 @@ struct _GtkWidgetPrivate GtkAllocation allocation; gint allocated_baseline; + graphene_matrix_t allocated_transform; graphene_matrix_t transform; /* The widget's requested sizes */ @@ -294,12 +295,6 @@ void gtk_widget_adjust_size_request (GtkWidget *widg GtkOrientation orientation, gint *minimum_size, gint *natural_size); -void gtk_widget_adjust_size_allocation (GtkWidget *widget, - GtkOrientation orientation, - gint *minimum_size, - gint *natural_size, - gint *allocated_pos, - gint *allocated_size); void gtk_widget_adjust_baseline_request (GtkWidget *widget, gint *minimum_baseline, gint *natural_baseline); |