2 * Copyright (C) 2007-2010 Openismus GmbH
5 * Tristan Van Berkom <tristanvb@openismus.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
26 * @Short_Description: A container that wraps its children;
29 * #GtkWrapBox allocates space for an ordered list of children
30 * by wrapping them over in the box's orentation.
35 #include "gtksizerequest.h"
36 #include "gtkorientable.h"
37 #include "gtkwrapbox.h"
38 #include "gtkprivate.h"
40 #include "gtktypeutils.h"
43 typedef struct _GtkWrapBoxChild GtkWrapBoxChild;
49 PROP_HORIZONTAL_SPREADING,
50 PROP_VERTICAL_SPREADING,
51 PROP_HORIZONTAL_SPACING,
52 PROP_VERTICAL_SPACING,
53 PROP_MINIMUM_LINE_CHILDREN,
54 PROP_NATURAL_LINE_CHILDREN
63 struct _GtkWrapBoxPrivate
65 GtkOrientation orientation;
66 GtkWrapAllocationMode mode;
67 GtkWrapBoxSpreading horizontal_spreading;
68 GtkWrapBoxSpreading vertical_spreading;
70 guint16 vertical_spacing;
71 guint16 horizontal_spacing;
73 guint16 minimum_line_children;
74 guint16 natural_line_children;
79 struct _GtkWrapBoxChild
83 GtkWrapBoxPacking packing;
87 static void gtk_wrap_box_get_property (GObject *object,
91 static void gtk_wrap_box_set_property (GObject *object,
97 static void gtk_wrap_box_size_allocate (GtkWidget *widget,
98 GtkAllocation *allocation);
100 /* GtkContainerClass */
101 static void gtk_wrap_box_add (GtkContainer *container,
103 static void gtk_wrap_box_remove (GtkContainer *container,
105 static void gtk_wrap_box_forall (GtkContainer *container,
106 gboolean include_internals,
107 GtkCallback callback,
108 gpointer callback_data);
109 static void gtk_wrap_box_set_child_property (GtkContainer *container,
114 static void gtk_wrap_box_get_child_property (GtkContainer *container,
119 static GType gtk_wrap_box_child_type (GtkContainer *container);
123 static GtkSizeRequestMode gtk_wrap_box_get_request_mode (GtkWidget *widget);
124 static void gtk_wrap_box_get_preferred_width (GtkWidget *widget,
127 static void gtk_wrap_box_get_preferred_height (GtkWidget *widget,
130 static void gtk_wrap_box_get_preferred_height_for_width (GtkWidget *box,
132 gint *minimum_height,
133 gint *natural_height);
134 static void gtk_wrap_box_get_preferred_width_for_height (GtkWidget *box,
136 gint *minimum_height,
137 gint *natural_height);
140 G_DEFINE_TYPE_WITH_CODE (GtkWrapBox, gtk_wrap_box, GTK_TYPE_CONTAINER,
141 G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
144 #define ORIENTATION_SPREADING(box) \
145 (((GtkWrapBox *)(box))->priv->orientation == GTK_ORIENTATION_HORIZONTAL ? \
146 ((GtkWrapBox *)(box))->priv->horizontal_spreading : \
147 ((GtkWrapBox *)(box))->priv->vertical_spreading)
149 #define OPPOSING_ORIENTATION_SPREADING(box) \
150 (((GtkWrapBox *)(box))->priv->orientation == GTK_ORIENTATION_HORIZONTAL ? \
151 ((GtkWrapBox *)(box))->priv->vertical_spreading : \
152 ((GtkWrapBox *)(box))->priv->horizontal_spreading)
157 gtk_wrap_box_class_init (GtkWrapBoxClass *class)
159 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
160 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
161 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
163 gobject_class->get_property = gtk_wrap_box_get_property;
164 gobject_class->set_property = gtk_wrap_box_set_property;
166 widget_class->size_allocate = gtk_wrap_box_size_allocate;
167 widget_class->get_request_mode = gtk_wrap_box_get_request_mode;
168 widget_class->get_preferred_width = gtk_wrap_box_get_preferred_width;
169 widget_class->get_preferred_height = gtk_wrap_box_get_preferred_height;
170 widget_class->get_preferred_height_for_width = gtk_wrap_box_get_preferred_height_for_width;
171 widget_class->get_preferred_width_for_height = gtk_wrap_box_get_preferred_width_for_height;
173 container_class->add = gtk_wrap_box_add;
174 container_class->remove = gtk_wrap_box_remove;
175 container_class->forall = gtk_wrap_box_forall;
176 container_class->child_type = gtk_wrap_box_child_type;
177 container_class->set_child_property = gtk_wrap_box_set_child_property;
178 container_class->get_child_property = gtk_wrap_box_get_child_property;
179 gtk_container_class_handle_border_width (container_class);
181 /* GObjectClass properties */
182 g_object_class_override_property (gobject_class, PROP_ORIENTATION, "orientation");
185 * GtkWrapBox:allocation-mode:
187 * The #GtkWrapAllocationMode to use.
189 g_object_class_install_property (gobject_class,
190 PROP_ALLOCATION_MODE,
191 g_param_spec_enum ("allocation-mode",
192 P_("Allocation Mode"),
193 P_("The allocation mode to use"),
194 GTK_TYPE_WRAP_ALLOCATION_MODE,
195 GTK_WRAP_ALLOCATE_FREE,
196 GTK_PARAM_READWRITE));
199 * GtkWrapBox:horizontal-spreading:
201 * The #GtkWrapBoxSpreading to used to define what is done with extra
202 * space in a given orientation.
204 g_object_class_install_property (gobject_class,
205 PROP_HORIZONTAL_SPREADING,
206 g_param_spec_enum ("horizontal-spreading",
207 P_("Horizontal Spreading"),
208 P_("The spreading mode to use horizontally"),
209 GTK_TYPE_WRAP_BOX_SPREADING,
210 GTK_WRAP_BOX_SPREAD_START,
211 GTK_PARAM_READWRITE));
214 * GtkWrapBox:vertical-spreading:
216 * The #GtkWrapBoxSpreading to used to define what is done with extra
217 * space in a given orientation.
219 g_object_class_install_property (gobject_class,
220 PROP_VERTICAL_SPREADING,
221 g_param_spec_enum ("vertical-spreading",
222 P_("Vertical Spreading"),
223 P_("The spreading mode to use vertically"),
224 GTK_TYPE_WRAP_BOX_SPREADING,
225 GTK_WRAP_BOX_SPREAD_START,
226 GTK_PARAM_READWRITE));
230 * GtkWrapBox:minimum-line-children:
232 * The minimum number of children to allocate consecutively in the given orientation.
234 * <note><para>Setting the minimum children per line ensures
235 * that a reasonably small height will be requested
236 * for the overall minimum width of the box.</para></note>
239 g_object_class_install_property (gobject_class,
240 PROP_MINIMUM_LINE_CHILDREN,
241 g_param_spec_uint ("minimum-line-children",
242 P_("Minimum Line Children"),
243 P_("The minimum number of children to allocate "
244 "consecutively in the given orientation."),
248 GTK_PARAM_READWRITE));
251 * GtkWrapBox:natural-line-children:
253 * The maximum amount of children to request space for consecutively in the given orientation.
256 g_object_class_install_property (gobject_class,
257 PROP_NATURAL_LINE_CHILDREN,
258 g_param_spec_uint ("natural-line-children",
259 P_("Natural Line Children"),
260 P_("The maximum amount of children to request space for "
261 "consecutively in the given orientation."),
265 GTK_PARAM_READWRITE));
268 * GtkWrapBox:vertical-spacing:
270 * The amount of vertical space between two children.
273 g_object_class_install_property (gobject_class,
274 PROP_VERTICAL_SPACING,
275 g_param_spec_uint ("vertical-spacing",
276 P_("Vertical spacing"),
277 P_("The amount of vertical space between two children"),
281 GTK_PARAM_READWRITE));
284 * GtkWrapBox:horizontal-spacing:
286 * The amount of horizontal space between two children.
289 g_object_class_install_property (gobject_class,
290 PROP_HORIZONTAL_SPACING,
291 g_param_spec_uint ("horizontal-spacing",
292 P_("Horizontal spacing"),
293 P_("The amount of horizontal space between two children"),
297 GTK_PARAM_READWRITE));
299 /* GtkContainerClass child properties */
302 * GtkWrapBox:packing:
304 * The #GtkWrapBoxPacking options to specify how to pack a child into the box.
306 gtk_container_class_install_child_property (container_class,
311 P_("The packing options to use for this child"),
312 GTK_TYPE_WRAP_BOX_PACKING, 0,
313 GTK_PARAM_READWRITE));
315 g_type_class_add_private (class, sizeof (GtkWrapBoxPrivate));
319 gtk_wrap_box_init (GtkWrapBox *box)
321 GtkWrapBoxPrivate *priv;
324 G_TYPE_INSTANCE_GET_PRIVATE (box, GTK_TYPE_WRAP_BOX, GtkWrapBoxPrivate);
326 priv->orientation = GTK_ORIENTATION_HORIZONTAL;
327 priv->mode = GTK_WRAP_ALLOCATE_FREE;
328 priv->horizontal_spreading = GTK_WRAP_BOX_SPREAD_START;
329 priv->vertical_spreading = GTK_WRAP_BOX_SPREAD_START;
330 priv->horizontal_spacing = 0;
331 priv->vertical_spacing = 0;
332 priv->children = NULL;
334 gtk_widget_set_has_window (GTK_WIDGET (box), FALSE);
337 /*****************************************************
339 *****************************************************/
341 gtk_wrap_box_get_property (GObject *object,
346 GtkWrapBox *box = GTK_WRAP_BOX (object);
347 GtkWrapBoxPrivate *priv = box->priv;
351 case PROP_ORIENTATION:
352 g_value_set_boolean (value, priv->orientation);
354 case PROP_ALLOCATION_MODE:
355 g_value_set_enum (value, priv->mode);
357 case PROP_HORIZONTAL_SPREADING:
358 g_value_set_enum (value, priv->horizontal_spreading);
360 case PROP_VERTICAL_SPREADING:
361 g_value_set_enum (value, priv->vertical_spreading);
363 case PROP_HORIZONTAL_SPACING:
364 g_value_set_uint (value, priv->horizontal_spacing);
366 case PROP_VERTICAL_SPACING:
367 g_value_set_uint (value, priv->vertical_spacing);
369 case PROP_MINIMUM_LINE_CHILDREN:
370 g_value_set_uint (value, priv->minimum_line_children);
372 case PROP_NATURAL_LINE_CHILDREN:
373 g_value_set_uint (value, priv->natural_line_children);
376 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
382 gtk_wrap_box_set_property (GObject *object,
387 GtkWrapBox *box = GTK_WRAP_BOX (object);
388 GtkWrapBoxPrivate *priv = box->priv;
392 case PROP_ORIENTATION:
393 priv->orientation = g_value_get_enum (value);
395 /* Re-box the children in the new orientation */
396 gtk_widget_queue_resize (GTK_WIDGET (box));
398 case PROP_ALLOCATION_MODE:
399 gtk_wrap_box_set_allocation_mode (box, g_value_get_enum (value));
401 case PROP_HORIZONTAL_SPREADING:
402 gtk_wrap_box_set_horizontal_spreading (box, g_value_get_enum (value));
404 case PROP_VERTICAL_SPREADING:
405 gtk_wrap_box_set_vertical_spreading (box, g_value_get_enum (value));
407 case PROP_HORIZONTAL_SPACING:
408 gtk_wrap_box_set_horizontal_spacing (box, g_value_get_uint (value));
410 case PROP_VERTICAL_SPACING:
411 gtk_wrap_box_set_vertical_spacing (box, g_value_get_uint (value));
413 case PROP_MINIMUM_LINE_CHILDREN:
414 gtk_wrap_box_set_minimum_line_children (box, g_value_get_uint (value));
416 case PROP_NATURAL_LINE_CHILDREN:
417 gtk_wrap_box_set_natural_line_children (box, g_value_get_uint (value));
420 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
425 /*****************************************************
427 *****************************************************/
430 get_visible_children (GtkWrapBox *box)
432 GtkWrapBoxPrivate *priv = box->priv;
436 for (list = priv->children; list; list = list->next)
438 GtkWrapBoxChild *child = list->data;
440 if (!gtk_widget_get_visible (child->widget))
450 get_visible_expand_children (GtkWrapBox *box,
451 GtkOrientation orientation,
456 gint i, expand_children = 0;
458 for (i = 0, list = cursor; (n_visible > 0 ? i < n_visible : TRUE) && list; list = list->next)
460 GtkWrapBoxChild *child = list->data;
462 if (!gtk_widget_get_visible (child->widget))
465 if ((orientation == GTK_ORIENTATION_HORIZONTAL && (child->packing & GTK_WRAP_BOX_H_EXPAND) != 0) ||
466 (orientation == GTK_ORIENTATION_VERTICAL && (child->packing & GTK_WRAP_BOX_V_EXPAND) != 0))
472 return expand_children;
475 /* Used in columned modes where all items share at least their
476 * equal widths or heights
479 get_average_item_size (GtkWrapBox *box,
480 GtkOrientation orientation,
484 GtkWrapBoxPrivate *priv = box->priv;
486 gint max_min_size = 0;
487 gint max_nat_size = 0;
489 for (list = priv->children; list; list = list->next)
491 GtkWrapBoxChild *child = list->data;
492 gint child_min, child_nat;
494 if (!gtk_widget_get_visible (child->widget))
497 if (orientation == GTK_ORIENTATION_HORIZONTAL)
498 gtk_widget_get_preferred_width (child->widget, &child_min, &child_nat);
500 gtk_widget_get_preferred_height (child->widget, &child_min, &child_nat);
502 max_min_size = MAX (max_min_size, child_min);
503 max_nat_size = MAX (max_nat_size, child_nat);
507 *min_size = max_min_size;
510 *nat_size = max_nat_size;
514 /* Gets the largest minimum/natural size for a given size
515 * (used to get the largest item heights for a fixed item width and the opposite) */
517 get_largest_size_for_opposing_orientation (GtkWrapBox *box,
518 GtkOrientation orientation,
523 GtkWrapBoxPrivate *priv = box->priv;
525 gint max_min_size = 0;
526 gint max_nat_size = 0;
528 for (list = priv->children; list; list = list->next)
530 GtkWrapBoxChild *child = list->data;
531 gint child_min, child_nat;
533 if (!gtk_widget_get_visible (child->widget))
536 if (orientation == GTK_ORIENTATION_HORIZONTAL)
537 gtk_widget_get_preferred_height_for_width (child->widget,
539 &child_min, &child_nat);
541 gtk_widget_get_preferred_width_for_height (child->widget,
543 &child_min, &child_nat);
545 max_min_size = MAX (max_min_size, child_min);
546 max_nat_size = MAX (max_nat_size, child_nat);
550 *min_item_size = max_min_size;
553 *nat_item_size = max_nat_size;
557 /* Gets the largest minimum/natural size on a single line for a given size
558 * (used to get the largest line heights for a fixed item width and the opposite
559 * while itterating over a list of children, note the new index is returned) */
561 get_largest_size_for_line_in_opposing_orientation (GtkWrapBox *box,
562 GtkOrientation orientation,
565 GtkRequestedSize *item_sizes,
571 gint max_min_size = 0;
572 gint max_nat_size = 0;
575 for (list = cursor, i = 0; list && i < line_length; list = list->next)
577 GtkWrapBoxChild *child = list->data;
578 gint child_min, child_nat, this_item_size;
580 if (!gtk_widget_get_visible (child->widget))
583 /* Distribute the extra pixels to the first children in the line
584 * (could be fancier and spread them out more evenly) */
585 this_item_size = item_sizes[i].minimum_size;
586 if (extra_pixels > 0 && ORIENTATION_SPREADING (box) == GTK_WRAP_BOX_SPREAD_EXPAND)
592 if (orientation == GTK_ORIENTATION_HORIZONTAL)
593 gtk_widget_get_preferred_height_for_width (child->widget,
595 &child_min, &child_nat);
597 gtk_widget_get_preferred_width_for_height (child->widget,
599 &child_min, &child_nat);
601 max_min_size = MAX (max_min_size, child_min);
602 max_nat_size = MAX (max_nat_size, child_nat);
608 *min_item_size = max_min_size;
611 *nat_item_size = max_nat_size;
613 /* Return next item in the list */
618 /* Gets the largest minimum/natural size on a single line for a given allocated line size
619 * (used to get the largest line heights for a width in pixels and the opposite
620 * while itterating over a list of children, note the new index is returned) */
622 get_largest_size_for_free_line_in_opposing_orientation (GtkWrapBox *box,
623 GtkOrientation orientation,
632 GtkWrapBoxPrivate *priv = box->priv;
633 GtkRequestedSize *sizes;
636 gint max_min_size = 0;
637 gint max_nat_size = 0;
638 gint i, size = avail_size;
639 gint line_length, spacing;
640 gint expand_children = 0;
641 gint expand_per_child;
642 gint expand_remainder;
644 if (orientation == GTK_ORIENTATION_HORIZONTAL)
645 spacing = priv->horizontal_spacing;
647 spacing = priv->vertical_spacing;
649 /* First determine the length of this line in items (how many items fit) */
650 for (i = 0, list = cursor; size > 0 && list; list = list->next)
652 GtkWrapBoxChild *child = list->data;
655 if (!gtk_widget_get_visible (child->widget))
658 if (orientation == GTK_ORIENTATION_HORIZONTAL)
659 gtk_widget_get_preferred_width (child->widget, NULL, &child_size);
661 gtk_widget_get_preferred_height (child->widget, NULL, &child_size);
664 child_size += spacing;
666 if (size - child_size >= 0)
674 line_length = MAX (min_items, i);
677 /* Collect the sizes of the items on this line */
678 array = g_array_new (0, TRUE, sizeof (GtkRequestedSize));
680 for (i = 0, list = cursor; i < line_length && list; list = list->next)
682 GtkWrapBoxChild *child = list->data;
683 GtkRequestedSize requested;
685 if (!gtk_widget_get_visible (child->widget))
688 requested.data = child;
689 if (orientation == GTK_ORIENTATION_HORIZONTAL)
690 gtk_widget_get_preferred_width (child->widget,
691 &requested.minimum_size,
692 &requested.natural_size);
694 gtk_widget_get_preferred_height (child->widget,
695 &requested.minimum_size,
696 &requested.natural_size);
701 size -= requested.minimum_size;
703 g_array_append_val (array, requested);
708 sizes = (GtkRequestedSize *)array->data;
709 size = gtk_distribute_natural_allocation (size, array->len, sizes);
712 *extra_pixels = size;
714 /* Cut out any expand space if we're not distributing any */
715 if (ORIENTATION_SPREADING (box) != GTK_WRAP_BOX_SPREAD_EXPAND)
718 /* Count how many children are going to expand... */
719 expand_children = get_visible_expand_children (box, orientation,
720 cursor, line_length);
722 /* If no child prefers to expand, they all get some expand space */
723 if (expand_children == 0)
725 expand_per_child = size / line_length;
726 expand_remainder = size % line_length;
730 expand_per_child = size / expand_children;
731 expand_remainder = size % expand_children;
734 /* Now add the remaining expand space and get the collective size of this line
735 * in the opposing orientation */
736 for (i = 0, list = cursor; i < line_length && list; list = list->next)
738 GtkWrapBoxChild *child = list->data;
739 gint child_min, child_nat;
741 if (!gtk_widget_get_visible (child->widget))
744 g_assert (child == sizes[i].data);
746 if ((orientation == GTK_ORIENTATION_HORIZONTAL && (child->packing & GTK_WRAP_BOX_H_EXPAND) != 0) ||
747 (orientation == GTK_ORIENTATION_VERTICAL && (child->packing & GTK_WRAP_BOX_V_EXPAND) != 0) ||
748 expand_children == 0)
750 sizes[i].minimum_size += expand_per_child;
751 if (expand_remainder)
753 sizes[i].minimum_size++;
758 if (orientation == GTK_ORIENTATION_HORIZONTAL)
759 gtk_widget_get_preferred_height_for_width (child->widget,
760 sizes[i].minimum_size,
761 &child_min, &child_nat);
763 gtk_widget_get_preferred_width_for_height (child->widget,
764 sizes[i].minimum_size,
765 &child_min, &child_nat);
767 max_min_size = MAX (max_min_size, child_min);
768 max_nat_size = MAX (max_nat_size, child_nat);
776 g_array_free (array, TRUE);
779 *min_item_size = max_min_size;
782 *nat_item_size = max_nat_size;
784 /* Return the next item */
789 allocate_child (GtkWrapBox *box,
790 GtkWrapBoxChild *child,
796 GtkWrapBoxPrivate *priv = box->priv;
797 GtkAllocation widget_allocation;
798 GtkAllocation child_allocation;
800 gtk_widget_get_allocation (GTK_WIDGET (box), &widget_allocation);
802 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
804 child_allocation.x = widget_allocation.x + item_offset;
805 child_allocation.y = widget_allocation.y + line_offset;
806 child_allocation.width = item_size;
807 child_allocation.height = line_size;
809 else /* GTK_ORIENTATION_VERTICAL */
811 child_allocation.x = widget_allocation.x + line_offset;
812 child_allocation.y = widget_allocation.y + item_offset;
813 child_allocation.width = line_size;
814 child_allocation.height = item_size;
817 gtk_widget_size_allocate (child->widget, &child_allocation);
820 /* fit_aligned_item_requests() helper */
822 gather_aligned_item_requests (GtkWrapBox *box,
823 GtkOrientation orientation,
827 GtkRequestedSize *item_sizes)
829 GtkWrapBoxPrivate *priv = box->priv;
832 gint extra_items, natural_line_size = 0;
834 extra_items = n_children % line_length;
836 for (list = priv->children, i = 0; list; list = list->next, i++)
838 GtkWrapBoxChild *child = list->data;
839 gint child_min, child_nat;
842 if (!gtk_widget_get_visible (child->widget))
845 if (orientation == GTK_ORIENTATION_HORIZONTAL)
846 gtk_widget_get_preferred_width (child->widget,
847 &child_min, &child_nat);
849 gtk_widget_get_preferred_height (child->widget,
850 &child_min, &child_nat);
852 /* Get the index and push it over for the last line when spreading to the end */
853 position = i % line_length;
855 if (ORIENTATION_SPREADING (box) == GTK_WRAP_BOX_SPREAD_END && i >= n_children - extra_items)
856 position += line_length - extra_items;
858 /* Round up the size of every column/row */
859 item_sizes[position].minimum_size = MAX (item_sizes[position].minimum_size, child_min);
860 item_sizes[position].natural_size = MAX (item_sizes[position].natural_size, child_nat);
863 for (i = 0; i < line_length; i++)
864 natural_line_size += item_sizes[i].natural_size;
866 natural_line_size += (line_length - 1) * item_spacing;
868 return natural_line_size;
871 static GtkRequestedSize *
872 fit_aligned_item_requests (GtkWrapBox *box,
873 GtkOrientation orientation,
876 gint *line_length, /* in-out */
879 GtkRequestedSize *sizes, *try_sizes;
880 gint try_line_size, try_length;
882 sizes = g_new0 (GtkRequestedSize, *line_length);
884 /* get the sizes for the initial guess */
886 gather_aligned_item_requests (box, orientation, *line_length, item_spacing, n_children, sizes);
888 /* Try columnizing the whole thing and adding an item to the end of the line;
889 * try to fit as many columns into the available size as possible */
890 for (try_length = *line_length + 1; try_line_size < avail_size; try_length++)
892 try_sizes = g_new0 (GtkRequestedSize, try_length);
893 try_line_size = gather_aligned_item_requests (box, orientation, try_length, item_spacing,
894 n_children, try_sizes);
896 if (try_line_size <= avail_size)
898 *line_length = try_length;
905 /* oops, this one failed; stick to the last size that fit and then return */
921 gtk_wrap_box_size_allocate (GtkWidget *widget,
922 GtkAllocation *allocation)
924 GtkWrapBox *box = GTK_WRAP_BOX (widget);
925 GtkWrapBoxPrivate *priv = box->priv;
926 gint avail_size, avail_other_size, min_items, item_spacing, line_spacing;
927 GtkWrapBoxSpreading item_spreading;
928 GtkWrapBoxSpreading line_spreading;
930 gtk_widget_set_allocation (widget, allocation);
932 min_items = MAX (1, priv->minimum_line_children);
934 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
936 avail_size = allocation->width;
937 avail_other_size = allocation->height;
938 item_spacing = priv->horizontal_spacing;
939 line_spacing = priv->vertical_spacing;
941 else /* GTK_ORIENTATION_VERTICAL */
943 avail_size = allocation->height;
944 avail_other_size = allocation->width;
945 item_spacing = priv->vertical_spacing;
946 line_spacing = priv->horizontal_spacing;
949 item_spreading = ORIENTATION_SPREADING (box);
950 line_spreading = OPPOSING_ORIENTATION_SPREADING (box);
953 /*********************************************************
954 * Deal with ALIGNED/HOMOGENEOUS modes first, start with *
955 * initial guesses at item/line sizes *
956 *********************************************************/
957 if (priv->mode == GTK_WRAP_ALLOCATE_ALIGNED ||
958 priv->mode == GTK_WRAP_ALLOCATE_HOMOGENEOUS)
960 GtkRequestedSize *line_sizes = NULL;
961 GtkRequestedSize *item_sizes = NULL;
963 gint min_item_size, nat_item_size;
966 gint line_size = 0, min_fixed_line_size = 0, nat_fixed_line_size = 0;
967 gint line_offset, item_offset, n_children, n_lines, line_count;
968 gint extra_pixels, extra_per_item = 0, extra_extra = 0;
969 gint extra_line_pixels, extra_per_line = 0, extra_line_extra = 0;
970 gint i, this_line_size;
972 get_average_item_size (box, priv->orientation, &min_item_size, &nat_item_size);
974 /* By default wrap at the natural item width */
975 line_length = avail_size / (nat_item_size + item_spacing);
977 /* After the above aproximation, check if we cant fit one more on the line */
978 if (line_length * item_spacing + (line_length + 1) * nat_item_size <= avail_size)
981 /* Its possible we were allocated just less than the natural width of the
982 * minimum item wrap length */
983 line_length = MAX (min_items, line_length);
985 /* Get how many lines we'll be needing to wrap */
986 n_children = get_visible_children (box);
988 /* Here we just use the largest height-for-width and use that for the height
990 if (priv->mode == GTK_WRAP_ALLOCATE_HOMOGENEOUS)
992 n_lines = n_children / line_length;
993 if ((n_children % line_length) > 0)
996 n_lines = MAX (n_lines, 1);
998 /* Now we need the real item allocation size */
999 item_size = (avail_size - (line_length - 1) * item_spacing) / line_length;
1001 /* Cut out the expand space if we're not distributing any */
1002 if (item_spreading != GTK_WRAP_BOX_SPREAD_EXPAND)
1003 item_size = MIN (item_size, nat_item_size);
1005 get_largest_size_for_opposing_orientation (box, priv->orientation, item_size,
1006 &min_fixed_line_size,
1007 &nat_fixed_line_size);
1009 /* resolve a fixed 'line_size' */
1010 line_size = (avail_other_size - (n_lines - 1) * line_spacing) / n_lines;
1012 if (line_spreading != GTK_WRAP_BOX_SPREAD_EXPAND)
1013 line_size = MIN (line_size, nat_fixed_line_size);
1015 /* Get the real extra pixels incase of GTK_WRAP_BOX_SPREAD_START lines */
1016 extra_pixels = avail_size - (line_length - 1) * item_spacing - item_size * line_length;
1017 extra_line_pixels = avail_other_size - (n_lines - 1) * line_spacing - line_size * n_lines;
1019 else /* GTK_WRAP_ALLOCATE_ALIGNED */
1022 gboolean first_line = TRUE;
1024 /* Find the amount of columns that can fit aligned into the available space
1025 * and collect their requests.
1027 item_sizes = fit_aligned_item_requests (box, priv->orientation, avail_size,
1028 item_spacing, &line_length, n_children);
1030 /* Calculate the number of lines after determining the final line_length */
1031 n_lines = n_children / line_length;
1032 if ((n_children % line_length) > 0)
1035 n_lines = MAX (n_lines, 1);
1036 line_sizes = g_new0 (GtkRequestedSize, n_lines);
1038 /* Get the available remaining size */
1039 avail_size -= (line_length - 1) * item_spacing;
1040 for (i = 0; i < line_length; i++)
1041 avail_size -= item_sizes[i].minimum_size;
1043 /* Perform a natural allocation on the columnized items and get the remaining pixels */
1044 extra_pixels = gtk_distribute_natural_allocation (avail_size, line_length, item_sizes);
1046 /* Now that we have the size of each column of items find the size of each individual
1047 * line based on the aligned item sizes.
1049 for (i = 0, list = priv->children; list != NULL; i++)
1053 get_largest_size_for_line_in_opposing_orientation (box, priv->orientation,
1055 item_sizes, extra_pixels,
1056 &line_sizes[i].minimum_size,
1057 &line_sizes[i].natural_size);
1060 /* Its possible a line is made of completely invisible children */
1061 if (line_sizes[i].natural_size > 0)
1066 avail_other_size -= line_spacing;
1068 avail_other_size -= line_sizes[i].minimum_size;
1070 line_sizes[i].data = GINT_TO_POINTER (i);
1074 /* Distribute space among lines naturally */
1075 extra_line_pixels = gtk_distribute_natural_allocation (avail_other_size, n_lines, line_sizes);
1078 /*********************************************************
1079 * Initial sizes of items/lines guessed at this point, *
1080 * go on to distribute expand space if needed. *
1081 *********************************************************/
1083 /* FIXME: This portion needs to consider which columns
1084 * and rows asked for expand space and distribute those
1085 * accordingly for the case of ALIGNED allocation.
1087 * If at least one child in a column/row asked for expand;
1088 * we should make that row/column expand entirely.
1091 /* Calculate expand space per item */
1092 if (item_spreading == GTK_WRAP_BOX_SPREAD_EVEN)
1094 extra_per_item = extra_pixels / MAX (line_length -1, 1);
1095 extra_extra = extra_pixels % MAX (line_length -1, 1);
1097 else if (item_spreading == GTK_WRAP_BOX_SPREAD_EXPAND)
1099 extra_per_item = extra_pixels / line_length;
1100 extra_extra = extra_pixels % line_length;
1103 /* Calculate expand space per line */
1104 if (line_spreading == GTK_WRAP_BOX_SPREAD_EVEN)
1106 extra_per_line = extra_line_pixels / MAX (n_lines -1, 1);
1107 extra_line_extra = extra_line_pixels % MAX (n_lines -1, 1);
1109 else if (line_spreading == GTK_WRAP_BOX_SPREAD_EXPAND)
1111 extra_per_line = extra_line_pixels / n_lines;
1112 extra_line_extra = extra_line_pixels % n_lines;
1115 /*********************************************************
1116 * Prepare item/line initial offsets and jump into the *
1117 * real allocation loop. *
1118 *********************************************************/
1119 line_offset = item_offset = 0;
1121 /* prepend extra space to item_offset/line_offset for SPREAD_END */
1122 if (item_spreading == GTK_WRAP_BOX_SPREAD_END)
1123 item_offset += extra_pixels;
1125 if (line_spreading == GTK_WRAP_BOX_SPREAD_END)
1126 line_offset += extra_line_pixels;
1128 /* Get the allocation size for the first line */
1129 if (priv->mode == GTK_WRAP_ALLOCATE_HOMOGENEOUS)
1130 this_line_size = line_size;
1133 this_line_size = line_sizes[0].minimum_size;
1135 if (line_spreading == GTK_WRAP_BOX_SPREAD_EXPAND)
1137 this_line_size += extra_per_line;
1139 if (extra_line_extra > 0)
1144 for (i = 0, line_count = 0, list = priv->children; list; list = list->next)
1146 GtkWrapBoxChild *child = list->data;
1148 gint this_item_size;
1150 if (!gtk_widget_get_visible (child->widget))
1153 /* Get item position */
1154 position = i % line_length;
1156 /* adjust the line_offset/count at the beginning of each new line */
1157 if (i > 0 && position == 0)
1159 /* Push the line_offset */
1160 line_offset += this_line_size + line_spacing;
1162 if (line_spreading == GTK_WRAP_BOX_SPREAD_EVEN)
1164 line_offset += extra_per_line;
1166 if (line_count < extra_line_extra)
1172 /* Get the new line size */
1173 if (priv->mode == GTK_WRAP_ALLOCATE_HOMOGENEOUS)
1174 this_line_size = line_size;
1177 this_line_size = line_sizes[line_count].minimum_size;
1179 if (line_spreading == GTK_WRAP_BOX_SPREAD_EXPAND)
1181 this_line_size += extra_per_line;
1183 if (line_count < extra_line_extra)
1190 if (item_spreading == GTK_WRAP_BOX_SPREAD_END)
1192 item_offset += extra_pixels;
1194 /* If we're on the last line, prepend the space for
1195 * any leading items */
1196 if (line_count == n_lines -1)
1198 gint extra_items = n_children % line_length;
1200 if (priv->mode == GTK_WRAP_ALLOCATE_HOMOGENEOUS)
1202 item_offset += item_size * (line_length - extra_items);
1203 item_offset += item_spacing * (line_length - extra_items);
1209 for (j = 0; j < (line_length - extra_items); j++)
1211 item_offset += item_sizes[j].minimum_size;
1212 item_offset += item_spacing;
1219 /* Push the index along for the last line when spreading to the end */
1220 if (item_spreading == GTK_WRAP_BOX_SPREAD_END &&
1221 line_count == n_lines -1)
1223 gint extra_items = n_children % line_length;
1225 position += line_length - extra_items;
1228 if (priv->mode == GTK_WRAP_ALLOCATE_HOMOGENEOUS)
1229 this_item_size = item_size;
1230 else /* aligned mode */
1231 this_item_size = item_sizes[position].minimum_size;
1233 if (item_spreading == GTK_WRAP_BOX_SPREAD_EXPAND)
1235 this_item_size += extra_per_item;
1237 if (position < extra_extra)
1241 /* Do the actual allocation */
1242 allocate_child (box, child, item_offset, line_offset, this_item_size, this_line_size);
1244 item_offset += this_item_size;
1245 item_offset += item_spacing;
1247 /* deal with extra spacing here */
1248 if (item_spreading == GTK_WRAP_BOX_SPREAD_EVEN)
1250 item_offset += extra_per_item;
1252 if (position < extra_extra)
1259 g_free (item_sizes);
1260 g_free (line_sizes);
1262 else /* GTK_WRAP_ALLOCATE_FREE */
1264 /* Here we just fit as many children as we can allocate their natural size to
1265 * on each line and add the heights for each of them on each line */
1266 GtkRequestedSize requested;
1267 GtkRequestedSize *sizes = NULL;
1268 GList *list = priv->children;
1269 gboolean first_line = TRUE;
1270 gint i, line_count = 0;
1271 gint line_offset, item_offset;
1272 gint extra_per_line = 0, extra_line_extra = 0;
1276 array = g_array_new (0, TRUE, sizeof (GtkRequestedSize));
1278 while (list != NULL)
1281 AllocatedLine *line;
1284 get_largest_size_for_free_line_in_opposing_orientation (box, priv->orientation,
1285 list, min_items, avail_size,
1286 &requested.minimum_size,
1287 &requested.natural_size,
1291 /* Its possible a line is made of completely invisible children */
1292 if (requested.natural_size > 0)
1297 avail_other_size -= line_spacing;
1299 avail_other_size -= requested.minimum_size;
1301 line = g_slice_new0 (AllocatedLine);
1302 line->requested = line_array;
1303 line->extra_pixels = extra_pixels;
1305 requested.data = line;
1307 g_array_append_val (array, requested);
1311 /* Distribute space among lines naturally */
1312 sizes = (GtkRequestedSize *)array->data;
1313 avail_other_size = gtk_distribute_natural_allocation (avail_other_size, array->len, sizes);
1315 /* Calculate expand space per line */
1316 if (line_spreading == GTK_WRAP_BOX_SPREAD_EVEN)
1318 extra_per_line = avail_other_size / MAX (array->len -1, 1);
1319 extra_line_extra = avail_other_size % MAX (array->len -1, 1);
1321 else if (line_spreading == GTK_WRAP_BOX_SPREAD_EXPAND)
1323 extra_per_line = avail_other_size / array->len;
1324 extra_line_extra = avail_other_size % array->len;
1327 if (line_spreading == GTK_WRAP_BOX_SPREAD_END)
1328 line_offset = avail_other_size;
1332 for (line_count = 0; line_count < array->len; line_count++)
1334 AllocatedLine *line = (AllocatedLine *)sizes[line_count].data;
1335 GArray *line_array = line->requested;
1336 GtkRequestedSize *line_sizes = (GtkRequestedSize *)line_array->data;
1337 gint line_size = sizes[line_count].minimum_size;
1338 gint extra_per_item = 0;
1339 gint extra_extra = 0;
1341 /* Set line start offset */
1344 if (line_spreading == GTK_WRAP_BOX_SPREAD_EXPAND)
1346 line_size += extra_per_line;
1348 if (line_count < extra_line_extra)
1352 if (item_spreading == GTK_WRAP_BOX_SPREAD_END)
1353 item_offset += line->extra_pixels;
1354 else if (item_spreading == GTK_WRAP_BOX_SPREAD_EVEN)
1356 extra_per_item = line->extra_pixels / MAX (line_array->len -1, 1);
1357 extra_extra = line->extra_pixels % MAX (line_array->len -1, 1);
1360 for (i = 0; i < line_array->len; i++)
1362 GtkWrapBoxChild *child = line_sizes[i].data;
1363 gint item_size = line_sizes[i].minimum_size;
1365 /* Do the actual allocation */
1366 allocate_child (box, child, item_offset, line_offset, item_size, line_size);
1368 /* Add extra space evenly between children */
1369 if (item_spreading == GTK_WRAP_BOX_SPREAD_EVEN)
1371 item_offset += extra_per_item;
1372 if (i < extra_extra)
1376 /* Move item cursor along for the next allocation */
1377 item_offset += item_spacing;
1378 item_offset += item_size;
1381 /* New line, increment offset and reset item cursor */
1382 line_offset += line_spacing;
1383 line_offset += line_size;
1385 if (line_spreading == GTK_WRAP_BOX_SPREAD_EVEN)
1387 line_offset += extra_per_line;
1389 if (line_count < extra_line_extra)
1393 /* Free the array for this line now its not needed anymore */
1394 g_array_free (line_array, TRUE);
1395 g_slice_free (AllocatedLine, line);
1398 g_array_free (array, TRUE);
1402 /*****************************************************
1403 * GtkContainerClass *
1404 *****************************************************/
1406 gtk_wrap_box_add (GtkContainer *container,
1409 gtk_wrap_box_insert_child (GTK_WRAP_BOX (container), widget, -1, 0);
1413 find_child_in_list (GtkWrapBoxChild *child_in_list,
1416 return (child_in_list->widget == search) ? 0 : -1;
1420 gtk_wrap_box_remove (GtkContainer *container,
1423 GtkWrapBox *box = GTK_WRAP_BOX (container);
1424 GtkWrapBoxPrivate *priv = box->priv;
1427 list = g_list_find_custom (priv->children, widget,
1428 (GCompareFunc)find_child_in_list);
1432 GtkWrapBoxChild *child = list->data;
1433 gboolean was_visible = gtk_widget_get_visible (widget);
1435 gtk_widget_unparent (widget);
1437 g_slice_free (GtkWrapBoxChild, child);
1438 priv->children = g_list_delete_link (priv->children, list);
1440 if (was_visible && gtk_widget_get_visible (GTK_WIDGET (container)))
1441 gtk_widget_queue_resize (GTK_WIDGET (container));
1446 gtk_wrap_box_forall (GtkContainer *container,
1447 gboolean include_internals,
1448 GtkCallback callback,
1449 gpointer callback_data)
1451 GtkWrapBox *box = GTK_WRAP_BOX (container);
1452 GtkWrapBoxPrivate *priv = box->priv;
1453 GtkWrapBoxChild *child;
1456 for (list = priv->children; list; list = list->next)
1460 (* callback) (child->widget, callback_data);
1465 gtk_wrap_box_child_type (GtkContainer *container)
1467 return GTK_TYPE_WIDGET;
1471 gtk_wrap_box_set_child_property (GtkContainer *container,
1474 const GValue *value,
1477 GtkWrapBox *box = GTK_WRAP_BOX (container);
1478 GtkWrapBoxPrivate *priv = box->priv;
1479 GtkWrapBoxChild *child;
1482 list = g_list_find_custom (priv->children, widget,
1483 (GCompareFunc)find_child_in_list);
1484 g_return_if_fail (list != NULL);
1488 switch (property_id)
1490 case CHILD_PROP_PACKING:
1491 child->packing = g_value_get_flags (value);
1494 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
1498 if (gtk_widget_get_visible (widget) &&
1499 gtk_widget_get_visible (GTK_WIDGET (box)))
1500 gtk_widget_queue_resize (widget);
1504 gtk_wrap_box_get_child_property (GtkContainer *container,
1510 GtkWrapBox *box = GTK_WRAP_BOX (container);
1511 GtkWrapBoxPrivate *priv = box->priv;
1512 GtkWrapBoxChild *child;
1515 list = g_list_find_custom (priv->children, widget,
1516 (GCompareFunc)find_child_in_list);
1517 g_return_if_fail (list != NULL);
1521 switch (property_id)
1523 case CHILD_PROP_PACKING:
1524 g_value_set_flags (value, child->packing);
1527 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
1532 /*****************************************************
1534 *****************************************************/
1537 static GtkSizeRequestMode
1538 gtk_wrap_box_get_request_mode (GtkWidget *widget)
1540 GtkWrapBox *box = GTK_WRAP_BOX (widget);
1541 GtkWrapBoxPrivate *priv = box->priv;
1543 return (priv->orientation == GTK_ORIENTATION_HORIZONTAL) ?
1544 GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH : GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
1547 /* Gets the largest minimum and natural length of
1548 * 'line_length' consecutive items */
1550 get_largest_line_length (GtkWrapBox *box,
1551 GtkOrientation orientation,
1556 GtkWrapBoxPrivate *priv = box->priv;
1558 gint max_min_size = 0;
1559 gint max_nat_size = 0;
1562 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1563 spacing = priv->horizontal_spacing;
1565 spacing = priv->vertical_spacing;
1567 /* Get the largest size of 'line_length' consecutive items in the list.
1569 for (list = priv->children; list; list = list->next)
1575 for (l = list, i = 0; l && i < line_length; l = l->next)
1577 GtkWrapBoxChild *child = l->data;
1578 gint child_min, child_nat;
1580 if (!gtk_widget_get_visible (child->widget))
1583 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1584 gtk_widget_get_preferred_width (child->widget,
1585 &child_min, &child_nat);
1586 else /* GTK_ORIENTATION_VERTICAL */
1587 gtk_widget_get_preferred_height (child->widget,
1588 &child_min, &child_nat);
1590 line_min += child_min;
1591 line_nat += child_nat;
1596 max_min_size = MAX (max_min_size, line_min);
1597 max_nat_size = MAX (max_nat_size, line_nat);
1600 max_min_size += (line_length - 1) * spacing;
1601 max_nat_size += (line_length - 1) * spacing;
1604 *min_size = max_min_size;
1607 *nat_size = max_nat_size;
1610 /* Gets the largest minimum and natural length of
1611 * 'line_length' consecutive items when aligned into rows/columns */
1613 get_largest_aligned_line_length (GtkWrapBox *box,
1614 GtkOrientation orientation,
1619 GtkWrapBoxPrivate *priv = box->priv;
1621 gint max_min_size = 0;
1622 gint max_nat_size = 0;
1624 GtkRequestedSize *aligned_item_sizes;
1626 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1627 spacing = priv->horizontal_spacing;
1629 spacing = priv->vertical_spacing;
1631 aligned_item_sizes = g_new0 (GtkRequestedSize, line_length);
1633 /* Get the largest sizes of each index in the line.
1635 for (list = priv->children, i = 0; list; list = list->next)
1637 GtkWrapBoxChild *child = list->data;
1638 gint child_min, child_nat;
1640 if (!gtk_widget_get_visible (child->widget))
1643 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1644 gtk_widget_get_preferred_width (child->widget,
1645 &child_min, &child_nat);
1646 else /* GTK_ORIENTATION_VERTICAL */
1647 gtk_widget_get_preferred_height (child->widget,
1648 &child_min, &child_nat);
1650 aligned_item_sizes[i % line_length].minimum_size =
1651 MAX (aligned_item_sizes[i % line_length].minimum_size, child_min);
1653 aligned_item_sizes[i % line_length].natural_size =
1654 MAX (aligned_item_sizes[i % line_length].natural_size, child_nat);
1659 /* Add up the largest indexes */
1660 for (i = 0; i < line_length; i++)
1662 max_min_size += aligned_item_sizes[i].minimum_size;
1663 max_nat_size += aligned_item_sizes[i].natural_size;
1666 g_free (aligned_item_sizes);
1668 max_min_size += (line_length - 1) * spacing;
1669 max_nat_size += (line_length - 1) * spacing;
1672 *min_size = max_min_size;
1675 *nat_size = max_nat_size;
1680 gtk_wrap_box_get_preferred_width (GtkWidget *widget,
1684 GtkWrapBox *box = GTK_WRAP_BOX (widget);
1685 GtkWrapBoxPrivate *priv = box->priv;
1686 gint min_item_width, nat_item_width;
1687 gint min_items, nat_items;
1688 gint min_width, nat_width;
1690 min_items = MAX (1, priv->minimum_line_children);
1691 nat_items = MAX (min_items, priv->natural_line_children);
1693 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1695 min_width = nat_width = 0;
1697 if (priv->mode == GTK_WRAP_ALLOCATE_FREE ||
1698 priv->mode == GTK_WRAP_ALLOCATE_ALIGNED)
1700 /* In FREE and ALIGNED modes; horizontally oriented boxes
1701 * need enough width for the widest row */
1704 get_average_item_size (box, GTK_ORIENTATION_HORIZONTAL,
1705 &min_item_width, &nat_item_width);
1707 min_width += min_item_width;
1708 nat_width += nat_item_width;
1710 else if (priv->mode == GTK_WRAP_ALLOCATE_FREE)
1712 gint min_line_length, nat_line_length;
1714 get_largest_line_length (box, GTK_ORIENTATION_HORIZONTAL, min_items,
1715 &min_line_length, &nat_line_length);
1717 if (nat_items > min_items)
1718 get_largest_line_length (box, GTK_ORIENTATION_HORIZONTAL, nat_items,
1719 NULL, &nat_line_length);
1721 min_width += min_line_length;
1722 nat_width += nat_line_length;
1724 else /* GTK_WRAP_MODE_ALIGNED */
1726 gint min_line_length, nat_line_length;
1728 get_largest_aligned_line_length (box, GTK_ORIENTATION_HORIZONTAL, min_items,
1729 &min_line_length, &nat_line_length);
1731 if (nat_items > min_items)
1732 get_largest_aligned_line_length (box, GTK_ORIENTATION_HORIZONTAL, nat_items,
1733 NULL, &nat_line_length);
1735 min_width += min_line_length;
1736 nat_width += nat_line_length;
1739 else /* In HOMOGENEOUS mode; horizontally oriented boxs
1740 * give the same width to all children */
1742 get_average_item_size (box, GTK_ORIENTATION_HORIZONTAL,
1743 &min_item_width, &nat_item_width);
1745 min_width += min_item_width * min_items;
1746 min_width += (min_items -1) * priv->horizontal_spacing;
1748 nat_width += nat_item_width * nat_items;
1749 nat_width += (nat_items -1) * priv->horizontal_spacing;
1752 else /* GTK_ORIENTATION_VERTICAL */
1754 /* Return the width for the minimum height */
1757 GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_height, NULL);
1758 GTK_WIDGET_GET_CLASS (widget)->get_preferred_width_for_height (widget, min_height,
1759 &min_width, &nat_width);
1764 *minimum_size = min_width;
1767 *natural_size = nat_width;
1771 gtk_wrap_box_get_preferred_height (GtkWidget *widget,
1775 GtkWrapBox *box = GTK_WRAP_BOX (widget);
1776 GtkWrapBoxPrivate *priv = box->priv;
1777 gint min_item_height, nat_item_height;
1778 gint min_items, nat_items;
1779 gint min_height, nat_height;
1781 min_items = MAX (1, priv->minimum_line_children);
1782 nat_items = MAX (min_items, priv->natural_line_children);
1784 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1786 /* Return the height for the minimum width */
1789 GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, NULL);
1790 GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, min_width,
1791 &min_height, &nat_height);
1793 else /* GTK_ORIENTATION_VERTICAL */
1795 min_height = nat_height = 0;
1797 if (priv->mode == GTK_WRAP_ALLOCATE_FREE ||
1798 priv->mode == GTK_WRAP_ALLOCATE_ALIGNED)
1800 /* In FREE and ALIGNED modes; vertically oriented boxes
1801 * need enough height for the tallest column */
1804 get_average_item_size (box, GTK_ORIENTATION_VERTICAL,
1805 &min_item_height, &nat_item_height);
1807 min_height += min_item_height;
1808 nat_height += nat_item_height;
1810 else if (priv->mode == GTK_WRAP_ALLOCATE_FREE)
1812 gint min_line_length, nat_line_length;
1814 get_largest_line_length (box, GTK_ORIENTATION_VERTICAL, min_items,
1815 &min_line_length, &nat_line_length);
1817 if (nat_items > min_items)
1818 get_largest_line_length (box, GTK_ORIENTATION_VERTICAL, nat_items,
1819 NULL, &nat_line_length);
1821 min_height += min_line_length;
1822 nat_height += nat_line_length;
1824 else /* GTK_WRAP_ALLOCATE_ALIGNED */
1826 gint min_line_length, nat_line_length;
1828 get_largest_aligned_line_length (box, GTK_ORIENTATION_VERTICAL, min_items,
1829 &min_line_length, &nat_line_length);
1831 if (nat_items > min_items)
1832 get_largest_aligned_line_length (box, GTK_ORIENTATION_VERTICAL, nat_items,
1833 NULL, &nat_line_length);
1835 min_height += min_line_length;
1836 nat_height += nat_line_length;
1840 else /* In HOMOGENEOUS mode; vertically oriented boxs
1841 * give the same height to all children */
1843 get_average_item_size (box, GTK_ORIENTATION_VERTICAL,
1844 &min_item_height, &nat_item_height);
1846 min_height += min_item_height * min_items;
1847 min_height += (min_items -1) * priv->vertical_spacing;
1849 nat_height += nat_item_height * nat_items;
1850 nat_height += (nat_items -1) * priv->vertical_spacing;
1855 *minimum_size = min_height;
1858 *natural_size = nat_height;
1862 gtk_wrap_box_get_preferred_height_for_width (GtkWidget *widget,
1864 gint *minimum_height,
1865 gint *natural_height)
1867 GtkWrapBox *box = GTK_WRAP_BOX (widget);
1868 GtkWrapBoxPrivate *priv = box->priv;
1869 gint min_item_width, nat_item_width;
1871 gint min_height, nat_height;
1872 gint avail_size, n_children;
1874 min_items = MAX (1, priv->minimum_line_children);
1879 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1883 n_children = get_visible_children (box);
1885 /* Make sure its no smaller than the minimum */
1886 GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, NULL);
1888 avail_size = MAX (width, min_width);
1890 if (priv->mode == GTK_WRAP_ALLOCATE_ALIGNED ||
1891 priv->mode == GTK_WRAP_ALLOCATE_HOMOGENEOUS)
1894 gint item_size, extra_pixels;
1896 get_average_item_size (box, GTK_ORIENTATION_HORIZONTAL, &min_item_width, &nat_item_width);
1898 /* By default wrap at the natural item width */
1899 line_length = avail_size / (nat_item_width + priv->horizontal_spacing);
1901 /* After the above aproximation, check if we cant fit one more on the line */
1902 if (line_length * priv->horizontal_spacing + (line_length + 1) * nat_item_width <= avail_size)
1905 /* Its possible we were allocated just less than the natural width of the
1906 * minimum item wrap length */
1907 line_length = MAX (min_items, line_length);
1909 /* Now we need the real item allocation size */
1910 item_size = (avail_size - (line_length - 1) * priv->horizontal_spacing) / line_length;
1912 /* Cut out the expand space if we're not distributing any */
1913 if (priv->horizontal_spreading != GTK_WRAP_BOX_SPREAD_EXPAND)
1915 item_size = MIN (item_size, nat_item_width);
1919 /* Collect the extra pixels for expand children */
1920 extra_pixels = (avail_size - (line_length - 1) * priv->horizontal_spacing) % line_length;
1922 if (priv->mode == GTK_WRAP_ALLOCATE_HOMOGENEOUS)
1924 gint min_item_height, nat_item_height;
1927 /* Here we just use the largest height-for-width and
1928 * add up the size accordingly */
1929 get_largest_size_for_opposing_orientation (box, GTK_ORIENTATION_HORIZONTAL, item_size,
1930 &min_item_height, &nat_item_height);
1932 /* Round up how many lines we need to allocate for */
1933 lines = n_children / line_length;
1934 if ((n_children % line_length) > 0)
1937 min_height = min_item_height * lines;
1938 nat_height = nat_item_height * lines;
1940 min_height += (lines - 1) * priv->vertical_spacing;
1941 nat_height += (lines - 1) * priv->vertical_spacing;
1943 else /* GTK_WRAP_ALLOCATE_ALIGNED */
1945 GList *list = priv->children;
1946 gint min_line_height, nat_line_height, i;
1947 gboolean first_line = TRUE;
1948 GtkRequestedSize *item_sizes;
1950 /* First get the size each set of items take to span the line
1951 * when aligning the items above and below after wrapping.
1953 item_sizes = fit_aligned_item_requests (box, priv->orientation, avail_size,
1954 priv->horizontal_spacing, &line_length, n_children);
1957 /* Get the available remaining size */
1958 avail_size -= (line_length - 1) * priv->horizontal_spacing;
1959 for (i = 0; i < line_length; i++)
1960 avail_size -= item_sizes[i].minimum_size;
1962 extra_pixels = gtk_distribute_natural_allocation (avail_size, line_length, item_sizes);
1964 while (list != NULL)
1967 get_largest_size_for_line_in_opposing_orientation (box, GTK_ORIENTATION_HORIZONTAL,
1969 item_sizes, extra_pixels,
1970 &min_line_height, &nat_line_height);
1972 /* Its possible the line only had invisible widgets */
1973 if (nat_line_height > 0)
1979 min_height += priv->vertical_spacing;
1980 nat_height += priv->vertical_spacing;
1983 min_height += min_line_height;
1984 nat_height += nat_line_height;
1988 g_free (item_sizes);
1991 else /* GTK_WRAP_ALLOCATE_FREE */
1993 /* Here we just fit as many children as we can allocate their natural size to
1994 * on each line and add the heights for each of them on each line */
1995 GList *list = priv->children;
1996 gint min_line_height = 0, nat_line_height = 0;
1997 gboolean first_line = TRUE;
1999 while (list != NULL)
2002 get_largest_size_for_free_line_in_opposing_orientation (box, GTK_ORIENTATION_HORIZONTAL,
2003 list, min_items, avail_size,
2004 &min_line_height, &nat_line_height,
2007 /* Its possible the last line only had invisible widgets */
2008 if (nat_line_height > 0)
2014 min_height += priv->vertical_spacing;
2015 nat_height += priv->vertical_spacing;
2018 min_height += min_line_height;
2019 nat_height += nat_line_height;
2024 else /* GTK_ORIENTATION_VERTICAL */
2026 /* Return the minimum height */
2027 GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_height, &nat_height);
2031 *minimum_height = min_height;
2034 *natural_height = nat_height;
2038 gtk_wrap_box_get_preferred_width_for_height (GtkWidget *widget,
2040 gint *minimum_width,
2041 gint *natural_width)
2043 GtkWrapBox *box = GTK_WRAP_BOX (widget);
2044 GtkWrapBoxPrivate *priv = box->priv;
2045 gint min_item_height, nat_item_height;
2047 gint min_width, nat_width;
2048 gint avail_size, n_children;
2050 min_items = MAX (1, priv->minimum_line_children);
2055 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2057 /* Return the minimum width */
2058 GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, &nat_width);
2060 else /* GTK_ORIENTATION_VERTICAL */
2064 n_children = get_visible_children (box);
2066 /* Make sure its no smaller than the minimum */
2067 GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_height, NULL);
2069 avail_size = MAX (height, min_height);
2071 if (priv->mode == GTK_WRAP_ALLOCATE_ALIGNED ||
2072 priv->mode == GTK_WRAP_ALLOCATE_HOMOGENEOUS)
2075 gint item_size, extra_pixels;
2077 get_average_item_size (box, GTK_ORIENTATION_VERTICAL, &min_item_height, &nat_item_height);
2079 /* By default wrap at the natural item width */
2080 line_length = avail_size / (nat_item_height + priv->vertical_spacing);
2082 /* After the above aproximation, check if we cant fit one more on the line */
2083 if (line_length * priv->vertical_spacing + (line_length + 1) * nat_item_height <= avail_size)
2086 /* Its possible we were allocated just less than the natural width of the
2087 * minimum item wrap length */
2088 line_length = MAX (min_items, line_length);
2090 /* Now we need the real item allocation size */
2091 item_size = (avail_size - (line_length - 1) * priv->vertical_spacing) / line_length;
2093 /* Cut out the expand space if we're not distributing any */
2094 if (priv->vertical_spreading != GTK_WRAP_BOX_SPREAD_EXPAND)
2096 item_size = MIN (item_size, nat_item_height);
2100 /* Collect the extra pixels for expand children */
2101 extra_pixels = (avail_size - (line_length - 1) * priv->vertical_spacing) % line_length;
2103 if (priv->mode == GTK_WRAP_ALLOCATE_HOMOGENEOUS)
2105 gint min_item_width, nat_item_width;
2108 /* Here we just use the largest height-for-width and
2109 * add up the size accordingly */
2110 get_largest_size_for_opposing_orientation (box, GTK_ORIENTATION_VERTICAL, item_size,
2111 &min_item_width, &nat_item_width);
2113 /* Round up how many lines we need to allocate for */
2114 n_children = get_visible_children (box);
2115 lines = n_children / line_length;
2116 if ((n_children % line_length) > 0)
2119 min_width = min_item_width * lines;
2120 nat_width = nat_item_width * lines;
2122 min_width += (lines - 1) * priv->horizontal_spacing;
2123 nat_width += (lines - 1) * priv->horizontal_spacing;
2125 else /* GTK_WRAP_ALLOCATE_ALIGNED */
2127 GList *list = priv->children;
2128 gint min_line_width, nat_line_width, i;
2129 gboolean first_line = TRUE;
2130 GtkRequestedSize *item_sizes;
2132 /* First get the size each set of items take to span the line
2133 * when aligning the items above and below after wrapping.
2135 item_sizes = fit_aligned_item_requests (box, priv->orientation, avail_size,
2136 priv->vertical_spacing, &line_length, n_children);
2138 /* Get the available remaining size */
2139 avail_size -= (line_length - 1) * priv->horizontal_spacing;
2140 for (i = 0; i < line_length; i++)
2141 avail_size -= item_sizes[i].minimum_size;
2143 extra_pixels = gtk_distribute_natural_allocation (avail_size, line_length, item_sizes);
2145 while (list != NULL)
2148 get_largest_size_for_line_in_opposing_orientation (box, GTK_ORIENTATION_VERTICAL,
2150 item_sizes, extra_pixels,
2151 &min_line_width, &nat_line_width);
2153 /* Its possible the last line only had invisible widgets */
2154 if (nat_line_width > 0)
2160 min_width += priv->horizontal_spacing;
2161 nat_width += priv->horizontal_spacing;
2164 min_width += min_line_width;
2165 nat_width += nat_line_width;
2168 g_free (item_sizes);
2171 else /* GTK_WRAP_ALLOCATE_FREE */
2173 /* Here we just fit as many children as we can allocate their natural size to
2174 * on each line and add the heights for each of them on each line */
2175 GList *list = priv->children;
2176 gint min_line_width = 0, nat_line_width = 0;
2177 gboolean first_line = TRUE;
2179 while (list != NULL)
2182 get_largest_size_for_free_line_in_opposing_orientation (box, GTK_ORIENTATION_VERTICAL,
2183 list, min_items, avail_size,
2184 &min_line_width, &nat_line_width,
2187 /* Its possible the last line only had invisible widgets */
2188 if (nat_line_width > 0)
2194 min_width += priv->horizontal_spacing;
2195 nat_width += priv->horizontal_spacing;
2198 min_width += min_line_width;
2199 nat_width += nat_line_width;
2206 *minimum_width = min_width;
2209 *natural_width = nat_width;
2212 /*****************************************************
2214 *****************************************************/
2218 * @mode: The #GtkWrapAllocationMode to use
2219 * @horizontal_spreading: The horizontal #GtkWrapBoxSpreading policy to use
2220 * @vertical_spreading: The vertical #GtkWrapBoxSpreading policy to use
2221 * @horizontal_spacing: The horizontal spacing to add between children
2222 * @vertical_spacing: The vertical spacing to add between children
2224 * Creates an #GtkWrapBox.
2226 * Returns: A new #GtkWrapBox container
2229 gtk_wrap_box_new (GtkWrapAllocationMode mode,
2230 GtkWrapBoxSpreading horizontal_spreading,
2231 GtkWrapBoxSpreading vertical_spreading,
2232 guint horizontal_spacing,
2233 guint vertical_spacing)
2235 return (GtkWidget *)g_object_new (GTK_TYPE_WRAP_BOX,
2236 "allocation-mode", mode,
2237 "horizontal-spreading", horizontal_spreading,
2238 "vertical-spreading", vertical_spreading,
2239 "vertical-spacing", vertical_spacing,
2240 "horizontal-spacing", horizontal_spacing,
2245 * gtk_wrap_box_set_allocation_mode:
2246 * @box: An #GtkWrapBox
2247 * @mode: The #GtkWrapAllocationMode to use.
2249 * Sets the allocation mode for @box's children.
2252 gtk_wrap_box_set_allocation_mode (GtkWrapBox *box,
2253 GtkWrapAllocationMode mode)
2255 GtkWrapBoxPrivate *priv;
2257 g_return_if_fail (GTK_IS_WRAP_BOX (box));
2261 if (priv->mode != mode)
2265 gtk_widget_queue_resize (GTK_WIDGET (box));
2267 g_object_notify (G_OBJECT (box), "allocation-mode");
2272 * gtk_wrap_box_get_allocation_mode:
2273 * @box: An #GtkWrapBox
2275 * Gets the allocation mode.
2277 * Returns: The #GtkWrapAllocationMode for @box.
2279 GtkWrapAllocationMode
2280 gtk_wrap_box_get_allocation_mode (GtkWrapBox *box)
2282 g_return_val_if_fail (GTK_IS_WRAP_BOX (box), FALSE);
2284 return box->priv->mode;
2289 * gtk_wrap_box_set_horizontal_spreading:
2290 * @box: An #GtkWrapBox
2291 * @spreading: The #GtkWrapBoxSpreading to use.
2293 * Sets the horizontal spreading mode for @box's children.
2296 gtk_wrap_box_set_horizontal_spreading (GtkWrapBox *box,
2297 GtkWrapBoxSpreading spreading)
2299 GtkWrapBoxPrivate *priv;
2301 g_return_if_fail (GTK_IS_WRAP_BOX (box));
2305 if (priv->horizontal_spreading != spreading)
2307 priv->horizontal_spreading = spreading;
2309 gtk_widget_queue_resize (GTK_WIDGET (box));
2311 g_object_notify (G_OBJECT (box), "horizontal-spreading");
2316 * gtk_wrap_box_get_horizontal_spreading:
2317 * @box: An #GtkWrapBox
2319 * Gets the horizontal spreading mode.
2321 * Returns: The horizontal #GtkWrapBoxSpreading for @box.
2324 gtk_wrap_box_get_horizontal_spreading (GtkWrapBox *box)
2326 g_return_val_if_fail (GTK_IS_WRAP_BOX (box), FALSE);
2328 return box->priv->horizontal_spreading;
2333 * gtk_wrap_box_set_vertical_spreading:
2334 * @box: An #GtkWrapBox
2335 * @spreading: The #GtkWrapBoxSpreading to use.
2337 * Sets the vertical spreading mode for @box's children.
2340 gtk_wrap_box_set_vertical_spreading (GtkWrapBox *box,
2341 GtkWrapBoxSpreading spreading)
2343 GtkWrapBoxPrivate *priv;
2345 g_return_if_fail (GTK_IS_WRAP_BOX (box));
2349 if (priv->vertical_spreading != spreading)
2351 priv->vertical_spreading = spreading;
2353 gtk_widget_queue_resize (GTK_WIDGET (box));
2355 g_object_notify (G_OBJECT (box), "vertical-spreading");
2360 * gtk_wrap_box_get_vertical_spreading:
2361 * @box: An #GtkWrapBox
2363 * Gets the vertical spreading mode.
2365 * Returns: The vertical #GtkWrapBoxSpreading for @box.
2368 gtk_wrap_box_get_vertical_spreading (GtkWrapBox *box)
2370 g_return_val_if_fail (GTK_IS_WRAP_BOX (box), FALSE);
2372 return box->priv->vertical_spreading;
2377 * gtk_wrap_box_set_vertical_spacing:
2378 * @box: An #GtkWrapBox
2379 * @spacing: The spacing to use.
2381 * Sets the vertical space to add between children.
2384 gtk_wrap_box_set_vertical_spacing (GtkWrapBox *box,
2387 GtkWrapBoxPrivate *priv;
2389 g_return_if_fail (GTK_IS_WRAP_BOX (box));
2393 if (priv->vertical_spacing != spacing)
2395 priv->vertical_spacing = spacing;
2397 gtk_widget_queue_resize (GTK_WIDGET (box));
2399 g_object_notify (G_OBJECT (box), "vertical-spacing");
2404 * gtk_wrap_box_get_vertical_spacing:
2405 * @box: An #GtkWrapBox
2407 * Gets the vertical spacing.
2409 * Returns: The vertical spacing.
2412 gtk_wrap_box_get_vertical_spacing (GtkWrapBox *box)
2414 g_return_val_if_fail (GTK_IS_WRAP_BOX (box), FALSE);
2416 return box->priv->vertical_spacing;
2420 * gtk_wrap_box_set_horizontal_spacing:
2421 * @box: An #GtkWrapBox
2422 * @spacing: The spacing to use.
2424 * Sets the horizontal space to add between children.
2427 gtk_wrap_box_set_horizontal_spacing (GtkWrapBox *box,
2430 GtkWrapBoxPrivate *priv;
2432 g_return_if_fail (GTK_IS_WRAP_BOX (box));
2436 if (priv->horizontal_spacing != spacing)
2438 priv->horizontal_spacing = spacing;
2440 gtk_widget_queue_resize (GTK_WIDGET (box));
2442 g_object_notify (G_OBJECT (box), "horizontal-spacing");
2447 * gtk_wrap_box_get_horizontal_spacing:
2448 * @box: An #GtkWrapBox
2450 * Gets the horizontal spacing.
2452 * Returns: The horizontal spacing.
2455 gtk_wrap_box_get_horizontal_spacing (GtkWrapBox *box)
2457 g_return_val_if_fail (GTK_IS_WRAP_BOX (box), FALSE);
2459 return box->priv->horizontal_spacing;
2463 * gtk_wrap_box_set_minimum_line_children:
2464 * @box: An #GtkWrapBox
2465 * @n_children: The minimum amount of children per line.
2467 * Sets the minimum amount of children to line up
2468 * in @box's orientation before wrapping.
2471 gtk_wrap_box_set_minimum_line_children (GtkWrapBox *box,
2474 GtkWrapBoxPrivate *priv;
2476 g_return_if_fail (GTK_IS_WRAP_BOX (box));
2480 if (priv->minimum_line_children != n_children)
2482 priv->minimum_line_children = n_children;
2484 gtk_widget_queue_resize (GTK_WIDGET (box));
2486 g_object_notify (G_OBJECT (box), "minimum-line-children");
2491 * gtk_wrap_box_get_minimum_line_children:
2492 * @box: An #GtkWrapBox
2494 * Gets the minimum amount of children per line.
2496 * Returns: The minimum amount of children per line.
2499 gtk_wrap_box_get_minimum_line_children (GtkWrapBox *box)
2501 g_return_val_if_fail (GTK_IS_WRAP_BOX (box), FALSE);
2503 return box->priv->minimum_line_children;
2507 * gtk_wrap_box_set_natural_line_children:
2508 * @box: An #GtkWrapBox
2509 * @n_children: The natural amount of children per line.
2511 * Sets the natural length of items to request and
2512 * allocate space for in @box's orientation.
2514 * Setting the natural amount of children per line
2515 * limits the overall natural size request to be no more
2516 * than @n_children items long in the given orientation.
2519 gtk_wrap_box_set_natural_line_children (GtkWrapBox *box,
2522 GtkWrapBoxPrivate *priv;
2524 g_return_if_fail (GTK_IS_WRAP_BOX (box));
2528 if (priv->natural_line_children != n_children)
2530 priv->natural_line_children = n_children;
2532 gtk_widget_queue_resize (GTK_WIDGET (box));
2534 g_object_notify (G_OBJECT (box), "natural-line-children");
2539 * gtk_wrap_box_get_natural_line_children:
2540 * @box: An #GtkWrapBox
2542 * Gets the natural amount of children per line.
2544 * Returns: The natural amount of children per line.
2547 gtk_wrap_box_get_natural_line_children (GtkWrapBox *box)
2549 g_return_val_if_fail (GTK_IS_WRAP_BOX (box), FALSE);
2551 return box->priv->natural_line_children;
2556 * gtk_wrap_box_insert_child:
2557 * @box: And #GtkWrapBox
2558 * @widget: the child #GtkWidget to add
2559 * @index: the position in the child list to insert, specify -1 to append to the list.
2560 * @packing: The #GtkWrapBoxPacking options to use.
2562 * Adds a child to an #GtkWrapBox with its packing options set
2566 gtk_wrap_box_insert_child (GtkWrapBox *box,
2569 GtkWrapBoxPacking packing)
2571 GtkWrapBoxPrivate *priv;
2572 GtkWrapBoxChild *child;
2575 g_return_if_fail (GTK_IS_WRAP_BOX (box));
2576 g_return_if_fail (GTK_IS_WIDGET (widget));
2580 list = g_list_find_custom (priv->children, widget,
2581 (GCompareFunc)find_child_in_list);
2582 g_return_if_fail (list == NULL);
2584 child = g_slice_new0 (GtkWrapBoxChild);
2585 child->widget = widget;
2586 child->packing = packing;
2588 priv->children = g_list_insert (priv->children, child, index);
2590 gtk_widget_set_parent (widget, GTK_WIDGET (box));
2594 * gtk_wrap_box_reorder_child:
2595 * @box: An #GtkWrapBox
2596 * @widget: The child to reorder
2597 * @index: The new child position
2599 * Reorders the child @widget in @box's list of children.
2602 gtk_wrap_box_reorder_child (GtkWrapBox *box,
2606 GtkWrapBoxPrivate *priv;
2607 GtkWrapBoxChild *child;
2610 g_return_if_fail (GTK_IS_WRAP_BOX (box));
2611 g_return_if_fail (GTK_IS_WIDGET (widget));
2615 list = g_list_find_custom (priv->children, widget,
2616 (GCompareFunc)find_child_in_list);
2617 g_return_if_fail (list != NULL);
2619 if (g_list_position (priv->children, list) != index)
2622 priv->children = g_list_delete_link (priv->children, list);
2623 priv->children = g_list_insert (priv->children, child, index);
2625 gtk_widget_queue_resize (GTK_WIDGET (box));