X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkbbox.c;h=8385e2dd2e659a7489f56b40c8b34e579e56ab35;hb=fa4878979e0a72890ca577a210ccd7cf6291dbf0;hp=aae0f742a5c54a7589177044230229ab476400ce;hpb=fe1a39b1f2358af206b6cd8107360427cca21bb5;p=~andy%2Fgtk diff --git a/gtk/gtkbbox.c b/gtk/gtkbbox.c index aae0f742a..8385e2dd2 100644 --- a/gtk/gtkbbox.c +++ b/gtk/gtkbbox.c @@ -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 . */ /* @@ -26,40 +24,43 @@ /** * 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. - * - * gtk_button_box_get_child_size() retrieves the minimum width and height - * for widgets in a given button box. - * - * The internal padding of buttons can be retrieved and changed per button box - * using gtk_button_box_get_child_ipadding() and - * gtk_button_box_set_child_ipadding() respectively. - * - * gtk_button_box_get_spacing() and gtk_button_box_set_spacing() retrieve and - * change default number of pixels between buttons, respectively. + * 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 * container, respectively. * * The main purpose of GtkButtonBox is to make sure the children have all the - * same size. Therefore it ignores the homogeneous property which it inherited - * from GtkBox, and always behaves as if homogeneous was %TRUE. + * 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. + * + * 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" -struct _GtkButtonBoxPriv +struct _GtkButtonBoxPrivate { GtkButtonBoxStyle layout_style; }; @@ -71,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, @@ -84,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, @@ -123,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. @@ -172,7 +192,7 @@ gtk_button_box_class_init (GtkButtonBoxClass *class) PROP_LAYOUT_STYLE, g_param_spec_enum ("layout-style", P_("Layout style"), - P_("How to layout the buttons in the box. Possible values are spread, edge, start and end"), + P_("How to lay out the buttons in the box. Possible values are: spread, edge, start and end"), GTK_TYPE_BUTTON_BOX_STYLE, DEFAULT_LAYOUT_STYLE, GTK_PARAM_READWRITE)); @@ -185,17 +205,25 @@ gtk_button_box_class_init (GtkButtonBoxClass *class) FALSE, GTK_PARAM_READWRITE)); - g_type_class_add_private (class, sizeof (GtkButtonBoxPriv)); + 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)); } static void gtk_button_box_init (GtkButtonBox *button_box) { - GtkButtonBoxPriv *priv; + GtkButtonBoxPrivate *priv; button_box->priv = G_TYPE_INSTANCE_GET_PRIVATE (button_box, GTK_TYPE_BUTTON_BOX, - GtkButtonBoxPriv); + GtkButtonBoxPrivate); priv = button_box->priv; gtk_box_set_spacing (GTK_BOX (button_box), 0); @@ -226,7 +254,7 @@ gtk_button_box_get_property (GObject *object, GValue *value, GParamSpec *pspec) { - GtkButtonBoxPriv *priv = GTK_BUTTON_BOX (object)->priv; + GtkButtonBoxPrivate *priv = GTK_BUTTON_BOX (object)->priv; switch (prop_id) { @@ -252,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; @@ -272,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; @@ -282,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); } @@ -303,7 +339,7 @@ void gtk_button_box_set_layout (GtkButtonBox *widget, GtkButtonBoxStyle layout_style) { - GtkButtonBoxPriv *priv; + GtkButtonBoxPrivate *priv; g_return_if_fail (GTK_IS_BUTTON_BOX (widget)); @@ -323,7 +359,7 @@ gtk_button_box_set_layout (GtkButtonBox *widget, * * Retrieves the method being used to arrange the buttons in a button box. * - * Returns: the method used to layout buttons in @widget. + * Returns: the method used to lay out buttons in @widget. */ GtkButtonBoxStyle gtk_button_box_get_layout (GtkButtonBox *widget) @@ -355,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 @@ -381,7 +417,7 @@ gtk_button_box_set_child_secondary (GtkButtonBox *widget, { g_return_if_fail (GTK_IS_BUTTON_BOX (widget)); g_return_if_fail (GTK_IS_WIDGET (child)); - g_return_if_fail (child->parent == GTK_WIDGET (widget)); + g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (widget)); g_object_set_data (G_OBJECT (child), GTK_BOX_SECONDARY_CHILD, @@ -404,7 +440,6 @@ gtk_button_box_child_requisition (GtkWidget *widget, gint **widths, gint **heights) { - GtkButtonBoxPriv *priv; GtkButtonBox *bbox; GList *children, *list; gint nchildren; @@ -425,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)); @@ -455,13 +489,14 @@ 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; } } - avg_w /= nchildren; - avg_h /= nchildren; + avg_w /= MAX (nchildren, 1); + avg_h /= MAX (nchildren, 1); *widths = g_new (gint, nchildren); *heights = g_new (gint, nchildren); @@ -472,6 +507,7 @@ gtk_button_box_child_requisition (GtkWidget *widget, { GtkWidget *child; gboolean is_secondary; + gboolean non_homogeneous; child = children->data; children = children->next; @@ -479,14 +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)) /* && - child_requisition.width + ipad_w > avg_w / 1.5)) */ + (!non_homogeneous && (child_requisition.width + ipad_w < avg_w * 1.5))) { (*widths)[i] = -1; if (child_requisition.width + ipad_w > needed_width) @@ -498,8 +535,7 @@ gtk_button_box_child_requisition (GtkWidget *widget, } if (homogeneous || - (child_requisition.height + ipad_h < avg_h * 1.5)) /* && - child_requisition.height + ipad_h > avg_h / 1.5)) */ + (!non_homogeneous && (child_requisition.height + ipad_h < avg_h * 1.5))) { (*heights)[i] = -1; if (child_requisition.height + ipad_h > needed_height) @@ -535,13 +571,12 @@ static void gtk_button_box_size_request (GtkWidget *widget, GtkRequisition *requisition) { - GtkButtonBoxPriv *priv; + GtkButtonBoxPrivate *priv; GtkButtonBox *bbox; gint nvis_children; gint max_size; gint total_size; gint spacing; - guint border_width; GtkOrientation orientation; gint *widths; gint *heights; @@ -612,17 +647,55 @@ 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); + + *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; +} - border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - requisition->width += border_width * 2; - requisition->height += border_width * 2; +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 gtk_button_box_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { - GtkButtonBoxPriv *priv; + GtkButtonBoxPrivate *priv; GtkButtonBox *bbox; GList *children, *list; GtkAllocation child_allocation; @@ -637,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; @@ -651,9 +723,9 @@ 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)); + gtk_widget_style_get (widget, "child-internal-pad-x", &ipad_x, "child-internal-pad-y", &ipad_y, @@ -691,12 +763,12 @@ gtk_button_box_size_allocate (GtkWidget *widget, } total_size = primary_size + secondary_size; - widget->allocation = *allocation; + 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) { @@ -705,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; } @@ -724,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; } } @@ -759,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; @@ -779,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; @@ -801,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 { @@ -810,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; @@ -896,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); +}