]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkbbox.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkbbox.c
index 6056e43a8892e460a213467d5bd9f47506aa3e87..8385e2dd2e659a7489f56b40c8b34e579e56ab35 100644 (file)
@@ -12,9 +12,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 /*
 
 /**
  * SECTION:gtkbbox
- * @Short_description: Base class for GtkHButtonBox and GtkVButtonBox
+ * @Short_description: A container for arranging buttons
  * @Title: GtkButtonBox
- * @See_also: #GtkVButtonBox, #GtkHButtonBox
  *
- * The primary purpose of this class is to keep track of the various
- * properties of #GtkHButtonBox and #GtkVButtonBox widgets.
+ * A button box should be used to provide a consistent layout of buttons
+ * throughout your application. The layout/spacing can be altered by the
+ * programmer, or if desired, by the user to alter the 'feel' of a
+ * program to a small degree.
  *
  * gtk_button_box_get_layout() and gtk_button_box_set_layout() retrieve and
  * alter the method used to spread the buttons in a button box across the
  * same size. GtkButtonBox gives all children the same size, but it does allow
  * 'outliers' to keep their own larger size. To force all children to be
  * strictly the same size without exceptions, you can set the
- * #GtkButtonBox::homogeneous property to %TRUE.
+ * #GtkButtonBox:homogeneous property to %TRUE.
+ *
+ * To excempt individual children from homogeneous sizing regardless of their
+ * 'outlier' status, you can set the #GtkButtonBox:non-homogeneous child
+ * property.
  */
 
 #include "config.h"
+
 #include "gtkbbox.h"
+
+#include "gtkboxprivate.h"
 #include "gtkorientable.h"
+#include "gtktypebuiltins.h"
 #include "gtkprivate.h"
+#include "gtksizerequest.h"
+
 #include "gtkintl.h"
 
 
@@ -63,10 +72,12 @@ enum {
 
 enum {
   CHILD_PROP_0,
-  CHILD_PROP_SECONDARY
+  CHILD_PROP_SECONDARY,
+  CHILD_PROP_NONHOMOGENEOUS
 };
 
 #define GTK_BOX_SECONDARY_CHILD "gtk-box-secondary-child"
+#define GTK_BOX_NON_HOMOGENEOUS "gtk-box-non-homogeneous"
 
 static void gtk_button_box_set_property       (GObject           *object,
                                                guint              prop_id,
@@ -76,8 +87,21 @@ static void gtk_button_box_get_property       (GObject           *object,
                                                guint              prop_id,
                                                GValue            *value,
                                                GParamSpec        *pspec);
-static void gtk_button_box_size_request       (GtkWidget         *widget,
-                                               GtkRequisition    *requisition);
+static void gtk_button_box_get_preferred_width            (GtkWidget *widget,
+                                                           gint      *minimum,
+                                                           gint      *natural);
+static void gtk_button_box_get_preferred_height           (GtkWidget *widget,
+                                                           gint      *minimum,
+                                                           gint      *natural);
+static void gtk_button_box_get_preferred_width_for_height (GtkWidget *widget,
+                                                           gint       height,
+                                                           gint      *minimum,
+                                                           gint      *natural);
+static void gtk_button_box_get_preferred_height_for_width (GtkWidget *widget,
+                                                           gint       width,
+                                                           gint      *minimum,
+                                                           gint      *natural);
+
 static void gtk_button_box_size_allocate      (GtkWidget         *widget,
                                                GtkAllocation     *allocation);
 static void gtk_button_box_remove             (GtkContainer      *container,
@@ -115,12 +139,16 @@ gtk_button_box_class_init (GtkButtonBoxClass *class)
   gobject_class->set_property = gtk_button_box_set_property;
   gobject_class->get_property = gtk_button_box_get_property;
 
-  widget_class->size_request = gtk_button_box_size_request;
+  widget_class->get_preferred_width = gtk_button_box_get_preferred_width;
+  widget_class->get_preferred_height = gtk_button_box_get_preferred_height;
+  widget_class->get_preferred_width_for_height = gtk_button_box_get_preferred_width_for_height;
+  widget_class->get_preferred_height_for_width = gtk_button_box_get_preferred_height_for_width;
   widget_class->size_allocate = gtk_button_box_size_allocate;
 
   container_class->remove = gtk_button_box_remove;
   container_class->set_child_property = gtk_button_box_set_child_property;
   container_class->get_child_property = gtk_button_box_get_child_property;
+  gtk_container_class_handle_border_width (container_class);
 
   /* FIXME we need to override the "spacing" property on GtkBox once
    * libgobject allows that.
@@ -177,6 +205,14 @@ gtk_button_box_class_init (GtkButtonBoxClass *class)
                                                                     FALSE,
                                                                     GTK_PARAM_READWRITE));
 
+  gtk_container_class_install_child_property (container_class,
+                                              CHILD_PROP_NONHOMOGENEOUS,
+                                              g_param_spec_boolean ("non-homogeneous",
+                                                                    P_("Non-Homogeneous"),
+                                                                    P_("If TRUE, the child will not be subject to homogeneous sizing"),
+                                                                    FALSE,
+                                                                    GTK_PARAM_READWRITE));
+
   g_type_class_add_private (class, sizeof (GtkButtonBoxPrivate));
 }
 
@@ -244,6 +280,10 @@ gtk_button_box_set_child_property (GtkContainer *container,
       gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (container), child,
                                           g_value_get_boolean (value));
       break;
+    case CHILD_PROP_NONHOMOGENEOUS:
+      gtk_button_box_set_child_non_homogeneous (GTK_BUTTON_BOX (container), child,
+                                                g_value_get_boolean (value));
+      break;
     default:
       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
       break;
@@ -264,6 +304,11 @@ gtk_button_box_get_child_property (GtkContainer *container,
                            gtk_button_box_get_child_secondary (GTK_BUTTON_BOX (container),
                                                                child));
       break;
+    case CHILD_PROP_NONHOMOGENEOUS:
+      g_value_set_boolean (value,
+                           gtk_button_box_get_child_non_homogeneous (GTK_BUTTON_BOX (container),
+                                                                     child));
+      break;
     default:
       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
       break;
@@ -274,12 +319,11 @@ static void
 gtk_button_box_remove (GtkContainer *container,
                        GtkWidget    *widget)
 {
-  /* clear is_secondary flag in case the widget
+  /* clear is_secondary and nonhomogeneous flag in case the widget
    * is added to another container
    */
-  gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (container),
-                                      widget,
-                                      FALSE);
+  gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (container), widget, FALSE);
+  gtk_button_box_set_child_non_homogeneous (GTK_BUTTON_BOX (container), widget, FALSE);
 
   GTK_CONTAINER_CLASS (gtk_button_box_parent_class)->remove (container, widget);
 }
