1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * GtkWrapBox: Wrapping box widget
5 * Copyright (C) 1999 Tim Janik
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.
23 #include "gtkwrapbox.h"
26 /* --- arguments --- */
49 /* --- prototypes --- */
50 static void gtk_wrap_box_class_init (GtkWrapBoxClass
*klass
);
51 static void gtk_wrap_box_init (GtkWrapBox
*wbox
);
52 static void gtk_wrap_box_get_arg (GtkObject
*object
,
55 static void gtk_wrap_box_set_arg (GtkObject
*object
,
58 static void gtk_wrap_box_set_child_property (GtkContainer
*container
,
63 static void gtk_wrap_box_get_child_property (GtkContainer
*container
,
68 static void gtk_wrap_box_map (GtkWidget
*widget
);
69 static void gtk_wrap_box_unmap (GtkWidget
*widget
);
70 static gint
gtk_wrap_box_expose (GtkWidget
*widget
,
71 GdkEventExpose
*event
);
72 static void gtk_wrap_box_add (GtkContainer
*container
,
74 static void gtk_wrap_box_remove (GtkContainer
*container
,
76 static void gtk_wrap_box_forall (GtkContainer
*container
,
77 gboolean include_internals
,
79 gpointer callback_data
);
80 static GtkType
gtk_wrap_box_child_type (GtkContainer
*container
);
83 /* --- variables --- */
84 static gpointer parent_class
= NULL
;
87 /* --- functions --- */
89 gtk_wrap_box_get_type (void)
91 static GtkType wrap_box_type
= 0;
95 static const GtkTypeInfo wrap_box_info
=
99 sizeof (GtkWrapBoxClass
),
100 (GtkClassInitFunc
) gtk_wrap_box_class_init
,
101 (GtkObjectInitFunc
) gtk_wrap_box_init
,
102 /* reserved_1 */ NULL
,
103 /* reserved_2 */ NULL
,
104 (GtkClassInitFunc
) NULL
,
107 wrap_box_type
= gtk_type_unique (GTK_TYPE_CONTAINER
, &wrap_box_info
);
110 return wrap_box_type
;
114 gtk_wrap_box_class_init (GtkWrapBoxClass
*class)
116 GtkObjectClass
*object_class
;
117 GtkWidgetClass
*widget_class
;
118 GtkContainerClass
*container_class
;
120 object_class
= GTK_OBJECT_CLASS (class);
121 widget_class
= GTK_WIDGET_CLASS (class);
122 container_class
= GTK_CONTAINER_CLASS (class);
124 parent_class
= g_type_class_peek_parent (class);
126 object_class
->set_arg
= gtk_wrap_box_set_arg
;
127 object_class
->get_arg
= gtk_wrap_box_get_arg
;
129 widget_class
->map
= gtk_wrap_box_map
;
130 widget_class
->unmap
= gtk_wrap_box_unmap
;
131 widget_class
->expose_event
= gtk_wrap_box_expose
;
133 container_class
->add
= gtk_wrap_box_add
;
134 container_class
->remove
= gtk_wrap_box_remove
;
135 container_class
->forall
= gtk_wrap_box_forall
;
136 container_class
->child_type
= gtk_wrap_box_child_type
;
137 container_class
->set_child_property
= gtk_wrap_box_set_child_property
;
138 container_class
->get_child_property
= gtk_wrap_box_get_child_property
;
140 class->rlist_line_children
= NULL
;
142 gtk_object_add_arg_type ("GtkWrapBox::homogeneous",
143 GTK_TYPE_BOOL
, GTK_ARG_READWRITE
, ARG_HOMOGENEOUS
);
144 gtk_object_add_arg_type ("GtkWrapBox::justify",
145 GTK_TYPE_JUSTIFICATION
, GTK_ARG_READWRITE
, ARG_JUSTIFY
);
146 gtk_object_add_arg_type ("GtkWrapBox::hspacing",
147 GTK_TYPE_UINT
, GTK_ARG_READWRITE
, ARG_HSPACING
);
148 gtk_object_add_arg_type ("GtkWrapBox::vspacing",
149 GTK_TYPE_UINT
, GTK_ARG_READWRITE
, ARG_VSPACING
);
150 gtk_object_add_arg_type ("GtkWrapBox::line_justify",
151 GTK_TYPE_JUSTIFICATION
, GTK_ARG_READWRITE
, ARG_LINE_JUSTIFY
);
152 gtk_object_add_arg_type ("GtkWrapBox::aspect_ratio",
153 GTK_TYPE_FLOAT
, GTK_ARG_READWRITE
, ARG_ASPECT_RATIO
);
154 gtk_object_add_arg_type ("GtkWrapBox::current_ratio",
155 GTK_TYPE_FLOAT
, GTK_ARG_READABLE
, ARG_CURRENT_RATIO
);
156 gtk_object_add_arg_type ("GtkWrapBox::max_children_per_line",
157 GTK_TYPE_UINT
, GTK_ARG_READWRITE
, ARG_CHILD_LIMIT
);
159 gtk_container_class_install_child_property (container_class
, CHILD_PROP_POSITION
,
160 g_param_spec_int ("position", NULL
, NULL
,
163 gtk_container_class_install_child_property (container_class
, CHILD_PROP_HEXPAND
,
164 g_param_spec_boolean ("hexpand", NULL
, NULL
,
167 gtk_container_class_install_child_property (container_class
, CHILD_PROP_HFILL
,
168 g_param_spec_boolean ("hfill", NULL
, NULL
,
171 gtk_container_class_install_child_property (container_class
, CHILD_PROP_VEXPAND
,
172 g_param_spec_boolean ("vexpand", NULL
, NULL
,
175 gtk_container_class_install_child_property (container_class
, CHILD_PROP_VFILL
,
176 g_param_spec_boolean ("vfill", NULL
, NULL
,
179 gtk_container_class_install_child_property (container_class
, CHILD_PROP_VFILL
,
180 g_param_spec_boolean ("wrapped", NULL
, NULL
,
186 gtk_wrap_box_init (GtkWrapBox
*wbox
)
188 GTK_WIDGET_SET_FLAGS (wbox
, GTK_NO_WINDOW
);
190 wbox
->homogeneous
= FALSE
;
193 wbox
->justify
= GTK_JUSTIFY_LEFT
;
194 wbox
->line_justify
= GTK_JUSTIFY_BOTTOM
;
195 wbox
->n_children
= 0;
196 wbox
->children
= NULL
;
197 wbox
->aspect_ratio
= 1;
198 wbox
->child_limit
= 32767;
202 gtk_wrap_box_set_arg (GtkObject
*object
,
206 GtkWrapBox
*wbox
= GTK_WRAP_BOX (object
);
210 case ARG_HOMOGENEOUS
:
211 gtk_wrap_box_set_homogeneous (wbox
, GTK_VALUE_BOOL (*arg
));
214 gtk_wrap_box_set_justify (wbox
, GTK_VALUE_ENUM (*arg
));
216 case ARG_LINE_JUSTIFY
:
217 gtk_wrap_box_set_line_justify (wbox
, GTK_VALUE_ENUM (*arg
));
220 gtk_wrap_box_set_hspacing (wbox
, GTK_VALUE_UINT (*arg
));
223 gtk_wrap_box_set_vspacing (wbox
, GTK_VALUE_UINT (*arg
));
225 case ARG_ASPECT_RATIO
:
226 gtk_wrap_box_set_aspect_ratio (wbox
, GTK_VALUE_FLOAT (*arg
));
228 case ARG_CHILD_LIMIT
:
229 if (wbox
->child_limit
!= GTK_VALUE_UINT (*arg
))
231 wbox
->child_limit
= CLAMP (GTK_VALUE_UINT (*arg
), 1, 32767);
232 gtk_widget_queue_resize (GTK_WIDGET (wbox
));
239 gtk_wrap_box_get_arg (GtkObject
*object
,
243 GtkWrapBox
*wbox
= GTK_WRAP_BOX (object
);
244 GtkWidget
*widget
= GTK_WIDGET (object
);
248 case ARG_HOMOGENEOUS
:
249 GTK_VALUE_BOOL (*arg
) = wbox
->homogeneous
;
252 GTK_VALUE_ENUM (*arg
) = wbox
->justify
;
254 case ARG_LINE_JUSTIFY
:
255 GTK_VALUE_ENUM (*arg
) = wbox
->line_justify
;
258 GTK_VALUE_UINT (*arg
) = wbox
->hspacing
;
261 GTK_VALUE_UINT (*arg
) = wbox
->vspacing
;
263 case ARG_ASPECT_RATIO
:
264 GTK_VALUE_FLOAT (*arg
) = wbox
->aspect_ratio
;
266 case ARG_CURRENT_RATIO
:
267 GTK_VALUE_FLOAT (*arg
) = (((gfloat
) widget
->allocation
.width
) /
268 ((gfloat
) widget
->allocation
.height
));
270 case ARG_CHILD_LIMIT
:
271 GTK_VALUE_UINT (*arg
) = wbox
->child_limit
;
274 arg
->type
= GTK_TYPE_INVALID
;
280 gtk_wrap_box_set_child_property (GtkContainer
*container
,
286 GtkWrapBox
*wbox
= GTK_WRAP_BOX (container
);
287 gboolean hexpand
= FALSE
, hfill
= FALSE
, vexpand
= FALSE
, vfill
= FALSE
, wrapped
= FALSE
;
289 if (property_id
!= CHILD_PROP_POSITION
)
290 gtk_wrap_box_query_child_packing (wbox
, child
, &hexpand
, &hfill
, &vexpand
, &vfill
, &wrapped
);
294 case CHILD_PROP_POSITION
:
295 gtk_wrap_box_reorder_child (wbox
, child
, g_value_get_int (value
));
297 case CHILD_PROP_HEXPAND
:
298 gtk_wrap_box_set_child_packing (wbox
, child
,
299 g_value_get_boolean (value
), hfill
,
303 case CHILD_PROP_HFILL
:
304 gtk_wrap_box_set_child_packing (wbox
, child
,
305 hexpand
, g_value_get_boolean (value
),
309 case CHILD_PROP_VEXPAND
:
310 gtk_wrap_box_set_child_packing (wbox
, child
,
312 g_value_get_boolean (value
), vfill
,
315 case CHILD_PROP_VFILL
:
316 gtk_wrap_box_set_child_packing (wbox
, child
,
318 vexpand
, g_value_get_boolean (value
),
321 case CHILD_PROP_WRAPPED
:
322 gtk_wrap_box_set_child_packing (wbox
, child
,
325 g_value_get_boolean (value
));
328 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container
, property_id
, pspec
);
334 gtk_wrap_box_get_child_property (GtkContainer
*container
,
340 GtkWrapBox
*wbox
= GTK_WRAP_BOX (container
);
341 gboolean hexpand
= FALSE
, hfill
= FALSE
, vexpand
= FALSE
, vfill
= FALSE
, wrapped
= FALSE
;
343 if (property_id
!= CHILD_PROP_POSITION
)
344 gtk_wrap_box_query_child_packing (wbox
, child
, &hexpand
, &hfill
, &vexpand
, &vfill
, &wrapped
);
348 GtkWrapBoxChild
*child_info
;
350 case CHILD_PROP_POSITION
:
352 for (child_info
= wbox
->children
; child_info
; child_info
= child_info
->next
)
354 if (child_info
->widget
== child
)
358 g_value_set_int (value
, child_info
? i
: -1);
360 case CHILD_PROP_HEXPAND
:
361 g_value_set_boolean (value
, hexpand
);
363 case CHILD_PROP_HFILL
:
364 g_value_set_boolean (value
, hfill
);
366 case CHILD_PROP_VEXPAND
:
367 g_value_set_boolean (value
, vexpand
);
369 case CHILD_PROP_VFILL
:
370 g_value_set_boolean (value
, vfill
);
372 case CHILD_PROP_WRAPPED
:
373 g_value_set_boolean (value
, wrapped
);
376 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container
, property_id
, pspec
);
382 gtk_wrap_box_child_type (GtkContainer
*container
)
384 return GTK_TYPE_WIDGET
;
388 gtk_wrap_box_set_homogeneous (GtkWrapBox
*wbox
,
389 gboolean homogeneous
)
391 g_return_if_fail (GTK_IS_WRAP_BOX (wbox
));
393 homogeneous
= homogeneous
!= FALSE
;
394 if (wbox
->homogeneous
!= homogeneous
)
396 wbox
->homogeneous
= homogeneous
;
397 gtk_widget_queue_resize (GTK_WIDGET (wbox
));
402 gtk_wrap_box_set_hspacing (GtkWrapBox
*wbox
,
405 g_return_if_fail (GTK_IS_WRAP_BOX (wbox
));
407 if (wbox
->hspacing
!= hspacing
)
409 wbox
->hspacing
= hspacing
;
410 gtk_widget_queue_resize (GTK_WIDGET (wbox
));
415 gtk_wrap_box_set_vspacing (GtkWrapBox
*wbox
,
418 g_return_if_fail (GTK_IS_WRAP_BOX (wbox
));
420 if (wbox
->vspacing
!= vspacing
)
422 wbox
->vspacing
= vspacing
;
423 gtk_widget_queue_resize (GTK_WIDGET (wbox
));
428 gtk_wrap_box_set_justify (GtkWrapBox
*wbox
,
429 GtkJustification justify
)
431 g_return_if_fail (GTK_IS_WRAP_BOX (wbox
));
432 g_return_if_fail (justify
<= GTK_JUSTIFY_FILL
);
434 if (wbox
->justify
!= justify
)
436 wbox
->justify
= justify
;
437 gtk_widget_queue_resize (GTK_WIDGET (wbox
));
442 gtk_wrap_box_set_line_justify (GtkWrapBox
*wbox
,
443 GtkJustification line_justify
)
445 g_return_if_fail (GTK_IS_WRAP_BOX (wbox
));
446 g_return_if_fail (line_justify
<= GTK_JUSTIFY_FILL
);
448 if (wbox
->line_justify
!= line_justify
)
450 wbox
->line_justify
= line_justify
;
451 gtk_widget_queue_resize (GTK_WIDGET (wbox
));
456 gtk_wrap_box_set_aspect_ratio (GtkWrapBox
*wbox
,
459 g_return_if_fail (GTK_IS_WRAP_BOX (wbox
));
461 aspect_ratio
= CLAMP (aspect_ratio
, 1.0 / 256.0, 256.0);
463 if (wbox
->aspect_ratio
!= aspect_ratio
)
465 wbox
->aspect_ratio
= aspect_ratio
;
466 gtk_widget_queue_resize (GTK_WIDGET (wbox
));
471 gtk_wrap_box_pack (GtkWrapBox
*wbox
,
478 g_return_if_fail (GTK_IS_WRAP_BOX (wbox
));
479 g_return_if_fail (GTK_IS_WIDGET (child
));
480 g_return_if_fail (child
->parent
== NULL
);
482 gtk_wrap_box_pack_wrapped (wbox
, child
, hexpand
, hfill
, vexpand
, vfill
, FALSE
);
486 gtk_wrap_box_pack_wrapped (GtkWrapBox
*wbox
,
494 GtkWrapBoxChild
*child_info
;
496 g_return_if_fail (GTK_IS_WRAP_BOX (wbox
));
497 g_return_if_fail (GTK_IS_WIDGET (child
));
498 g_return_if_fail (child
->parent
== NULL
);
500 child_info
= g_new (GtkWrapBoxChild
, 1);
501 child_info
->widget
= child
;
502 child_info
->hexpand
= hexpand
? TRUE
: FALSE
;
503 child_info
->hfill
= hfill
? TRUE
: FALSE
;
504 child_info
->vexpand
= vexpand
? TRUE
: FALSE
;
505 child_info
->vfill
= vfill
? TRUE
: FALSE
;
506 child_info
->wrapped
= wrapped
? TRUE
: FALSE
;
507 child_info
->next
= NULL
;
510 GtkWrapBoxChild
*last
= wbox
->children
;
514 last
->next
= child_info
;
517 wbox
->children
= child_info
;
520 gtk_widget_set_parent (child
, GTK_WIDGET (wbox
));
522 if (GTK_WIDGET_REALIZED (wbox
))
523 gtk_widget_realize (child
);
525 if (GTK_WIDGET_VISIBLE (wbox
) && GTK_WIDGET_VISIBLE (child
))
527 if (GTK_WIDGET_MAPPED (wbox
))
528 gtk_widget_map (child
);
530 gtk_widget_queue_resize (child
);
535 gtk_wrap_box_reorder_child (GtkWrapBox
*wbox
,
539 GtkWrapBoxChild
*child_info
, *last
= NULL
;
541 g_return_if_fail (GTK_IS_WRAP_BOX (wbox
));
542 g_return_if_fail (GTK_IS_WIDGET (child
));
544 for (child_info
= wbox
->children
; child_info
; last
= child_info
, child_info
= last
->next
)
545 if (child_info
->widget
== child
)
548 if (child_info
&& wbox
->children
->next
)
550 GtkWrapBoxChild
*tmp
;
553 last
->next
= child_info
->next
;
555 wbox
->children
= child_info
->next
;
558 tmp
= wbox
->children
;
559 while (position
&& tmp
->next
)
568 tmp
->next
= child_info
;
569 child_info
->next
= NULL
;
573 child_info
->next
= tmp
;
575 last
->next
= child_info
;
577 wbox
->children
= child_info
;
580 if (GTK_WIDGET_VISIBLE (child
) && GTK_WIDGET_VISIBLE (wbox
))
581 gtk_widget_queue_resize (child
);
586 gtk_wrap_box_query_child_packing (GtkWrapBox
*wbox
,
594 GtkWrapBoxChild
*child_info
;
596 g_return_if_fail (GTK_IS_WRAP_BOX (wbox
));
597 g_return_if_fail (GTK_IS_WIDGET (child
));
599 for (child_info
= wbox
->children
; child_info
; child_info
= child_info
->next
)
600 if (child_info
->widget
== child
)
606 *hexpand
= child_info
->hexpand
;
608 *hfill
= child_info
->hfill
;
610 *vexpand
= child_info
->vexpand
;
612 *vfill
= child_info
->vfill
;
614 *wrapped
= child_info
->wrapped
;
619 gtk_wrap_box_set_child_packing (GtkWrapBox
*wbox
,
627 GtkWrapBoxChild
*child_info
;
629 g_return_if_fail (GTK_IS_WRAP_BOX (wbox
));
630 g_return_if_fail (GTK_IS_WIDGET (child
));
632 hexpand
= hexpand
!= FALSE
;
633 hfill
= hfill
!= FALSE
;
634 vexpand
= vexpand
!= FALSE
;
635 vfill
= vfill
!= FALSE
;
636 wrapped
= wrapped
!= FALSE
;
638 for (child_info
= wbox
->children
; child_info
; child_info
= child_info
->next
)
639 if (child_info
->widget
== child
)
643 (child_info
->hexpand
!= hexpand
|| child_info
->vexpand
!= vexpand
||
644 child_info
->hfill
!= hfill
|| child_info
->vfill
!= vfill
||
645 child_info
->wrapped
!= wrapped
))
647 child_info
->hexpand
= hexpand
;
648 child_info
->hfill
= hfill
;
649 child_info
->vexpand
= vexpand
;
650 child_info
->vfill
= vfill
;
651 child_info
->wrapped
= wrapped
;
653 if (GTK_WIDGET_VISIBLE (child
) && GTK_WIDGET_VISIBLE (wbox
))
654 gtk_widget_queue_resize (child
);
659 gtk_wrap_box_query_line_lengths (GtkWrapBox
*wbox
,
662 GtkWrapBoxChild
*next_child
= NULL
;
663 GtkAllocation area
, *allocation
;
664 gboolean expand_line
;
666 guint max_child_size
, border
, n_lines
= 0, *lines
= NULL
;
670 g_return_val_if_fail (GTK_IS_WRAP_BOX (wbox
), NULL
);
672 allocation
= >K_WIDGET (wbox
)->allocation
;
673 border
= GTK_CONTAINER (wbox
)->border_width
;
674 area
.x
= allocation
->x
+ border
;
675 area
.y
= allocation
->y
+ border
;
676 area
.width
= MAX (1, (gint
) allocation
->width
- border
* 2);
677 area
.height
= MAX (1, (gint
) allocation
->height
- border
* 2);
679 next_child
= wbox
->children
;
680 slist
= GTK_WRAP_BOX_GET_CLASS (wbox
)->rlist_line_children (wbox
,
689 lines
= g_renew (guint
, lines
, n_lines
);
690 lines
[l
] = g_slist_length (slist
);
691 g_slist_free (slist
);
693 slist
= GTK_WRAP_BOX_GET_CLASS (wbox
)->rlist_line_children (wbox
,
707 gtk_wrap_box_map (GtkWidget
*widget
)
709 GtkWrapBox
*wbox
= GTK_WRAP_BOX (widget
);
710 GtkWrapBoxChild
*child
;
712 GTK_WIDGET_SET_FLAGS (wbox
, GTK_MAPPED
);
714 for (child
= wbox
->children
; child
; child
= child
->next
)
715 if (GTK_WIDGET_VISIBLE (child
->widget
) &&
716 !GTK_WIDGET_MAPPED (child
->widget
))
717 gtk_widget_map (child
->widget
);
721 gtk_wrap_box_unmap (GtkWidget
*widget
)
723 GtkWrapBox
*wbox
= GTK_WRAP_BOX (widget
);
724 GtkWrapBoxChild
*child
;
726 GTK_WIDGET_UNSET_FLAGS (wbox
, GTK_MAPPED
);
728 for (child
= wbox
->children
; child
; child
= child
->next
)
729 if (GTK_WIDGET_VISIBLE (child
->widget
) &&
730 GTK_WIDGET_MAPPED (child
->widget
))
731 gtk_widget_unmap (child
->widget
);
735 gtk_wrap_box_expose (GtkWidget
*widget
,
736 GdkEventExpose
*event
)
738 return GTK_WIDGET_CLASS (parent_class
)->expose_event (widget
, event
);
742 gtk_wrap_box_add (GtkContainer
*container
,
745 gtk_wrap_box_pack (GTK_WRAP_BOX (container
), widget
, FALSE
, TRUE
, FALSE
, TRUE
);
749 gtk_wrap_box_remove (GtkContainer
*container
,
752 GtkWrapBox
*wbox
= GTK_WRAP_BOX (container
);
753 GtkWrapBoxChild
*child
, *last
= NULL
;
755 child
= wbox
->children
;
758 if (child
->widget
== widget
)
760 gboolean was_visible
;
762 was_visible
= GTK_WIDGET_VISIBLE (widget
);
763 gtk_widget_unparent (widget
);
766 last
->next
= child
->next
;
768 wbox
->children
= child
->next
;
773 gtk_widget_queue_resize (GTK_WIDGET (container
));
784 gtk_wrap_box_forall (GtkContainer
*container
,
785 gboolean include_internals
,
786 GtkCallback callback
,
787 gpointer callback_data
)
789 GtkWrapBox
*wbox
= GTK_WRAP_BOX (container
);
790 GtkWrapBoxChild
*child
;
792 child
= wbox
->children
;
795 GtkWidget
*widget
= child
->widget
;
799 callback (widget
, callback_data
);