]> Pileus Git - ~andy/gtk/commitdiff
Fixed problems with combination of height-for-width apis and
authorTristan Van Berkom <tristan.van.berkom@gmail.com>
Fri, 22 Oct 2010 15:04:46 +0000 (00:04 +0900)
committerTristan Van Berkom <tristan.van.berkom@gmail.com>
Fri, 22 Oct 2010 15:11:37 +0000 (00:11 +0900)
alignment/margin vfuncs adjust_size_request/allocation

Now get_height_for_width() will internally update the for_width
before passing it to the real height_for_width() vfunc, allowing
margins and extra space for alignments to be stripped, thus requesting
sufficient height for greater than natural widths (and also accounting
for margins properly). Test case adjusted in testadjustsize to ensure
proper behavior.

gtk/gtkcontainer.c
gtk/gtksizerequest.c
gtk/gtkwidget.c
gtk/gtkwidget.h
tests/testadjustsize.c

index 0cfedfb793a1693c467bee7071aeed169ca1e404..5b2d3baa30ecd3ab705d75ba17125f8abeb3f357 100644 (file)
@@ -323,11 +323,13 @@ static void     gtk_container_map                  (GtkWidget         *widget);
 static void     gtk_container_unmap                (GtkWidget         *widget);
 static void     gtk_container_adjust_size_request  (GtkWidget         *widget,
                                                     GtkOrientation     orientation,
-                                                    gint               for_size,
                                                     gint              *minimum_size,
                                                     gint              *natural_size);
 static void     gtk_container_adjust_size_allocation (GtkWidget       *widget,
-                                                      GtkAllocation   *allocation);
+                                                      GtkOrientation   orientation,
+                                                      gint            *natural_size,
+                                                      gint            *allocated_pos,
+                                                      gint            *allocated_size);
 
 static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
                                                          GtkWidget    *child);
