[gtk+] Make button boxes semi-homogeneous



commit fe1a39b1f2358af206b6cd8107360427cca21bb5
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Aug 22 00:30:31 2010 -0400

    Make button boxes semi-homogeneous
    
    If a child is too large (> 1.5 the average), let it have its own
    size. The old behaviour of fully homogeneous button boxes can still
    be had by setting the homogeneous property to TRUE. Bug 84188.

 gtk/gtkbbox.c |  314 +++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 196 insertions(+), 118 deletions(-)
---
diff --git a/gtk/gtkbbox.c b/gtk/gtkbbox.c
index 655ba9a..aae0f74 100644
--- a/gtk/gtkbbox.c
+++ b/gtk/gtkbbox.c
@@ -394,14 +394,15 @@ gtk_button_box_set_child_secondary (GtkButtonBox *widget,
 }
 
 /* Ask children how much space they require and round up
-   to match minimum size and internal padding.
-   Returns the size each single child should have. */
+ * to match minimum size and internal padding.
+ * Returns the size each single child should have.
+ */
 static void
-_gtk_button_box_child_requisition (GtkWidget *widget,
-                                   int       *nvis_children,
-                                   int       *nvis_secondaries,
-                                   int       *width,
-                                   int       *height)
+gtk_button_box_child_requisition (GtkWidget  *widget,
+                                  gint       *nvis_children,
+                                  gint       *nvis_secondaries,
+                                  gint      **widths,
+                                  gint      **heights)
 {
   GtkButtonBoxPriv *priv;
   GtkButtonBox *bbox;
@@ -410,6 +411,7 @@ _gtk_button_box_child_requisition (GtkWidget *widget,
   gint nsecondaries;
   gint needed_width;
   gint needed_height;
+  gint avg_w, avg_h;
   GtkRequisition child_requisition;
   gint ipad_w;
   gint ipad_h;
@@ -417,12 +419,16 @@ _gtk_button_box_child_requisition (GtkWidget *widget,
   gint child_min_height;
   gint ipad_x;
   gint ipad_y;
+  gboolean homogeneous;
+  gint i;
 
   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
 
   bbox = GTK_BUTTON_BOX (widget);
   priv = bbox->priv;
 
+  homogeneous = gtk_box_get_homogeneous (GTK_BOX (widget));
+
   gtk_widget_style_get (widget,
                         "child-min-width", &child_min_width,
                         "child-min-height", &child_min_height,
@@ -437,41 +443,92 @@ _gtk_button_box_child_requisition (GtkWidget *widget,
   needed_height = child_min_height;
   ipad_w = ipad_x * 2;
   ipad_h = ipad_y * 2;
-  
+
+  avg_w = avg_h = 0;
   while (children)
     {
       GtkWidget *child;
-      gboolean is_secondary;
 
       child = children->data;
       children = children->next;
 
-      is_secondary = gtk_button_box_get_child_secondary (bbox, child);
-
       if (gtk_widget_get_visible (child))
         {
           nchildren += 1;
           gtk_widget_size_request (child, &child_requisition);
+          avg_w += child_requisition.width + ipad_w;
+          avg_h += child_requisition.height + ipad_h;
+        }
+    }
+  avg_w /= nchildren;
+  avg_h /= nchildren;
+
+  *widths = g_new (gint, nchildren);
+  *heights = g_new (gint, nchildren);
+
+  i = 0;
+  children = list;
+  while (children)
+    {
+      GtkWidget *child;
+      gboolean is_secondary;
 
-          if (child_requisition.width + ipad_w > needed_width)
-            needed_width = child_requisition.width + ipad_w;
-          if (child_requisition.height + ipad_h > needed_height)
-            needed_height = child_requisition.height + ipad_h;
+      child = children->data;
+      children = children->next;
+
+      if (gtk_widget_get_visible (child))
+        {
+          is_secondary = gtk_button_box_get_child_secondary (bbox, child);
           if (is_secondary)
             nsecondaries++;
+
+          gtk_widget_get_child_requisition (child, &child_requisition);
+
+          if (homogeneous ||
+              (child_requisition.width + ipad_w < avg_w * 1.5)) /* &&
+               child_requisition.width + ipad_w > avg_w / 1.5)) */
+            {
+              (*widths)[i] = -1;
+              if (child_requisition.width + ipad_w > needed_width)
+                needed_width = child_requisition.width + ipad_w;
+            }
+          else
+            {
+              (*widths)[i] = child_requisition.width + ipad_w;
+            }
+
+          if (homogeneous ||
+              (child_requisition.height + ipad_h < avg_h * 1.5)) /* &&
+               child_requisition.height + ipad_h > avg_h / 1.5)) */
+            {
+              (*heights)[i] = -1;
+              if (child_requisition.height + ipad_h > needed_height)
+                needed_height = child_requisition.height + ipad_h;
+            }
+          else
+            {
+              (*heights)[i] = child_requisition.height + ipad_h;
+            }
+
+          i++;
         }
     }
 
   g_list_free (list);
 
+  for (i = 0; i < nchildren; i++)
+    {
+      if ((*widths)[i] == -1)
+        (*widths)[i] = needed_width;
+      if ((*heights)[i] == -1)
+        (*heights)[i] = needed_height;
+    }
+
   if (nvis_children)
     *nvis_children = nchildren;
+
   if (nvis_secondaries)
     *nvis_secondaries = nsecondaries;
-  if (width)
-    *width = needed_width;
-  if (height)
-    *height = needed_height;
 }
 
 static void
@@ -479,27 +536,45 @@ gtk_button_box_size_request (GtkWidget      *widget,
                              GtkRequisition *requisition)
 {
   GtkButtonBoxPriv *priv;
-  GtkBox *box;
   GtkButtonBox *bbox;
   gint nvis_children;
-  gint child_width;
-  gint child_height;
+  gint max_size;
+  gint total_size;
   gint spacing;
   guint border_width;
   GtkOrientation orientation;
+  gint *widths;
+  gint *heights;
+  gint i;
 
-  box = GTK_BOX (widget);
   bbox = GTK_BUTTON_BOX (widget);
   priv = bbox->priv;
 
   orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
-  spacing = gtk_box_get_spacing (box);
+  spacing = gtk_box_get_spacing (GTK_BOX (widget));
 
-  _gtk_button_box_child_requisition (widget,
-                                     &nvis_children,
-                                     NULL,
-                                     &child_width,
-                                     &child_height);
+  gtk_button_box_child_requisition (widget,
+                                    &nvis_children,
+                                    NULL,
+                                    &widths, &heights);
+
+  max_size = 0;
+  total_size = 0;
+  for (i = 0; i < nvis_children; i++)
+    {
+      if (orientation == GTK_ORIENTATION_HORIZONTAL)
+        {
+          total_size += widths[i];
+          max_size = MAX (max_size, heights[i]);
+        }
+      else
+        {
+          total_size += heights[i];
+          max_size = MAX (max_size, widths[i]);
+        }
+    }
+  g_free (widths);
+  g_free (heights);
 
   if (nvis_children == 0)
     {
@@ -512,11 +587,9 @@ gtk_button_box_size_request (GtkWidget      *widget,
         {
           case GTK_BUTTONBOX_SPREAD:
             if (orientation == GTK_ORIENTATION_HORIZONTAL)
-              requisition->width =
-                      nvis_children*child_width + ((nvis_children+1)*spacing);
+              requisition->width = total_size + ((nvis_children + 1)*spacing);
             else
-              requisition->height =
-                      nvis_children*child_height + ((nvis_children+1)*spacing);
+              requisition->height = total_size + ((nvis_children + 1)*spacing);
 
             break;
           case GTK_BUTTONBOX_EDGE:
@@ -524,11 +597,9 @@ gtk_button_box_size_request (GtkWidget      *widget,
           case GTK_BUTTONBOX_END:
           case GTK_BUTTONBOX_CENTER:
             if (orientation == GTK_ORIENTATION_HORIZONTAL)
-              requisition->width =
-                      nvis_children*child_width + ((nvis_children-1)*spacing);
+              requisition->width = total_size + ((nvis_children - 1)*spacing);
             else
-              requisition->height =
-                      nvis_children*child_height + ((nvis_children-1)*spacing);
+              requisition->height = total_size + ((nvis_children - 1)*spacing);
 
             break;
           default:
@@ -537,12 +608,12 @@ gtk_button_box_size_request (GtkWidget      *widget,
         }
 
       if (orientation == GTK_ORIENTATION_HORIZONTAL)
-        requisition->height = child_height;
+        requisition->height = max_size;
       else
-        requisition->width = child_width;
+        requisition->width = max_size;
     }
 
-  border_width = gtk_container_get_border_width (GTK_CONTAINER (box));
+  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
   requisition->width += border_width * 2;
   requisition->height += border_width * 2;
 }
@@ -552,38 +623,74 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
                               GtkAllocation *allocation)
 {
   GtkButtonBoxPriv *priv;
-  GtkBox *base_box;
-  GtkButtonBox *box;
+  GtkButtonBox *bbox;
   GList *children, *list;
   GtkAllocation child_allocation;
   gint nvis_children;
+  gint n_primaries;
   gint n_secondaries;
-  gint child_width;
-  gint child_height;
   gint x = 0;
   gint y = 0;
   gint secondary_x = 0;
   gint secondary_y = 0;
   gint width = 0;
   gint height = 0;
-  gint childspace;
   gint childspacing = 0;
   gint spacing;
   guint border_width;
   GtkOrientation orientation;
+  gint ipad_x, ipad_y;
+  gint *widths;
+  gint *heights;
+  gint *sizes;
+  gint primary_size;
+  gint secondary_size;
+  gint total_size;
+  gint i;
 
-  base_box = GTK_BOX (widget);
-  box = GTK_BUTTON_BOX (widget);
-  priv = box->priv;
+  bbox = GTK_BUTTON_BOX (widget);
+  priv = bbox->priv;
 
-  border_width = gtk_container_get_border_width (GTK_CONTAINER (box));
+  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
   orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
-  spacing = gtk_box_get_spacing (base_box);
-  _gtk_button_box_child_requisition (widget,
-                                     &nvis_children,
-                                     &n_secondaries,
-                                     &child_width,
-                                     &child_height);
+  spacing = gtk_box_get_spacing (GTK_BOX (widget));
+  gtk_widget_style_get (widget,
+                        "child-internal-pad-x", &ipad_x,
+                        "child-internal-pad-y", &ipad_y,
+                        NULL);
+  gtk_button_box_child_requisition (widget,
+                                    &nvis_children,
+                                    &n_secondaries,
+                                    &widths, &heights);
+
+  n_primaries = nvis_children - n_secondaries;
+  primary_size = 0;
+  secondary_size = 0;
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    sizes = widths;
+  else
+    sizes = heights;
+
+  i = 0;
+  list = children = _gtk_box_get_children (GTK_BOX (widget));
+  while (children)
+    {
+      GtkWidget *child;
+
+      child = children->data;
+      children = children->next;
+
+      if (gtk_widget_get_visible (child))
+        {
+          if (gtk_button_box_get_child_secondary (bbox, child))
+            secondary_size += sizes[i];
+          else
+            primary_size += sizes[i];
+          i++;
+        }
+    }
+  total_size = primary_size + secondary_size;
+
   widget->allocation = *allocation;
 
   if (orientation == GTK_ORIENTATION_HORIZONTAL)
@@ -597,19 +704,15 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
 
         if (orientation == GTK_ORIENTATION_HORIZONTAL)
           {
-            childspacing = (width - (nvis_children * child_width))
-                    / (nvis_children + 1);
+            childspacing = (width - total_size) / (nvis_children + 1);
             x = allocation->x + border_width + childspacing;
-            secondary_x = x + ((nvis_children - n_secondaries)
-                            * (child_width + childspacing));
+            secondary_x = x + primary_size + n_primaries * childspacing;
           }
         else
           {
-            childspacing = (height - (nvis_children * child_height))
-                    / (nvis_children + 1);
+            childspacing = (height - total_size) / (nvis_children + 1);
             y = allocation->y + border_width + childspacing;
-            secondary_y = y + ((nvis_children - n_secondaries)
-                            * (child_height + childspacing));
+            secondary_y = y + primary_size + n_primaries * childspacing;
           }
 
         break;
@@ -620,36 +723,32 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
           {
             if (nvis_children >= 2)
               {
-                childspacing = (width - (nvis_children * child_width))
-                      / (nvis_children - 1);
+                childspacing = (width - total_size) / (nvis_children - 1);
                 x = allocation->x + border_width;
-                secondary_x = x + ((nvis_children - n_secondaries)
-                                   * (child_width + childspacing));
+                secondary_x = x + primary_size + n_primaries * childspacing;
               }
             else
               {
                 /* one or zero children, just center */
                 childspacing = width;
                 x = secondary_x = allocation->x
-                      + (allocation->width - child_width) / 2;
+                                  + (allocation->width - widths[0]) / 2;
               }
           }
         else
           {
             if (nvis_children >= 2)
               {
-                childspacing = (height - (nvis_children*child_height))
-                        / (nvis_children-1);
+                childspacing = (height - total_size) / (nvis_children - 1);
                 y = allocation->y + border_width;
-                secondary_y = y + ((nvis_children - n_secondaries)
-                                * (child_height + childspacing));
+                secondary_y = y + primary_size + n_primaries * childspacing;
               }
             else
               {
                 /* one or zero children, just center */
                 childspacing = height;
                 y = secondary_y = allocation->y
-                        + (allocation->height - child_height) / 2;
+                        + (allocation->height - heights[0]) / 2;
               }
           }
 
@@ -662,18 +761,14 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
             childspacing = spacing;
             x = allocation->x + border_width;
             secondary_x = allocation->x + allocation->width
-              - child_width * n_secondaries
-              - spacing * (n_secondaries - 1)
-              - border_width;
+              - secondary_size - spacing * (n_secondaries - 1) - border_width;
           }
         else
           {
             childspacing = spacing;
             y = allocation->y + border_width;
             secondary_y = allocation->y + allocation->height
-              - child_height * n_secondaries
-              - spacing * (n_secondaries - 1)
-              - border_width;
+              - secondary_size - spacing * (n_secondaries - 1) - border_width;
           }
 
         break;
@@ -684,18 +779,14 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
           {
             childspacing = spacing;
             x = allocation->x + allocation->width
-              - child_width * (nvis_children - n_secondaries)
-              - spacing * (nvis_children - n_secondaries - 1)
-              - border_width;
+              - primary_size - spacing * (n_primaries - 1) - border_width;
             secondary_x = allocation->x + border_width;
           }
         else
           {
             childspacing = spacing;
             y = allocation->y + allocation->height
-              - child_height * (nvis_children - n_secondaries)
-              - spacing * (nvis_children - n_secondaries - 1)
-              - border_width;
+              - primary_size - spacing * (n_primaries - 1) - border_width;
             secondary_y = allocation->y + border_width;
           }
 
@@ -708,9 +799,8 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
             childspacing = spacing;
             x = allocation->x +
               (allocation->width
-               - (child_width * (nvis_children - n_secondaries)
-               + spacing * (nvis_children - n_secondaries - 1))) / 2
-              + (n_secondaries * child_width + n_secondaries * spacing) / 2;
+               - (primary_size + spacing * (n_primaries - 1))) / 2
+              + (secondary_size + n_secondaries * spacing) / 2;
             secondary_x = allocation->x + border_width;
           }
         else
@@ -718,9 +808,8 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
             childspacing = spacing;
             y = allocation->y +
               (allocation->height
-               - (child_height * (nvis_children - n_secondaries)
-                  + spacing * (nvis_children - n_secondaries - 1))) / 2
-              + (n_secondaries * child_height + n_secondaries * spacing) / 2;
+               - (primary_size + spacing * (n_primaries - 1))) / 2
+              + (secondary_size + n_secondaries * spacing) / 2;
             secondary_y = allocation->y + border_width;
           }
 
@@ -731,74 +820,63 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
         break;
     }
 
-    if (orientation == GTK_ORIENTATION_HORIZONTAL)
-      {
-        y = allocation->y + (allocation->height - child_height) / 2;
-        childspace = child_width + childspacing;
-      }
-    else
-      {
-        x = allocation->x + (allocation->width - child_width) / 2;
-        childspace = child_height + childspacing;
-      }
-
-  list = children = _gtk_box_get_children (GTK_BOX (box));
-
+  children = list;
+  i = 0;
   while (children)
     {
       GtkWidget *child;
-      gboolean is_secondary;
 
       child = children->data;
       children = children->next;
 
-      is_secondary = gtk_button_box_get_child_secondary (box, child);
-
       if (gtk_widget_get_visible (child))
         {
-          child_allocation.width = child_width;
-          child_allocation.height = child_height;
+          child_allocation.width = widths[i];
+          child_allocation.height = heights[i];
 
           if (orientation == GTK_ORIENTATION_HORIZONTAL)
             {
-              child_allocation.y = y;
+              child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2;
 
-              if (is_secondary)
+              if (gtk_button_box_get_child_secondary (bbox, child))
                 {
                   child_allocation.x = secondary_x;
-                  secondary_x += childspace;
+                  secondary_x += child_allocation.width + childspacing;
                 }
               else
                 {
                   child_allocation.x = x;
-                  x += childspace;
+                  x += child_allocation.width + childspacing;
                 }
 
               if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
                   child_allocation.x = (allocation->x + allocation->width)
-                          - (child_allocation.x + child_width - allocation->x);
+                          - (child_allocation.x + child_allocation.width - allocation->x);
             }
           else
             {
-              child_allocation.x = x;
+              child_allocation.x = allocation->x + (allocation->width - child_allocation.width) / 2;
 
-              if (is_secondary)
+              if (gtk_button_box_get_child_secondary (bbox, child))
                 {
                   child_allocation.y = secondary_y;
-                  secondary_y += childspace;
+                  secondary_y += child_allocation.height + childspacing;
                 }
               else
                 {
                   child_allocation.y = y;
-                  y += childspace;
+                  y += child_allocation.height + childspacing;
                 }
             }
 
           gtk_widget_size_allocate (child, &child_allocation);
+          i++;
         }
     }
 
   g_list_free (list);
+  g_free (widths);
+  g_free (heights);
 }
 
 /**



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