@@ -347,7 +391,7 @@ gtk_button_box_get_child_secondary (GtkButtonBox *widget,
 }
 
 /**
- * gtk_button_box_set_child_secondary
+ * gtk_button_box_set_child_secondary:
  * @widget: a #GtkButtonBox
  * @child: a child of @widget
  * @is_secondary: if %TRUE, the @child appears in a secondary group of the
@@ -396,7 +440,6 @@ gtk_button_box_child_requisition (GtkWidget  *widget,
                                   gint      **widths,
                                   gint      **heights)
 {
-  GtkButtonBoxPrivate *priv;
   GtkButtonBox *bbox;
   GList *children, *list;
   gint nchildren;
@@ -417,7 +460,6 @@ gtk_button_box_child_requisition (GtkWidget  *widget,
   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));
 
@@ -447,7 +489,8 @@ gtk_button_box_child_requisition (GtkWidget  *widget,
       if (gtk_widget_get_visible (child))
         {
           nchildren += 1;
-          gtk_widget_size_request (child, &child_requisition);
+          gtk_widget_get_preferred_size (child,
+                                         &child_requisition, NULL);
           avg_w += child_requisition.width + ipad_w;
           avg_h += child_requisition.height + ipad_h;
         }
@@ -464,6 +507,7 @@ gtk_button_box_child_requisition (GtkWidget  *widget,
     {
       GtkWidget *child;
       gboolean is_secondary;
+      gboolean non_homogeneous;
 
       child = children->data;
       children = children->next;
@@ -471,12 +515,15 @@ gtk_button_box_child_requisition (GtkWidget  *widget,
       if (gtk_widget_get_visible (child))
         {
           is_secondary = gtk_button_box_get_child_secondary (bbox, child);
+          non_homogeneous = gtk_button_box_get_child_non_homogeneous (bbox, child);
+
           if (is_secondary)
             nsecondaries++;
 
-          gtk_widget_get_child_requisition (child, &child_requisition);
+          gtk_widget_get_preferred_size (child, &child_requisition, NULL);
 
-          if (homogeneous || (child_requisition.width + ipad_w < avg_w * 1.5))
+          if (homogeneous ||
+              (!non_homogeneous && (child_requisition.width + ipad_w < avg_w * 1.5)))
             {
               (*widths)[i] = -1;
               if (child_requisition.width + ipad_w > needed_width)
@@ -487,7 +534,8 @@ gtk_button_box_child_requisition (GtkWidget  *widget,
               (*widths)[i] = child_requisition.width + ipad_w;
             }
 
-          if (homogeneous || (child_requisition.height + ipad_h < avg_h * 1.5))
+          if (homogeneous ||
+              (!non_homogeneous && (child_requisition.height + ipad_h < avg_h * 1.5)))
             {
               (*heights)[i] = -1;
               if (child_requisition.height + ipad_h > needed_height)
@@ -529,7 +577,6 @@ gtk_button_box_size_request (GtkWidget      *widget,
   gint max_size;
   gint total_size;
   gint spacing;
-  guint border_width;
   GtkOrientation orientation;
   gint *widths;
   gint *heights;
@@ -600,10 +647,48 @@ gtk_button_box_size_request (GtkWidget      *widget,
       else
         requisition->width = max_size;
     }
+}
+
+static void
+gtk_button_box_get_preferred_width (GtkWidget *widget,
+                                    gint      *minimum,
+                                    gint      *natural)
+{
+  GtkRequisition requisition;
+
+  gtk_button_box_size_request (widget, &requisition);
 
-  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
-  requisition->width += border_width * 2;
-  requisition->height += border_width * 2;
+  *minimum = *natural = requisition.width;
+}
+
+static void
+gtk_button_box_get_preferred_height (GtkWidget *widget,
+                                     gint      *minimum,
+                                     gint      *natural)
+{
+  GtkRequisition requisition;
+
+  gtk_button_box_size_request (widget, &requisition);
+
+  *minimum = *natural = requisition.height;
+}
+
+static void
+gtk_button_box_get_preferred_width_for_height (GtkWidget *widget,
+                                               gint       height,
+                                               gint      *minimum,
+                                               gint      *natural)
+{
+  gtk_button_box_get_preferred_width (widget, minimum, natural);
+}
+
+static void
+gtk_button_box_get_preferred_height_for_width (GtkWidget *widget,
+                                               gint       width,
+                                               gint      *minimum,
+                                               gint      *natural)
+{
+  gtk_button_box_get_preferred_height (widget, minimum, natural);
 }
 
 static void
@@ -625,7 +710,6 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
   gint height = 0;
   gint childspacing = 0;
   gint spacing;
-  guint border_width;
   GtkOrientation orientation;
   gint ipad_x, ipad_y;
   gint *widths;
@@ -639,7 +723,6 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
   bbox = GTK_BUTTON_BOX (widget);
   priv = bbox->priv;
 
-  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
   orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
   spacing = gtk_box_get_spacing (GTK_BOX (widget));
 
@@ -683,9 +766,9 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
   gtk_widget_set_allocation (widget, allocation);
 
   if (orientation == GTK_ORIENTATION_HORIZONTAL)
-    width = allocation->width - border_width*2;
+    width = allocation->width;
   else
-    height = allocation->height - border_width*2;
+    height = allocation->height;
 
   switch (priv->layout_style)
     {
@@ -694,13 +777,13 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
         if (orientation == GTK_ORIENTATION_HORIZONTAL)
           {
             childspacing = (width - total_size) / (nvis_children + 1);
-            x = allocation->x + border_width + childspacing;
+            x = allocation->x + childspacing;
             secondary_x = x + primary_size + n_primaries * childspacing;
           }
         else
           {
             childspacing = (height - total_size) / (nvis_children + 1);
-            y = allocation->y + border_width + childspacing;
+            y = allocation->y + childspacing;
             secondary_y = y + primary_size + n_primaries * childspacing;
           }
 
@@ -713,31 +796,43 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
             if (nvis_children >= 2)
               {
                 childspacing = (width - total_size) / (nvis_children - 1);
-                x = allocation->x + border_width;
+                x = allocation->x;
                 secondary_x = x + primary_size + n_primaries * childspacing;
               }
-            else
+            else if (nvis_children == 1)
               {
-                /* one or zero children, just center */
+                /* one child, just center */
                 childspacing = width;
                 x = secondary_x = allocation->x
                                   + (allocation->width - widths[0]) / 2;
               }