@@ -1776,7 +1778,6 @@ gtk_container_resize_children (GtkContainer *container)
 static void
 gtk_container_adjust_size_request (GtkWidget         *widget,
                                    GtkOrientation     orientation,
-                                   gint               for_size,
                                    gint              *minimum_size,
                                    gint              *natural_size)
 {
@@ -1797,28 +1798,33 @@ gtk_container_adjust_size_request (GtkWidget         *widget,
   /* chain up last so gtk_widget_set_size_request() values
    * will have a chance to overwrite our border width.
    */
-  parent_class->adjust_size_request (widget, orientation, for_size,
+  parent_class->adjust_size_request (widget, orientation, 
                                      minimum_size, natural_size);
 }
 
 static void
 gtk_container_adjust_size_allocation (GtkWidget         *widget,
-                                      GtkAllocation     *allocation)
+                                      GtkOrientation     orientation,
+                                      gint              *natural_size,
+                                      gint              *allocated_pos,
+                                      gint              *allocated_size)
 {
   GtkContainer *container;
   int border_width;
 
   container = GTK_CONTAINER (widget);
 
-  parent_class->adjust_size_allocation (widget, allocation);
-
   if (!GTK_CONTAINER_GET_CLASS (widget)->handle_border_width)
-    return;
+    {
+      parent_class->adjust_size_allocation (widget, orientation,
+                                           natural_size, allocated_pos,
+                                           allocated_size);
+      return;
+    }
 
   border_width = container->priv->border_width;
 
-  allocation->width -= border_width * 2;
-  allocation->height -= border_width * 2;
+  *allocated_size -= border_width * 2;
 
   /* If we get a pathological too-small allocation to hold
    * even the border width, leave all allocation to the actual
@@ -1828,23 +1834,26 @@ gtk_container_adjust_size_allocation (GtkWidget         *widget,
    * As long as we have space, set x,y properly.
    */
 
-  if (allocation->width < 1)
+  if (*allocated_size < 1)
     {
-      allocation->width += border_width * 2;
+      *allocated_size += border_width * 2;
     }
   else
     {
-      allocation->x += border_width;
+      *allocated_pos += border_width;
+      *natural_size -= border_width * 2;
     }
 
-  if (allocation->height < 1)
-    {
-      allocation->height += border_width * 2;
-    }
-  else
-    {
-      allocation->y += border_width;
-    }
+  /* Chain up to GtkWidgetClass *after* removing our border width from
+   * the proposed allocation size. This is because it's possible that the
+   * widget was allocated more space than it needs in a said orientation,
+   * if GtkWidgetClass does any alignments and thus limits the size to the 
+   * natural size... then we need that to be done *after* removing any margins 
+   * and padding values.
+   */
+  parent_class->adjust_size_allocation (widget, orientation,
+                                       natural_size, allocated_pos,
+                                       allocated_size);
 }
 
 /**
index 55979f41b5b4753f77b9d80a6f53d35d4be18efd..da91d0c13c5dd7d1c03754dd0fae0bebdfea4196 100644 (file)
@@ -226,20 +226,56 @@ compute_size_for_orientation (GtkWidget         *request,
           requisition_size = requisition.width;
 
           if (for_size < 0)
-            GTK_WIDGET_GET_CLASS (request)->get_preferred_width (request, &min_size, &nat_size);
+            {
+              GTK_WIDGET_GET_CLASS (request)->get_preferred_width (request, &min_size, &nat_size);
+            }
           else
-            GTK_WIDGET_GET_CLASS (request)->get_preferred_width_for_height (request, for_size, 
-                                                                                  &min_size, &nat_size);
+            {
+              int ignored_position = 0;
+              int natural_height;
+
+             /* Pull the base natural height from the cache as it's needed to adjust 
+              * the proposed 'for_size' */
+             gtk_widget_get_preferred_height (widget, NULL, &natural_height);
+
+              /* convert for_size to unadjusted height (for_size is a proposed allocation) */
+              GTK_WIDGET_GET_CLASS (request)->adjust_size_allocation (widget,
+                                                                      GTK_ORIENTATION_VERTICAL,
+                                                                      &natural_height,
+                                                                      &ignored_position,
+                                                                      &for_size);
+
+              GTK_WIDGET_GET_CLASS (request)->get_preferred_width_for_height (request, for_size,
+                                                                              &min_size, &nat_size);
+            }
         }
       else
         {
           requisition_size = requisition.height;
 
           if (for_size < 0)
-            GTK_WIDGET_GET_CLASS (request)->get_preferred_height (request, &min_size, &nat_size);
+            {
+              GTK_WIDGET_GET_CLASS (request)->get_preferred_height (request, &min_size, &nat_size);
+            }
           else
-            GTK_WIDGET_GET_CLASS (request)->get_preferred_height_for_width (request, for_size, 
-                                                                                  &min_size, &nat_size);
+            {
+              int ignored_position = 0;
+              int natural_width;
+
+             /* Pull the base natural width from the cache as it's needed to adjust 
+              * the proposed 'for_size' */
+             gtk_widget_get_preferred_width (widget, NULL, &natural_width);
+
+              /* convert for_size to unadjusted width (for_size is a proposed allocation) */
+              GTK_WIDGET_GET_CLASS (request)->adjust_size_allocation (widget,
+                                                                      GTK_ORIENTATION_HORIZONTAL,
+                                                                      &natural_width,
+                                                                      &ignored_position,
+                                                                      &for_size);
+
+              GTK_WIDGET_GET_CLASS (request)->get_preferred_height_for_width (request, for_size,
+                                                                              &min_size, &nat_size);
+            }
         }
       pop_recursion_check (request, orientation);
 
