[gtk/wip/otte/canvas: 26/36] canvas: Add variables to canvasitems




commit e848ead629fa52d47815d09905cbbaa98885ee86
Author: Benjamin Otte <otte redhat com>
Date:   Sun Jul 3 05:30:20 2022 +0200

    canvas: Add variables to canvasitems
    
    This allows referencing the actual allocation as well as the bounds.

 gtk/gtkcanvas.c            | 114 ++++++++++++++++++++++++++++++++-------------
 gtk/gtkcanvasbox.c         |  17 +++++++
 gtk/gtkcanvasbox.h         |   5 ++
 gtk/gtkcanvasboxprivate.h  |   4 ++
 gtk/gtkcanvasitem.c        |  54 ++++++++++++++++++++-
 gtk/gtkcanvasitemprivate.h |   4 ++
 gtk/gtkcanvasvec2.c        |   6 +++
 gtk/gtkcanvasvec2private.h |   6 ++-
 8 files changed, 174 insertions(+), 36 deletions(-)
---
diff --git a/gtk/gtkcanvas.c b/gtk/gtkcanvas.c
index a1aef6f566..33a8a4973d 100644
--- a/gtk/gtkcanvas.c
+++ b/gtk/gtkcanvas.c
@@ -238,54 +238,104 @@ gtk_canvas_allocate (GtkWidget *widget,
                      int        baseline)
 {
   GtkCanvas *self = GTK_CANVAS (widget);
+  gboolean missing, force, success;
   gsize i;
 
   gtk_canvas_validate_variables (self);
 
   gtk_canvas_vec2_init_constant (gtk_canvas_vec2_get_variable (&self->viewport_size), width, height);
 
+  force = FALSE;
+  do
+    {
+      /* Try to allocate items in a loop */
+      success = FALSE;
+      missing = FALSE;
+
+      for (i = 0; i < gtk_canvas_items_get_size (&self->items); i++)
+        {
+          GtkCanvasItem *ci = gtk_canvas_items_get (&self->items, i);
+          GtkWidget *child = gtk_canvas_item_get_widget (ci);
+          const GtkCanvasBox *bounds;
+          float origin_x, origin_y;
+          graphene_rect_t rect;
+          int x, y, w, h;
+
+          if (child == NULL || gtk_canvas_item_has_allocation (ci, NULL))
+            continue;
+
+          bounds = gtk_canvas_item_get_bounds (ci);
+          if (!gtk_canvas_box_eval (bounds, &rect))
+            {
+              if (force)
+                {
+                  rect = *graphene_rect_zero ();
+                  /* XXX: set force to FALSE? */
+                }
+              else
+                {
+                  missing = TRUE;
+                  continue;
+                }
+            }
+
+          if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
+            {
+              gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, &w, NULL, NULL, NULL);
+              w = MAX (w, ceil (rect.size.width));
+              gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL, w, &h, NULL, NULL, NULL);
+              h = MAX (h, ceil (rect.size.height));
+            }
+          else
+            {
+              gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL, -1, &h, NULL, NULL, NULL);
+              h = MAX (h, ceil (rect.size.height));
+              gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, h, &w, NULL, NULL, NULL);
+              w = MAX (w, ceil (rect.size.width));
+            }
+
+          gtk_canvas_box_get_origin (bounds, &origin_x, &origin_y);
+          if (w > rect.size.width)
+            x = round (rect.origin.x + origin_x * (rect.size.width - w));
+          else
+            x = round (rect.origin.x);
+          if (h > rect.size.height)
+            y = round (rect.origin.y + origin_y * (rect.size.height - h));
+          else
+            y = round (rect.origin.y);
+
+          gtk_canvas_item_allocate (ci, &GRAPHENE_RECT_INIT (x, y, w, h));
+          success = TRUE;
+        }
+      if (!success)
+        {
+          /* We didn't allocate a single widget in this loop, do something! */
+          g_warning ("Could not allocate all Canvas items");
+          force = TRUE;
+        }
+    }
+  while (missing);
+  
   for (i = 0; i < gtk_canvas_items_get_size (&self->items); i++)
     {
       GtkCanvasItem *ci = gtk_canvas_items_get (&self->items, i);
       GtkWidget *child = gtk_canvas_item_get_widget (ci);
-      const GtkCanvasBox *bounds;
-      float origin_x, origin_y;
-      graphene_rect_t rect;
-      int x, y, w, h;
+      graphene_rect_t allocation;
 
       if (child == NULL)
         continue;
 
-      bounds = gtk_canvas_item_get_bounds (ci);
-      if (!gtk_canvas_box_eval (bounds, &rect))
-        rect = *graphene_rect_zero ();
-
-      if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
+      if (!gtk_canvas_item_has_allocation (ci, &allocation))
         {
-          gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, &w, NULL, NULL, NULL);
-          w = MAX (w, ceil (rect.size.width));
-          gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL, w, &h, NULL, NULL, NULL);
-          h = MAX (h, ceil (rect.size.height));
+          g_assert_not_reached ();
         }
