From dbf0654e5b52e1cfd983cd8382185adb5feff095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Sun, 17 Feb 2019 08:47:09 +0100 Subject: [PATCH] widget: Add gtk_widget_compute_transform --- docs/reference/gtk/gtk4-sections.txt | 1 + gtk/gtkwidget.c | 128 ++++++++++++++++++--------- gtk/gtkwidget.h | 4 + 3 files changed, 90 insertions(+), 43 deletions(-) diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 9ddc0c6c96..b6785ed0c5 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -4541,6 +4541,7 @@ gtk_widget_get_allocated_size gtk_widget_get_width gtk_widget_get_height gtk_widget_compute_bounds +gtk_widget_compute_transform gtk_widget_contains gtk_widget_pick gtk_widget_get_can_default diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 0ba379e23a..42e43a28f6 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -820,11 +820,11 @@ gtk_widget_real_pick (GtkWidget *widget, child = _gtk_widget_get_prev_sibling (child)) { GtkWidget *picked; - int dx, dy; + double dx, dy; - gtk_widget_get_origin_relative_to_parent (child, &dx, &dy); + gtk_widget_translate_coordinatesf (widget, child, x, y, &dx, &dy); - picked = gtk_widget_pick (child, x - dx, y - dy); + picked = gtk_widget_pick (child, dx, dy); if (picked) return picked; } @@ -4507,54 +4507,31 @@ gtk_widget_translate_coordinatesf (GtkWidget *src_widget, double *dest_x, double *dest_y) { - GtkWidget *ancestor; - GtkWidget *parent; + graphene_matrix_t transform; + graphene_point_t p; g_return_val_if_fail (GTK_IS_WIDGET (src_widget), FALSE); g_return_val_if_fail (GTK_IS_WIDGET (dest_widget), FALSE); - ancestor = gtk_widget_common_ancestor (src_widget, dest_widget); - if (!ancestor) + if (!gtk_widget_compute_transform (src_widget, dest_widget, &transform)) { if (dest_x) *dest_x = 0; + if (dest_y) *dest_y = 0; + return FALSE; } - - parent = src_widget; - while (parent != ancestor) - { - int origin_x, origin_y; - - gtk_widget_get_origin_relative_to_parent (parent, &origin_x, &origin_y); - - src_x += origin_x; - src_y += origin_y; - - parent = _gtk_widget_get_parent (parent); - } - - parent = dest_widget; - while (parent != ancestor) - { - int origin_x, origin_y; - - gtk_widget_get_origin_relative_to_parent (parent, &origin_x, &origin_y); - - src_x -= origin_x; - src_y -= origin_y; - - parent = _gtk_widget_get_parent (parent); - } + graphene_point_init (&p, src_x, src_y); + graphene_matrix_transform_point (&transform, &p, &p); if (dest_x) - *dest_x = src_x; + *dest_x = p.x; if (dest_y) - *dest_y = src_y; + *dest_y = p.y; return TRUE; } @@ -11300,6 +11277,74 @@ gtk_widget_pick (GtkWidget *widget, return GTK_WIDGET_GET_CLASS (widget)->pick (widget, x, y); } +/** + * gtk_widget_compute_transform: + * @widget: a #GtkWidget + * @target: the target widget that the matrix will transform to + * @out_transform: (out caller-allocates): location to + * store the final transformation + * + * Computes a matrix suitable to describe a transformation from + * @widget's coordinate system into @target's coordinate system. + * + * Returns: %TRUE if the transform could be computed, %FALSE otherwise. + * The transform can not be computed in certain cases, for example when + * @widget and @target do not share a common ancestor. + */ +gboolean +gtk_widget_compute_transform (GtkWidget *widget, + GtkWidget *target, + graphene_matrix_t *out_transform) +{ + GtkWidget *parent; + GtkWidget *ancestor; + graphene_matrix_t transform; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (GTK_IS_WIDGET (target), FALSE); + g_return_val_if_fail (out_transform != NULL, FALSE); + + ancestor = gtk_widget_common_ancestor (widget, target); + + if (!ancestor) + return FALSE; + + graphene_matrix_init_identity (&transform); + parent = widget; + while (parent != ancestor) + { + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (parent); + + graphene_matrix_multiply (&transform, &priv->transform, &transform); + + parent = priv->parent; + } + + g_assert (parent == ancestor); + + { + graphene_matrix_t down_transform; + graphene_matrix_t inv; + + graphene_matrix_init_identity (&down_transform); + + while (parent != ancestor) + { + graphene_matrix_multiply (&down_transform, &parent->priv->transform, &down_transform); + parent = parent->priv->parent; + } + + graphene_matrix_inverse (&down_transform, &inv); + + graphene_matrix_multiply (&transform, &inv, &transform); + } + + + *out_transform = transform; + + return TRUE; +} + /** * gtk_widget_compute_bounds: * @widget: the #GtkWidget to query @@ -11323,26 +11368,23 @@ gtk_widget_compute_bounds (GtkWidget *widget, GtkWidget *target, graphene_rect_t *out_bounds) { + graphene_matrix_t transform; GtkCssBoxes boxes; - int x, y; g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); g_return_val_if_fail (GTK_IS_WIDGET (target), FALSE); g_return_val_if_fail (out_bounds != NULL, FALSE); - if (!gtk_widget_translate_coordinates (widget, - target, - 0, 0, - &x, &y)) + if (!gtk_widget_compute_transform (widget, target, &transform)) { graphene_rect_init_from_rect (out_bounds, graphene_rect_zero ()); return FALSE; } gtk_css_boxes_init (&boxes, widget); - graphene_rect_offset_r (gtk_css_boxes_get_border_rect (&boxes), - x, y, - out_bounds); + graphene_matrix_transform_bounds (&transform, + gtk_css_boxes_get_border_rect (&boxes), + out_bounds); return TRUE; } diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index e912b6e612..f62049a894 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -614,6 +614,10 @@ GDK_AVAILABLE_IN_ALL void gtk_widget_get_allocation (GtkWidget *widget, GtkAllocation *allocation); GDK_AVAILABLE_IN_ALL +gboolean gtk_widget_compute_transform (GtkWidget *widget, + GtkWidget *target, + graphene_matrix_t *out_transform); +GDK_AVAILABLE_IN_ALL gboolean gtk_widget_compute_bounds (GtkWidget *widget, GtkWidget *target, graphene_rect_t *out_bounds);