1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GtkWrapBox: Wrapping box widget
5  * Copyright (C) 1999 Tim Janik
6  *
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 3 of the License, or (at your option) any later version.
11  *
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.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library.  If not, see
19  * <https://www.gnu.org/licenses/>.
20  */
21 
22 #include "config.h"
23 
24 #undef GSEAL_ENABLE
25 #undef GTK_DISABLE_DEPRECATED
26 
27 #include "gtkwrapbox.h"
28 
29 
30 /* --- properties --- */
31 enum {
32   PROP_0,
33   PROP_HOMOGENEOUS,
34   PROP_JUSTIFY,
35   PROP_HSPACING,
36   PROP_VSPACING,
37   PROP_LINE_JUSTIFY,
38   PROP_ASPECT_RATIO,
39   PROP_CURRENT_RATIO,
40   PROP_CHILD_LIMIT
41 };
42 
43 enum {
44   CHILD_PROP_0,
45   CHILD_PROP_POSITION,
46   CHILD_PROP_HEXPAND,
47   CHILD_PROP_HFILL,
48   CHILD_PROP_VEXPAND,
49   CHILD_PROP_VFILL,
50   CHILD_PROP_WRAPPED
51 };
52 
53 
54 /* --- prototypes --- */
55 static void gtk_wrap_box_class_init    (GtkWrapBoxClass    *klass);
56 static void gtk_wrap_box_init          (GtkWrapBox         *wbox);
57 static void gtk_wrap_box_set_property  (GObject            *object,
58                                         guint               property_id,
59                                         const GValue       *value,
60                                         GParamSpec         *pspec);
61 static void gtk_wrap_box_get_property  (GObject            *object,
62                                         guint               property_id,
63                                         GValue             *value,
64                                         GParamSpec         *pspec);
65 static void gtk_wrap_box_set_child_property (GtkContainer    *container,
66                                              GtkWidget       *child,
67                                              guint            property_id,
68                                              const GValue    *value,
69                                              GParamSpec      *pspec);
70 static void gtk_wrap_box_get_child_property (GtkContainer    *container,
71                                              GtkWidget       *child,
72                                              guint            property_id,
73                                              GValue          *value,
74                                              GParamSpec      *pspec);
75 static void gtk_wrap_box_map           (GtkWidget          *widget);
76 static void gtk_wrap_box_unmap         (GtkWidget          *widget);
77 static gint gtk_wrap_box_expose        (GtkWidget          *widget,
78                                         GdkEventExpose     *event);
79 static void gtk_wrap_box_add           (GtkContainer       *container,
80                                         GtkWidget          *widget);
81 static void gtk_wrap_box_remove        (GtkContainer       *container,
82                                         GtkWidget          *widget);
83 static void gtk_wrap_box_forall        (GtkContainer       *container,
84                                         gboolean            include_internals,
85                                         GtkCallback         callback,
86                                         gpointer            callback_data);
87 static GType gtk_wrap_box_child_type   (GtkContainer       *container);
88 
89 
90 /* --- variables --- */
91 static gpointer parent_class = NULL;
92 
93 
94 /* --- functions --- */
95 GType
gtk_wrap_box_get_type(void)96 gtk_wrap_box_get_type (void)
97 {
98   static GType wrap_box_type = 0;
99 
100   if (! wrap_box_type)
101     {
102       const GTypeInfo wrap_box_info =
103       {
104         sizeof (GtkWrapBoxClass),
105         NULL,                /* base_init */
106         NULL,                /* base_finalize */
107         (GClassInitFunc) gtk_wrap_box_class_init,
108         NULL,                /* class_finalize */
109         NULL,                /* class_data */
110         sizeof (GtkWrapBox),
111         0,                /* n_preallocs */
112         (GInstanceInitFunc) gtk_wrap_box_init,
113       };
114 
115       wrap_box_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkWrapBox",
116                                               &wrap_box_info, 0);
117     }
118 
119   return wrap_box_type;
120 }
121 
122 static void
gtk_wrap_box_class_init(GtkWrapBoxClass * class)123 gtk_wrap_box_class_init (GtkWrapBoxClass *class)
124 {
125   GObjectClass *object_class;
126   GtkWidgetClass *widget_class;
127   GtkContainerClass *container_class;
128 
129   object_class = G_OBJECT_CLASS (class);
130   widget_class = GTK_WIDGET_CLASS (class);
131   container_class = GTK_CONTAINER_CLASS (class);
132 
133   parent_class = g_type_class_peek_parent (class);
134 
135   object_class->set_property = gtk_wrap_box_set_property;
136   object_class->get_property = gtk_wrap_box_get_property;
137 
138   widget_class->map = gtk_wrap_box_map;
139   widget_class->unmap = gtk_wrap_box_unmap;
140   widget_class->expose_event = gtk_wrap_box_expose;
141 
142   container_class->add = gtk_wrap_box_add;
143   container_class->remove = gtk_wrap_box_remove;
144   container_class->forall = gtk_wrap_box_forall;
145   container_class->child_type = gtk_wrap_box_child_type;
146   container_class->set_child_property = gtk_wrap_box_set_child_property;
147   container_class->get_child_property = gtk_wrap_box_get_child_property;
148 
149   class->rlist_line_children = NULL;
150 
151   g_object_class_install_property (object_class,
152                                    PROP_HOMOGENEOUS,
153                                    g_param_spec_boolean ("homogeneous",
154                                                          NULL,
155                                                          NULL,
156                                                          FALSE,
157                                                          G_PARAM_READWRITE));
158   g_object_class_install_property (object_class,
159                                    PROP_JUSTIFY,
160                                    g_param_spec_enum ("justify",
161                                                       NULL,
162                                                       NULL,
163                                                       GTK_TYPE_JUSTIFICATION,
164                                                       GTK_JUSTIFY_LEFT,
165                                                       G_PARAM_READWRITE));
166   g_object_class_install_property (object_class,
167                                    PROP_HSPACING,
168                                    g_param_spec_uint ("hspacing",
169                                                       NULL,
170                                                       NULL,
171                                                       0,
172                                                       G_MAXINT,
173                                                       0,
174                                                       G_PARAM_READWRITE));
175 
176   g_object_class_install_property (object_class,
177                                    PROP_VSPACING,
178                                    g_param_spec_uint ("vspacing",
179                                                       NULL,
180                                                       NULL,
181                                                       0,
182                                                       G_MAXINT,
183                                                       0,
184                                                       G_PARAM_READWRITE));
185 
186   g_object_class_install_property (object_class,
187                                    PROP_LINE_JUSTIFY,
188                                    g_param_spec_enum ("line-justify",
189                                                       NULL,
190                                                       NULL,
191                                                       GTK_TYPE_JUSTIFICATION,
192                                                       GTK_JUSTIFY_BOTTOM,
193                                                       G_PARAM_READWRITE));
194 
195   g_object_class_install_property (object_class,
196                                    PROP_ASPECT_RATIO,
197                                    g_param_spec_float ("aspect-ratio",
198                                                        NULL,
199                                                        NULL,
200                                                        0.0,
201                                                        G_MAXFLOAT,
202                                                        1.0,
203                                                        G_PARAM_READWRITE));
204 
205   g_object_class_install_property (object_class,
206                                    PROP_CURRENT_RATIO,
207                                    g_param_spec_float ("current-ratio",
208                                                        NULL,
209                                                        NULL,
210                                                        0.0,
211                                                        G_MAXFLOAT,
212                                                        1.0,
213                                                        G_PARAM_READABLE));
214 
215   g_object_class_install_property (object_class,
216                                    PROP_CHILD_LIMIT,
217                                    g_param_spec_uint ("max-children-per-line",
218                                                       NULL,
219                                                       NULL,
220                                                       1,
221                                                       32767,
222                                                       32767,
223                                                       G_PARAM_READWRITE));
224 
225   gtk_container_class_install_child_property (container_class,
226                                               CHILD_PROP_POSITION,
227                                               g_param_spec_int ("position",
228                                                                 NULL,
229                                                                 NULL,
230                                                                 -1, G_MAXINT, 0,
231                                                                 G_PARAM_READWRITE));
232   gtk_container_class_install_child_property (container_class,
233                                               CHILD_PROP_HEXPAND,
234                                               g_param_spec_boolean ("hexpand",
235                                                                     NULL,
236                                                                     NULL,
237                                                                     FALSE,
238                                                                     G_PARAM_READWRITE));
239   gtk_container_class_install_child_property (container_class,
240                                               CHILD_PROP_HFILL,
241                                               g_param_spec_boolean ("hfill",
242                                                                     NULL,
243                                                                     NULL,
244                                                                     FALSE,
245                                                                     G_PARAM_READWRITE));
246   gtk_container_class_install_child_property (container_class,
247                                               CHILD_PROP_VEXPAND,
248                                               g_param_spec_boolean ("vexpand",
249                                                                     NULL,
250                                                                     NULL,
251                                                                     FALSE,
252                                                                     G_PARAM_READWRITE));
253   gtk_container_class_install_child_property (container_class,
254                                               CHILD_PROP_VFILL,
255                                               g_param_spec_boolean ("vfill",
256                                                                     NULL,
257                                                                     NULL,
258                                                                     FALSE,
259                                                                     G_PARAM_READWRITE));
260   gtk_container_class_install_child_property (container_class,
261                                               CHILD_PROP_WRAPPED,
262                                               g_param_spec_boolean ("wrapped",
263                                                                     NULL,
264                                                                     NULL,
265                                                                     FALSE,
266                                                                     G_PARAM_READWRITE));
267 }
268 
269 static void
gtk_wrap_box_init(GtkWrapBox * wbox)270 gtk_wrap_box_init (GtkWrapBox *wbox)
271 {
272   GTK_WIDGET_SET_FLAGS (wbox, GTK_NO_WINDOW);
273 
274   wbox->homogeneous = FALSE;
275   wbox->hspacing = 0;
276   wbox->vspacing = 0;
277   wbox->justify = GTK_JUSTIFY_LEFT;
278   wbox->line_justify = GTK_JUSTIFY_BOTTOM;
279   wbox->n_children = 0;
280   wbox->children = NULL;
281   wbox->aspect_ratio = 1.0;
282   wbox->child_limit = 32767;
283 }
284 
285 static void
gtk_wrap_box_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)286 gtk_wrap_box_set_property (GObject      *object,
287                            guint         property_id,
288                            const GValue *value,
289                            GParamSpec   *pspec)
290 {
291   GtkWrapBox *wbox = GTK_WRAP_BOX (object);
292 
293   switch (property_id)
294     {
295     case PROP_HOMOGENEOUS:
296       gtk_wrap_box_set_homogeneous (wbox, g_value_get_boolean (value));
297       break;
298     case PROP_JUSTIFY:
299       gtk_wrap_box_set_justify (wbox, g_value_get_enum (value));
300       break;
301     case PROP_LINE_JUSTIFY:
302       gtk_wrap_box_set_line_justify (wbox, g_value_get_enum (value));
303       break;
304     case PROP_HSPACING:
305       gtk_wrap_box_set_hspacing (wbox, g_value_get_uint (value));
306       break;
307     case PROP_VSPACING:
308       gtk_wrap_box_set_vspacing (wbox, g_value_get_uint (value));
309       break;
310     case PROP_ASPECT_RATIO:
311       gtk_wrap_box_set_aspect_ratio (wbox, g_value_get_float (value));
312       break;
313     case PROP_CHILD_LIMIT:
314       if (wbox->child_limit != g_value_get_uint (value))
315         gtk_widget_queue_resize (GTK_WIDGET (wbox));
316       break;
317     default:
318       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
319       break;
320     }
321 }
322 
323 static void
gtk_wrap_box_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)324 gtk_wrap_box_get_property (GObject    *object,
325                            guint       property_id,
326                            GValue     *value,
327                            GParamSpec *pspec)
328 {
329   GtkWrapBox *wbox = GTK_WRAP_BOX (object);
330   GtkWidget *widget = GTK_WIDGET (object);
331 
332   switch (property_id)
333     {
334     case PROP_HOMOGENEOUS:
335       g_value_set_boolean (value, wbox->homogeneous);
336       break;
337     case PROP_JUSTIFY:
338       g_value_set_enum (value, wbox->justify);
339       break;
340     case PROP_LINE_JUSTIFY:
341       g_value_set_enum (value, wbox->line_justify);
342       break;
343     case PROP_HSPACING:
344       g_value_set_uint (value, wbox->hspacing);
345       break;
346     case PROP_VSPACING:
347       g_value_set_uint (value, wbox->vspacing);
348       break;
349     case PROP_ASPECT_RATIO:
350       g_value_set_float (value, wbox->aspect_ratio);
351       break;
352     case PROP_CURRENT_RATIO:
353       g_value_set_float (value, (((gfloat) widget->allocation.width) /
354                                  ((gfloat) widget->allocation.height)));
355       break;
356     case PROP_CHILD_LIMIT:
357       g_value_set_uint (value, wbox->child_limit);
358       break;
359     default:
360       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
361       break;
362     }
363 }
364 
365 static void
gtk_wrap_box_set_child_property(GtkContainer * container,GtkWidget * child,guint property_id,const GValue * value,GParamSpec * pspec)366 gtk_wrap_box_set_child_property (GtkContainer    *container,
367                                  GtkWidget       *child,
368                                  guint            property_id,
369                                  const GValue    *value,
370                                  GParamSpec      *pspec)
371 {
372   GtkWrapBox *wbox = GTK_WRAP_BOX (container);
373   gboolean hexpand = FALSE, hfill = FALSE;
374   gboolean vexpand = FALSE, vfill = FALSE;
375   gboolean wrapped = FALSE;
376 
377   if (property_id != CHILD_PROP_POSITION)
378     gtk_wrap_box_query_child_packing (wbox, child,
379                                       &hexpand, &hfill,
380                                       &vexpand, &vfill,
381                                       &wrapped);
382 
383   switch (property_id)
384     {
385     case CHILD_PROP_POSITION:
386       gtk_wrap_box_reorder_child (wbox, child, g_value_get_int (value));
387       break;
388     case CHILD_PROP_HEXPAND:
389       gtk_wrap_box_set_child_packing (wbox, child,
390                                       g_value_get_boolean (value), hfill,
391                                       vexpand, vfill,
392                                       wrapped);
393       break;
394     case CHILD_PROP_HFILL:
395       gtk_wrap_box_set_child_packing (wbox, child,
396                                       hexpand, g_value_get_boolean (value),
397                                       vexpand, vfill,
398                                       wrapped);
399       break;
400     case CHILD_PROP_VEXPAND:
401       gtk_wrap_box_set_child_packing (wbox, child,
402                                       hexpand, hfill,
403                                       g_value_get_boolean (value), vfill,
404                                       wrapped);
405       break;
406     case CHILD_PROP_VFILL:
407       gtk_wrap_box_set_child_packing (wbox, child,
408                                       hexpand, hfill,
409                                       vexpand, g_value_get_boolean (value),
410                                       wrapped);
411       break;
412     case CHILD_PROP_WRAPPED:
413       gtk_wrap_box_set_child_packing (wbox, child,
414                                       hexpand, hfill,
415                                       vexpand, vfill,
416                                       g_value_get_boolean (value));
417       break;
418     default:
419       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
420       break;
421     }
422 }
423 
424 static void
gtk_wrap_box_get_child_property(GtkContainer * container,GtkWidget * child,guint property_id,GValue * value,GParamSpec * pspec)425 gtk_wrap_box_get_child_property (GtkContainer    *container,
426                                  GtkWidget       *child,
427                                  guint            property_id,
428                                  GValue          *value,
429                                  GParamSpec      *pspec)
430 {
431   GtkWrapBox *wbox = GTK_WRAP_BOX (container);
432   gboolean hexpand = FALSE, hfill = FALSE;
433   gboolean vexpand = FALSE, vfill = FALSE;
434   gboolean wrapped = FALSE;
435 
436   if (property_id != CHILD_PROP_POSITION)
437     gtk_wrap_box_query_child_packing (wbox, child,
438                                       &hexpand, &hfill,
439                                       &vexpand, &vfill,
440                                       &wrapped);
441 
442   switch (property_id)
443     {
444       GtkWrapBoxChild *child_info;
445       guint i;
446     case CHILD_PROP_POSITION:
447       i = 0;
448       for (child_info = wbox->children; child_info; child_info = child_info->next)
449         {
450           if (child_info->widget == child)
451             break;
452           i += 1;
453         }
454       g_value_set_int (value, child_info ? i : -1);
455       break;
456     case CHILD_PROP_HEXPAND:
457       g_value_set_boolean (value, hexpand);
458       break;
459     case CHILD_PROP_HFILL:
460       g_value_set_boolean (value, hfill);
461       break;
462     case CHILD_PROP_VEXPAND:
463       g_value_set_boolean (value, vexpand);
464       break;
465     case CHILD_PROP_VFILL:
466       g_value_set_boolean (value, vfill);
467       break;
468     case CHILD_PROP_WRAPPED:
469       g_value_set_boolean (value, wrapped);
470       break;
471     default:
472       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
473       break;
474     }
475 }
476 
477 static GType
gtk_wrap_box_child_type(GtkContainer * container)478 gtk_wrap_box_child_type        (GtkContainer *container)
479 {
480   return GTK_TYPE_WIDGET;
481 }
482 
483 void
gtk_wrap_box_set_homogeneous(GtkWrapBox * wbox,gboolean homogeneous)484 gtk_wrap_box_set_homogeneous (GtkWrapBox *wbox,
485                               gboolean    homogeneous)
486 {
487   g_return_if_fail (GTK_IS_WRAP_BOX (wbox));
488 
489   homogeneous = homogeneous != FALSE;
490   if (wbox->homogeneous != homogeneous)
491     {
492       wbox->homogeneous = homogeneous;
493       gtk_widget_queue_resize (GTK_WIDGET (wbox));
494     }
495 }
496 
497 void
gtk_wrap_box_set_hspacing(GtkWrapBox * wbox,guint hspacing)498 gtk_wrap_box_set_hspacing (GtkWrapBox *wbox,
499                            guint       hspacing)
500 {
501   g_return_if_fail (GTK_IS_WRAP_BOX (wbox));
502 
503   if (wbox->hspacing != hspacing)
504     {
505       wbox->hspacing = hspacing;
506       gtk_widget_queue_resize (GTK_WIDGET (wbox));
507     }
508 }
509 
510 void
gtk_wrap_box_set_vspacing(GtkWrapBox * wbox,guint vspacing)511 gtk_wrap_box_set_vspacing (GtkWrapBox *wbox,
512                            guint       vspacing)
513 {
514   g_return_if_fail (GTK_IS_WRAP_BOX (wbox));
515 
516   if (wbox->vspacing != vspacing)
517     {
518       wbox->vspacing = vspacing;
519       gtk_widget_queue_resize (GTK_WIDGET (wbox));
520     }
521 }
522 
523 void
gtk_wrap_box_set_justify(GtkWrapBox * wbox,GtkJustification justify)524 gtk_wrap_box_set_justify (GtkWrapBox      *wbox,
525                           GtkJustification justify)
526 {
527   g_return_if_fail (GTK_IS_WRAP_BOX (wbox));
528   g_return_if_fail (justify <= GTK_JUSTIFY_FILL);
529 
530   if (wbox->justify != justify)
531     {
532       wbox->justify = justify;
533       gtk_widget_queue_resize (GTK_WIDGET (wbox));
534     }
535 }
536 
537 void
gtk_wrap_box_set_line_justify(GtkWrapBox * wbox,GtkJustification line_justify)538 gtk_wrap_box_set_line_justify (GtkWrapBox      *wbox,
539                                GtkJustification line_justify)
540 {
541   g_return_if_fail (GTK_IS_WRAP_BOX (wbox));
542   g_return_if_fail (line_justify <= GTK_JUSTIFY_FILL);
543 
544   if (wbox->line_justify != line_justify)
545     {
546       wbox->line_justify = line_justify;
547       gtk_widget_queue_resize (GTK_WIDGET (wbox));
548     }
549 }
550 
551 void
gtk_wrap_box_set_aspect_ratio(GtkWrapBox * wbox,gfloat aspect_ratio)552 gtk_wrap_box_set_aspect_ratio (GtkWrapBox *wbox,
553                                gfloat      aspect_ratio)
554 {
555   g_return_if_fail (GTK_IS_WRAP_BOX (wbox));
556 
557   aspect_ratio = CLAMP (aspect_ratio, 1.0 / 256.0, 256.0);
558 
559   if (wbox->aspect_ratio != aspect_ratio)
560     {
561       wbox->aspect_ratio = aspect_ratio;
562       gtk_widget_queue_resize (GTK_WIDGET (wbox));
563     }
564 }
565 
566 void
gtk_wrap_box_pack(GtkWrapBox * wbox,GtkWidget * child,gboolean hexpand,gboolean hfill,gboolean vexpand,gboolean vfill)567 gtk_wrap_box_pack (GtkWrapBox *wbox,
568                    GtkWidget  *child,
569                    gboolean    hexpand,
570                    gboolean    hfill,
571                    gboolean    vexpand,
572                    gboolean    vfill)
573 {
574   g_return_if_fail (GTK_IS_WRAP_BOX (wbox));
575   g_return_if_fail (GTK_IS_WIDGET (child));
576   g_return_if_fail (child->parent == NULL);
577 
578   gtk_wrap_box_pack_wrapped (wbox, child, hexpand, hfill, vexpand, vfill, FALSE);
579 }
580 
581 void
gtk_wrap_box_pack_wrapped(GtkWrapBox * wbox,GtkWidget * child,gboolean hexpand,gboolean hfill,gboolean vexpand,gboolean vfill,gboolean wrapped)582 gtk_wrap_box_pack_wrapped (GtkWrapBox *wbox,
583                            GtkWidget  *child,
584                            gboolean    hexpand,
585                            gboolean    hfill,
586                            gboolean    vexpand,
587                            gboolean    vfill,
588                            gboolean    wrapped)
589 {
590   GtkWrapBoxChild *child_info;
591 
592   g_return_if_fail (GTK_IS_WRAP_BOX (wbox));
593   g_return_if_fail (GTK_IS_WIDGET (child));
594   g_return_if_fail (child->parent == NULL);
595 
596   child_info = g_slice_new (GtkWrapBoxChild);
597 
598   child_info->widget = child;
599   child_info->hexpand = hexpand ? TRUE : FALSE;
600   child_info->hfill = hfill ? TRUE : FALSE;
601   child_info->vexpand = vexpand ? TRUE : FALSE;
602   child_info->vfill = vfill ? TRUE : FALSE;
603   child_info->wrapped = wrapped ? TRUE : FALSE;
604   child_info->next = NULL;
605   if (wbox->children)
606     {
607       GtkWrapBoxChild *last = wbox->children;
608 
609       while (last->next)
610         last = last->next;
611       last->next = child_info;
612     }
613   else
614     wbox->children = child_info;
615   wbox->n_children++;
616 
617   gtk_widget_set_parent (child, GTK_WIDGET (wbox));
618 
619   if (GTK_WIDGET_REALIZED (wbox))
620     gtk_widget_realize (child);
621 
622   if (GTK_WIDGET_VISIBLE (wbox) && GTK_WIDGET_VISIBLE (child))
623     {
624       if (GTK_WIDGET_MAPPED (wbox))
625         gtk_widget_map (child);
626 
627       gtk_widget_queue_resize (child);
628     }
629 }
630 
631 void
gtk_wrap_box_reorder_child(GtkWrapBox * wbox,GtkWidget * child,gint position)632 gtk_wrap_box_reorder_child (GtkWrapBox *wbox,
633                             GtkWidget  *child,
634                             gint        position)
635 {
636   GtkWrapBoxChild *child_info, *last = NULL;
637 
638   g_return_if_fail (GTK_IS_WRAP_BOX (wbox));
639   g_return_if_fail (GTK_IS_WIDGET (child));
640 
641   for (child_info = wbox->children; child_info; last = child_info, child_info = last->next)
642     if (child_info->widget == child)
643       break;
644 
645   if (child_info && wbox->children->next)
646     {
647       GtkWrapBoxChild *tmp;
648 
649       if (last)
650         last->next = child_info->next;
651       else
652         wbox->children = child_info->next;
653 
654       last = NULL;
655       tmp = wbox->children;
656       while (position && tmp->next)
657         {
658           position--;
659           last = tmp;
660           tmp = last->next;
661         }
662 
663       if (position)
664         {
665           tmp->next = child_info;
666           child_info->next = NULL;
667         }
668       else
669         {
670           child_info->next = tmp;
671           if (last)
672             last->next = child_info;
673           else
674             wbox->children = child_info;
675         }
676 
677       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (wbox))
678         gtk_widget_queue_resize (child);
679     }
680 }
681 
682 void
gtk_wrap_box_query_child_packing(GtkWrapBox * wbox,GtkWidget * child,gboolean * hexpand,gboolean * hfill,gboolean * vexpand,gboolean * vfill,gboolean * wrapped)683 gtk_wrap_box_query_child_packing (GtkWrapBox *wbox,
684                                   GtkWidget  *child,
685                                   gboolean   *hexpand,
686                                   gboolean   *hfill,
687                                   gboolean   *vexpand,
688                                   gboolean   *vfill,
689                                   gboolean   *wrapped)
690 {
691   GtkWrapBoxChild *child_info;
692 
693   g_return_if_fail (GTK_IS_WRAP_BOX (wbox));
694   g_return_if_fail (GTK_IS_WIDGET (child));
695 
696   for (child_info = wbox->children; child_info; child_info = child_info->next)
697     if (child_info->widget == child)
698       break;
699 
700   if (child_info)
701     {
702       if (hexpand)
703         *hexpand = child_info->hexpand;
704       if (hfill)
705         *hfill = child_info->hfill;
706       if (vexpand)
707         *vexpand = child_info->vexpand;
708       if (vfill)
709         *vfill = child_info->vfill;
710       if (wrapped)
711         *wrapped = child_info->wrapped;
712     }
713 }
714 
715 void
gtk_wrap_box_set_child_packing(GtkWrapBox * wbox,GtkWidget * child,gboolean hexpand,gboolean hfill,gboolean vexpand,gboolean vfill,gboolean wrapped)716 gtk_wrap_box_set_child_packing (GtkWrapBox *wbox,
717                                 GtkWidget  *child,
718                                 gboolean    hexpand,
719                                 gboolean    hfill,
720                                 gboolean    vexpand,
721                                 gboolean    vfill,
722                                 gboolean    wrapped)
723 {
724   GtkWrapBoxChild *child_info;
725 
726   g_return_if_fail (GTK_IS_WRAP_BOX (wbox));
727   g_return_if_fail (GTK_IS_WIDGET (child));
728 
729   hexpand = hexpand != FALSE;
730   hfill = hfill != FALSE;
731   vexpand = vexpand != FALSE;
732   vfill = vfill != FALSE;
733   wrapped = wrapped != FALSE;
734 
735   for (child_info = wbox->children; child_info; child_info = child_info->next)
736     if (child_info->widget == child)
737       break;
738 
739   if (child_info &&
740       (child_info->hexpand != hexpand || child_info->vexpand != vexpand ||
741        child_info->hfill != hfill || child_info->vfill != vfill ||
742        child_info->wrapped != wrapped))
743     {
744       child_info->hexpand = hexpand;
745       child_info->hfill = hfill;
746       child_info->vexpand = vexpand;
747       child_info->vfill = vfill;
748       child_info->wrapped = wrapped;
749 
750       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (wbox))
751         gtk_widget_queue_resize (child);
752     }
753 }
754 
755 guint*
gtk_wrap_box_query_line_lengths(GtkWrapBox * wbox,guint * _n_lines)756 gtk_wrap_box_query_line_lengths (GtkWrapBox *wbox,
757                                  guint      *_n_lines)
758 {
759   GtkWrapBoxChild *next_child = NULL;
760   GtkAllocation area, *allocation;
761   gboolean expand_line;
762   GSList *slist;
763   guint max_child_size, border, n_lines = 0, *lines = NULL;
764 
765   if (_n_lines)
766     *_n_lines = 0;
767   g_return_val_if_fail (GTK_IS_WRAP_BOX (wbox), NULL);
768 
769   allocation = &GTK_WIDGET (wbox)->allocation;
770   border = GTK_CONTAINER (wbox)->border_width;
771   area.x = allocation->x + border;
772   area.y = allocation->y + border;
773   area.width = MAX (1, (gint) allocation->width - border * 2);
774   area.height = MAX (1, (gint) allocation->height - border * 2);
775 
776   next_child = wbox->children;
777   slist = GTK_WRAP_BOX_GET_CLASS (wbox)->rlist_line_children (wbox,
778                                                               &next_child,
779                                                               &area,
780                                                               &max_child_size,
781                                                               &expand_line);
782   while (slist)
783     {
784       guint l = n_lines++;
785 
786       lines = g_renew (guint, lines, n_lines);
787       lines[l] = g_slist_length (slist);
788       g_slist_free (slist);
789 
790       slist = GTK_WRAP_BOX_GET_CLASS (wbox)->rlist_line_children (wbox,
791                                                                   &next_child,
792                                                                   &area,
793                                                                   &max_child_size,
794                                                                   &expand_line);
795     }
796 
797   if (_n_lines)
798     *_n_lines = n_lines;
799 
800   return lines;
801 }
802 
803 static void
gtk_wrap_box_map(GtkWidget * widget)804 gtk_wrap_box_map (GtkWidget *widget)
805 {
806   GtkWrapBox *wbox = GTK_WRAP_BOX (widget);
807   GtkWrapBoxChild *child;
808 
809   GTK_WIDGET_SET_FLAGS (wbox, GTK_MAPPED);
810 
811   for (child = wbox->children; child; child = child->next)
812     if (GTK_WIDGET_VISIBLE (child->widget) &&
813         !GTK_WIDGET_MAPPED (child->widget))
814       gtk_widget_map (child->widget);
815 }
816 
817 static void
gtk_wrap_box_unmap(GtkWidget * widget)818 gtk_wrap_box_unmap (GtkWidget *widget)
819 {
820   GtkWrapBox *wbox = GTK_WRAP_BOX (widget);
821   GtkWrapBoxChild *child;
822 
823   GTK_WIDGET_UNSET_FLAGS (wbox, GTK_MAPPED);
824 
825   for (child = wbox->children; child; child = child->next)
826     if (GTK_WIDGET_VISIBLE (child->widget) &&
827         GTK_WIDGET_MAPPED (child->widget))
828       gtk_widget_unmap (child->widget);
829 }
830 
831 static gint
gtk_wrap_box_expose(GtkWidget * widget,GdkEventExpose * event)832 gtk_wrap_box_expose (GtkWidget      *widget,
833                      GdkEventExpose *event)
834 {
835   return GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
836 }
837 
838 static void
gtk_wrap_box_add(GtkContainer * container,GtkWidget * widget)839 gtk_wrap_box_add (GtkContainer *container,
840                   GtkWidget    *widget)
841 {
842   gtk_wrap_box_pack (GTK_WRAP_BOX (container), widget, FALSE, TRUE, FALSE, TRUE);
843 }
844 
845 static void
gtk_wrap_box_remove(GtkContainer * container,GtkWidget * widget)846 gtk_wrap_box_remove (GtkContainer *container,
847                      GtkWidget    *widget)
848 {
849   GtkWrapBox *wbox = GTK_WRAP_BOX (container);
850   GtkWrapBoxChild *child, *last = NULL;
851 
852   child = wbox->children;
853   while (child)
854     {
855       if (child->widget == widget)
856         {
857           gboolean was_visible;
858 
859           was_visible = GTK_WIDGET_VISIBLE (widget);
860           gtk_widget_unparent (widget);
861 
862           if (last)
863             last->next = child->next;
864           else
865             wbox->children = child->next;
866           g_slice_free (GtkWrapBoxChild, child);
867           wbox->n_children--;
868 
869           if (was_visible)
870             gtk_widget_queue_resize (GTK_WIDGET (container));
871 
872           break;
873         }
874 
875       last = child;
876       child = last->next;
877     }
878 }
879 
880 static void
gtk_wrap_box_forall(GtkContainer * container,gboolean include_internals,GtkCallback callback,gpointer callback_data)881 gtk_wrap_box_forall (GtkContainer *container,
882                      gboolean      include_internals,
883                      GtkCallback   callback,
884                      gpointer      callback_data)
885 {
886   GtkWrapBox *wbox = GTK_WRAP_BOX (container);
887   GtkWrapBoxChild *child;
888 
889   child = wbox->children;
890   while (child)
891     {
892       GtkWidget *widget = child->widget;
893 
894       child = child->next;
895 
896       callback (widget, callback_data);
897     }
898 }
899