-      else
-        {
-          gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL, -1, &h, NULL, NULL, NULL);
-          h = MAX (h, ceil (rect.size.height));
-          gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, h, &w, NULL, NULL, NULL);
-          w = MAX (w, ceil (rect.size.width));
-        }
-
-      gtk_canvas_box_get_origin (bounds, &origin_x, &origin_y);
-      if (w > rect.size.width)
-        x = round (rect.origin.x + origin_x * (rect.size.width - w));
-      else
-        x = round (rect.origin.x);
-      if (h > rect.size.height)
-        y = round (rect.origin.y + origin_y * (rect.size.height - h));
-      else
-        y = round (rect.origin.y);
-
-      gtk_widget_size_allocate (child, &(GtkAllocation) { x, y, w, h }, -1);
+      gtk_widget_size_allocate (child,
+                                &(GtkAllocation) {
+                                  allocation.origin.x,
+                                  allocation.origin.y,
+                                  allocation.size.width,
+                                  allocation.size.height
+                                }, -1);
     }
 }
 
diff --git a/gtk/gtkcanvasbox.c b/gtk/gtkcanvasbox.c
index 52dac1f7cc..774be46110 100644
--- a/gtk/gtkcanvasbox.c
+++ b/gtk/gtkcanvasbox.c
@@ -62,6 +62,23 @@ gtk_canvas_box_finish (GtkCanvasBox *self)
   gtk_canvas_vec2_finish (&self->size);
 }
 
+void
+gtk_canvas_box_init_variable (GtkCanvasBox *self)
+{
+  gtk_canvas_vec2_init_variable (&self->point);
+  gtk_canvas_vec2_init_variable (&self->size);
+  graphene_vec2_init (&self->origin, 0, 0);
+}
+
+void
+gtk_canvas_box_update_variable (GtkCanvasBox       *self,
+                                const GtkCanvasBox *other)
+{
+  gtk_canvas_vec2_init_copy (gtk_canvas_vec2_get_variable (&self->point), &other->point);
+  gtk_canvas_vec2_init_copy (gtk_canvas_vec2_get_variable (&self->size), &other->size);
+  graphene_vec2_init_from_vec2 (&self->origin, &other->origin);
+}
+
 /**
  * gtk_canvas_box_new_points:
  * @point1: the first point
diff --git a/gtk/gtkcanvasbox.h b/gtk/gtkcanvasbox.h
index 0fede6dcca..4bbfde583a 100644
--- a/gtk/gtkcanvasbox.h
+++ b/gtk/gtkcanvasbox.h
@@ -62,6 +62,11 @@ GDK_AVAILABLE_IN_ALL
 GtkCanvasBox *          gtk_canvas_box_new_points             (const GtkCanvasPoint     *point1,
                                                                const GtkCanvasPoint     *point2);
 
+GDK_AVAILABLE_IN_ALL
+const GtkCanvasBox *    gtk_canvas_box_get_item_bounds        (GtkCanvasItem            *item);
+GDK_AVAILABLE_IN_ALL
+const GtkCanvasBox *    gtk_canvas_box_get_item_allocation    (GtkCanvasItem            *item);
+
 G_END_DECLS
 
 #endif /* __GTK_BOX_H__ */