@@ -270,7 +306,6 @@ compute_size_for_orientation (GtkWidget         *request,
                                                            orientation == GTK_SIZE_GROUP_HORIZONTAL ?
                                                            GTK_ORIENTATION_HORIZONTAL :
                                                            GTK_ORIENTATION_VERTICAL,
-                                                           cached_size->for_size,
                                                            &adjusted_min,
                                                            &adjusted_natural);
 
index 6d7faf8abc0845754d001f4daf1d836532a3719b..43f8c377badfee9decba252b35de896215e911ea 100644 (file)
@@ -685,11 +685,13 @@ static void             gtk_widget_queue_tooltip_query          (GtkWidget *widg
 
 static void             gtk_widget_real_adjust_size_request     (GtkWidget         *widget,
                                                                  GtkOrientation     orientation,
-                                                                 gint               for_size,
                                                                  gint              *minimum_size,
                                                                  gint              *natural_size);
 static void             gtk_widget_real_adjust_size_allocation  (GtkWidget         *widget,
-                                                                 GtkAllocation     *allocation);
+                                                                 GtkOrientation     orientation,
+                                                                 gint              *natural_size,
+                                                                 gint              *allocated_pos,
+                                                                 gint              *allocated_size);
 
 static void gtk_widget_set_usize_internal (GtkWidget          *widget,
                                           gint                width,
@@ -4609,6 +4611,8 @@ gtk_widget_size_allocate (GtkWidget       *widget,
   gboolean alloc_needed;
   gboolean size_changed;
   gboolean position_changed;
+  gint natural_width, natural_height;
+  gint min_width, min_height;
 
   priv = widget->priv;
 
@@ -4645,7 +4649,37 @@ gtk_widget_size_allocate (GtkWidget      *widget,
   real_allocation = *allocation;
 
   adjusted_allocation = real_allocation;
-  GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget, &adjusted_allocation);
+  if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
+    {
+      /* Go ahead and request the height for allocated width, note that the internals
+       * of get_height_for_width will internally limit the for_size to natural size
+       * when aligning implicitly.
+       */
+      gtk_widget_get_preferred_width (widget, &min_width, &natural_width);
+      gtk_widget_get_preferred_height_for_width (widget, real_allocation.width, NULL, &natural_height);
+    }
+  else
+    {
+      /* Go ahead and request the width for allocated height, note that the internals
+       * of get_width_for_height will internally limit the for_size to natural size
+       * when aligning implicitly.
+       */
+      gtk_widget_get_preferred_height (widget, &min_height, &natural_height);
+      gtk_widget_get_preferred_width_for_height (widget, real_allocation.height, NULL, &natural_width);
+    }
+
+  /* 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_GET_CLASS (widget)->adjust_size_allocation (widget,
+                                                        GTK_ORIENTATION_HORIZONTAL,
+                                                        &natural_width,
+                                                        &adjusted_allocation.x,
+                                                        &adjusted_allocation.width);
+  GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget,
+                                                        GTK_ORIENTATION_VERTICAL,
+                                                        &natural_height,
+                                                        &adjusted_allocation.y,
+                                                        &adjusted_allocation.height);
 
   if (adjusted_allocation.x < real_allocation.x ||
       adjusted_allocation.y < real_allocation.y ||
@@ -4920,140 +4954,76 @@ gtk_widget_real_size_allocate (GtkWidget     *widget,
 }
 
 static void
-get_span_inside_border (GtkWidget              *widget,
-                        GtkAlign                align,
-                        int                     start_pad,
-                        int                     end_pad,
-                        int                     allocated_outside_size,
-                        int                     natural_inside_size,
-                        int                    *coord_inside_p,
-                        int                    *size_inside_p)
+adjust_for_align(GtkAlign           align,
+                 gint              *natural_size,
+                 gint              *allocated_pos,
+                 gint              *allocated_size)
 {
-  int inside_allocated;
-  int content_size;
-  int coord, size;
-
-  inside_allocated = allocated_outside_size - start_pad - end_pad;
-
-  content_size = natural_inside_size;
-  if (content_size > inside_allocated)
-    {
-      /* didn't get full natural size */
-      content_size = inside_allocated;
-    }
-
-  coord = size = 0; /* silence compiler */
   switch (align)
     {
     case GTK_ALIGN_FILL:
-      coord = start_pad;
-      size = inside_allocated;
+      /* change nothing */
       break;
     case GTK_ALIGN_START:
-      coord = start_pad;
-      size = content_size;
+      /* keep *allocated_pos where it is */
+      *allocated_size = MIN (*allocated_size, *natural_size);
       break;
     case GTK_ALIGN_END:
-      coord = allocated_outside_size - end_pad - content_size;
-      size = content_size;
+      if (*allocated_size > *natural_size)
+       {
+         *allocated_pos += (*allocated_size - *natural_size);
+         *allocated_size = *natural_size;
+       }
       break;
     case GTK_ALIGN_CENTER:
-      coord = start_pad + (inside_allocated - content_size) / 2;
-      size = content_size;
+      if (*allocated_size > *natural_size)
+       {
+         *allocated_pos += (*allocated_size - *natural_size) / 2;
+         *allocated_size = MIN (*allocated_size, *natural_size);
+       }
       break;
     }
-
-  if (coord_inside_p)
-    *coord_inside_p = coord;
-
-  if (size_inside_p)
-    *size_inside_p = size;
-}
-
-static void
-get_span_inside_border_horizontal (GtkWidget              *widget,
-                                   const GtkWidgetAuxInfo *aux_info,
-                                   int                     allocated_outside_width,
-                                   int                     natural_inside_width,
-                                   int                    *x_inside_p,
-                                   int                    *width_inside_p)
-{
-  get_span_inside_border (widget,
-                          aux_info->halign,
-                          aux_info->margin.left,
-                          aux_info->margin.right,
-                          allocated_outside_width,
-                          natural_inside_width,
-                          x_inside_p,
-                          width_inside_p);
 }
 
 static void