+            else
+              {
+                /* zero children, meh */
+                childspacing = width;
+                x = secondary_x = allocation->x + allocation->width / 2;
+              }
           }
         else
           {
             if (nvis_children >= 2)
               {
                 childspacing = (height - total_size) / (nvis_children - 1);
-                y = allocation->y + border_width;
+                y = allocation->y;
                 secondary_y = y + primary_size + n_primaries * childspacing;
               }
-            else
+            else if (nvis_children == 1)
               {
-                /* one or zero children, just center */
+                /* one child, just center */
                 childspacing = height;
                 y = secondary_y = allocation->y
-                        + (allocation->height - heights[0]) / 2;
+                                     + (allocation->height - heights[0]) / 2;
+              }
+            else
+              {
+                /* zero children, meh */
+                childspacing = height;
+                y = secondary_y = allocation->y + allocation->height / 2;
               }
           }
 
@@ -748,16 +843,16 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
         if (orientation == GTK_ORIENTATION_HORIZONTAL)
           {
             childspacing = spacing;
-            x = allocation->x + border_width;
+            x = allocation->x;
             secondary_x = allocation->x + allocation->width
-              - secondary_size - spacing * (n_secondaries - 1) - border_width;
+              - secondary_size - spacing * (n_secondaries - 1);
           }
         else
           {
             childspacing = spacing;
-            y = allocation->y + border_width;
+            y = allocation->y;
             secondary_y = allocation->y + allocation->height
-              - secondary_size - spacing * (n_secondaries - 1) - border_width;
+              - secondary_size - spacing * (n_secondaries - 1);
           }
 
         break;