diff --git a/gtk/gtkcanvasboxprivate.h b/gtk/gtkcanvasboxprivate.h
index 99e7e7f084..0660f8761f 100644
--- a/gtk/gtkcanvasboxprivate.h
+++ b/gtk/gtkcanvasboxprivate.h
@@ -23,6 +23,10 @@ void                    gtk_canvas_box_init_copy                (GtkCanvasBox
                                                                  const GtkCanvasBox     *source);
 void                    gtk_canvas_box_finish                   (GtkCanvasBox           *self);
 
+void                    gtk_canvas_box_init_variable            (GtkCanvasBox           *self);
+void                    gtk_canvas_box_update_variable          (GtkCanvasBox           *self,
+                                                                 const GtkCanvasBox     *other);
+
 G_END_DECLS
 
 #endif /* __GTK_CANVAS_BOX_PRIVATE_H__ */
diff --git a/gtk/gtkcanvasitem.c b/gtk/gtkcanvasitem.c
index b5def0b8ba..d911c66095 100644
--- a/gtk/gtkcanvasitem.c
+++ b/gtk/gtkcanvasitem.c
@@ -42,6 +42,8 @@ struct _GtkCanvasItem
   gpointer item;
   GtkWidget *widget;
   GtkCanvasBox bounds;
+  GtkCanvasBox bounds_var;
+  GtkCanvasBox allocation_var;
 
   GtkCanvasVec2 size_vecs[4];
 };
@@ -72,8 +74,6 @@ gtk_canvas_item_dispose (GObject *object)
   g_assert (self->item == NULL);
   g_assert (self->widget == NULL);
 
-  gtk_canvas_box_finish (&self->bounds);
-
   G_OBJECT_CLASS (gtk_canvas_item_parent_class)->dispose (object);
 }
 
@@ -86,6 +86,10 @@ gtk_canvas_item_finalize (GObject *object)
   for (i = 0; i < 4; i++)
     gtk_canvas_vec2_finish (&self->size_vecs[i]);
 
+  gtk_canvas_box_finish (&self->bounds);
+  gtk_canvas_box_finish (&self->bounds_var);
+  gtk_canvas_box_finish (&self->allocation_var);
+
   G_OBJECT_CLASS (gtk_canvas_item_parent_class)->finalize (object);
 }
 
@@ -209,6 +213,9 @@ gtk_canvas_item_init (GtkCanvasItem *self)
   gtk_canvas_vec2_init_constant (&self->bounds.point, 0, 0);
   gtk_canvas_vec2_init_copy (&self->bounds.size, &self->size_vecs[GTK_CANVAS_ITEM_MEASURE_NAT_FOR_NAT]);
   graphene_vec2_init (&self->bounds.origin, 0, 0);
+  gtk_canvas_box_init_variable (&self->bounds_var);
+  gtk_canvas_box_update_variable (&self->bounds_var, &self->bounds);
+  gtk_canvas_box_init_variable (&self->allocation_var);
 }
 
 GtkCanvasItem *
@@ -264,6 +271,35 @@ gtk_canvas_item_validate_variables (GtkCanvasItem *self)
           gtk_canvas_vec2_get_variable (&self->size_vecs[i]),
           0, 0);
     }
+
+  gtk_canvas_vec2_init_invalid (
+      gtk_canvas_vec2_get_variable (&self->allocation_var.point));
+  gtk_canvas_vec2_init_invalid (
+      gtk_canvas_vec2_get_variable (&self->allocation_var.size));
+}
+
+void
+gtk_canvas_item_allocate (GtkCanvasItem   *self,
+                          graphene_rect_t *rect)
+{
+  gtk_canvas_vec2_init_constant (
+      gtk_canvas_vec2_get_variable (&self->allocation_var.point),
+      rect->origin.x + graphene_vec2_get_x (&self->bounds.origin) * rect->size.width,
+      rect->origin.y + graphene_vec2_get_y (&self->bounds.origin) * rect->size.height);
+  gtk_canvas_vec2_init_constant (
+      gtk_canvas_vec2_get_variable (&self->allocation_var.size),
+      rect->size.width, rect->size.height);
+  graphene_vec2_init_from_vec2 (&self->allocation_var.origin, &self->bounds.origin);
+}
+
+gboolean
+gtk_canvas_item_has_allocation (GtkCanvasItem   *self,
+                                graphene_rect_t *rect)
+{
+  if (rect == NULL)
+    return !gtk_canvas_vec2_is_invalid (gtk_canvas_vec2_get_variable (&self->allocation_var.point));
+
+  return gtk_canvas_box_eval (&self->allocation_var, rect);
 }
 
 const GtkCanvasVec2 *