-get_span_inside_border_vertical (GtkWidget              *widget,
-                                 const GtkWidgetAuxInfo *aux_info,
-                                 int                     allocated_outside_height,
-                                 int                     natural_inside_height,
-                                 int                    *y_inside_p,
-                                 int                    *height_inside_p)
-{
-  get_span_inside_border (widget,
-                          aux_info->valign,
-                          aux_info->margin.top,
-                          aux_info->margin.bottom,
-                          allocated_outside_height,
-                          natural_inside_height,
-                          y_inside_p,
-                          height_inside_p);
+adjust_for_margin(gint               start_margin,
+                  gint               end_margin,
+                  gint              *natural_size,
+                  gint              *allocated_pos,
+                  gint              *allocated_size)
+{
+  *natural_size -= (start_margin + end_margin);
+  *allocated_pos += start_margin;
+  *allocated_size -= (start_margin + end_margin);
 }
 
 static void
 gtk_widget_real_adjust_size_allocation (GtkWidget         *widget,
-                                        GtkAllocation     *allocation)
+                                        GtkOrientation     orientation,
+                                        gint              *natural_size,
+                                        gint              *allocated_pos,
+                                        gint              *allocated_size)
 {
   const GtkWidgetAuxInfo *aux_info;
-  gint natural_width;
-  gint natural_height;
-  int x, y, w, h;
 
   aux_info = _gtk_widget_get_aux_info_or_defaults (widget);
 
-  if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
     {
-      gtk_widget_get_preferred_width (widget, NULL, &natural_width);
-      get_span_inside_border_horizontal (widget,
-                                        aux_info,
-                                        allocation->width,
-                                        natural_width,
-                                        &x, &w);
-
-      gtk_widget_get_preferred_height_for_width (widget, w, NULL, &natural_height);
-      get_span_inside_border_vertical (widget,
-                                      aux_info,
-                                      allocation->height,
-                                      natural_height,
-                                      &y, &h);
+      adjust_for_margin (aux_info->margin.left,
+                         aux_info->margin.right,
+                         natural_size, allocated_pos, allocated_size);
+      adjust_for_align (aux_info->halign,
+                        natural_size, allocated_pos, allocated_size);
     }
-  else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT */
+  else
     {
-      gtk_widget_get_preferred_height (widget, NULL, &natural_height);
-      get_span_inside_border_vertical (widget,
-                                      aux_info,
-                                      allocation->height,
-                                      natural_height,
-                                      &y, &h);
-
-      gtk_widget_get_preferred_width_for_height (widget, h, NULL, &natural_width);
-      get_span_inside_border_horizontal (widget,
-                                        aux_info,
-                                        allocation->width,
-                                        natural_width,
-                                        &x, &w);
+      adjust_for_margin (aux_info->margin.top,
+                         aux_info->margin.bottom,
+                         natural_size, allocated_pos, allocated_size);
+      adjust_for_align (aux_info->valign,
+                        natural_size, allocated_pos, allocated_size);
     }
-
-  allocation->x += x;
-  allocation->y += y;
-  allocation->width = w;
-  allocation->height = h;
 }
 
 static gboolean