@@ -768,15 +863,15 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
           {
             childspacing = spacing;
             x = allocation->x + allocation->width
-              - primary_size - spacing * (n_primaries - 1) - border_width;
-            secondary_x = allocation->x + border_width;
+              - primary_size - spacing * (n_primaries - 1);
+            secondary_x = allocation->x;
           }
         else
           {
             childspacing = spacing;
             y = allocation->y + allocation->height
-              - primary_size - spacing * (n_primaries - 1) - border_width;
-            secondary_y = allocation->y + border_width;
+              - primary_size - spacing * (n_primaries - 1);
+            secondary_y = allocation->y;
           }
 
         break;
@@ -790,7 +885,7 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
               (allocation->width
                - (primary_size + spacing * (n_primaries - 1))) / 2
               + (secondary_size + n_secondaries * spacing) / 2;
-            secondary_x = allocation->x + border_width;
+            secondary_x = allocation->x;
           }
         else
           {
@@ -799,7 +894,7 @@ gtk_button_box_size_allocate (GtkWidget     *widget,
               (allocation->height
                - (primary_size + spacing * (n_primaries - 1))) / 2
               + (secondary_size + n_secondaries * spacing) / 2;
-            secondary_y = allocation->y + border_width;
+            secondary_y = allocation->y;
           }
 
         break;
@@ -885,3 +980,54 @@ gtk_button_box_new (GtkOrientation orientation)
                        "orientation", orientation,
                        NULL);
 }
+
+/**
+ * gtk_button_box_get_child_non_homogeneous:
+ * @widget: a #GtkButtonBox
+ * @child: a child of @widget
+ *
+ * Returns whether the child is exempted from homogenous
+ * sizing.
+ *
+ * Returns: %TRUE if the child is not subject to homogenous sizing
+ *
+ * Since: 3.2
+ */
+gboolean
+gtk_button_box_get_child_non_homogeneous (GtkButtonBox *widget,
+                                          GtkWidget    *child)
+{
+  g_return_val_if_fail (GTK_IS_BUTTON_BOX (widget), FALSE);
+  g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
+
+  return (g_object_get_data (G_OBJECT (child), GTK_BOX_NON_HOMOGENEOUS) != NULL);
+}
+
+/**
+ * gtk_button_box_set_child_non_homogeneous:
+ * @widget: a #GtkButtonBox
+ * @child: a child of @widget
+ * @non_homogeneous: the new value
+ *
+ * Sets whether the child is exempted from homogeous sizing.
+ *
+ * Since: 3.2
+ */
+void
+gtk_button_box_set_child_non_homogeneous (GtkButtonBox *widget,
+                                          GtkWidget    *child,
+                                          gboolean      non_homogeneous)
+{
+  g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
+  g_return_if_fail (GTK_IS_WIDGET (child));
+  g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (widget));
+
+  g_object_set_data (G_OBJECT (child),
+                     GTK_BOX_NON_HOMOGENEOUS,
+                     non_homogeneous ? GINT_TO_POINTER (1) : NULL);
+  gtk_widget_child_notify (child, "non-homogeneous");
+
+  if (gtk_widget_get_visible (GTK_WIDGET (widget)) &&
+      gtk_widget_get_visible (child))
+    gtk_widget_queue_resize (child);
+}