1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
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.
8 *
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.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /*
19 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 */
24
25 /**
26 * SECTION:gtkbbox
27 * @Short_description: A container for arranging buttons
28 * @Title: GtkButtonBox
29 *
30 * A button box should be used to provide a consistent layout of buttons
31 * throughout your application. The layout/spacing can be altered by the
32 * programmer, or if desired, by the user to alter the “feel” of a
33 * program to a small degree.
34 *
35 * gtk_button_box_get_layout() and gtk_button_box_set_layout() retrieve and
36 * alter the method used to spread the buttons in a button box across the
37 * container, respectively.
38 *
39 * The main purpose of GtkButtonBox is to make sure the children have all the
40 * same size. GtkButtonBox gives all children the same size, but it does allow
41 * 'outliers' to keep their own larger size.
42 *
43 * To exempt individual children from homogeneous sizing regardless of their
44 * 'outlier' status, you can set the non-homogeneous child
45 * property.
46 *
47 * # CSS nodes
48 *
49 * GtkButtonBox uses a single CSS node with name buttonbox.
50 */
51
52 #include "config.h"
53
54 #include "gtkbbox.h"
55
56 #include "gtkboxprivate.h"
57 #include "gtkorientable.h"
58 #include "gtktypebuiltins.h"
59 #include "gtkprivate.h"
60 #include "gtksizerequest.h"
61 #include "gtkwidgetprivate.h"
62 #include "gtkcontainerprivate.h"
63 #include "gtkcsscustomgadgetprivate.h"
64 #include "gtkintl.h"
65
66
67 struct _GtkButtonBoxPrivate
68 {
69 GtkButtonBoxStyle layout_style;
70 GtkCssGadget *gadget;
71 };
72
73 enum {
74 PROP_0,
75 PROP_LAYOUT_STYLE
76 };
77
78 enum {
79 CHILD_PROP_0,
80 CHILD_PROP_SECONDARY,
81 CHILD_PROP_NONHOMOGENEOUS
82 };
83
84 #define GTK_BOX_SECONDARY_CHILD "gtk-box-secondary-child"
85 #define GTK_BOX_NON_HOMOGENEOUS "gtk-box-non-homogeneous"
86
87 static void gtk_button_box_set_property (GObject *object,
88 guint prop_id,
89 const GValue *value,
90 GParamSpec *pspec);
91 static void gtk_button_box_get_property (GObject *object,
92 guint prop_id,
93 GValue *value,
94 GParamSpec *pspec);
95 static gboolean gtk_button_box_draw (GtkWidget *widget,
96 cairo_t *cr);
97 static void gtk_button_box_get_preferred_width (GtkWidget *widget,
98 gint *minimum,
99 gint *natural);
100 static void gtk_button_box_get_preferred_height (GtkWidget *widget,
101 gint *minimum,
102 gint *natural);
103 static void gtk_button_box_get_preferred_width_for_height (GtkWidget *widget,
104 gint height,
105 gint *minimum,
106 gint *natural);
107 static void gtk_button_box_get_preferred_height_for_width (GtkWidget *widget,
108 gint width,
109 gint *minimum,
110 gint *natural);
111 static void gtk_button_box_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
112 gint width,
113 gint *minimum,
114 gint *natural,
115 gint *minimum_baseline,
116 gint *natural_baseline);
117
118 static void gtk_button_box_size_allocate (GtkWidget *widget,
119 GtkAllocation *allocation);
120 static void gtk_button_box_remove (GtkContainer *container,
121 GtkWidget *widget);
122 static void gtk_button_box_set_child_property (GtkContainer *container,
123 GtkWidget *child,
124 guint property_id,
125 const GValue *value,
126 GParamSpec *pspec);
127 static void gtk_button_box_get_child_property (GtkContainer *container,
128 GtkWidget *child,
129 guint property_id,
130 GValue *value,
131 GParamSpec *pspec);
132
133 static void gtk_button_box_measure (GtkCssGadget *gadget,
134 GtkOrientation orientation,
135 int for_size,
136 int *minimum,
137 int *natural,
138 int *minimum_baseline,
139 int *natural_baseline,
140 gpointer unused);
141 static void gtk_button_box_allocate (GtkCssGadget *gadget,
142 const GtkAllocation *allocation,
143 int baseline,
144 GtkAllocation *out_clip,
145 gpointer unused);
146 static gboolean gtk_button_box_render (GtkCssGadget *gadget,
147 cairo_t *cr,
148 int x,
149 int y,
150 int width,
151 int height,
152 gpointer data);
153
154 #define DEFAULT_CHILD_MIN_WIDTH 85
155 #define DEFAULT_CHILD_MIN_HEIGHT 27
156 #define DEFAULT_CHILD_IPAD_X 4
157 #define DEFAULT_CHILD_IPAD_Y 0
158 #define DEFAULT_LAYOUT_STYLE GTK_BUTTONBOX_EDGE
159
G_DEFINE_TYPE_WITH_PRIVATE(GtkButtonBox,gtk_button_box,GTK_TYPE_BOX)160 G_DEFINE_TYPE_WITH_PRIVATE (GtkButtonBox, gtk_button_box, GTK_TYPE_BOX)
161
162 static void
163 gtk_button_box_add (GtkContainer *container,
164 GtkWidget *widget)
165 {
166 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
167 }
168
169 static void
gtk_button_box_finalize(GObject * object)170 gtk_button_box_finalize (GObject *object)
171 {
172 GtkButtonBox *button_box = GTK_BUTTON_BOX (object);
173
174 g_clear_object (&button_box->priv->gadget);
175
176 G_OBJECT_CLASS (gtk_button_box_parent_class)->finalize (object);
177 }
178
179 static void
gtk_button_box_class_init(GtkButtonBoxClass * class)180 gtk_button_box_class_init (GtkButtonBoxClass *class)
181 {
182 GtkWidgetClass *widget_class;
183 GObjectClass *gobject_class;
184 GtkContainerClass *container_class;
185
186 gobject_class = G_OBJECT_CLASS (class);
187 widget_class = (GtkWidgetClass*) class;
188 container_class = (GtkContainerClass*) class;
189
190 gobject_class->set_property = gtk_button_box_set_property;
191 gobject_class->get_property = gtk_button_box_get_property;
192 gobject_class->finalize = gtk_button_box_finalize;
193
194 widget_class->get_preferred_width = gtk_button_box_get_preferred_width;
195 widget_class->get_preferred_height = gtk_button_box_get_preferred_height;
196 widget_class->get_preferred_width_for_height = gtk_button_box_get_preferred_width_for_height;
197 widget_class->get_preferred_height_for_width = gtk_button_box_get_preferred_height_for_width;
198 widget_class->get_preferred_height_and_baseline_for_width = gtk_button_box_get_preferred_height_and_baseline_for_width;
199 widget_class->size_allocate = gtk_button_box_size_allocate;
200 widget_class->draw = gtk_button_box_draw;
201
202 container_class->remove = gtk_button_box_remove;
203 container_class->add = gtk_button_box_add;
204 container_class->set_child_property = gtk_button_box_set_child_property;
205 container_class->get_child_property = gtk_button_box_get_child_property;
206 gtk_container_class_handle_border_width (container_class);
207
208 /**
209 * GtkButtonBox:child-min-width:
210 *
211 * The minimum width of buttons inside the box.
212 *
213 * Deprecated: 3.20: Use CSS min-width instead.
214 */
215 gtk_widget_class_install_style_property (widget_class,
216 g_param_spec_int ("child-min-width",
217 P_("Minimum child width"),
218 P_("Minimum width of buttons inside the box"),
219 0,
220 G_MAXINT,
221 DEFAULT_CHILD_MIN_WIDTH,
222 GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
223
224 /**
225 * GtkButtonBox:child-min-height:
226 *
227 * The minimum height of buttons inside the box.
228 *
229 * Deprecated: 3.20: Use CSS min-height instead.
230 */
231 gtk_widget_class_install_style_property (widget_class,
232 g_param_spec_int ("child-min-height",
233 P_("Minimum child height"),
234 P_("Minimum height of buttons inside the box"),
235 0,
236 G_MAXINT,
237 DEFAULT_CHILD_MIN_HEIGHT,
238 GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
239
240 /**
241 * GtkButtonBox:child-internal-pad-x:
242 *
243 * The amount to increase a child's size on either side.
244 *
245 * Deprecated: 3.20: Use CSS padding instead.
246 */
247 gtk_widget_class_install_style_property (widget_class,
248 g_param_spec_int ("child-internal-pad-x",
249 P_("Child internal width padding"),
250 P_("Amount to increase child's size on either side"),
251 0,
252 G_MAXINT,
253 DEFAULT_CHILD_IPAD_X,
254 GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
255
256 /**
257 * GtkButtonBox:child-internal-pad-y:
258 *
259 * The amount to increase a child's size on the top and bottom.
260 *
261 * Deprecated: 3.20: Use CSS padding instead.
262 */
263 gtk_widget_class_install_style_property (widget_class,
264 g_param_spec_int ("child-internal-pad-y",
265 P_("Child internal height padding"),
266 P_("Amount to increase child's size on the top and bottom"),
267 0,
268 G_MAXINT,
269 DEFAULT_CHILD_IPAD_Y,
270 GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
271
272 g_object_class_install_property (gobject_class,
273 PROP_LAYOUT_STYLE,
274 g_param_spec_enum ("layout-style",
275 P_("Layout style"),
276 P_("How to lay out the buttons in the box. Possible values are: spread, edge, start and end"),
277 GTK_TYPE_BUTTON_BOX_STYLE,
278 DEFAULT_LAYOUT_STYLE,
279 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
280
281 gtk_container_class_install_child_property (container_class,
282 CHILD_PROP_SECONDARY,
283 g_param_spec_boolean ("secondary",
284 P_("Secondary"),
285 P_("If TRUE, the child appears in a secondary group of children, suitable for, e.g., help buttons"),
286 FALSE,
287 GTK_PARAM_READWRITE));
288
289 gtk_container_class_install_child_property (container_class,
290 CHILD_PROP_NONHOMOGENEOUS,
291 g_param_spec_boolean ("non-homogeneous",
292 P_("Non-Homogeneous"),
293 P_("If TRUE, the child will not be subject to homogeneous sizing"),
294 FALSE,
295 GTK_PARAM_READWRITE));
296
297 gtk_widget_class_set_css_name (widget_class, "buttonbox");
298 }
299
300 static gboolean
gtk_button_box_render(GtkCssGadget * gadget,cairo_t * cr,int x,int y,int width,int height,gpointer unused)301 gtk_button_box_render (GtkCssGadget *gadget,
302 cairo_t *cr,
303 int x,
304 int y,
305 int width,
306 int height,
307 gpointer unused)
308 {
309 GtkWidget *widget;
310 GList *children, *l;
311
312 widget = gtk_css_gadget_get_owner (gadget);
313 children = gtk_container_get_children (GTK_CONTAINER (widget));
314
315 for (l = children; l; l = l->next)
316 {
317 GtkWidget *child = l->data;
318
319 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
320 }
321
322 g_list_free (children);
323
324 return FALSE;
325 }
326
327
328 static gboolean
gtk_button_box_draw(GtkWidget * widget,cairo_t * cr)329 gtk_button_box_draw (GtkWidget *widget,
330 cairo_t *cr)
331 {
332 GtkButtonBoxPrivate *priv = GTK_BUTTON_BOX (widget)->priv;
333 GtkCssGadget *gadget;
334
335 if (priv->layout_style == GTK_BUTTONBOX_EXPAND)
336 gadget = gtk_box_get_gadget (GTK_BOX (widget));
337 else
338 gadget = priv->gadget;
339
340 gtk_css_gadget_draw (gadget, cr);
341
342 return FALSE;
343 }
344
345 static void
gtk_button_box_init(GtkButtonBox * button_box)346 gtk_button_box_init (GtkButtonBox *button_box)
347 {
348 button_box->priv = gtk_button_box_get_instance_private (button_box);
349 button_box->priv->layout_style = DEFAULT_LAYOUT_STYLE;
350
351 gtk_box_set_spacing (GTK_BOX (button_box), 0);
352
353 button_box->priv->gadget = gtk_css_custom_gadget_new_for_node (gtk_widget_get_css_node (GTK_WIDGET (button_box)),
354 GTK_WIDGET (button_box),
355 gtk_button_box_measure,
356 gtk_button_box_allocate,
357 gtk_button_box_render,
358 NULL,
359 NULL);
360 }
361
362 static void
gtk_button_box_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)363 gtk_button_box_set_property (GObject *object,
364 guint prop_id,
365 const GValue *value,
366 GParamSpec *pspec)
367 {
368 switch (prop_id)
369 {
370 case PROP_LAYOUT_STYLE:
371 gtk_button_box_set_layout (GTK_BUTTON_BOX (object),
372 g_value_get_enum (value));
373 break;
374 default:
375 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
376 break;
377 }
378 }
379
380 static void
gtk_button_box_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)381 gtk_button_box_get_property (GObject *object,
382 guint prop_id,
383 GValue *value,
384 GParamSpec *pspec)
385 {
386 GtkButtonBoxPrivate *priv = GTK_BUTTON_BOX (object)->priv;
387
388 switch (prop_id)
389 {
390 case PROP_LAYOUT_STYLE:
391 g_value_set_enum (value, priv->layout_style);
392 break;
393 default:
394 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
395 break;
396 }
397 }
398
399 static void
gtk_button_box_set_child_property(GtkContainer * container,GtkWidget * child,guint property_id,const GValue * value,GParamSpec * pspec)400 gtk_button_box_set_child_property (GtkContainer *container,
401 GtkWidget *child,
402 guint property_id,
403 const GValue *value,
404 GParamSpec *pspec)
405 {
406 switch (property_id)
407 {
408 case CHILD_PROP_SECONDARY:
409 gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (container), child,
410 g_value_get_boolean (value));
411 break;
412 case CHILD_PROP_NONHOMOGENEOUS:
413 gtk_button_box_set_child_non_homogeneous (GTK_BUTTON_BOX (container), child,
414 g_value_get_boolean (value));
415 break;
416 default:
417 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
418 break;
419 }
420 }
421
422 static void
gtk_button_box_get_child_property(GtkContainer * container,GtkWidget * child,guint property_id,GValue * value,GParamSpec * pspec)423 gtk_button_box_get_child_property (GtkContainer *container,
424 GtkWidget *child,
425 guint property_id,
426 GValue *value,
427 GParamSpec *pspec)
428 {
429 switch (property_id)
430 {
431 case CHILD_PROP_SECONDARY:
432 g_value_set_boolean (value,
433 gtk_button_box_get_child_secondary (GTK_BUTTON_BOX (container),
434 child));
435 break;
436 case CHILD_PROP_NONHOMOGENEOUS:
437 g_value_set_boolean (value,
438 gtk_button_box_get_child_non_homogeneous (GTK_BUTTON_BOX (container),
439 child));
440 break;
441 default:
442 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
443 break;
444 }
445 }
446
447 static void
gtk_button_box_remove(GtkContainer * container,GtkWidget * widget)448 gtk_button_box_remove (GtkContainer *container,
449 GtkWidget *widget)
450 {
451 /* clear is_secondary and nonhomogeneous flag in case the widget
452 * is added to another container
453 */
454 gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (container), widget, FALSE);
455 gtk_button_box_set_child_non_homogeneous (GTK_BUTTON_BOX (container), widget, FALSE);
456
457 GTK_CONTAINER_CLASS (gtk_button_box_parent_class)->remove (container, widget);
458 }
459
460 /**
461 * gtk_button_box_set_layout:
462 * @widget: a #GtkButtonBox
463 * @layout_style: the new layout style
464 *
465 * Changes the way buttons are arranged in their container.
466 */
467 void
gtk_button_box_set_layout(GtkButtonBox * widget,GtkButtonBoxStyle layout_style)468 gtk_button_box_set_layout (GtkButtonBox *widget,
469 GtkButtonBoxStyle layout_style)
470 {
471 GtkButtonBoxPrivate *priv;
472
473 g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
474
475 priv = widget->priv;
476
477 if (priv->layout_style != layout_style)
478 {
479 priv->layout_style = layout_style;
480
481 if (priv->layout_style == GTK_BUTTONBOX_EXPAND)
482 {
483 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (widget)), "linked");
484 gtk_box_set_spacing (GTK_BOX (widget), 0);
485 gtk_box_set_homogeneous (GTK_BOX (widget), TRUE);
486 }
487 else
488 {
489 gtk_style_context_remove_class (gtk_widget_get_style_context (GTK_WIDGET (widget)), "linked");
490 gtk_box_set_homogeneous (GTK_BOX (widget), FALSE);
491 }
492
493 g_object_notify (G_OBJECT (widget), "layout-style");
494 gtk_widget_queue_resize (GTK_WIDGET (widget));
495 }
496 }
497
498 /**
499 * gtk_button_box_get_layout:
500 * @widget: a #GtkButtonBox
501 *
502 * Retrieves the method being used to arrange the buttons in a button box.
503 *
504 * Returns: the method used to lay out buttons in @widget.
505 */
506 GtkButtonBoxStyle
gtk_button_box_get_layout(GtkButtonBox * widget)507 gtk_button_box_get_layout (GtkButtonBox *widget)
508 {
509 g_return_val_if_fail (GTK_IS_BUTTON_BOX (widget), DEFAULT_LAYOUT_STYLE);
510
511 return widget->priv->layout_style;
512 }
513
514 /**
515 * gtk_button_box_get_child_secondary:
516 * @widget: a #GtkButtonBox
517 * @child: a child of @widget
518 *
519 * Returns whether @child should appear in a secondary group of children.
520 *
521 * Returns: whether @child should appear in a secondary group of children.
522 *
523 * Since: 2.4
524 **/
525 gboolean
gtk_button_box_get_child_secondary(GtkButtonBox * widget,GtkWidget * child)526 gtk_button_box_get_child_secondary (GtkButtonBox *widget,
527 GtkWidget *child)
528 {
529 g_return_val_if_fail (GTK_IS_BUTTON_BOX (widget), FALSE);
530 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
531
532 return (g_object_get_data (G_OBJECT (child), GTK_BOX_SECONDARY_CHILD) != NULL);
533 }
534
535 /**
536 * gtk_button_box_set_child_secondary:
537 * @widget: a #GtkButtonBox
538 * @child: a child of @widget
539 * @is_secondary: if %TRUE, the @child appears in a secondary group of the
540 * button box.
541 *
542 * Sets whether @child should appear in a secondary group of children.
543 * A typical use of a secondary child is the help button in a dialog.
544 *
545 * This group appears after the other children if the style
546 * is %GTK_BUTTONBOX_START, %GTK_BUTTONBOX_SPREAD or
547 * %GTK_BUTTONBOX_EDGE, and before the other children if the style
548 * is %GTK_BUTTONBOX_END. For horizontal button boxes, the definition
549 * of before/after depends on direction of the widget (see
550 * gtk_widget_set_direction()). If the style is %GTK_BUTTONBOX_START
551 * or %GTK_BUTTONBOX_END, then the secondary children are aligned at
552 * the other end of the button box from the main children. For the
553 * other styles, they appear immediately next to the main children.
554 **/
555 void
gtk_button_box_set_child_secondary(GtkButtonBox * widget,GtkWidget * child,gboolean is_secondary)556 gtk_button_box_set_child_secondary (GtkButtonBox *widget,
557 GtkWidget *child,
558 gboolean is_secondary)
559 {
560 GtkButtonBox *bbox;
561
562 g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
563 g_return_if_fail (GTK_IS_WIDGET (child));
564 g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (widget));
565
566 bbox = GTK_BUTTON_BOX (widget);
567
568 g_object_set_data (G_OBJECT (child),
569 GTK_BOX_SECONDARY_CHILD,
570 is_secondary ? GINT_TO_POINTER (1) : NULL);
571 gtk_widget_child_notify (child, "secondary");
572
573 if (bbox->priv->layout_style == GTK_BUTTONBOX_EXPAND)
574 {
575 gtk_box_reorder_child (GTK_BOX (bbox), child, is_secondary ? 0 : -1);
576 }
577
578 if (gtk_widget_get_visible (GTK_WIDGET (widget)) &&
579 gtk_widget_get_visible (child))
580 gtk_widget_queue_resize (child);
581 }
582
583 /* Ask children how much space they require and round up
584 * to match minimum size and internal padding.
585 * Returns the size each single child should have.
586 */
587 static void
gtk_button_box_child_requisition(GtkWidget * widget,gint * nvis_children,gint * nvis_secondaries,gint ** widths,gint ** heights,gint ** baselines,gint * baseline,gint * baseline_height)588 gtk_button_box_child_requisition (GtkWidget *widget,
589 gint *nvis_children,
590 gint *nvis_secondaries,
591 gint **widths,
592 gint **heights,
593 gint **baselines,
594 gint *baseline,
595 gint *baseline_height)
596 {
597 GtkButtonBox *bbox;
598 GList *children, *list;
599 gint nchildren;
600 gint nsecondaries;
601 gint needed_width;
602 gint needed_height;
603 gint needed_above, needed_below;
604 gint avg_w, avg_h;
605 GtkRequisition child_requisition;
606 gint ipad_w;
607 gint ipad_h;
608 gint child_min_width;
609 gint child_min_height;
610 gint ipad_x;
611 gint ipad_y;
612 gboolean homogeneous;
613 gint i;
614 gint max_above, max_below, child_baseline;
615 GtkOrientation orientation;
616 gboolean have_baseline;
617
618 g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
619
620 bbox = GTK_BUTTON_BOX (widget);
621
622 orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
623 homogeneous = gtk_box_get_homogeneous (GTK_BOX (widget));
624
625 gtk_widget_style_get (widget,
626 "child-min-width", &child_min_width,
627 "child-min-height", &child_min_height,
628 "child-internal-pad-x", &ipad_x,
629 "child-internal-pad-y", &ipad_y,
630 NULL);
631
632 nchildren = 0;
633 nsecondaries = 0;
634 list = children = _gtk_box_get_children (GTK_BOX (bbox));
635 needed_width = child_min_width;
636 needed_height = child_min_height;
637 needed_above = 0;
638 needed_below = 0;
639 ipad_w = ipad_x * 2;
640 ipad_h = ipad_y * 2;
641
642 have_baseline = FALSE;
643 max_above = max_below = 0;
644 avg_w = avg_h = 0;
645 for (children = list; children != NULL; children = children->next)
646 {
647 GtkWidget *child;
648
649 child = children->data;
650
651 if (gtk_widget_get_visible (child))
652 {
653 nchildren += 1;
654 _gtk_widget_get_preferred_size_and_baseline (child,
655 &child_requisition, NULL, &child_baseline, NULL);
656 if (orientation == GTK_ORIENTATION_HORIZONTAL &&
657 gtk_widget_get_valign_with_baseline (child) == GTK_ALIGN_BASELINE &&
658 child_baseline != -1)
659 {
660 have_baseline = TRUE;
661 max_above = MAX (max_above, child_baseline + ipad_y);
662 max_below = MAX (max_below , child_requisition.height + ipad_h - (child_baseline + ipad_y));
663 }
664 avg_w += child_requisition.width + ipad_w;
665 avg_h += child_requisition.height + ipad_h;
666 }
667 }
668 avg_w /= MAX (nchildren, 1);
669 avg_h /= MAX (nchildren, 1);
670
671 if (baseline)
672 *baseline = have_baseline ? max_above : -1;
673 if (baseline_height)
674 *baseline_height = max_above + max_below;
675
676 *widths = g_new (gint, nchildren);
677 *heights = g_new (gint, nchildren);
678 *baselines = g_new (gint, nchildren);
679
680 i = 0;
681 children = list;
682 while (children)
683 {
684 GtkWidget *child;
685 gboolean is_secondary;
686 gboolean non_homogeneous;
687
688 child = children->data;
689 children = children->next;
690
691 if (gtk_widget_get_visible (child))
692 {
693 is_secondary = gtk_button_box_get_child_secondary (bbox, child);
694 non_homogeneous = gtk_button_box_get_child_non_homogeneous (bbox, child);
695
696 if (is_secondary)
697 nsecondaries++;
698
699 _gtk_widget_get_preferred_size_and_baseline (child,
700 &child_requisition, NULL, &child_baseline, NULL);
701
702 if (homogeneous ||
703 (!non_homogeneous && (child_requisition.width + ipad_w < avg_w * 1.5)))
704 {
705 (*widths)[i] = -1;
706 if (child_requisition.width + ipad_w > needed_width)
707 needed_width = child_requisition.width + ipad_w;
708 }
709 else
710 {
711 (*widths)[i] = child_requisition.width + ipad_w;
712 }
713
714 (*baselines)[i] = -1;
715
716 if (homogeneous ||
717 (!non_homogeneous && (child_requisition.height + ipad_h < avg_h * 1.5)))
718 {
719 (*heights)[i] = -1;
720
721 if (orientation == GTK_ORIENTATION_HORIZONTAL &&
722 gtk_widget_get_valign_with_baseline (child) == GTK_ALIGN_BASELINE &&
723 child_baseline != -1)
724 {
725 (*baselines)[i] = child_baseline + ipad_y;
726
727 if (child_baseline + ipad_y > needed_above)
728 needed_above = child_baseline + ipad_y;
729 if (child_requisition.height - child_baseline + ipad_y > needed_below)
730 needed_below = child_requisition.height - child_baseline + ipad_y;
731 }
732 else
733 {
734 if (child_requisition.height + ipad_h > needed_height)
735 needed_height = child_requisition.height + ipad_h;
736 }
737 }
738 else
739 {
740 (*heights)[i] = child_requisition.height + ipad_h;
741
742 if (orientation == GTK_ORIENTATION_HORIZONTAL &&
743 gtk_widget_get_valign_with_baseline (child) == GTK_ALIGN_BASELINE &&
744 child_baseline != -1)
745 (*baselines)[i] = child_baseline + ipad_y;
746 }
747
748 i++;
749 }
750 }
751
752 g_list_free (list);
753
754 needed_height = MAX (needed_height, needed_above + needed_below);
755
756 for (i = 0; i < nchildren; i++)
757 {
758 if ((*widths)[i] == -1)
759 (*widths)[i] = needed_width;
760 if ((*heights)[i] == -1)
761 {
762 (*heights)[i] = needed_height;
763 if ((*baselines)[i] != -1)
764 (*baselines)[i] = needed_above;
765 }
766 }
767
768 if (nvis_children)
769 *nvis_children = nchildren;
770
771 if (nvis_secondaries)
772 *nvis_secondaries = nsecondaries;
773 }
774
775 static void
gtk_button_box_size_request(GtkWidget * widget,GtkRequisition * requisition,gint * baseline)776 gtk_button_box_size_request (GtkWidget *widget,
777 GtkRequisition *requisition,
778 gint *baseline)
779 {
780 GtkButtonBoxPrivate *priv;
781 GtkButtonBox *bbox;
782 gint nvis_children;
783 gint max_size, max_above, max_below;
784 gint total_size;
785 gint spacing;
786 GtkOrientation orientation;
787 gint *widths;
788 gint *heights;
789 gint *baselines;
790 gint i;
791
792 if (baseline)
793 *baseline = -1;
794
795 bbox = GTK_BUTTON_BOX (widget);
796 priv = bbox->priv;
797
798 orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
799 spacing = gtk_box_get_spacing (GTK_BOX (widget));
800
801 gtk_button_box_child_requisition (widget,
802 &nvis_children,
803 NULL,
804 &widths, &heights, &baselines, baseline, NULL);
805
806 max_size = max_above = max_below = 0;
807 total_size = 0;
808 for (i = 0; i < nvis_children; i++)
809 {
810 if (orientation == GTK_ORIENTATION_HORIZONTAL)
811 {
812 total_size += widths[i];
813 if (baselines[i] == -1)
814 max_size = MAX (max_size, heights[i]);
815 else
816 {
817 max_above = MAX (max_above, baselines[i]);
818 max_below = MAX (max_below, heights[i] - baselines[i]);
819 }
820 }
821 else
822 {
823 total_size += heights[i];
824 max_size = MAX (max_size, widths[i]);
825 }
826 }
827 g_free (widths);
828 g_free (heights);
829 g_free (baselines);
830
831 max_size = MAX (max_size, max_above + max_below);
832
833 switch (gtk_box_get_baseline_position (GTK_BOX (widget)))
834 {
835 case GTK_BASELINE_POSITION_TOP:
836 break;
837 case GTK_BASELINE_POSITION_CENTER:
838 if (baseline != NULL && *baseline != -1)
839 *baseline += (max_size - (max_above + max_below)) / 2;
840 break;
841 case GTK_BASELINE_POSITION_BOTTOM:
842 if (baseline != NULL && *baseline != -1)
843 *baseline += max_size - (max_above + max_below);
844 break;
845 }
846
847 if (nvis_children == 0)
848 {
849 requisition->width = 0;
850 requisition->height = 0;
851 }
852 else
853 {
854 switch (priv->layout_style)
855 {
856 case GTK_BUTTONBOX_SPREAD:
857 if (orientation == GTK_ORIENTATION_HORIZONTAL)
858 requisition->width = total_size + ((nvis_children + 1)*spacing);
859 else
860 requisition->height = total_size + ((nvis_children + 1)*spacing);
861
862 break;
863 case GTK_BUTTONBOX_EDGE:
864 case GTK_BUTTONBOX_START:
865 case GTK_BUTTONBOX_END:
866 case GTK_BUTTONBOX_CENTER:
867 case GTK_BUTTONBOX_EXPAND:
868 if (orientation == GTK_ORIENTATION_HORIZONTAL)
869 requisition->width = total_size + ((nvis_children - 1)*spacing);
870 else
871 requisition->height = total_size + ((nvis_children - 1)*spacing);
872
873 break;
874 default:
875 g_assert_not_reached ();
876 break;
877 }
878
879 if (orientation == GTK_ORIENTATION_HORIZONTAL)
880 requisition->height = max_size;
881 else
882 requisition->width = max_size;
883 }
884 }
885
886 static void
gtk_button_box_measure(GtkCssGadget * gadget,GtkOrientation orientation,int for_size,int * minimum,int * natural,int * minimum_baseline,int * natural_baseline,gpointer unused)887 gtk_button_box_measure (GtkCssGadget *gadget,
888 GtkOrientation orientation,
889 int for_size,
890 int *minimum,
891 int *natural,
892 int *minimum_baseline,
893 int *natural_baseline,
894 gpointer unused)
895 {
896 GtkWidget *widget;
897 GtkRequisition requisition;
898 int baseline;
899 int *pb;
900
901 if (minimum_baseline || natural_baseline)
902 pb = &baseline;
903 else
904 pb = NULL;
905
906 widget = gtk_css_gadget_get_owner (gadget);
907 gtk_button_box_size_request (widget, &requisition, pb);
908
909 if (orientation == GTK_ORIENTATION_HORIZONTAL)
910 *minimum = *natural = requisition.width;
911 else
912 *minimum = *natural = requisition.height;
913
914 if (minimum_baseline)
915 *minimum_baseline = baseline;
916 if (natural_baseline)
917 *natural_baseline = baseline;
918 }
919
920 static void
gtk_button_box_get_preferred_width(GtkWidget * widget,gint * minimum,gint * natural)921 gtk_button_box_get_preferred_width (GtkWidget *widget,
922 gint *minimum,
923 gint *natural)
924 {
925 GtkButtonBoxPrivate *priv = GTK_BUTTON_BOX (widget)->priv;
926 GtkCssGadget *gadget;
927
928 if (priv->layout_style == GTK_BUTTONBOX_EXPAND)
929 gadget = gtk_box_get_gadget (GTK_BOX (widget));
930 else
931 gadget = priv->gadget;
932
933 gtk_css_gadget_get_preferred_size (gadget,
934 GTK_ORIENTATION_HORIZONTAL,
935 -1,
936 minimum, natural,
937 NULL, NULL);
938 }
939
940 static void
gtk_button_box_get_preferred_height(GtkWidget * widget,gint * minimum,gint * natural)941 gtk_button_box_get_preferred_height (GtkWidget *widget,
942 gint *minimum,
943 gint *natural)
944 {
945 GtkButtonBoxPrivate *priv = GTK_BUTTON_BOX (widget)->priv;
946 GtkCssGadget *gadget;
947
948 if (priv->layout_style == GTK_BUTTONBOX_EXPAND)
949 gadget = gtk_box_get_gadget (GTK_BOX (widget));
950 else
951 gadget = priv->gadget;
952
953 gtk_css_gadget_get_preferred_size (gadget,
954 GTK_ORIENTATION_VERTICAL,
955 -1,
956 minimum, natural,
957 NULL, NULL);
958 }
959
960 static void
gtk_button_box_get_preferred_width_for_height(GtkWidget * widget,gint height,gint * minimum,gint * natural)961 gtk_button_box_get_preferred_width_for_height (GtkWidget *widget,
962 gint height,
963 gint *minimum,
964 gint *natural)
965 {
966 GtkButtonBoxPrivate *priv = GTK_BUTTON_BOX (widget)->priv;
967 GtkCssGadget *gadget;
968
969 if (priv->layout_style == GTK_BUTTONBOX_EXPAND)
970 gadget = gtk_box_get_gadget (GTK_BOX (widget));
971 else
972 gadget = priv->gadget;
973
974 gtk_css_gadget_get_preferred_size (gadget,
975 GTK_ORIENTATION_HORIZONTAL,
976 height,
977 minimum, natural,
978 NULL, NULL);
979 }
980
981 static void
gtk_button_box_get_preferred_height_for_width(GtkWidget * widget,gint width,gint * minimum,gint * natural)982 gtk_button_box_get_preferred_height_for_width (GtkWidget *widget,
983 gint width,
984 gint *minimum,
985 gint *natural)
986 {
987 GtkButtonBoxPrivate *priv = GTK_BUTTON_BOX (widget)->priv;
988 GtkCssGadget *gadget;
989
990 if (priv->layout_style == GTK_BUTTONBOX_EXPAND)
991 gadget = gtk_box_get_gadget (GTK_BOX (widget));
992 else
993 gadget = priv->gadget;
994
995 gtk_css_gadget_get_preferred_size (gadget,
996 GTK_ORIENTATION_VERTICAL,
997 width,
998 minimum, natural,
999 NULL, NULL);
1000 }
1001
1002 static void
gtk_button_box_get_preferred_height_and_baseline_for_width(GtkWidget * widget,gint width,gint * minimum,gint * natural,gint * minimum_baseline,gint * natural_baseline)1003 gtk_button_box_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
1004 gint width,
1005 gint *minimum,
1006 gint *natural,
1007 gint *minimum_baseline,
1008 gint *natural_baseline)
1009 {
1010 GtkButtonBoxPrivate *priv = GTK_BUTTON_BOX (widget)->priv;
1011 GtkCssGadget *gadget;
1012
1013 if (priv->layout_style == GTK_BUTTONBOX_EXPAND)
1014 gadget = gtk_box_get_gadget (GTK_BOX (widget));
1015 else
1016 gadget = priv->gadget;
1017
1018 gtk_css_gadget_get_preferred_size (gadget,
1019 GTK_ORIENTATION_VERTICAL,
1020 width,
1021 minimum, natural,
1022 minimum_baseline, natural_baseline);
1023 }
1024
1025 static void
gtk_button_box_size_allocate(GtkWidget * widget,GtkAllocation * allocation)1026 gtk_button_box_size_allocate (GtkWidget *widget,
1027 GtkAllocation *allocation)
1028 {
1029 GtkButtonBoxPrivate *priv = GTK_BUTTON_BOX (widget)->priv;
1030 GtkCssGadget *gadget;
1031 GdkRectangle clip;
1032
1033 if (priv->layout_style == GTK_BUTTONBOX_EXPAND)
1034 gadget = gtk_box_get_gadget (GTK_BOX (widget));
1035 else
1036 gadget = priv->gadget;
1037
1038 gtk_widget_set_allocation (widget, allocation);
1039
1040 gtk_css_gadget_allocate (gadget,
1041 allocation,
1042 gtk_widget_get_allocated_baseline (widget),
1043 &clip);
1044
1045 gtk_widget_set_clip (widget, &clip);
1046 }
1047
1048 static void
gtk_button_box_allocate(GtkCssGadget * gadget,const GtkAllocation * allocation,int baseline,GtkAllocation * out_clip,gpointer unused)1049 gtk_button_box_allocate (GtkCssGadget *gadget,
1050 const GtkAllocation *allocation,
1051 int baseline,
1052 GtkAllocation *out_clip,
1053 gpointer unused)
1054 {
1055 GtkWidget *widget;
1056 GtkButtonBoxPrivate *priv;
1057 GtkButtonBox *bbox;
1058 GList *children, *list;
1059 GtkAllocation child_allocation;
1060 gint nvis_children;
1061 gint n_primaries;
1062 gint n_secondaries;
1063 gint x = 0;
1064 gint y = 0;
1065 gint secondary_x = 0;
1066 gint secondary_y = 0;
1067 gint width = 0;
1068 gint height = 0;
1069 gint childspacing = 0;
1070 gint spacing;
1071 GtkOrientation orientation;
1072 gint ipad_x, ipad_y;
1073 gint *widths;
1074 gint *heights;
1075 gint *baselines;
1076 gint *sizes;
1077 gint primary_size;
1078 gint secondary_size;
1079 gint total_size;
1080 gint baseline_height;
1081 gint child_baseline;
1082 gint i;
1083
1084 widget = gtk_css_gadget_get_owner (gadget);
1085 bbox = GTK_BUTTON_BOX (widget);
1086 priv = bbox->priv;
1087
1088 orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
1089 spacing = gtk_box_get_spacing (GTK_BOX (widget));
1090
1091 gtk_widget_style_get (widget,
1092 "child-internal-pad-x", &ipad_x,
1093 "child-internal-pad-y", &ipad_y,
1094 NULL);
1095 gtk_button_box_child_requisition (widget,
1096 &nvis_children,
1097 &n_secondaries,
1098 &widths, &heights, &baselines, &baseline, &baseline_height);
1099
1100 if (baseline != -1)
1101 {
1102 /* TODO: modify baseline based on baseline_pos && allocated_baseline*/
1103 switch (gtk_box_get_baseline_position (GTK_BOX (widget)))
1104 {
1105 case GTK_BASELINE_POSITION_TOP:
1106 /* keep baseline as is */
1107 break;
1108 case GTK_BASELINE_POSITION_CENTER:
1109 baseline = baseline + (allocation->height - baseline_height) / 2;
1110 break;
1111 case GTK_BASELINE_POSITION_BOTTOM:
1112 baseline = allocation->height - (baseline_height - baseline);
1113 break;
1114 }
1115 }
1116
1117 n_primaries = nvis_children - n_secondaries;
1118 primary_size = 0;
1119 secondary_size = 0;
1120 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1121 sizes = widths;
1122 else
1123 sizes = heights;
1124
1125 i = 0;
1126 list = children = _gtk_box_get_children (GTK_BOX (widget));
1127 while (children)
1128 {
1129 GtkWidget *child;
1130
1131 child = children->data;
1132 children = children->next;
1133
1134 if (gtk_widget_get_visible (child))
1135 {
1136 if (gtk_button_box_get_child_secondary (bbox, child))
1137 secondary_size += sizes[i];
1138 else
1139 primary_size += sizes[i];
1140 i++;
1141 }
1142 }
1143 total_size = primary_size + secondary_size;
1144
1145 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1146 width = allocation->width;
1147 else
1148 height = allocation->height;
1149
1150 switch (priv->layout_style)
1151 {
1152 case GTK_BUTTONBOX_SPREAD:
1153
1154 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1155 {
1156 childspacing = (width - total_size) / (nvis_children + 1);
1157 x = allocation->x + childspacing;
1158 secondary_x = x + primary_size + n_primaries * childspacing;
1159 }
1160 else
1161 {
1162 childspacing = (height - total_size) / (nvis_children + 1);
1163 y = allocation->y + childspacing;
1164 secondary_y = y + primary_size + n_primaries * childspacing;
1165 }
1166
1167 break;
1168
1169 case GTK_BUTTONBOX_EDGE:
1170
1171 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1172 {
1173 if (nvis_children >= 2)
1174 {
1175 childspacing = (width - total_size) / (nvis_children - 1);
1176 x = allocation->x;
1177 secondary_x = x + primary_size + n_primaries * childspacing;
1178 }
1179 else if (nvis_children == 1)
1180 {
1181 /* one child, just center */
1182 childspacing = width;
1183 x = secondary_x = allocation->x
1184 + (allocation->width - widths[0]) / 2;
1185 }
1186 else
1187 {
1188 /* zero children, meh */
1189 childspacing = width;
1190 x = secondary_x = allocation->x + allocation->width / 2;
1191 }
1192 }
1193 else
1194 {
1195 if (nvis_children >= 2)
1196 {
1197 childspacing = (height - total_size) / (nvis_children - 1);
1198 y = allocation->y;
1199 secondary_y = y + primary_size + n_primaries * childspacing;
1200 }
1201 else if (nvis_children == 1)
1202 {
1203 /* one child, just center */
1204 childspacing = height;
1205 y = secondary_y = allocation->y
1206 + (allocation->height - heights[0]) / 2;
1207 }
1208 else
1209 {
1210 /* zero children, meh */
1211 childspacing = height;
1212 y = secondary_y = allocation->y + allocation->height / 2;
1213 }
1214 }
1215
1216 break;
1217
1218 case GTK_BUTTONBOX_START:
1219
1220 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1221 {
1222 childspacing = spacing;
1223 x = allocation->x;
1224 secondary_x = allocation->x + allocation->width
1225 - secondary_size - spacing * (n_secondaries - 1);
1226 }
1227 else
1228 {
1229 childspacing = spacing;
1230 y = allocation->y;
1231 secondary_y = allocation->y + allocation->height
1232 - secondary_size - spacing * (n_secondaries - 1);
1233 }
1234
1235 break;
1236
1237 case GTK_BUTTONBOX_END:
1238
1239 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1240 {
1241 childspacing = spacing;
1242 x = allocation->x + allocation->width
1243 - primary_size - spacing * (n_primaries - 1);
1244 secondary_x = allocation->x;
1245 }
1246 else
1247 {
1248 childspacing = spacing;
1249 y = allocation->y + allocation->height
1250 - primary_size - spacing * (n_primaries - 1);
1251 secondary_y = allocation->y;
1252 }
1253
1254 break;
1255
1256 case GTK_BUTTONBOX_CENTER:
1257
1258 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1259 {
1260 childspacing = spacing;
1261 x = allocation->x +
1262 (allocation->width
1263 - (primary_size + spacing * (n_primaries - 1))) / 2
1264 + (secondary_size + n_secondaries * spacing) / 2;
1265 secondary_x = allocation->x;
1266 }
1267 else
1268 {
1269 childspacing = spacing;
1270 y = allocation->y +
1271 (allocation->height
1272 - (primary_size + spacing * (n_primaries - 1))) / 2
1273 + (secondary_size + n_secondaries * spacing) / 2;
1274 secondary_y = allocation->y;
1275 }
1276
1277 break;
1278
1279 default:
1280 g_assert_not_reached ();
1281 break;
1282 }
1283
1284 children = list;
1285 i = 0;
1286 while (children)
1287 {
1288 GtkWidget *child;
1289
1290 child = children->data;
1291 children = children->next;
1292
1293 if (gtk_widget_get_visible (child))
1294 {
1295 child_allocation.width = widths[i];
1296 child_allocation.height = heights[i];
1297 child_baseline = -1;
1298
1299 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1300 {
1301 if (baselines[i] != -1)
1302 {
1303 child_allocation.y = allocation->y + baseline - baselines[i];
1304 child_baseline = baselines[i];
1305 }
1306 else
1307 child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2;
1308
1309 if (gtk_button_box_get_child_secondary (bbox, child))
1310 {
1311 child_allocation.x = secondary_x;
1312 secondary_x += child_allocation.width + childspacing;
1313 }
1314 else
1315 {
1316 child_allocation.x = x;
1317 x += child_allocation.width + childspacing;
1318 }
1319
1320 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1321 child_allocation.x = (allocation->x + allocation->width)
1322 - (child_allocation.x + child_allocation.width - allocation->x);
1323 }
1324 else
1325 {
1326 child_allocation.x = allocation->x + (allocation->width - child_allocation.width) / 2;
1327
1328 if (gtk_button_box_get_child_secondary (bbox, child))
1329 {
1330 child_allocation.y = secondary_y;
1331 secondary_y += child_allocation.height + childspacing;
1332 }
1333 else
1334 {
1335 child_allocation.y = y;
1336 y += child_allocation.height + childspacing;
1337 }
1338 }
1339
1340 gtk_widget_size_allocate_with_baseline (child, &child_allocation, child_baseline);
1341 i++;
1342 }
1343 }
1344
1345 g_list_free (list);
1346 g_free (widths);
1347 g_free (heights);
1348 g_free (baselines);
1349
1350 gtk_container_get_children_clip (GTK_CONTAINER (widget), out_clip);
1351 }
1352
1353 /**
1354 * gtk_button_box_new:
1355 * @orientation: the box's orientation.
1356 *
1357 * Creates a new #GtkButtonBox.
1358 *
1359 * Returns: a new #GtkButtonBox.
1360 *
1361 * Since: 3.0
1362 */
1363 GtkWidget *
gtk_button_box_new(GtkOrientation orientation)1364 gtk_button_box_new (GtkOrientation orientation)
1365 {
1366 return g_object_new (GTK_TYPE_BUTTON_BOX,
1367 "orientation", orientation,
1368 NULL);
1369 }
1370
1371 /**
1372 * gtk_button_box_get_child_non_homogeneous:
1373 * @widget: a #GtkButtonBox
1374 * @child: a child of @widget
1375 *
1376 * Returns whether the child is exempted from homogenous
1377 * sizing.
1378 *
1379 * Returns: %TRUE if the child is not subject to homogenous sizing
1380 *
1381 * Since: 3.2
1382 */
1383 gboolean
gtk_button_box_get_child_non_homogeneous(GtkButtonBox * widget,GtkWidget * child)1384 gtk_button_box_get_child_non_homogeneous (GtkButtonBox *widget,
1385 GtkWidget *child)
1386 {
1387 g_return_val_if_fail (GTK_IS_BUTTON_BOX (widget), FALSE);
1388 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
1389
1390 return (g_object_get_data (G_OBJECT (child), GTK_BOX_NON_HOMOGENEOUS) != NULL);
1391 }
1392
1393 /**
1394 * gtk_button_box_set_child_non_homogeneous:
1395 * @widget: a #GtkButtonBox
1396 * @child: a child of @widget
1397 * @non_homogeneous: the new value
1398 *
1399 * Sets whether the child is exempted from homogeous sizing.
1400 *
1401 * Since: 3.2
1402 */
1403 void
gtk_button_box_set_child_non_homogeneous(GtkButtonBox * widget,GtkWidget * child,gboolean non_homogeneous)1404 gtk_button_box_set_child_non_homogeneous (GtkButtonBox *widget,
1405 GtkWidget *child,
1406 gboolean non_homogeneous)
1407 {
1408 g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
1409 g_return_if_fail (GTK_IS_WIDGET (child));
1410 g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (widget));
1411
1412 g_object_set_data (G_OBJECT (child),
1413 GTK_BOX_NON_HOMOGENEOUS,
1414 non_homogeneous ? GINT_TO_POINTER (1) : NULL);
1415 gtk_widget_child_notify (child, "non-homogeneous");
1416
1417 if (gtk_widget_get_visible (GTK_WIDGET (widget)) &&
1418 gtk_widget_get_visible (child))
1419 gtk_widget_queue_resize (child);
1420 }
1421