1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
31 #include "gtkorientable.h"
32 #include "gtkprivate.h"
46 static void gtk_button_box_set_property (GObject *object,
50 static void gtk_button_box_get_property (GObject *object,
54 static void gtk_button_box_size_request (GtkWidget *widget,
55 GtkRequisition *requisition);
56 static void gtk_button_box_size_allocate (GtkWidget *widget,
57 GtkAllocation *allocation);
58 static void gtk_button_box_set_child_property (GtkContainer *container,
63 static void gtk_button_box_get_child_property (GtkContainer *container,
69 #define DEFAULT_CHILD_MIN_WIDTH 85
70 #define DEFAULT_CHILD_MIN_HEIGHT 27
71 #define DEFAULT_CHILD_IPAD_X 4
72 #define DEFAULT_CHILD_IPAD_Y 0
74 G_DEFINE_ABSTRACT_TYPE (GtkButtonBox, gtk_button_box, GTK_TYPE_BOX)
77 gtk_button_box_class_init (GtkButtonBoxClass *class)
79 GtkWidgetClass *widget_class;
80 GObjectClass *gobject_class;
81 GtkContainerClass *container_class;
83 gobject_class = G_OBJECT_CLASS (class);
84 widget_class = (GtkWidgetClass*) class;
85 container_class = (GtkContainerClass*) class;
87 gobject_class->set_property = gtk_button_box_set_property;
88 gobject_class->get_property = gtk_button_box_get_property;
90 widget_class->size_request = gtk_button_box_size_request;
91 widget_class->size_allocate = gtk_button_box_size_allocate;
93 container_class->set_child_property = gtk_button_box_set_child_property;
94 container_class->get_child_property = gtk_button_box_get_child_property;
96 /* FIXME we need to override the "spacing" property on GtkBox once
97 * libgobject allows that.
99 gtk_widget_class_install_style_property (widget_class,
100 g_param_spec_int ("child-min-width",
101 P_("Minimum child width"),
102 P_("Minimum width of buttons inside the box"),
105 DEFAULT_CHILD_MIN_WIDTH,
106 GTK_PARAM_READABLE));
108 gtk_widget_class_install_style_property (widget_class,
109 g_param_spec_int ("child-min-height",
110 P_("Minimum child height"),
111 P_("Minimum height of buttons inside the box"),
114 DEFAULT_CHILD_MIN_HEIGHT,
115 GTK_PARAM_READABLE));
117 gtk_widget_class_install_style_property (widget_class,
118 g_param_spec_int ("child-internal-pad-x",
119 P_("Child internal width padding"),
120 P_("Amount to increase child's size on either side"),
123 DEFAULT_CHILD_IPAD_X,
124 GTK_PARAM_READABLE));
126 gtk_widget_class_install_style_property (widget_class,
127 g_param_spec_int ("child-internal-pad-y",
128 P_("Child internal height padding"),
129 P_("Amount to increase child's size on the top and bottom"),
132 DEFAULT_CHILD_IPAD_Y,
133 GTK_PARAM_READABLE));
134 g_object_class_install_property (gobject_class,
136 g_param_spec_enum ("layout-style",
138 P_("How to layout the buttons in the box. Possible values are default, spread, edge, start and end"),
139 GTK_TYPE_BUTTON_BOX_STYLE,
140 GTK_BUTTONBOX_DEFAULT_STYLE,
141 GTK_PARAM_READWRITE));
143 gtk_container_class_install_child_property (container_class,
144 CHILD_PROP_SECONDARY,
145 g_param_spec_boolean ("secondary",
147 P_("If TRUE, the child appears in a secondary group of children, suitable for, e.g., help buttons"),
149 GTK_PARAM_READWRITE));
153 gtk_button_box_init (GtkButtonBox *button_box)
155 GTK_BOX (button_box)->spacing = 0;
156 button_box->child_min_width = GTK_BUTTONBOX_DEFAULT;
157 button_box->child_min_height = GTK_BUTTONBOX_DEFAULT;
158 button_box->child_ipad_x = GTK_BUTTONBOX_DEFAULT;
159 button_box->child_ipad_y = GTK_BUTTONBOX_DEFAULT;
160 button_box->layout_style = GTK_BUTTONBOX_DEFAULT_STYLE;
164 gtk_button_box_set_property (GObject *object,
171 case PROP_LAYOUT_STYLE:
172 gtk_button_box_set_layout (GTK_BUTTON_BOX (object),
173 g_value_get_enum (value));
176 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
182 gtk_button_box_get_property (GObject *object,
189 case PROP_LAYOUT_STYLE:
190 g_value_set_enum (value, GTK_BUTTON_BOX (object)->layout_style);
193 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
199 gtk_button_box_set_child_property (GtkContainer *container,
207 case CHILD_PROP_SECONDARY:
208 gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (container), child,
209 g_value_get_boolean (value));
212 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
218 gtk_button_box_get_child_property (GtkContainer *container,
226 case CHILD_PROP_SECONDARY:
227 g_value_set_boolean (value,
228 gtk_button_box_get_child_secondary (GTK_BUTTON_BOX (container),
232 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
237 /* set per widget values for spacing, child size and child internal padding */
240 gtk_button_box_set_child_size (GtkButtonBox *widget,
241 gint width, gint height)
243 g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
245 widget->child_min_width = width;
246 widget->child_min_height = height;
250 gtk_button_box_set_child_ipadding (GtkButtonBox *widget,
251 gint ipad_x, gint ipad_y)
253 g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
255 widget->child_ipad_x = ipad_x;
256 widget->child_ipad_y = ipad_y;
260 gtk_button_box_set_layout (GtkButtonBox *widget,
261 GtkButtonBoxStyle layout_style)
263 g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
264 g_return_if_fail (layout_style >= GTK_BUTTONBOX_DEFAULT_STYLE &&
265 layout_style <= GTK_BUTTONBOX_CENTER);
267 if (widget->layout_style != layout_style)
269 widget->layout_style = layout_style;
270 g_object_notify (G_OBJECT (widget), "layout-style");
271 gtk_widget_queue_resize (GTK_WIDGET (widget));
276 /* get per widget values for spacing, child size and child internal padding */
279 gtk_button_box_get_child_size (GtkButtonBox *widget,
280 gint *width, gint *height)
282 g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
283 g_return_if_fail (width != NULL);
284 g_return_if_fail (height != NULL);
286 *width = widget->child_min_width;
287 *height = widget->child_min_height;
291 gtk_button_box_get_child_ipadding (GtkButtonBox *widget,
292 gint* ipad_x, gint *ipad_y)
294 g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
295 g_return_if_fail (ipad_x != NULL);
296 g_return_if_fail (ipad_y != NULL);
298 *ipad_x = widget->child_ipad_x;
299 *ipad_y = widget->child_ipad_y;
303 gtk_button_box_get_layout (GtkButtonBox *widget)
305 g_return_val_if_fail (GTK_IS_BUTTON_BOX (widget), GTK_BUTTONBOX_SPREAD);
307 return widget->layout_style;
311 * gtk_button_box_get_child_secondary:
312 * @widget: a #GtkButtonBox
313 * @child: a child of @widget
315 * Returns whether @child should appear in a secondary group of children.
317 * Return value: whether @child should appear in a secondary group of children.
322 gtk_button_box_get_child_secondary (GtkButtonBox *widget,
326 GtkBoxChild *child_info;
328 g_return_val_if_fail (GTK_IS_BUTTON_BOX (widget), FALSE);
329 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
332 list = GTK_BOX (widget)->children;
335 child_info = list->data;
336 if (child_info->widget == child)
342 g_return_val_if_fail (list != NULL, FALSE);
344 return child_info->is_secondary;
348 * gtk_button_box_set_child_secondary
349 * @widget: a #GtkButtonBox
350 * @child: a child of @widget
351 * @is_secondary: if %TRUE, the @child appears in a secondary group of the
354 * Sets whether @child should appear in a secondary group of children.
355 * A typical use of a secondary child is the help button in a dialog.
357 * This group appears after the other children if the style
358 * is %GTK_BUTTONBOX_START, %GTK_BUTTONBOX_SPREAD or
359 * %GTK_BUTTONBOX_EDGE, and before the other children if the style
360 * is %GTK_BUTTONBOX_END. For horizontal button boxes, the definition
361 * of before/after depends on direction of the widget (see
362 * gtk_widget_set_direction()). If the style is %GTK_BUTTONBOX_START
363 * or %GTK_BUTTONBOX_END, then the secondary children are aligned at
364 * the other end of the button box from the main children. For the
365 * other styles, they appear immediately next to the main children.
368 gtk_button_box_set_child_secondary (GtkButtonBox *widget,
370 gboolean is_secondary)
374 g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
375 g_return_if_fail (GTK_IS_WIDGET (child));
376 g_return_if_fail (child->parent == GTK_WIDGET (widget));
378 list = GTK_BOX (widget)->children;
381 GtkBoxChild *child_info = list->data;
382 if (child_info->widget == child)
384 child_info->is_secondary = is_secondary;
391 gtk_widget_child_notify (child, "secondary");
393 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (child))
394 gtk_widget_queue_resize (child);
397 /* Ask children how much space they require and round up
398 to match minimum size and internal padding.
399 Returns the size each single child should have. */
401 _gtk_button_box_child_requisition (GtkWidget *widget,
403 int *nvis_secondaries,
414 GtkRequisition child_requisition;
422 gint child_min_width;
423 gint child_min_height;
427 g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
429 bbox = GTK_BUTTON_BOX (widget);
431 gtk_widget_style_get (widget,
432 "child-min-width", &width_default,
433 "child-min-height", &height_default,
434 "child-internal-pad-x", &ipad_x_default,
435 "child-internal-pad-y", &ipad_y_default,
438 child_min_width = bbox->child_min_width != GTK_BUTTONBOX_DEFAULT
439 ? bbox->child_min_width : width_default;
440 child_min_height = bbox->child_min_height !=GTK_BUTTONBOX_DEFAULT
441 ? bbox->child_min_height : height_default;
442 ipad_x = bbox->child_ipad_x != GTK_BUTTONBOX_DEFAULT
443 ? bbox->child_ipad_x : ipad_x_default;
444 ipad_y = bbox->child_ipad_y != GTK_BUTTONBOX_DEFAULT
445 ? bbox->child_ipad_y : ipad_y_default;
449 children = GTK_BOX(bbox)->children;
450 needed_width = child_min_width;
451 needed_height = child_min_height;
457 child = children->data;
458 children = children->next;
460 if (GTK_WIDGET_VISIBLE (child->widget))
463 gtk_widget_size_request (child->widget, &child_requisition);
465 if (child_requisition.width + ipad_w > needed_width)
466 needed_width = child_requisition.width + ipad_w;
467 if (child_requisition.height + ipad_h > needed_height)
468 needed_height = child_requisition.height + ipad_h;
469 if (child->is_secondary)
475 *nvis_children = nchildren;
476 if (nvis_secondaries)
477 *nvis_secondaries = nsecondaries;
479 *width = needed_width;
481 *height = needed_height;
484 /* this is a kludge function to support the deprecated
485 * gtk_[vh]button_box_set_layout_default() just in case anyone is still
488 static GtkButtonBoxStyle
489 gtk_button_box_kludge_get_layout_default (GtkButtonBox *widget)
491 GtkOrientation orientation;
493 orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
495 if (orientation == GTK_ORIENTATION_HORIZONTAL)
496 return _gtk_hbutton_box_get_layout_default ();
498 return _gtk_vbutton_box_get_layout_default ();
502 gtk_button_box_size_request (GtkWidget *widget,
503 GtkRequisition *requisition)
511 GtkButtonBoxStyle layout;
512 GtkOrientation orientation;
514 box = GTK_BOX (widget);
515 bbox = GTK_BUTTON_BOX (widget);
517 orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
518 spacing = box->spacing;
519 layout = bbox->layout_style != GTK_BUTTONBOX_DEFAULT_STYLE
520 ? bbox->layout_style : gtk_button_box_kludge_get_layout_default (GTK_BUTTON_BOX (widget));
522 _gtk_button_box_child_requisition (widget,
528 if (nvis_children == 0)
530 requisition->width = 0;
531 requisition->height = 0;
537 case GTK_BUTTONBOX_SPREAD:
538 if (orientation == GTK_ORIENTATION_HORIZONTAL)
540 nvis_children*child_width + ((nvis_children+1)*spacing);
542 requisition->height =
543 nvis_children*child_height + ((nvis_children+1)*spacing);
546 case GTK_BUTTONBOX_EDGE:
547 case GTK_BUTTONBOX_START:
548 case GTK_BUTTONBOX_END:
549 case GTK_BUTTONBOX_CENTER:
550 if (orientation == GTK_ORIENTATION_HORIZONTAL)
552 nvis_children*child_width + ((nvis_children-1)*spacing);
554 requisition->height =
555 nvis_children*child_height + ((nvis_children-1)*spacing);
559 g_assert_not_reached ();
563 if (orientation == GTK_ORIENTATION_HORIZONTAL)
564 requisition->height = child_height;
566 requisition->width = child_width;
569 requisition->width += GTK_CONTAINER (box)->border_width * 2;
570 requisition->height += GTK_CONTAINER (box)->border_width * 2;
574 gtk_button_box_size_allocate (GtkWidget *widget,
575 GtkAllocation *allocation)
581 GtkAllocation child_allocation;
588 gint secondary_x = 0;
589 gint secondary_y = 0;
593 gint childspacing = 0;
594 GtkButtonBoxStyle layout;
596 GtkOrientation orientation;
598 orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
599 base_box = GTK_BOX (widget);
600 box = GTK_BUTTON_BOX (widget);
601 spacing = base_box->spacing;
602 layout = box->layout_style != GTK_BUTTONBOX_DEFAULT_STYLE
603 ? box->layout_style : gtk_button_box_kludge_get_layout_default (GTK_BUTTON_BOX (widget));
604 _gtk_button_box_child_requisition (widget,
609 widget->allocation = *allocation;
611 if (orientation == GTK_ORIENTATION_HORIZONTAL)
612 width = allocation->width - GTK_CONTAINER (box)->border_width*2;
614 height = allocation->height - GTK_CONTAINER (box)->border_width*2;
618 case GTK_BUTTONBOX_SPREAD:
620 if (orientation == GTK_ORIENTATION_HORIZONTAL)
622 childspacing = (width - (nvis_children * child_width))
623 / (nvis_children + 1);
624 x = allocation->x + GTK_CONTAINER (box)->border_width
626 secondary_x = x + ((nvis_children - n_secondaries)
627 * (child_width + childspacing));
631 childspacing = (height - (nvis_children * child_height))
632 / (nvis_children + 1);
633 y = allocation->y + GTK_CONTAINER (box)->border_width
635 secondary_y = y + ((nvis_children - n_secondaries)
636 * (child_height + childspacing));
641 case GTK_BUTTONBOX_EDGE:
643 if (orientation == GTK_ORIENTATION_HORIZONTAL)
645 if (nvis_children >= 2)
647 childspacing = (width - (nvis_children * child_width))
648 / (nvis_children - 1);
649 x = allocation->x + GTK_CONTAINER (box)->border_width;
650 secondary_x = x + ((nvis_children - n_secondaries)
651 * (child_width + childspacing));
655 /* one or zero children, just center */
656 childspacing = width;
657 x = secondary_x = allocation->x
658 + (allocation->width - child_width) / 2;
663 if (nvis_children >= 2)
665 childspacing = (height - (nvis_children*child_height))
667 y = allocation->y + GTK_CONTAINER (box)->border_width;
668 secondary_y = y + ((nvis_children - n_secondaries)
669 * (child_height + childspacing));
673 /* one or zero children, just center */
674 childspacing = height;
675 y = secondary_y = allocation->y
676 + (allocation->height - child_height) / 2;
682 case GTK_BUTTONBOX_START:
684 if (orientation == GTK_ORIENTATION_HORIZONTAL)
686 childspacing = spacing;
687 x = allocation->x + GTK_CONTAINER (box)->border_width;
688 secondary_x = allocation->x + allocation->width
689 - child_width * n_secondaries
690 - spacing * (n_secondaries - 1)
691 - GTK_CONTAINER (box)->border_width;
695 childspacing = spacing;
696 y = allocation->y + GTK_CONTAINER (box)->border_width;
697 secondary_y = allocation->y + allocation->height
698 - child_height * n_secondaries
699 - spacing * (n_secondaries - 1)
700 - GTK_CONTAINER (box)->border_width;
705 case GTK_BUTTONBOX_END:
707 if (orientation == GTK_ORIENTATION_HORIZONTAL)
709 childspacing = spacing;
710 x = allocation->x + allocation->width
711 - child_width * (nvis_children - n_secondaries)
712 - spacing * (nvis_children - n_secondaries - 1)
713 - GTK_CONTAINER (box)->border_width;
714 secondary_x = allocation->x + GTK_CONTAINER (box)->border_width;
718 childspacing = spacing;
719 y = allocation->y + allocation->height
720 - child_height * (nvis_children - n_secondaries)
721 - spacing * (nvis_children - n_secondaries - 1)
722 - GTK_CONTAINER (box)->border_width;
723 secondary_y = allocation->y + GTK_CONTAINER (box)->border_width;
728 case GTK_BUTTONBOX_CENTER:
730 if (orientation == GTK_ORIENTATION_HORIZONTAL)
732 childspacing = spacing;
735 - (child_width * (nvis_children - n_secondaries)
736 + spacing * (nvis_children - n_secondaries - 1))) / 2
737 + (n_secondaries * child_width + n_secondaries * spacing) / 2;
738 secondary_x = allocation->x + GTK_CONTAINER (box)->border_width;
742 childspacing = spacing;
745 - (child_height * (nvis_children - n_secondaries)
746 + spacing * (nvis_children - n_secondaries - 1))) / 2
747 + (n_secondaries * child_height + n_secondaries * spacing) / 2;
748 secondary_y = allocation->y + GTK_CONTAINER (box)->border_width;
754 g_assert_not_reached ();
758 if (orientation == GTK_ORIENTATION_HORIZONTAL)
760 y = allocation->y + (allocation->height - child_height) / 2;
761 childspace = child_width + childspacing;
765 x = allocation->x + (allocation->width - child_width) / 2;
766 childspace = child_height + childspacing;
769 children = GTK_BOX (box)->children;
773 child = children->data;
774 children = children->next;
776 if (GTK_WIDGET_VISIBLE (child->widget))
778 child_allocation.width = child_width;
779 child_allocation.height = child_height;
781 if (orientation == GTK_ORIENTATION_HORIZONTAL)
783 child_allocation.y = y;
785 if (child->is_secondary)
787 child_allocation.x = secondary_x;
788 secondary_x += childspace;
792 child_allocation.x = x;
796 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
797 child_allocation.x = (allocation->x + allocation->width)
798 - (child_allocation.x + child_width - allocation->x);
802 child_allocation.x = x;
804 if (child->is_secondary)
806 child_allocation.y = secondary_y;
807 secondary_y += childspace;
811 child_allocation.y = y;
816 gtk_widget_size_allocate (child->widget, &child_allocation);
821 #define __GTK_BUTTON_BOX_C__
822 #include "gtkaliasdef.c"