@@ -9960,7 +9930,6 @@ gtk_widget_real_size_request (GtkWidget         *widget,
 static void
 gtk_widget_real_adjust_size_request (GtkWidget         *widget,
                                      GtkOrientation     orientation,
-                                     gint               for_size,
                                      gint              *minimum_size,
                                      gint              *natural_size)
 {
index 576f085c01470834fdbdc90ed18a682050580976..6e5b020d371556b082f8f206a713dfc279460d14 100644 (file)
@@ -157,7 +157,10 @@ struct _GtkWidget
  *   and alignment properties of #GtkWidget. Chain up
  *   <emphasis>before</emphasis> performing your own adjustments so your
  *   own adjustments remove more allocation after the #GtkWidget base
- *   class has already removed margin and alignment.
+ *   class has already removed margin and alignment. The natural size
+ *   passed in should be adjusted in the same way as the allocated size,
+ *   which allows adjustments to perform alignments or other changes
+ *   based on natural size.
  */
 struct _GtkWidgetClass
 {
@@ -372,11 +375,13 @@ struct _GtkWidgetClass
 
   void         (* adjust_size_request)    (GtkWidget         *widget,
                                            GtkOrientation     orientation,
-                                           gint               for_size,
                                            gint              *minimum_size,
                                            gint              *natural_size);
   void         (* adjust_size_allocation) (GtkWidget         *widget,
-                                           GtkAllocation     *allocation);
+                                           GtkOrientation     orientation,
+                                           gint              *natural_size,
+                                           gint              *allocated_pos,
+                                           gint              *allocated_size);
 
   /*< private >*/
 
index 889ea52c7234b3dd5dc33c54181c8cc055a3a83e..13ec9449869640066181cc1372ca73db90e206ae 100644 (file)
@@ -408,6 +408,9 @@ open_valigned_label_window (void)
   gtk_widget_show (box);
   gtk_container_add (GTK_CONTAINER (window), box);
 
+  label = gtk_label_new ("Both labels expand");
+  gtk_widget_show (label);
+  gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
 
   label = gtk_label_new ("Some wrapping text with width-chars = 15 and max-width-chars = 35");
   gtk_label_set_line_wrap  (GTK_LABEL (label), TRUE);
@@ -421,7 +424,7 @@ open_valigned_label_window (void)
   gtk_container_add (GTK_CONTAINER (frame), label);
 
   gtk_widget_set_valign (frame, GTK_ALIGN_CENTER);
-  gtk_widget_set_halign (frame, GTK_ALIGN_FILL);
+  gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
 
   gtk_box_pack_start (GTK_BOX (box), frame, TRUE, TRUE, 0);