@@ -273,6 +309,18 @@ gtk_canvas_item_get_measure_vec2 (GtkCanvasItem            *self,
   return &self->size_vecs[measure];
 }
 
+const GtkCanvasBox *
+gtk_canvas_box_get_item_bounds (GtkCanvasItem *item)
+{
+  return &item->bounds_var;
+}
+
+const GtkCanvasBox *
+gtk_canvas_box_get_item_allocation (GtkCanvasItem *item)
+{
+  return &item->allocation_var;
+}
+
 /**
  * gtk_canvas_item_get_canvas: (attributes org.gtk.Method.get_property=canvas)
  * @self: a `GtkCanvasItem`
@@ -323,6 +371,8 @@ gtk_canvas_item_set_bounds (GtkCanvasItem      *self,
   g_return_if_fail (bounds != NULL);
 
   gtk_canvas_box_init_copy (&self->bounds, bounds);
+  gtk_canvas_box_update_variable (&self->bounds_var, bounds);
+
   if (self->canvas)
     gtk_widget_queue_allocate (GTK_WIDGET (self->canvas));
 
diff --git a/gtk/gtkcanvasitemprivate.h b/gtk/gtkcanvasitemprivate.h
index 49724204ff..d50c68a569 100644
--- a/gtk/gtkcanvasitemprivate.h
+++ b/gtk/gtkcanvasitemprivate.h
@@ -12,6 +12,10 @@ GtkCanvasItem *         gtk_canvas_item_new                      (GtkCanvas
                                                                   gpointer               item);
 
 void                    gtk_canvas_item_validate_variables       (GtkCanvasItem         *self);
+void                    gtk_canvas_item_allocate                 (GtkCanvasItem         *self,
+                                                                  graphene_rect_t       *rect);
+gboolean                gtk_canvas_item_has_allocation           (GtkCanvasItem         *self,
+                                                                  graphene_rect_t       *rect);
 const GtkCanvasVec2 *   gtk_canvas_item_get_measure_vec2         (GtkCanvasItem         *self,
                                                                   GtkCanvasItemMeasurement measure);
 
diff --git a/gtk/gtkcanvasvec2.c b/gtk/gtkcanvasvec2.c
index dfba1b10b0..5965d3ba30 100644
--- a/gtk/gtkcanvasvec2.c
+++ b/gtk/gtkcanvasvec2.c
@@ -77,6 +77,12 @@ gtk_canvas_vec2_init_invalid (GtkCanvasVec2 *vec2)
   vec2->class = &GTK_CANVAS_VEC2_INVALID_CLASS;
 }
 
+gboolean
+gtk_canvas_vec2_is_invalid (GtkCanvasVec2 *vec2)
+{
+  return vec2->class == &GTK_CANVAS_VEC2_INVALID_CLASS;
+}
+
 /* }}} */
 /* {{{ CONSTANT */
 
diff --git a/gtk/gtkcanvasvec2private.h b/gtk/gtkcanvasvec2private.h
index b8ad4875b8..85470356fc 100644
--- a/gtk/gtkcanvasvec2private.h
+++ b/gtk/gtkcanvasvec2private.h
@@ -91,8 +91,10 @@ void                    gtk_canvas_vec2_init_sum                (GtkCanvasVec2
                                                                  const graphene_vec2_t  *scale,
                                                                  ...) G_GNUC_NULL_TERMINATED;
 
-void                    gtk_canvas_vec2_init_variable          (GtkCanvasVec2           *vec2);
-GtkCanvasVec2 *         gtk_canvas_vec2_get_variable           (GtkCanvasVec2           *vec2);
+void                    gtk_canvas_vec2_init_variable           (GtkCanvasVec2          *vec2);
+GtkCanvasVec2 *         gtk_canvas_vec2_get_variable            (GtkCanvasVec2          *vec2);
+
+gboolean                gtk_canvas_vec2_is_invalid              (GtkCanvasVec2          *vec2);
 
 G_END_DECLS
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]