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
* #EggWrapBox positions child widgets in sequence according to its
30
* orientation. For instance, with the horizontal orientation, the widgets
31
* will be arranged from left to right, starting a new row under the
32
* previous row when necessary. Reducing the width in this case will
33
* require more rows, so a larger height will be requested.
35
* Likewise, with the vertical orientation, the widgets will be arranged
36
* from top to bottom, starting a new column to the right when necessary.
37
* Reducing the height will require more columns, so a larger width will be
40
* Unlike a GtkTable, the child widgets do not need to align in a grid.
47
#include "eggwrapbox.h"
48
#include "eggwrapbox-enums.h"
50
#define P_(msgid) (msgid)
51
#define GTK_PARAM_READWRITE (G_PARAM_READABLE | G_PARAM_WRITABLE)
54
typedef struct _EggWrapBoxChild EggWrapBoxChild;
60
PROP_HORIZONTAL_SPREADING,
61
PROP_VERTICAL_SPREADING,
62
PROP_HORIZONTAL_SPACING,
63
PROP_VERTICAL_SPACING,
64
PROP_MINIMUM_LINE_CHILDREN,
65
PROP_NATURAL_LINE_CHILDREN
74
struct _EggWrapBoxPrivate
76
GtkOrientation orientation;
77
EggWrapAllocationMode mode;
78
EggWrapBoxSpreading horizontal_spreading;
79
EggWrapBoxSpreading vertical_spreading;
81
guint16 vertical_spacing;
82
guint16 horizontal_spacing;
84
guint16 minimum_line_children;
85
guint16 natural_line_children;
90
struct _EggWrapBoxChild
94
EggWrapBoxPacking packing;
98
static void egg_wrap_box_get_property (GObject *object,
102
static void egg_wrap_box_set_property (GObject *object,
108
static void egg_wrap_box_size_allocate (GtkWidget *widget,
109
GtkAllocation *allocation);
111
/* GtkContainerClass */
112
static void egg_wrap_box_add (GtkContainer *container,
114
static void egg_wrap_box_remove (GtkContainer *container,
116
static void egg_wrap_box_forall (GtkContainer *container,
117
gboolean include_internals,
118
GtkCallback callback,
119
gpointer callback_data);
120
static void egg_wrap_box_set_child_property (GtkContainer *container,
125
static void egg_wrap_box_get_child_property (GtkContainer *container,
130
static GType egg_wrap_box_child_type (GtkContainer *container);
134
static GtkSizeRequestMode egg_wrap_box_get_request_mode (GtkWidget *widget);
135
static void egg_wrap_box_get_preferred_width (GtkWidget *widget,
138
static void egg_wrap_box_get_preferred_height (GtkWidget *widget,
141
static void egg_wrap_box_get_preferred_height_for_width (GtkWidget *box,
143
gint *minimum_height,
144
gint *natural_height);
145
static void egg_wrap_box_get_preferred_width_for_height (GtkWidget *box,
147
gint *minimum_height,
148
gint *natural_height);
151
G_DEFINE_TYPE_WITH_CODE (EggWrapBox, egg_wrap_box, GTK_TYPE_CONTAINER,
152
G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
155
#define ORIENTATION_SPREADING(box) \
156
(((EggWrapBox *)(box))->priv->orientation == GTK_ORIENTATION_HORIZONTAL ? \
157
((EggWrapBox *)(box))->priv->horizontal_spreading : \
158
((EggWrapBox *)(box))->priv->vertical_spreading)
160
#define OPPOSING_ORIENTATION_SPREADING(box) \
161
(((EggWrapBox *)(box))->priv->orientation == GTK_ORIENTATION_HORIZONTAL ? \
162
((EggWrapBox *)(box))->priv->vertical_spreading : \
163
((EggWrapBox *)(box))->priv->horizontal_spreading)
168
egg_wrap_box_class_init (EggWrapBoxClass *class)
170
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
171
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
172
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
174
gobject_class->get_property = egg_wrap_box_get_property;
175
gobject_class->set_property = egg_wrap_box_set_property;
177
widget_class->size_allocate = egg_wrap_box_size_allocate;
178
widget_class->get_request_mode = egg_wrap_box_get_request_mode;
179
widget_class->get_preferred_width = egg_wrap_box_get_preferred_width;
180
widget_class->get_preferred_height = egg_wrap_box_get_preferred_height;
181
widget_class->get_preferred_height_for_width = egg_wrap_box_get_preferred_height_for_width;
182
widget_class->get_preferred_width_for_height = egg_wrap_box_get_preferred_width_for_height;
184
container_class->add = egg_wrap_box_add;
185
container_class->remove = egg_wrap_box_remove;
186
container_class->forall = egg_wrap_box_forall;
187
container_class->child_type = egg_wrap_box_child_type;
188
container_class->set_child_property = egg_wrap_box_set_child_property;
189
container_class->get_child_property = egg_wrap_box_get_child_property;
190
gtk_container_class_handle_border_width (container_class);
192
/* GObjectClass properties */
193
g_object_class_override_property (gobject_class, PROP_ORIENTATION, "orientation");
196
* EggWrapBox:allocation-mode:
198
* The #EggWrapAllocationMode to use.
200
g_object_class_install_property (gobject_class,
201
PROP_ALLOCATION_MODE,
202
g_param_spec_uint ("allocation-mode",
203
P_("Allocation Mode"),
204
P_("The allocation mode to use"),
205
0, EGG_WRAP_ALLOCATE_HOMOGENEOUS,
206
EGG_WRAP_ALLOCATE_FREE,
207
GTK_PARAM_READWRITE));
210
* EggWrapBox:horizontal-spreading:
212
* The #EggWrapBoxSpreading to used to define what is done with extra
213
* space in a given orientation.
215
g_object_class_install_property (gobject_class,
216
PROP_HORIZONTAL_SPREADING,
217
g_param_spec_uint ("horizontal-spreading",
218
P_("Horizontal Spreading"),
219
P_("The spreading mode to use horizontally"),
220
0, EGG_WRAP_BOX_SPREAD_EXPAND,
221
EGG_WRAP_BOX_SPREAD_START,
222
GTK_PARAM_READWRITE));
225
* EggWrapBox:vertical-spreading:
227
* The #EggWrapBoxSpreading to used to define what is done with extra
228
* space in a given orientation.
230
g_object_class_install_property (gobject_class,
231
PROP_VERTICAL_SPREADING,
232
g_param_spec_uint ("vertical-spreading",
233
P_("Vertical Spreading"),
234
P_("The spreading mode to use vertically"),
235
0, EGG_WRAP_BOX_SPREAD_EXPAND,
236
EGG_WRAP_BOX_SPREAD_START,
237
GTK_PARAM_READWRITE));
241
* EggWrapBox:minimum-line-children:
243
* The minimum number of children to allocate consecutively in the given orientation.
245
* <note><para>Setting the minimum children per line ensures
246
* that a reasonably small height will be requested
247
* for the overall minimum width of the box.</para></note>
250
g_object_class_install_property (gobject_class,
251
PROP_MINIMUM_LINE_CHILDREN,
252
g_param_spec_uint ("minimum-line-children",
253
P_("Minimum Line Children"),
254
P_("The minimum number of children to allocate "
255
"consecutively in the given orientation."),
259
GTK_PARAM_READWRITE));
262
* EggWrapBox:natural-line-children:
264
* The maximum amount of children to request space for consecutively in the given orientation.
267
g_object_class_install_property (gobject_class,
268
PROP_NATURAL_LINE_CHILDREN,
269
g_param_spec_uint ("natural-line-children",
270
P_("Natural Line Children"),
271
P_("The maximum amount of children to request space for "
272
"consecutively in the given orientation."),
276
GTK_PARAM_READWRITE));
279
* EggWrapBox:vertical-spacing:
281
* The amount of vertical space between two children.
284
g_object_class_install_property (gobject_class,
285
PROP_VERTICAL_SPACING,
286
g_param_spec_uint ("vertical-spacing",
287
P_("Vertical spacing"),
288
P_("The amount of vertical space between two children"),
292
GTK_PARAM_READWRITE));
295
* EggWrapBox:horizontal-spacing:
297
* The amount of horizontal space between two children.
300
g_object_class_install_property (gobject_class,
301
PROP_HORIZONTAL_SPACING,
302
g_param_spec_uint ("horizontal-spacing",
303
P_("Horizontal spacing"),
304
P_("The amount of horizontal space between two children"),
308
GTK_PARAM_READWRITE));
310
/* GtkContainerClass child properties */
313
* EggWrapBox:packing:
315
* The #EggWrapBoxPacking options to specify how to pack a child into the box.
317
gtk_container_class_install_child_property (container_class,
322
P_("The packing options to use for this child"),
323
EGG_TYPE_WRAP_BOX_PACKING, 0,
324
GTK_PARAM_READWRITE));
326
g_type_class_add_private (class, sizeof (EggWrapBoxPrivate));
330
egg_wrap_box_init (EggWrapBox *box)
332
EggWrapBoxPrivate *priv;
335
G_TYPE_INSTANCE_GET_PRIVATE (box, EGG_TYPE_WRAP_BOX, EggWrapBoxPrivate);
337
priv->orientation = GTK_ORIENTATION_HORIZONTAL;
338
priv->mode = EGG_WRAP_ALLOCATE_FREE;
339
priv->horizontal_spreading = EGG_WRAP_BOX_SPREAD_START;
340
priv->vertical_spreading = EGG_WRAP_BOX_SPREAD_START;
341
priv->horizontal_spacing = 0;
342
priv->vertical_spacing = 0;
343
priv->children = NULL;
345
gtk_widget_set_has_window (GTK_WIDGET (box), FALSE);
348
/*****************************************************
350
*****************************************************/
352
egg_wrap_box_get_property (GObject *object,
357
EggWrapBox *box = EGG_WRAP_BOX (object);
358
EggWrapBoxPrivate *priv = box->priv;
362
case PROP_ORIENTATION:
363
g_value_set_boolean (value, priv->orientation);
365
case PROP_ALLOCATION_MODE:
366
g_value_set_uint (value, priv->mode);
368
case PROP_HORIZONTAL_SPREADING:
369
g_value_set_uint (value, priv->horizontal_spreading);
371
case PROP_VERTICAL_SPREADING:
372
g_value_set_uint (value, priv->vertical_spreading);
374
case PROP_HORIZONTAL_SPACING:
375
g_value_set_uint (value, priv->horizontal_spacing);
377
case PROP_VERTICAL_SPACING:
378
g_value_set_uint (value, priv->vertical_spacing);
380
case PROP_MINIMUM_LINE_CHILDREN:
381
g_value_set_uint (value, priv->minimum_line_children);
383
case PROP_NATURAL_LINE_CHILDREN:
384
g_value_set_uint (value, priv->natural_line_children);
387
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
393
egg_wrap_box_set_property (GObject *object,
398
EggWrapBox *box = EGG_WRAP_BOX (object);
399
EggWrapBoxPrivate *priv = box->priv;
403
case PROP_ORIENTATION:
404
priv->orientation = g_value_get_enum (value);
406
/* Re-box the children in the new orientation */
407
gtk_widget_queue_resize (GTK_WIDGET (box));
409
case PROP_ALLOCATION_MODE:
410
egg_wrap_box_set_allocation_mode (box, g_value_get_uint (value));
412
case PROP_HORIZONTAL_SPREADING:
413
egg_wrap_box_set_horizontal_spreading (box, g_value_get_uint (value));
415
case PROP_VERTICAL_SPREADING:
416
egg_wrap_box_set_vertical_spreading (box, g_value_get_uint (value));
418
case PROP_HORIZONTAL_SPACING:
419
egg_wrap_box_set_horizontal_spacing (box, g_value_get_uint (value));
421
case PROP_VERTICAL_SPACING:
422
egg_wrap_box_set_vertical_spacing (box, g_value_get_uint (value));
424
case PROP_MINIMUM_LINE_CHILDREN:
425
egg_wrap_box_set_minimum_line_children (box, g_value_get_uint (value));
427
case PROP_NATURAL_LINE_CHILDREN:
428
egg_wrap_box_set_natural_line_children (box, g_value_get_uint (value));
431
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
436
/*****************************************************
438
*****************************************************/
441
get_visible_children (EggWrapBox *box)
443
EggWrapBoxPrivate *priv = box->priv;
447
for (list = priv->children; list; list = list->next)
449
EggWrapBoxChild *child = list->data;
451
if (!gtk_widget_get_visible (child->widget))
461
get_visible_expand_children (EggWrapBox *box,
462
GtkOrientation orientation,
467
gint i, expand_children = 0;
469
for (i = 0, list = cursor; (n_visible > 0 ? i < n_visible : TRUE) && list; list = list->next)
471
EggWrapBoxChild *child = list->data;
473
if (!gtk_widget_get_visible (child->widget))
476
if ((orientation == GTK_ORIENTATION_HORIZONTAL && (child->packing & EGG_WRAP_BOX_H_EXPAND) != 0) ||
477
(orientation == GTK_ORIENTATION_VERTICAL && (child->packing & EGG_WRAP_BOX_V_EXPAND) != 0))
483
return expand_children;
486
/* Used in columned modes where all items share at least their
487
* equal widths or heights
490
get_average_item_size (EggWrapBox *box,
491
GtkOrientation orientation,
495
EggWrapBoxPrivate *priv = box->priv;
497
gint max_min_size = 0;
498
gint max_nat_size = 0;
500
for (list = priv->children; list; list = list->next)
502
EggWrapBoxChild *child = list->data;
503
gint child_min, child_nat;
505
if (!gtk_widget_get_visible (child->widget))
508
if (orientation == GTK_ORIENTATION_HORIZONTAL)
509
gtk_widget_get_preferred_width (child->widget, &child_min, &child_nat);
511
gtk_widget_get_preferred_height (child->widget, &child_min, &child_nat);
513
max_min_size = MAX (max_min_size, child_min);
514
max_nat_size = MAX (max_nat_size, child_nat);
518
*min_size = max_min_size;
521
*nat_size = max_nat_size;
525
/* Gets the largest minimum/natural size for a given size
526
* (used to get the largest item heights for a fixed item width and the opposite) */
528
get_largest_size_for_opposing_orientation (EggWrapBox *box,
529
GtkOrientation orientation,
534
EggWrapBoxPrivate *priv = box->priv;
536
gint max_min_size = 0;
537
gint max_nat_size = 0;
539
for (list = priv->children; list; list = list->next)
541
EggWrapBoxChild *child = list->data;
542
gint child_min, child_nat;
544
if (!gtk_widget_get_visible (child->widget))
547
if (orientation == GTK_ORIENTATION_HORIZONTAL)
548
gtk_widget_get_preferred_height_for_width (child->widget,
550
&child_min, &child_nat);
552
gtk_widget_get_preferred_width_for_height (child->widget,
554
&child_min, &child_nat);
556
max_min_size = MAX (max_min_size, child_min);
557
max_nat_size = MAX (max_nat_size, child_nat);
561
*min_item_size = max_min_size;
564
*nat_item_size = max_nat_size;
568
/* Gets the largest minimum/natural size on a single line for a given size
569
* (used to get the largest line heights for a fixed item width and the opposite
570
* while itterating over a list of children, note the new index is returned) */
572
get_largest_size_for_line_in_opposing_orientation (EggWrapBox *box,
573
GtkOrientation orientation,
576
GtkRequestedSize *item_sizes,
582
gint max_min_size = 0;
583
gint max_nat_size = 0;
586
for (list = cursor, i = 0; list && i < line_length; list = list->next)
588
EggWrapBoxChild *child = list->data;
589
gint child_min, child_nat, this_item_size;
591
if (!gtk_widget_get_visible (child->widget))
594
/* Distribute the extra pixels to the first children in the line
595
* (could be fancier and spread them out more evenly) */
596
this_item_size = item_sizes[i].minimum_size;
597
if (extra_pixels > 0 && ORIENTATION_SPREADING (box) == EGG_WRAP_BOX_SPREAD_EXPAND)
603
if (orientation == GTK_ORIENTATION_HORIZONTAL)
604
gtk_widget_get_preferred_height_for_width (child->widget,
606
&child_min, &child_nat);
608
gtk_widget_get_preferred_width_for_height (child->widget,
610
&child_min, &child_nat);
612
max_min_size = MAX (max_min_size, child_min);
613
max_nat_size = MAX (max_nat_size, child_nat);
619
*min_item_size = max_min_size;
622
*nat_item_size = max_nat_size;
624
/* Return next item in the list */
629
/* Gets the largest minimum/natural size on a single line for a given allocated line size
630
* (used to get the largest line heights for a width in pixels and the opposite
631
* while itterating over a list of children, note the new index is returned) */
633
get_largest_size_for_free_line_in_opposing_orientation (EggWrapBox *box,
634
GtkOrientation orientation,
643
EggWrapBoxPrivate *priv = box->priv;
644
GtkRequestedSize *sizes;
647
gint max_min_size = 0;
648
gint max_nat_size = 0;
649
gint i, size = avail_size;
650
gint line_length, spacing;
651
gint expand_children = 0;
652
gint expand_per_child;
653
gint expand_remainder;
655
if (orientation == GTK_ORIENTATION_HORIZONTAL)
656
spacing = priv->horizontal_spacing;
658
spacing = priv->vertical_spacing;
660
/* First determine the length of this line in items (how many items fit) */
661
for (i = 0, list = cursor; size > 0 && list; list = list->next)
663
EggWrapBoxChild *child = list->data;
666
if (!gtk_widget_get_visible (child->widget))
669
if (orientation == GTK_ORIENTATION_HORIZONTAL)
670
gtk_widget_get_preferred_width (child->widget, NULL, &child_size);
672
gtk_widget_get_preferred_height (child->widget, NULL, &child_size);
675
child_size += spacing;
677
if (size - child_size >= 0)
685
line_length = MAX (min_items, i);
688
/* Collect the sizes of the items on this line */
689
array = g_array_new (0, TRUE, sizeof (GtkRequestedSize));
691
for (i = 0, list = cursor; i < line_length && list; list = list->next)
693
EggWrapBoxChild *child = list->data;
694
GtkRequestedSize requested;
696
if (!gtk_widget_get_visible (child->widget))
699
requested.data = child;
700
if (orientation == GTK_ORIENTATION_HORIZONTAL)
701
gtk_widget_get_preferred_width (child->widget,
702
&requested.minimum_size,
703
&requested.natural_size);
705
gtk_widget_get_preferred_height (child->widget,
706
&requested.minimum_size,
707
&requested.natural_size);
712
size -= requested.minimum_size;
714
g_array_append_val (array, requested);
719
sizes = (GtkRequestedSize *)array->data;
720
size = gtk_distribute_natural_allocation (size, array->len, sizes);
723
*extra_pixels = size;
725
/* Cut out any expand space if we're not distributing any */
726
if (ORIENTATION_SPREADING (box) != EGG_WRAP_BOX_SPREAD_EXPAND)
729
/* Count how many children are going to expand... */
730
expand_children = get_visible_expand_children (box, orientation,
731
cursor, line_length);
733
/* If no child prefers to expand, they all get some expand space */
734
if (expand_children == 0)
736
expand_per_child = size / line_length;
737
expand_remainder = size % line_length;
741
expand_per_child = size / expand_children;
742
expand_remainder = size % expand_children;
745
/* Now add the remaining expand space and get the collective size of this line
746
* in the opposing orientation */
747
for (i = 0, list = cursor; i < line_length && list; list = list->next)
749
EggWrapBoxChild *child = list->data;
750
gint child_min, child_nat;
752
if (!gtk_widget_get_visible (child->widget))
755
g_assert (child == sizes[i].data);
757
if ((orientation == GTK_ORIENTATION_HORIZONTAL && (child->packing & EGG_WRAP_BOX_H_EXPAND) != 0) ||
758
(orientation == GTK_ORIENTATION_VERTICAL && (child->packing & EGG_WRAP_BOX_V_EXPAND) != 0) ||
759
expand_children == 0)
761
sizes[i].minimum_size += expand_per_child;
762
if (expand_remainder)
764
sizes[i].minimum_size++;
769
if (orientation == GTK_ORIENTATION_HORIZONTAL)
770
gtk_widget_get_preferred_height_for_width (child->widget,
771
sizes[i].minimum_size,
772
&child_min, &child_nat);
774
gtk_widget_get_preferred_width_for_height (child->widget,
775
sizes[i].minimum_size,
776
&child_min, &child_nat);
778
max_min_size = MAX (max_min_size, child_min);
779
max_nat_size = MAX (max_nat_size, child_nat);
787
g_array_free (array, TRUE);
790
*min_item_size = max_min_size;
793
*nat_item_size = max_nat_size;
795
/* Return the next item */
800
allocate_child (EggWrapBox *box,
801
EggWrapBoxChild *child,
807
EggWrapBoxPrivate *priv = box->priv;
808
GtkAllocation widget_allocation;
809
GtkAllocation child_allocation;
811
gtk_widget_get_allocation (GTK_WIDGET (box), &widget_allocation);
813
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
815
child_allocation.x = widget_allocation.x + item_offset;
816
child_allocation.y = widget_allocation.y + line_offset;
817
child_allocation.width = item_size;
818
child_allocation.height = line_size;
820
else /* GTK_ORIENTATION_VERTICAL */
822
child_allocation.x = widget_allocation.x + line_offset;
823
child_allocation.y = widget_allocation.y + item_offset;
824
child_allocation.width = line_size;
825
child_allocation.height = item_size;
828
gtk_widget_size_allocate (child->widget, &child_allocation);
831
/* fit_aligned_item_requests() helper */
833
gather_aligned_item_requests (EggWrapBox *box,
834
GtkOrientation orientation,
838
GtkRequestedSize *item_sizes)
840
EggWrapBoxPrivate *priv = box->priv;
843
gint extra_items, natural_line_size = 0;
845
extra_items = n_children % line_length;
847
for (list = priv->children, i = 0; list; list = list->next, i++)
849
EggWrapBoxChild *child = list->data;
850
gint child_min, child_nat;
853
if (!gtk_widget_get_visible (child->widget))
856
if (orientation == GTK_ORIENTATION_HORIZONTAL)
857
gtk_widget_get_preferred_width (child->widget,
858
&child_min, &child_nat);
860
gtk_widget_get_preferred_height (child->widget,
861
&child_min, &child_nat);
863
/* Get the index and push it over for the last line when spreading to the end */
864
position = i % line_length;
866
if (ORIENTATION_SPREADING (box) == EGG_WRAP_BOX_SPREAD_END && i >= n_children - extra_items)
867
position += line_length - extra_items;
869
/* Round up the size of every column/row */
870
item_sizes[position].minimum_size = MAX (item_sizes[position].minimum_size, child_min);
871
item_sizes[position].natural_size = MAX (item_sizes[position].natural_size, child_nat);
874
for (i = 0; i < line_length; i++)
875
natural_line_size += item_sizes[i].natural_size;
877
natural_line_size += (line_length - 1) * item_spacing;
879
return natural_line_size;
882
static GtkRequestedSize *
883
fit_aligned_item_requests (EggWrapBox *box,
884
GtkOrientation orientation,
887
gint *line_length, /* in-out */
890
GtkRequestedSize *sizes, *try_sizes;
891
gint try_line_size, try_length;
893
sizes = g_new0 (GtkRequestedSize, *line_length);
895
/* get the sizes for the initial guess */
897
gather_aligned_item_requests (box, orientation, *line_length, item_spacing, n_children, sizes);
899
/* Try columnizing the whole thing and adding an item to the end of the line;
900
* try to fit as many columns into the available size as possible */
901
for (try_length = *line_length + 1; try_line_size < avail_size; try_length++)
903
try_sizes = g_new0 (GtkRequestedSize, try_length);
904
try_line_size = gather_aligned_item_requests (box, orientation, try_length, item_spacing,
905
n_children, try_sizes);
907
if (try_line_size <= avail_size)
909
*line_length = try_length;
916
/* oops, this one failed; stick to the last size that fit and then return */
932
egg_wrap_box_size_allocate (GtkWidget *widget,
933
GtkAllocation *allocation)
935
EggWrapBox *box = EGG_WRAP_BOX (widget);
936
EggWrapBoxPrivate *priv = box->priv;
937
gint avail_size, avail_other_size, min_items, item_spacing, line_spacing;
938
EggWrapBoxSpreading item_spreading;
939
EggWrapBoxSpreading line_spreading;
941
gtk_widget_set_allocation (widget, allocation);
943
min_items = MAX (1, priv->minimum_line_children);
945
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
947
avail_size = allocation->width;
948
avail_other_size = allocation->height;
949
item_spacing = priv->horizontal_spacing;
950
line_spacing = priv->vertical_spacing;
952
else /* GTK_ORIENTATION_VERTICAL */
954
avail_size = allocation->height;
955
avail_other_size = allocation->width;
956
item_spacing = priv->vertical_spacing;
957
line_spacing = priv->horizontal_spacing;
960
item_spreading = ORIENTATION_SPREADING (box);
961
line_spreading = OPPOSING_ORIENTATION_SPREADING (box);
964
/*********************************************************
965
* Deal with ALIGNED/HOMOGENEOUS modes first, start with *
966
* initial guesses at item/line sizes *
967
*********************************************************/
968
if (priv->mode == EGG_WRAP_ALLOCATE_ALIGNED ||
969
priv->mode == EGG_WRAP_ALLOCATE_HOMOGENEOUS)
971
GtkRequestedSize *line_sizes = NULL;
972
GtkRequestedSize *item_sizes = NULL;
974
gint min_item_size, nat_item_size;
977
gint line_size = 0, min_fixed_line_size = 0, nat_fixed_line_size = 0;
978
gint line_offset, item_offset, n_children, n_lines, line_count;
979
gint extra_pixels, extra_per_item = 0, extra_extra = 0;
980
gint extra_line_pixels, extra_per_line = 0, extra_line_extra = 0;
981
gint i, this_line_size;
983
get_average_item_size (box, priv->orientation, &min_item_size, &nat_item_size);
985
/* By default wrap at the natural item width */
986
line_length = avail_size / (nat_item_size + item_spacing);
988
/* After the above aproximation, check if we cant fit one more on the line */
989
if (line_length * item_spacing + (line_length + 1) * nat_item_size <= avail_size)
992
/* Its possible we were allocated just less than the natural width of the
993
* minimum item wrap length */
994
line_length = MAX (min_items, line_length);
996
/* Get how many lines we'll be needing to wrap */
997
n_children = get_visible_children (box);
999
/* Here we just use the largest height-for-width and use that for the height
1001
if (priv->mode == EGG_WRAP_ALLOCATE_HOMOGENEOUS)
1003
n_lines = n_children / line_length;
1004
if ((n_children % line_length) > 0)
1007
n_lines = MAX (n_lines, 1);
1009
/* Now we need the real item allocation size */
1010
item_size = (avail_size - (line_length - 1) * item_spacing) / line_length;
1012
/* Cut out the expand space if we're not distributing any */
1013
if (item_spreading != EGG_WRAP_BOX_SPREAD_EXPAND)
1014
item_size = MIN (item_size, nat_item_size);
1016
get_largest_size_for_opposing_orientation (box, priv->orientation, item_size,
1017
&min_fixed_line_size,
1018
&nat_fixed_line_size);
1020
/* resolve a fixed 'line_size' */
1021
line_size = (avail_other_size - (n_lines - 1) * line_spacing) / n_lines;
1023
if (line_spreading != EGG_WRAP_BOX_SPREAD_EXPAND)
1024
line_size = MIN (line_size, nat_fixed_line_size);
1026
/* Get the real extra pixels incase of EGG_WRAP_BOX_SPREAD_START lines */
1027
extra_pixels = avail_size - (line_length - 1) * item_spacing - item_size * line_length;
1028
extra_line_pixels = avail_other_size - (n_lines - 1) * line_spacing - line_size * n_lines;
1030
else /* EGG_WRAP_ALLOCATE_ALIGNED */
1033
gboolean first_line = TRUE;
1035
/* Find the amount of columns that can fit aligned into the available space
1036
* and collect their requests.
1038
item_sizes = fit_aligned_item_requests (box, priv->orientation, avail_size,
1039
item_spacing, &line_length, n_children);
1041
/* Calculate the number of lines after determining the final line_length */
1042
n_lines = n_children / line_length;
1043
if ((n_children % line_length) > 0)
1046
n_lines = MAX (n_lines, 1);
1047
line_sizes = g_new0 (GtkRequestedSize, n_lines);
1049
/* Get the available remaining size */
1050
avail_size -= (line_length - 1) * item_spacing;
1051
for (i = 0; i < line_length; i++)
1052
avail_size -= item_sizes[i].minimum_size;
1054
/* Perform a natural allocation on the columnized items and get the remaining pixels */
1055
extra_pixels = gtk_distribute_natural_allocation (avail_size, line_length, item_sizes);
1057
/* Now that we have the size of each column of items find the size of each individual
1058
* line based on the aligned item sizes.
1060
for (i = 0, list = priv->children; list != NULL; i++)
1064
get_largest_size_for_line_in_opposing_orientation (box, priv->orientation,
1066
item_sizes, extra_pixels,
1067
&line_sizes[i].minimum_size,
1068
&line_sizes[i].natural_size);
1071
/* Its possible a line is made of completely invisible children */
1072
if (line_sizes[i].natural_size > 0)
1077
avail_other_size -= line_spacing;
1079
avail_other_size -= line_sizes[i].minimum_size;
1081
line_sizes[i].data = GINT_TO_POINTER (i);
1085
/* Distribute space among lines naturally */
1086
extra_line_pixels = gtk_distribute_natural_allocation (avail_other_size, n_lines, line_sizes);
1089
/*********************************************************
1090
* Initial sizes of items/lines guessed at this point, *
1091
* go on to distribute expand space if needed. *
1092
*********************************************************/
1094
/* FIXME: This portion needs to consider which columns
1095
* and rows asked for expand space and distribute those
1096
* accordingly for the case of ALIGNED allocation.
1098
* If at least one child in a column/row asked for expand;
1099
* we should make that row/column expand entirely.
1102
/* Calculate expand space per item */
1103
if (item_spreading == EGG_WRAP_BOX_SPREAD_EVEN)
1105
extra_per_item = extra_pixels / MAX (line_length -1, 1);
1106
extra_extra = extra_pixels % MAX (line_length -1, 1);
1108
else if (item_spreading == EGG_WRAP_BOX_SPREAD_EXPAND)
1110
extra_per_item = extra_pixels / line_length;
1111
extra_extra = extra_pixels % line_length;
1114
/* Calculate expand space per line */
1115
if (line_spreading == EGG_WRAP_BOX_SPREAD_EVEN)
1117
extra_per_line = extra_line_pixels / MAX (n_lines -1, 1);
1118
extra_line_extra = extra_line_pixels % MAX (n_lines -1, 1);
1120
else if (line_spreading == EGG_WRAP_BOX_SPREAD_EXPAND)
1122
extra_per_line = extra_line_pixels / n_lines;
1123
extra_line_extra = extra_line_pixels % n_lines;
1126
/*********************************************************
1127
* Prepare item/line initial offsets and jump into the *
1128
* real allocation loop. *
1129
*********************************************************/
1130
line_offset = item_offset = 0;
1132
/* prepend extra space to item_offset/line_offset for SPREAD_END */
1133
if (item_spreading == EGG_WRAP_BOX_SPREAD_END)
1134
item_offset += extra_pixels;
1136
if (line_spreading == EGG_WRAP_BOX_SPREAD_END)
1137
line_offset += extra_line_pixels;
1139
/* Get the allocation size for the first line */
1140
if (priv->mode == EGG_WRAP_ALLOCATE_HOMOGENEOUS)
1141
this_line_size = line_size;
1144
this_line_size = line_sizes[0].minimum_size;
1146
if (line_spreading == EGG_WRAP_BOX_SPREAD_EXPAND)
1148
this_line_size += extra_per_line;
1150
if (extra_line_extra > 0)
1155
for (i = 0, line_count = 0, list = priv->children; list; list = list->next)
1157
EggWrapBoxChild *child = list->data;
1159
gint this_item_size;
1161
if (!gtk_widget_get_visible (child->widget))
1164
/* Get item position */
1165
position = i % line_length;
1167
/* adjust the line_offset/count at the beginning of each new line */
1168
if (i > 0 && position == 0)
1170
/* Push the line_offset */
1171
line_offset += this_line_size + line_spacing;
1173
if (line_spreading == EGG_WRAP_BOX_SPREAD_EVEN)
1175
line_offset += extra_per_line;
1177
if (line_count < extra_line_extra)
1183
/* Get the new line size */
1184
if (priv->mode == EGG_WRAP_ALLOCATE_HOMOGENEOUS)
1185
this_line_size = line_size;
1188
this_line_size = line_sizes[line_count].minimum_size;
1190
if (line_spreading == EGG_WRAP_BOX_SPREAD_EXPAND)
1192
this_line_size += extra_per_line;
1194
if (line_count < extra_line_extra)
1201
if (item_spreading == EGG_WRAP_BOX_SPREAD_END)
1203
item_offset += extra_pixels;
1205
/* If we're on the last line, prepend the space for
1206
* any leading items */
1207
if (line_count == n_lines -1)
1209
gint extra_items = n_children % line_length;
1211
if (priv->mode == EGG_WRAP_ALLOCATE_HOMOGENEOUS)
1213
item_offset += item_size * (line_length - extra_items);
1214
item_offset += item_spacing * (line_length - extra_items);
1220
for (j = 0; j < (line_length - extra_items); j++)
1222
item_offset += item_sizes[j].minimum_size;
1223
item_offset += item_spacing;
1230
/* Push the index along for the last line when spreading to the end */
1231
if (item_spreading == EGG_WRAP_BOX_SPREAD_END &&
1232
line_count == n_lines -1)
1234
gint extra_items = n_children % line_length;
1236
position += line_length - extra_items;
1239
if (priv->mode == EGG_WRAP_ALLOCATE_HOMOGENEOUS)
1240
this_item_size = item_size;
1241
else /* aligned mode */
1242
this_item_size = item_sizes[position].minimum_size;
1244
if (item_spreading == EGG_WRAP_BOX_SPREAD_EXPAND)
1246
this_item_size += extra_per_item;
1248
if (position < extra_extra)
1252
/* Do the actual allocation */
1253
allocate_child (box, child, item_offset, line_offset, this_item_size, this_line_size);
1255
item_offset += this_item_size;
1256
item_offset += item_spacing;
1258
/* deal with extra spacing here */
1259
if (item_spreading == EGG_WRAP_BOX_SPREAD_EVEN)
1261
item_offset += extra_per_item;
1263
if (position < extra_extra)
1270
g_free (item_sizes);
1271
g_free (line_sizes);
1273
else /* EGG_WRAP_ALLOCATE_FREE */
1275
/* Here we just fit as many children as we can allocate their natural size to
1276
* on each line and add the heights for each of them on each line */
1277
GtkRequestedSize requested;
1278
GtkRequestedSize *sizes = NULL;
1279
GList *list = priv->children;
1280
gboolean first_line = TRUE;
1281
gint i, line_count = 0;
1282
gint line_offset, item_offset;
1283
gint extra_per_line = 0, extra_line_extra = 0;
1287
array = g_array_new (0, TRUE, sizeof (GtkRequestedSize));
1289
while (list != NULL)
1292
AllocatedLine *line;
1295
get_largest_size_for_free_line_in_opposing_orientation (box, priv->orientation,
1296
list, min_items, avail_size,
1297
&requested.minimum_size,
1298
&requested.natural_size,
1302
/* Its possible a line is made of completely invisible children */
1303
if (requested.natural_size > 0)
1308
avail_other_size -= line_spacing;
1310
avail_other_size -= requested.minimum_size;
1312
line = g_slice_new0 (AllocatedLine);
1313
line->requested = line_array;
1314
line->extra_pixels = extra_pixels;
1316
requested.data = line;
1318
g_array_append_val (array, requested);
1322
/* Distribute space among lines naturally */
1323
sizes = (GtkRequestedSize *)array->data;
1324
avail_other_size = gtk_distribute_natural_allocation (avail_other_size, array->len, sizes);
1326
/* Calculate expand space per line */
1327
if (line_spreading == EGG_WRAP_BOX_SPREAD_EVEN)
1329
extra_per_line = avail_other_size / MAX (array->len -1, 1);
1330
extra_line_extra = avail_other_size % MAX (array->len -1, 1);
1332
else if (line_spreading == EGG_WRAP_BOX_SPREAD_EXPAND)
1334
extra_per_line = avail_other_size / array->len;
1335
extra_line_extra = avail_other_size % array->len;
1338
if (line_spreading == EGG_WRAP_BOX_SPREAD_END)
1339
line_offset = avail_other_size;
1343
for (line_count = 0; line_count < array->len; line_count++)
1345
AllocatedLine *line = (AllocatedLine *)sizes[line_count].data;
1346
GArray *line_array = line->requested;
1347
GtkRequestedSize *line_sizes = (GtkRequestedSize *)line_array->data;
1348
gint line_size = sizes[line_count].minimum_size;
1349
gint extra_per_item = 0;
1350
gint extra_extra = 0;
1352
/* Set line start offset */
1355
if (line_spreading == EGG_WRAP_BOX_SPREAD_EXPAND)
1357
line_size += extra_per_line;
1359
if (line_count < extra_line_extra)
1363
if (item_spreading == EGG_WRAP_BOX_SPREAD_END)
1364
item_offset += line->extra_pixels;
1365
else if (item_spreading == EGG_WRAP_BOX_SPREAD_EVEN)
1367
extra_per_item = line->extra_pixels / MAX (line_array->len -1, 1);
1368
extra_extra = line->extra_pixels % MAX (line_array->len -1, 1);
1371
for (i = 0; i < line_array->len; i++)
1373
EggWrapBoxChild *child = line_sizes[i].data;
1374
gint item_size = line_sizes[i].minimum_size;
1376
/* Do the actual allocation */
1377
allocate_child (box, child, item_offset, line_offset, item_size, line_size);
1379
/* Add extra space evenly between children */
1380
if (item_spreading == EGG_WRAP_BOX_SPREAD_EVEN)
1382
item_offset += extra_per_item;
1383
if (i < extra_extra)
1387
/* Move item cursor along for the next allocation */
1388
item_offset += item_spacing;
1389
item_offset += item_size;
1392
/* New line, increment offset and reset item cursor */
1393
line_offset += line_spacing;
1394
line_offset += line_size;
1396
if (line_spreading == EGG_WRAP_BOX_SPREAD_EVEN)
1398
line_offset += extra_per_line;
1400
if (line_count < extra_line_extra)
1404
/* Free the array for this line now its not needed anymore */
1405
g_array_free (line_array, TRUE);
1406
g_slice_free (AllocatedLine, line);
1409
g_array_free (array, TRUE);
1413
/*****************************************************
1414
* GtkContainerClass *
1415
*****************************************************/
1417
egg_wrap_box_add (GtkContainer *container,
1420
egg_wrap_box_insert_child (EGG_WRAP_BOX (container), widget, -1, 0);
1424
find_child_in_list (EggWrapBoxChild *child_in_list,
1427
return (child_in_list->widget == search) ? 0 : -1;
1431
egg_wrap_box_remove (GtkContainer *container,
1434
EggWrapBox *box = EGG_WRAP_BOX (container);
1435
EggWrapBoxPrivate *priv = box->priv;
1438
list = g_list_find_custom (priv->children, widget,
1439
(GCompareFunc)find_child_in_list);
1443
EggWrapBoxChild *child = list->data;
1444
gboolean was_visible = gtk_widget_get_visible (widget);
1446
gtk_widget_unparent (widget);
1448
g_slice_free (EggWrapBoxChild, child);
1449
priv->children = g_list_delete_link (priv->children, list);
1451
if (was_visible && gtk_widget_get_visible (GTK_WIDGET (container)))
1452
gtk_widget_queue_resize (GTK_WIDGET (container));
1457
egg_wrap_box_forall (GtkContainer *container,
1458
gboolean include_internals,
1459
GtkCallback callback,
1460
gpointer callback_data)
1462
EggWrapBox *box = EGG_WRAP_BOX (container);
1463
EggWrapBoxPrivate *priv = box->priv;
1464
EggWrapBoxChild *child;
1467
list = priv->children;
1474
(* callback) (child->widget, callback_data);
1479
egg_wrap_box_child_type (GtkContainer *container)
1481
return GTK_TYPE_WIDGET;
1485
egg_wrap_box_set_child_property (GtkContainer *container,
1488
const GValue *value,
1491
EggWrapBox *box = EGG_WRAP_BOX (container);
1492
EggWrapBoxPrivate *priv = box->priv;
1493
EggWrapBoxChild *child;
1496
list = g_list_find_custom (priv->children, widget,
1497
(GCompareFunc)find_child_in_list);
1498
g_return_if_fail (list != NULL);
1502
switch (property_id)
1504
case CHILD_PROP_PACKING:
1505
child->packing = g_value_get_flags (value);
1508
GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
1512
if (gtk_widget_get_visible (widget) &&
1513
gtk_widget_get_visible (GTK_WIDGET (box)))
1514
gtk_widget_queue_resize (widget);
1518
egg_wrap_box_get_child_property (GtkContainer *container,
1524
EggWrapBox *box = EGG_WRAP_BOX (container);
1525
EggWrapBoxPrivate *priv = box->priv;
1526
EggWrapBoxChild *child;
1529
list = g_list_find_custom (priv->children, widget,
1530
(GCompareFunc)find_child_in_list);
1531
g_return_if_fail (list != NULL);
1535
switch (property_id)
1537
case CHILD_PROP_PACKING:
1538
g_value_set_flags (value, child->packing);
1541
GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
1546
/*****************************************************
1548
*****************************************************/
1551
static GtkSizeRequestMode
1552
egg_wrap_box_get_request_mode (GtkWidget *widget)
1554
EggWrapBox *box = EGG_WRAP_BOX (widget);
1555
EggWrapBoxPrivate *priv = box->priv;
1557
return (priv->orientation == GTK_ORIENTATION_HORIZONTAL) ?
1558
GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH : GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
1561
/* Gets the largest minimum and natural length of
1562
* 'line_length' consecutive items */
1564
get_largest_line_length (EggWrapBox *box,
1565
GtkOrientation orientation,
1570
EggWrapBoxPrivate *priv = box->priv;
1572
gint max_min_size = 0;
1573
gint max_nat_size = 0;
1576
if (orientation == GTK_ORIENTATION_HORIZONTAL)
1577
spacing = priv->horizontal_spacing;
1579
spacing = priv->vertical_spacing;
1581
/* Get the largest size of 'line_length' consecutive items in the list.
1583
for (list = priv->children; list; list = list->next)
1589
for (l = list, i = 0; l && i < line_length; l = l->next)
1591
EggWrapBoxChild *child = l->data;
1592
gint child_min, child_nat;
1594
if (!gtk_widget_get_visible (child->widget))
1597
if (orientation == GTK_ORIENTATION_HORIZONTAL)
1598
gtk_widget_get_preferred_width (child->widget,
1599
&child_min, &child_nat);
1600
else /* GTK_ORIENTATION_VERTICAL */
1601
gtk_widget_get_preferred_height (child->widget,
1602
&child_min, &child_nat);
1604
line_min += child_min;
1605
line_nat += child_nat;
1610
max_min_size = MAX (max_min_size, line_min);
1611
max_nat_size = MAX (max_nat_size, line_nat);
1614
max_min_size += (line_length - 1) * spacing;
1615
max_nat_size += (line_length - 1) * spacing;
1618
*min_size = max_min_size;
1621
*nat_size = max_nat_size;
1624
/* Gets the largest minimum and natural length of
1625
* 'line_length' consecutive items when aligned into rows/columns */
1627
get_largest_aligned_line_length (EggWrapBox *box,
1628
GtkOrientation orientation,
1633
EggWrapBoxPrivate *priv = box->priv;
1635
gint max_min_size = 0;
1636
gint max_nat_size = 0;
1638
GtkRequestedSize *aligned_item_sizes;
1640
if (orientation == GTK_ORIENTATION_HORIZONTAL)
1641
spacing = priv->horizontal_spacing;
1643
spacing = priv->vertical_spacing;
1645
aligned_item_sizes = g_new0 (GtkRequestedSize, line_length);
1647
/* Get the largest sizes of each index in the line.
1649
for (list = priv->children, i = 0; list; list = list->next)
1651
EggWrapBoxChild *child = list->data;
1652
gint child_min, child_nat;
1654
if (!gtk_widget_get_visible (child->widget))
1657
if (orientation == GTK_ORIENTATION_HORIZONTAL)
1658
gtk_widget_get_preferred_width (child->widget,
1659
&child_min, &child_nat);
1660
else /* GTK_ORIENTATION_VERTICAL */
1661
gtk_widget_get_preferred_height (child->widget,
1662
&child_min, &child_nat);
1664
aligned_item_sizes[i % line_length].minimum_size =
1665
MAX (aligned_item_sizes[i % line_length].minimum_size, child_min);
1667
aligned_item_sizes[i % line_length].natural_size =
1668
MAX (aligned_item_sizes[i % line_length].natural_size, child_nat);
1673
/* Add up the largest indexes */
1674
for (i = 0; i < line_length; i++)
1676
max_min_size += aligned_item_sizes[i].minimum_size;
1677
max_nat_size += aligned_item_sizes[i].natural_size;
1680
g_free (aligned_item_sizes);
1682
max_min_size += (line_length - 1) * spacing;
1683
max_nat_size += (line_length - 1) * spacing;
1686
*min_size = max_min_size;
1689
*nat_size = max_nat_size;
1694
egg_wrap_box_get_preferred_width (GtkWidget *widget,
1698
EggWrapBox *box = EGG_WRAP_BOX (widget);
1699
EggWrapBoxPrivate *priv = box->priv;
1700
gint min_item_width, nat_item_width;
1701
gint min_items, nat_items;
1702
gint min_width, nat_width;
1704
min_items = MAX (1, priv->minimum_line_children);
1705
nat_items = MAX (min_items, priv->natural_line_children);
1707
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1709
min_width = nat_width = 0;
1711
if (priv->mode == EGG_WRAP_ALLOCATE_FREE ||
1712
priv->mode == EGG_WRAP_ALLOCATE_ALIGNED)
1714
/* In FREE and ALIGNED modes; horizontally oriented boxes
1715
* need enough width for the widest row */
1718
get_average_item_size (box, GTK_ORIENTATION_HORIZONTAL,
1719
&min_item_width, &nat_item_width);
1721
min_width += min_item_width;
1722
nat_width += nat_item_width;
1724
else if (priv->mode == EGG_WRAP_ALLOCATE_FREE)
1726
gint min_line_length, nat_line_length;
1728
get_largest_line_length (box, GTK_ORIENTATION_HORIZONTAL, min_items,
1729
&min_line_length, &nat_line_length);
1731
if (nat_items > min_items)
1732
get_largest_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;
1738
else /* EGG_WRAP_MODE_ALIGNED */
1740
gint min_line_length, nat_line_length;
1742
get_largest_aligned_line_length (box, GTK_ORIENTATION_HORIZONTAL, min_items,
1743
&min_line_length, &nat_line_length);
1745
if (nat_items > min_items)
1746
get_largest_aligned_line_length (box, GTK_ORIENTATION_HORIZONTAL, nat_items,
1747
NULL, &nat_line_length);
1749
min_width += min_line_length;
1750
nat_width += nat_line_length;
1753
else /* In HOMOGENEOUS mode; horizontally oriented boxs
1754
* give the same width to all children */
1756
get_average_item_size (box, GTK_ORIENTATION_HORIZONTAL,
1757
&min_item_width, &nat_item_width);
1759
min_width += min_item_width * min_items;
1760
min_width += (min_items -1) * priv->horizontal_spacing;
1762
nat_width += nat_item_width * nat_items;
1763
nat_width += (nat_items -1) * priv->horizontal_spacing;
1766
else /* GTK_ORIENTATION_VERTICAL */
1768
/* Return the width for the minimum height */
1771
GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_height, NULL);
1772
GTK_WIDGET_GET_CLASS (widget)->get_preferred_width_for_height (widget, min_height,
1773
&min_width, &nat_width);
1778
*minimum_size = min_width;
1781
*natural_size = nat_width;
1785
egg_wrap_box_get_preferred_height (GtkWidget *widget,
1789
EggWrapBox *box = EGG_WRAP_BOX (widget);
1790
EggWrapBoxPrivate *priv = box->priv;
1791
gint min_item_height, nat_item_height;
1792
gint min_items, nat_items;
1793
gint min_height, nat_height;
1795
min_items = MAX (1, priv->minimum_line_children);
1796
nat_items = MAX (min_items, priv->natural_line_children);
1798
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1800
/* Return the height for the minimum width */
1803
GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, NULL);
1804
GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, min_width,
1805
&min_height, &nat_height);
1807
else /* GTK_ORIENTATION_VERTICAL */
1809
min_height = nat_height = 0;
1811
if (priv->mode == EGG_WRAP_ALLOCATE_FREE ||
1812
priv->mode == EGG_WRAP_ALLOCATE_ALIGNED)
1814
/* In FREE and ALIGNED modes; vertically oriented boxes
1815
* need enough height for the tallest column */
1818
get_average_item_size (box, GTK_ORIENTATION_VERTICAL,
1819
&min_item_height, &nat_item_height);
1821
min_height += min_item_height;
1822
nat_height += nat_item_height;
1824
else if (priv->mode == EGG_WRAP_ALLOCATE_FREE)
1826
gint min_line_length, nat_line_length;
1828
get_largest_line_length (box, GTK_ORIENTATION_VERTICAL, min_items,
1829
&min_line_length, &nat_line_length);
1831
if (nat_items > min_items)
1832
get_largest_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;
1838
else /* EGG_WRAP_ALLOCATE_ALIGNED */
1840
gint min_line_length, nat_line_length;
1842
get_largest_aligned_line_length (box, GTK_ORIENTATION_VERTICAL, min_items,
1843
&min_line_length, &nat_line_length);
1845
if (nat_items > min_items)
1846
get_largest_aligned_line_length (box, GTK_ORIENTATION_VERTICAL, nat_items,
1847
NULL, &nat_line_length);
1849
min_height += min_line_length;
1850
nat_height += nat_line_length;
1854
else /* In HOMOGENEOUS mode; vertically oriented boxs
1855
* give the same height to all children */
1857
get_average_item_size (box, GTK_ORIENTATION_VERTICAL,
1858
&min_item_height, &nat_item_height);
1860
min_height += min_item_height * min_items;
1861
min_height += (min_items -1) * priv->vertical_spacing;
1863
nat_height += nat_item_height * nat_items;
1864
nat_height += (nat_items -1) * priv->vertical_spacing;
1869
*minimum_size = min_height;
1872
*natural_size = nat_height;
1876
egg_wrap_box_get_preferred_height_for_width (GtkWidget *widget,
1878
gint *minimum_height,
1879
gint *natural_height)
1881
EggWrapBox *box = EGG_WRAP_BOX (widget);
1882
EggWrapBoxPrivate *priv = box->priv;
1883
gint min_item_width, nat_item_width;
1885
gint min_height, nat_height;
1886
gint avail_size, n_children;
1888
min_items = MAX (1, priv->minimum_line_children);
1893
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1897
n_children = get_visible_children (box);
1899
/* Make sure its no smaller than the minimum */
1900
GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, NULL);
1902
avail_size = MAX (width, min_width);
1904
if (priv->mode == EGG_WRAP_ALLOCATE_ALIGNED ||
1905
priv->mode == EGG_WRAP_ALLOCATE_HOMOGENEOUS)
1908
gint item_size, extra_pixels;
1910
get_average_item_size (box, GTK_ORIENTATION_HORIZONTAL, &min_item_width, &nat_item_width);
1912
/* By default wrap at the natural item width */
1913
line_length = avail_size / (nat_item_width + priv->horizontal_spacing);
1915
/* After the above aproximation, check if we cant fit one more on the line */
1916
if (line_length * priv->horizontal_spacing + (line_length + 1) * nat_item_width <= avail_size)
1919
/* Its possible we were allocated just less than the natural width of the
1920
* minimum item wrap length */
1921
line_length = MAX (min_items, line_length);
1923
/* Now we need the real item allocation size */
1924
item_size = (avail_size - (line_length - 1) * priv->horizontal_spacing) / line_length;
1926
/* Cut out the expand space if we're not distributing any */
1927
if (priv->horizontal_spreading != EGG_WRAP_BOX_SPREAD_EXPAND)
1929
item_size = MIN (item_size, nat_item_width);
1933
/* Collect the extra pixels for expand children */
1934
extra_pixels = (avail_size - (line_length - 1) * priv->horizontal_spacing) % line_length;
1936
if (priv->mode == EGG_WRAP_ALLOCATE_HOMOGENEOUS)
1938
gint min_item_height, nat_item_height;
1941
/* Here we just use the largest height-for-width and
1942
* add up the size accordingly */
1943
get_largest_size_for_opposing_orientation (box, GTK_ORIENTATION_HORIZONTAL, item_size,
1944
&min_item_height, &nat_item_height);
1946
/* Round up how many lines we need to allocate for */
1947
lines = n_children / line_length;
1948
if ((n_children % line_length) > 0)
1951
min_height = min_item_height * lines;
1952
nat_height = nat_item_height * lines;
1954
min_height += (lines - 1) * priv->vertical_spacing;
1955
nat_height += (lines - 1) * priv->vertical_spacing;
1957
else /* EGG_WRAP_ALLOCATE_ALIGNED */
1959
GList *list = priv->children;
1960
gint min_line_height, nat_line_height, i;
1961
gboolean first_line = TRUE;
1962
GtkRequestedSize *item_sizes;
1964
/* First get the size each set of items take to span the line
1965
* when aligning the items above and below after wrapping.
1967
item_sizes = fit_aligned_item_requests (box, priv->orientation, avail_size,
1968
priv->horizontal_spacing, &line_length, n_children);
1971
/* Get the available remaining size */
1972
avail_size -= (line_length - 1) * priv->horizontal_spacing;
1973
for (i = 0; i < line_length; i++)
1974
avail_size -= item_sizes[i].minimum_size;
1976
extra_pixels = gtk_distribute_natural_allocation (avail_size, line_length, item_sizes);
1978
while (list != NULL)
1981
get_largest_size_for_line_in_opposing_orientation (box, GTK_ORIENTATION_HORIZONTAL,
1983
item_sizes, extra_pixels,
1984
&min_line_height, &nat_line_height);
1986
/* Its possible the line only had invisible widgets */
1987
if (nat_line_height > 0)
1993
min_height += priv->vertical_spacing;
1994
nat_height += priv->vertical_spacing;
1997
min_height += min_line_height;
1998
nat_height += nat_line_height;
2002
g_free (item_sizes);
2005
else /* EGG_WRAP_ALLOCATE_FREE */
2007
/* Here we just fit as many children as we can allocate their natural size to
2008
* on each line and add the heights for each of them on each line */
2009
GList *list = priv->children;
2010
gint min_line_height = 0, nat_line_height = 0;
2011
gboolean first_line = TRUE;
2013
while (list != NULL)
2016
get_largest_size_for_free_line_in_opposing_orientation (box, GTK_ORIENTATION_HORIZONTAL,
2017
list, min_items, avail_size,
2018
&min_line_height, &nat_line_height,
2021
/* Its possible the last line only had invisible widgets */
2022
if (nat_line_height > 0)
2028
min_height += priv->vertical_spacing;
2029
nat_height += priv->vertical_spacing;
2032
min_height += min_line_height;
2033
nat_height += nat_line_height;
2038
else /* GTK_ORIENTATION_VERTICAL */
2040
/* Return the minimum height */
2041
GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_height, &nat_height);
2045
*minimum_height = min_height;
2048
*natural_height = nat_height;
2052
egg_wrap_box_get_preferred_width_for_height (GtkWidget *widget,
2054
gint *minimum_width,
2055
gint *natural_width)
2057
EggWrapBox *box = EGG_WRAP_BOX (widget);
2058
EggWrapBoxPrivate *priv = box->priv;
2059
gint min_item_height, nat_item_height;
2061
gint min_width, nat_width;
2062
gint avail_size, n_children;
2064
min_items = MAX (1, priv->minimum_line_children);
2069
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2071
/* Return the minimum width */
2072
GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, &nat_width);
2074
else /* GTK_ORIENTATION_VERTICAL */
2078
n_children = get_visible_children (box);
2080
/* Make sure its no smaller than the minimum */
2081
GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_height, NULL);
2083
avail_size = MAX (height, min_height);
2085
if (priv->mode == EGG_WRAP_ALLOCATE_ALIGNED ||
2086
priv->mode == EGG_WRAP_ALLOCATE_HOMOGENEOUS)
2089
gint item_size, extra_pixels;
2091
get_average_item_size (box, GTK_ORIENTATION_VERTICAL, &min_item_height, &nat_item_height);
2093
/* By default wrap at the natural item width */
2094
line_length = avail_size / (nat_item_height + priv->vertical_spacing);
2096
/* After the above aproximation, check if we cant fit one more on the line */
2097
if (line_length * priv->vertical_spacing + (line_length + 1) * nat_item_height <= avail_size)
2100
/* Its possible we were allocated just less than the natural width of the
2101
* minimum item wrap length */
2102
line_length = MAX (min_items, line_length);
2104
/* Now we need the real item allocation size */
2105
item_size = (avail_size - (line_length - 1) * priv->vertical_spacing) / line_length;
2107
/* Cut out the expand space if we're not distributing any */
2108
if (priv->vertical_spreading != EGG_WRAP_BOX_SPREAD_EXPAND)
2110
item_size = MIN (item_size, nat_item_height);
2114
/* Collect the extra pixels for expand children */
2115
extra_pixels = (avail_size - (line_length - 1) * priv->vertical_spacing) % line_length;
2117
if (priv->mode == EGG_WRAP_ALLOCATE_HOMOGENEOUS)
2119
gint min_item_width, nat_item_width;
2122
/* Here we just use the largest height-for-width and
2123
* add up the size accordingly */
2124
get_largest_size_for_opposing_orientation (box, GTK_ORIENTATION_VERTICAL, item_size,
2125
&min_item_width, &nat_item_width);
2127
/* Round up how many lines we need to allocate for */
2128
n_children = get_visible_children (box);
2129
lines = n_children / line_length;
2130
if ((n_children % line_length) > 0)
2133
min_width = min_item_width * lines;
2134
nat_width = nat_item_width * lines;
2136
min_width += (lines - 1) * priv->horizontal_spacing;
2137
nat_width += (lines - 1) * priv->horizontal_spacing;
2139
else /* EGG_WRAP_ALLOCATE_ALIGNED */
2141
GList *list = priv->children;
2142
gint min_line_width, nat_line_width, i;
2143
gboolean first_line = TRUE;
2144
GtkRequestedSize *item_sizes;
2146
/* First get the size each set of items take to span the line
2147
* when aligning the items above and below after wrapping.
2149
item_sizes = fit_aligned_item_requests (box, priv->orientation, avail_size,
2150
priv->vertical_spacing, &line_length, n_children);
2152
/* Get the available remaining size */
2153
avail_size -= (line_length - 1) * priv->horizontal_spacing;
2154
for (i = 0; i < line_length; i++)
2155
avail_size -= item_sizes[i].minimum_size;
2157
extra_pixels = gtk_distribute_natural_allocation (avail_size, line_length, item_sizes);
2159
while (list != NULL)
2162
get_largest_size_for_line_in_opposing_orientation (box, GTK_ORIENTATION_VERTICAL,
2164
item_sizes, extra_pixels,
2165
&min_line_width, &nat_line_width);
2167
/* Its possible the last line only had invisible widgets */
2168
if (nat_line_width > 0)
2174
min_width += priv->horizontal_spacing;
2175
nat_width += priv->horizontal_spacing;
2178
min_width += min_line_width;
2179
nat_width += nat_line_width;
2182
g_free (item_sizes);
2185
else /* EGG_WRAP_ALLOCATE_FREE */
2187
/* Here we just fit as many children as we can allocate their natural size to
2188
* on each line and add the heights for each of them on each line */
2189
GList *list = priv->children;
2190
gint min_line_width = 0, nat_line_width = 0;
2191
gboolean first_line = TRUE;
2193
while (list != NULL)
2196
get_largest_size_for_free_line_in_opposing_orientation (box, GTK_ORIENTATION_VERTICAL,
2197
list, min_items, avail_size,
2198
&min_line_width, &nat_line_width,
2201
/* Its possible the last line only had invisible widgets */
2202
if (nat_line_width > 0)
2208
min_width += priv->horizontal_spacing;
2209
nat_width += priv->horizontal_spacing;
2212
min_width += min_line_width;
2213
nat_width += nat_line_width;
2220
*minimum_width = min_width;
2223
*natural_width = nat_width;
2226
/*****************************************************
2228
*****************************************************/
2232
* @mode: The #EggWrapAllocationMode to use
2233
* @horizontal_spreading: The horizontal #EggWrapBoxSpreading policy to use
2234
* @vertical_spreading: The vertical #EggWrapBoxSpreading policy to use
2235
* @horizontal_spacing: The horizontal spacing to add between children
2236
* @vertical_spacing: The vertical spacing to add between children
2238
* Creates an #EggWrapBox.
2240
* Returns: A new #EggWrapBox container
2243
egg_wrap_box_new (EggWrapAllocationMode mode,
2244
EggWrapBoxSpreading horizontal_spreading,
2245
EggWrapBoxSpreading vertical_spreading,
2246
guint horizontal_spacing,
2247
guint vertical_spacing)
2249
return (GtkWidget *)g_object_new (EGG_TYPE_WRAP_BOX,
2250
"allocation-mode", mode,
2251
"horizontal-spreading", horizontal_spreading,
2252
"vertical-spreading", vertical_spreading,
2253
"vertical-spacing", vertical_spacing,
2254
"horizontal-spacing", horizontal_spacing,
2259
* egg_wrap_box_set_allocation_mode:
2260
* @box: An #EggWrapBox
2261
* @mode: The #EggWrapAllocationMode to use.
2263
* Sets the allocation mode for @box's children.
2266
egg_wrap_box_set_allocation_mode (EggWrapBox *box,
2267
EggWrapAllocationMode mode)
2269
EggWrapBoxPrivate *priv;
2271
g_return_if_fail (EGG_IS_WRAP_BOX (box));
2275
if (priv->mode != mode)
2279
gtk_widget_queue_resize (GTK_WIDGET (box));
2281
g_object_notify (G_OBJECT (box), "allocation-mode");
2286
* egg_wrap_box_get_allocation_mode:
2287
* @box: An #EggWrapBox
2289
* Gets the allocation mode.
2291
* Returns: The #EggWrapAllocationMode for @box.
2293
EggWrapAllocationMode
2294
egg_wrap_box_get_allocation_mode (EggWrapBox *box)
2296
g_return_val_if_fail (EGG_IS_WRAP_BOX (box), FALSE);
2298
return box->priv->mode;
2303
* egg_wrap_box_set_horizontal_spreading:
2304
* @box: An #EggWrapBox
2305
* @spreading: The #EggWrapBoxSpreading to use.
2307
* Sets the horizontal spreading mode for @box's children.
2310
egg_wrap_box_set_horizontal_spreading (EggWrapBox *box,
2311
EggWrapBoxSpreading spreading)
2313
EggWrapBoxPrivate *priv;
2315
g_return_if_fail (EGG_IS_WRAP_BOX (box));
2319
if (priv->horizontal_spreading != spreading)
2321
priv->horizontal_spreading = spreading;
2323
gtk_widget_queue_resize (GTK_WIDGET (box));
2325
g_object_notify (G_OBJECT (box), "horizontal-spreading");
2330
* egg_wrap_box_get_horizontal_spreading:
2331
* @box: An #EggWrapBox
2333
* Gets the horizontal spreading mode.
2335
* Returns: The horizontal #EggWrapBoxSpreading for @box.
2338
egg_wrap_box_get_horizontal_spreading (EggWrapBox *box)
2340
g_return_val_if_fail (EGG_IS_WRAP_BOX (box), FALSE);
2342
return box->priv->horizontal_spreading;
2347
* egg_wrap_box_set_vertical_spreading:
2348
* @box: An #EggWrapBox
2349
* @spreading: The #EggWrapBoxSpreading to use.
2351
* Sets the vertical spreading mode for @box's children.
2354
egg_wrap_box_set_vertical_spreading (EggWrapBox *box,
2355
EggWrapBoxSpreading spreading)
2357
EggWrapBoxPrivate *priv;
2359
g_return_if_fail (EGG_IS_WRAP_BOX (box));
2363
if (priv->vertical_spreading != spreading)
2365
priv->vertical_spreading = spreading;
2367
gtk_widget_queue_resize (GTK_WIDGET (box));
2369
g_object_notify (G_OBJECT (box), "vertical-spreading");
2374
* egg_wrap_box_get_vertical_spreading:
2375
* @box: An #EggWrapBox
2377
* Gets the vertical spreading mode.
2379
* Returns: The vertical #EggWrapBoxSpreading for @box.
2382
egg_wrap_box_get_vertical_spreading (EggWrapBox *box)
2384
g_return_val_if_fail (EGG_IS_WRAP_BOX (box), FALSE);
2386
return box->priv->vertical_spreading;
2391
* egg_wrap_box_set_vertical_spacing:
2392
* @box: An #EggWrapBox
2393
* @spacing: The spacing to use.
2395
* Sets the vertical space to add between children.
2398
egg_wrap_box_set_vertical_spacing (EggWrapBox *box,
2401
EggWrapBoxPrivate *priv;
2403
g_return_if_fail (EGG_IS_WRAP_BOX (box));
2407
if (priv->vertical_spacing != spacing)
2409
priv->vertical_spacing = spacing;
2411
gtk_widget_queue_resize (GTK_WIDGET (box));
2413
g_object_notify (G_OBJECT (box), "vertical-spacing");
2418
* egg_wrap_box_get_vertical_spacing:
2419
* @box: An #EggWrapBox
2421
* Gets the vertical spacing.
2423
* Returns: The vertical spacing.
2426
egg_wrap_box_get_vertical_spacing (EggWrapBox *box)
2428
g_return_val_if_fail (EGG_IS_WRAP_BOX (box), FALSE);
2430
return box->priv->vertical_spacing;
2434
* egg_wrap_box_set_horizontal_spacing:
2435
* @box: An #EggWrapBox
2436
* @spacing: The spacing to use.
2438
* Sets the horizontal space to add between children.
2441
egg_wrap_box_set_horizontal_spacing (EggWrapBox *box,
2444
EggWrapBoxPrivate *priv;
2446
g_return_if_fail (EGG_IS_WRAP_BOX (box));
2450
if (priv->horizontal_spacing != spacing)
2452
priv->horizontal_spacing = spacing;
2454
gtk_widget_queue_resize (GTK_WIDGET (box));
2456
g_object_notify (G_OBJECT (box), "horizontal-spacing");
2461
* egg_wrap_box_get_horizontal_spacing:
2462
* @box: An #EggWrapBox
2464
* Gets the horizontal spacing.
2466
* Returns: The horizontal spacing.
2469
egg_wrap_box_get_horizontal_spacing (EggWrapBox *box)
2471
g_return_val_if_fail (EGG_IS_WRAP_BOX (box), FALSE);
2473
return box->priv->horizontal_spacing;
2477
* egg_wrap_box_set_minimum_line_children:
2478
* @box: An #EggWrapBox
2479
* @n_children: The minimum amount of children per line.
2481
* Sets the minimum amount of children to line up
2482
* in @box's orientation before wrapping.
2485
egg_wrap_box_set_minimum_line_children (EggWrapBox *box,
2488
EggWrapBoxPrivate *priv;
2490
g_return_if_fail (EGG_IS_WRAP_BOX (box));
2494
if (priv->minimum_line_children != n_children)
2496
priv->minimum_line_children = n_children;
2498
gtk_widget_queue_resize (GTK_WIDGET (box));
2500
g_object_notify (G_OBJECT (box), "minimum-line-children");
2505
* egg_wrap_box_get_minimum_line_children:
2506
* @box: An #EggWrapBox
2508
* Gets the minimum amount of children per line.
2510
* Returns: The minimum amount of children per line.
2513
egg_wrap_box_get_minimum_line_children (EggWrapBox *box)
2515
g_return_val_if_fail (EGG_IS_WRAP_BOX (box), FALSE);
2517
return box->priv->minimum_line_children;
2521
* egg_wrap_box_set_natural_line_children:
2522
* @box: An #EggWrapBox
2523
* @n_children: The natural amount of children per line.
2525
* Sets the natural length of items to request and
2526
* allocate space for in @box's orientation.
2528
* Setting the natural amount of children per line
2529
* limits the overall natural size request to be no more
2530
* than @n_children items long in the given orientation.
2533
egg_wrap_box_set_natural_line_children (EggWrapBox *box,
2536
EggWrapBoxPrivate *priv;
2538
g_return_if_fail (EGG_IS_WRAP_BOX (box));
2542
if (priv->natural_line_children != n_children)
2544
priv->natural_line_children = n_children;
2546
gtk_widget_queue_resize (GTK_WIDGET (box));
2548
g_object_notify (G_OBJECT (box), "natural-line-children");
2553
* egg_wrap_box_get_natural_line_children:
2554
* @box: An #EggWrapBox
2556
* Gets the natural amount of children per line.
2558
* Returns: The natural amount of children per line.
2561
egg_wrap_box_get_natural_line_children (EggWrapBox *box)
2563
g_return_val_if_fail (EGG_IS_WRAP_BOX (box), FALSE);
2565
return box->priv->natural_line_children;
2570
* egg_wrap_box_insert_child:
2571
* @box: And #EggWrapBox
2572
* @widget: the child #GtkWidget to add
2573
* @index: the position in the child list to insert, specify -1 to append to the list.
2574
* @packing: The #EggWrapBoxPacking options to use.
2576
* Adds a child to an #EggWrapBox with its packing options set
2580
egg_wrap_box_insert_child (EggWrapBox *box,
2583
EggWrapBoxPacking packing)
2585
EggWrapBoxPrivate *priv;
2586
EggWrapBoxChild *child;
2589
g_return_if_fail (EGG_IS_WRAP_BOX (box));
2590
g_return_if_fail (GTK_IS_WIDGET (widget));
2594
list = g_list_find_custom (priv->children, widget,
2595
(GCompareFunc)find_child_in_list);
2596
g_return_if_fail (list == NULL);
2598
child = g_slice_new0 (EggWrapBoxChild);
2599
child->widget = widget;
2600
child->packing = packing;
2602
priv->children = g_list_insert (priv->children, child, index);
2604
gtk_widget_set_parent (widget, GTK_WIDGET (box));
2608
* egg_wrap_box_reorder_child:
2609
* @box: An #EggWrapBox
2610
* @widget: The child to reorder
2611
* @index: The new child position
2613
* Reorders the child @widget in @box's list of children.
2616
egg_wrap_box_reorder_child (EggWrapBox *box,
2620
EggWrapBoxPrivate *priv;
2621
EggWrapBoxChild *child;
2624
g_return_if_fail (EGG_IS_WRAP_BOX (box));
2625
g_return_if_fail (GTK_IS_WIDGET (widget));
2629
list = g_list_find_custom (priv->children, widget,
2630
(GCompareFunc)find_child_in_list);
2631
g_return_if_fail (list != NULL);
2633
if (g_list_position (priv->children, list) != index)
2636
priv->children = g_list_delete_link (priv->children, list);
2637
priv->children = g_list_insert (priv->children, child, index);
2639
gtk_widget_queue_resize (GTK_WIDGET (box));