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 = >K_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