2 * gtkcols.c - implementation of the `Columns' GTK layout container.
9 static void columns_init(Columns *cols);
10 static void columns_class_init(ColumnsClass *klass);
11 static void columns_map(GtkWidget *widget);
12 static void columns_unmap(GtkWidget *widget);
13 #if !GTK_CHECK_VERSION(2,0,0)
14 static void columns_draw(GtkWidget *widget, GdkRectangle *area);
15 static gint columns_expose(GtkWidget *widget, GdkEventExpose *event);
17 static void columns_base_add(GtkContainer *container, GtkWidget *widget);
18 static void columns_remove(GtkContainer *container, GtkWidget *widget);
19 static void columns_forall(GtkContainer *container, gboolean include_internals,
20 GtkCallback callback, gpointer callback_data);
21 #if !GTK_CHECK_VERSION(2,0,0)
22 static gint columns_focus(GtkContainer *container, GtkDirectionType dir);
24 static GType columns_child_type(GtkContainer *container);
25 #if GTK_CHECK_VERSION(3,0,0)
26 static void columns_get_preferred_width(GtkWidget *widget,
27 gint *min, gint *nat);
28 static void columns_get_preferred_height(GtkWidget *widget,
29 gint *min, gint *nat);
30 static void columns_get_preferred_width_for_height(GtkWidget *widget,
32 gint *min, gint *nat);
33 static void columns_get_preferred_height_for_width(GtkWidget *widget,
35 gint *min, gint *nat);
37 static void columns_size_request(GtkWidget *widget, GtkRequisition *req);
39 static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc);
41 static GtkContainerClass *parent_class = NULL;
43 #if !GTK_CHECK_VERSION(2,0,0)
44 GType columns_get_type(void)
46 static GType columns_type = 0;
49 static const GtkTypeInfo columns_info = {
53 (GtkClassInitFunc) columns_class_init,
54 (GtkObjectInitFunc) columns_init,
55 /* reserved_1 */ NULL,
56 /* reserved_2 */ NULL,
57 (GtkClassInitFunc) NULL,
60 columns_type = gtk_type_unique(GTK_TYPE_CONTAINER, &columns_info);
66 GType columns_get_type(void)
68 static GType columns_type = 0;
71 static const GTypeInfo columns_info = {
75 (GClassInitFunc) columns_class_init,
80 (GInstanceInitFunc)columns_init,
83 columns_type = g_type_register_static(GTK_TYPE_CONTAINER, "Columns",
91 #if !GTK_CHECK_VERSION(2,0,0)
92 static gint (*columns_inherited_focus)(GtkContainer *container,
93 GtkDirectionType direction);
96 static void columns_class_init(ColumnsClass *klass)
98 #if !GTK_CHECK_VERSION(2,0,0)
99 /* GtkObjectClass *object_class = (GtkObjectClass *)klass; */
100 GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
101 GtkContainerClass *container_class = (GtkContainerClass *)klass;
103 /* GObjectClass *object_class = G_OBJECT_CLASS(klass); */
104 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
105 GtkContainerClass *container_class = GTK_CONTAINER_CLASS(klass);
108 #if !GTK_CHECK_VERSION(2,0,0)
109 parent_class = gtk_type_class(GTK_TYPE_CONTAINER);
111 parent_class = g_type_class_peek_parent(klass);
114 widget_class->map = columns_map;
115 widget_class->unmap = columns_unmap;
116 #if !GTK_CHECK_VERSION(2,0,0)
117 widget_class->draw = columns_draw;
118 widget_class->expose_event = columns_expose;
120 #if GTK_CHECK_VERSION(3,0,0)
121 widget_class->get_preferred_width = columns_get_preferred_width;
122 widget_class->get_preferred_height = columns_get_preferred_height;
123 widget_class->get_preferred_width_for_height =
124 columns_get_preferred_width_for_height;
125 widget_class->get_preferred_height_for_width =
126 columns_get_preferred_height_for_width;
128 widget_class->size_request = columns_size_request;
130 widget_class->size_allocate = columns_size_allocate;
132 container_class->add = columns_base_add;
133 container_class->remove = columns_remove;
134 container_class->forall = columns_forall;
135 container_class->child_type = columns_child_type;
136 #if !GTK_CHECK_VERSION(2,0,0)
137 /* Save the previous value of this method. */
138 if (!columns_inherited_focus)
139 columns_inherited_focus = container_class->focus;
140 container_class->focus = columns_focus;
144 static void columns_init(Columns *cols)
146 gtk_widget_set_has_window(GTK_WIDGET(cols), FALSE);
148 cols->children = NULL;
153 * These appear to be thoroughly tedious functions; the only reason
154 * we have to reimplement them at all is because we defined our own
155 * format for our GList of children...
157 static void columns_map(GtkWidget *widget)
163 g_return_if_fail(widget != NULL);
164 g_return_if_fail(IS_COLUMNS(widget));
166 cols = COLUMNS(widget);
167 gtk_widget_set_mapped(GTK_WIDGET(cols), TRUE);
169 for (children = cols->children;
170 children && (child = children->data);
171 children = children->next) {
173 gtk_widget_get_visible(child->widget) &&
174 !gtk_widget_get_mapped(child->widget))
175 gtk_widget_map(child->widget);
178 static void columns_unmap(GtkWidget *widget)
184 g_return_if_fail(widget != NULL);
185 g_return_if_fail(IS_COLUMNS(widget));
187 cols = COLUMNS(widget);
188 gtk_widget_set_mapped(GTK_WIDGET(cols), FALSE);
190 for (children = cols->children;
191 children && (child = children->data);
192 children = children->next) {
194 gtk_widget_get_visible(child->widget) &&
195 gtk_widget_get_mapped(child->widget))
196 gtk_widget_unmap(child->widget);
199 #if !GTK_CHECK_VERSION(2,0,0)
200 static void columns_draw(GtkWidget *widget, GdkRectangle *area)
205 GdkRectangle child_area;
207 g_return_if_fail(widget != NULL);
208 g_return_if_fail(IS_COLUMNS(widget));
210 if (GTK_WIDGET_DRAWABLE(widget)) {
211 cols = COLUMNS(widget);
213 for (children = cols->children;
214 children && (child = children->data);
215 children = children->next) {
217 GTK_WIDGET_DRAWABLE(child->widget) &&
218 gtk_widget_intersect(child->widget, area, &child_area))
219 gtk_widget_draw(child->widget, &child_area);
223 static gint columns_expose(GtkWidget *widget, GdkEventExpose *event)
228 GdkEventExpose child_event;
230 g_return_val_if_fail(widget != NULL, FALSE);
231 g_return_val_if_fail(IS_COLUMNS(widget), FALSE);
232 g_return_val_if_fail(event != NULL, FALSE);
234 if (GTK_WIDGET_DRAWABLE(widget)) {
235 cols = COLUMNS(widget);
236 child_event = *event;
238 for (children = cols->children;
239 children && (child = children->data);
240 children = children->next) {
242 GTK_WIDGET_DRAWABLE(child->widget) &&
243 GTK_WIDGET_NO_WINDOW(child->widget) &&
244 gtk_widget_intersect(child->widget, &event->area,
246 gtk_widget_event(child->widget, (GdkEvent *)&child_event);
253 static void columns_base_add(GtkContainer *container, GtkWidget *widget)
257 g_return_if_fail(container != NULL);
258 g_return_if_fail(IS_COLUMNS(container));
259 g_return_if_fail(widget != NULL);
261 cols = COLUMNS(container);
264 * Default is to add a new widget spanning all columns.
266 columns_add(cols, widget, 0, 0); /* 0 means ncols */
269 static void columns_remove(GtkContainer *container, GtkWidget *widget)
275 gboolean was_visible;
277 g_return_if_fail(container != NULL);
278 g_return_if_fail(IS_COLUMNS(container));
279 g_return_if_fail(widget != NULL);
281 cols = COLUMNS(container);
283 for (children = cols->children;
284 children && (child = children->data);
285 children = children->next) {
286 if (child->widget != widget)
289 was_visible = gtk_widget_get_visible(widget);
290 gtk_widget_unparent(widget);
291 cols->children = g_list_remove_link(cols->children, children);
292 g_list_free(children);
295 gtk_widget_queue_resize(GTK_WIDGET(container));
299 for (children = cols->taborder;
300 children && (childw = children->data);
301 children = children->next) {
302 if (childw != widget)
305 cols->taborder = g_list_remove_link(cols->taborder, children);
306 g_list_free(children);
307 #if GTK_CHECK_VERSION(2,0,0)
308 gtk_container_set_focus_chain(container, cols->taborder);
314 static void columns_forall(GtkContainer *container, gboolean include_internals,
315 GtkCallback callback, gpointer callback_data)
319 GList *children, *next;
321 g_return_if_fail(container != NULL);
322 g_return_if_fail(IS_COLUMNS(container));
323 g_return_if_fail(callback != NULL);
325 cols = COLUMNS(container);
327 for (children = cols->children;
328 children && (child = children->data);
331 * We can't wait until after the callback to assign
332 * `children = children->next', because the callback might
333 * be gtk_widget_destroy, which would remove the link
334 * `children' from the list! So instead we must get our
335 * hands on the value of the `next' pointer _before_ the
338 next = children->next;
340 callback(child->widget, callback_data);
344 static GType columns_child_type(GtkContainer *container)
346 return GTK_TYPE_WIDGET;
349 GtkWidget *columns_new(gint spacing)
353 #if !GTK_CHECK_VERSION(2,0,0)
354 cols = gtk_type_new(columns_get_type());
356 cols = g_object_new(TYPE_COLUMNS, NULL);
359 cols->spacing = spacing;
361 return GTK_WIDGET(cols);
364 void columns_set_cols(Columns *cols, gint ncols, const gint *percentages)
366 ColumnsChild *childdata;
369 g_return_if_fail(cols != NULL);
370 g_return_if_fail(IS_COLUMNS(cols));
371 g_return_if_fail(ncols > 0);
372 g_return_if_fail(percentages != NULL);
374 childdata = g_new(ColumnsChild, 1);
375 childdata->widget = NULL;
376 childdata->ncols = ncols;
377 childdata->percentages = g_new(gint, ncols);
378 childdata->force_left = FALSE;
379 for (i = 0; i < ncols; i++)
380 childdata->percentages[i] = percentages[i];
382 cols->children = g_list_append(cols->children, childdata);
385 void columns_add(Columns *cols, GtkWidget *child,
386 gint colstart, gint colspan)
388 ColumnsChild *childdata;
390 g_return_if_fail(cols != NULL);
391 g_return_if_fail(IS_COLUMNS(cols));
392 g_return_if_fail(child != NULL);
393 g_return_if_fail(gtk_widget_get_parent(child) == NULL);
395 childdata = g_new(ColumnsChild, 1);
396 childdata->widget = child;
397 childdata->colstart = colstart;
398 childdata->colspan = colspan;
399 childdata->force_left = FALSE;
401 cols->children = g_list_append(cols->children, childdata);
402 cols->taborder = g_list_append(cols->taborder, child);
404 gtk_widget_set_parent(child, GTK_WIDGET(cols));
406 #if GTK_CHECK_VERSION(2,0,0)
407 gtk_container_set_focus_chain(GTK_CONTAINER(cols), cols->taborder);
410 if (gtk_widget_get_realized(GTK_WIDGET(cols)))
411 gtk_widget_realize(child);
413 if (gtk_widget_get_visible(GTK_WIDGET(cols)) &&
414 gtk_widget_get_visible(child)) {
415 if (gtk_widget_get_mapped(GTK_WIDGET(cols)))
416 gtk_widget_map(child);
417 gtk_widget_queue_resize(child);
421 static ColumnsChild *columns_find_child(Columns *cols, GtkWidget *widget)
426 for (children = cols->children;
427 children && (child = children->data);
428 children = children->next) {
430 if (child->widget == widget)
437 void columns_force_left_align(Columns *cols, GtkWidget *widget)
441 g_return_if_fail(cols != NULL);
442 g_return_if_fail(IS_COLUMNS(cols));
443 g_return_if_fail(widget != NULL);
445 child = columns_find_child(cols, widget);
446 g_return_if_fail(child != NULL);
448 child->force_left = TRUE;
449 if (gtk_widget_get_visible(widget))
450 gtk_widget_queue_resize(GTK_WIDGET(cols));
453 void columns_taborder_last(Columns *cols, GtkWidget *widget)
458 g_return_if_fail(cols != NULL);
459 g_return_if_fail(IS_COLUMNS(cols));
460 g_return_if_fail(widget != NULL);
462 for (children = cols->taborder;
463 children && (childw = children->data);
464 children = children->next) {
465 if (childw != widget)
468 cols->taborder = g_list_remove_link(cols->taborder, children);
469 g_list_free(children);
470 cols->taborder = g_list_append(cols->taborder, widget);
471 #if GTK_CHECK_VERSION(2,0,0)
472 gtk_container_set_focus_chain(GTK_CONTAINER(cols), cols->taborder);
478 #if !GTK_CHECK_VERSION(2,0,0)
480 * Override GtkContainer's focus movement so the user can
481 * explicitly specify the tab order.
483 static gint columns_focus(GtkContainer *container, GtkDirectionType dir)
487 GtkWidget *focuschild;
489 g_return_val_if_fail(container != NULL, FALSE);
490 g_return_val_if_fail(IS_COLUMNS(container), FALSE);
492 cols = COLUMNS(container);
494 if (!GTK_WIDGET_DRAWABLE(cols) ||
495 !GTK_WIDGET_IS_SENSITIVE(cols))
498 if (!GTK_WIDGET_CAN_FOCUS(container) &&
499 (dir == GTK_DIR_TAB_FORWARD || dir == GTK_DIR_TAB_BACKWARD)) {
501 focuschild = container->focus_child;
502 gtk_container_set_focus_child(container, NULL);
504 if (dir == GTK_DIR_TAB_FORWARD)
505 pos = cols->taborder;
507 pos = g_list_last(cols->taborder);
510 GtkWidget *child = pos->data;
513 if (focuschild == child) {
514 focuschild = NULL; /* now we can start looking in here */
515 if (GTK_WIDGET_DRAWABLE(child) &&
516 GTK_IS_CONTAINER(child) &&
517 !GTK_WIDGET_HAS_FOCUS(child)) {
518 if (gtk_container_focus(GTK_CONTAINER(child), dir))
522 } else if (GTK_WIDGET_DRAWABLE(child)) {
523 if (GTK_IS_CONTAINER(child)) {
524 if (gtk_container_focus(GTK_CONTAINER(child), dir))
526 } else if (GTK_WIDGET_CAN_FOCUS(child)) {
527 gtk_widget_grab_focus(child);
532 if (dir == GTK_DIR_TAB_FORWARD)
540 return columns_inherited_focus(container, dir);
545 * Underlying parts of the layout algorithm, to compute the Columns
546 * container's width or height given the widths or heights of its
547 * children. These will be called in various ways with different
548 * notions of width and height in use, so we abstract them out and
549 * pass them a 'get width' or 'get height' function pointer.
552 typedef gint (*widget_dim_fn_t)(ColumnsChild *child);
554 static gint columns_compute_width(Columns *cols, widget_dim_fn_t get_width)
558 gint i, ncols, colspan, retwidth, childwidth;
559 const gint *percentages;
560 static const gint onecol[] = { 100 };
565 percentages = onecol;
567 for (children = cols->children;
568 children && (child = children->data);
569 children = children->next) {
571 if (!child->widget) {
572 /* Column reconfiguration. */
573 ncols = child->ncols;
574 percentages = child->percentages;
578 /* Only take visible widgets into account. */
579 if (!gtk_widget_get_visible(child->widget))
582 childwidth = get_width(child);
583 colspan = child->colspan ? child->colspan : ncols-child->colstart;
586 * To compute width: we know that childwidth + cols->spacing
587 * needs to equal a certain percentage of the full width of
588 * the container. So we work this value out, figure out how
589 * wide the container will need to be to make that percentage
590 * of it equal to that width, and ensure our returned width is
591 * at least that much. Very simple really.
594 int percent, thiswid, fullwid;
597 for (i = 0; i < colspan; i++)
598 percent += percentages[child->colstart+i];
600 thiswid = childwidth + cols->spacing;
602 * Since childwidth is (at least sometimes) the _minimum_
603 * size the child needs, we must ensure that it gets _at
604 * least_ that size. Hence, when scaling thiswid up to
605 * fullwid, we must round up, which means adding percent-1
606 * before dividing by percent.
608 fullwid = (thiswid * 100 + percent - 1) / percent;
611 * The above calculation assumes every widget gets
612 * cols->spacing on the right. So we subtract
613 * cols->spacing here to account for the extra load of
614 * spacing on the right.
616 if (retwidth < fullwid - cols->spacing)
617 retwidth = fullwid - cols->spacing;
621 retwidth += 2*gtk_container_get_border_width(GTK_CONTAINER(cols));
626 static void columns_alloc_horiz(Columns *cols, gint ourwidth,
627 widget_dim_fn_t get_width)
631 gint i, ncols, colspan, border, *colxpos, childwidth;
632 const gint *percentages;
633 static const gint onecol[] = { 100 };
635 border = gtk_container_get_border_width(GTK_CONTAINER(cols));
638 percentages = onecol;
639 /* colxpos gives the starting x position of each column.
640 * We supply n+1 of them, so that we can find the RH edge easily.
641 * All ending x positions are expected to be adjusted afterwards by
642 * subtracting the spacing. */
643 colxpos = g_new(gint, 2);
645 colxpos[1] = ourwidth - 2*border + cols->spacing;
647 for (children = cols->children;
648 children && (child = children->data);
649 children = children->next) {
651 if (!child->widget) {
654 /* Column reconfiguration. */
655 ncols = child->ncols;
656 percentages = child->percentages;
657 colxpos = g_renew(gint, colxpos, ncols + 1);
660 for (i = 0; i < ncols; i++) {
661 percent += percentages[i];
662 colxpos[i+1] = (((ourwidth - 2*border) + cols->spacing)
668 /* Only take visible widgets into account. */
669 if (!gtk_widget_get_visible(child->widget))
672 childwidth = get_width(child);
673 colspan = child->colspan ? child->colspan : ncols-child->colstart;
676 * Starting x position is cols[colstart].
677 * Ending x position is cols[colstart+colspan] - spacing.
679 * Unless we're forcing left, in which case the width is
680 * exactly the requisition width.
682 child->x = colxpos[child->colstart];
683 if (child->force_left)
684 child->w = childwidth;
686 child->w = (colxpos[child->colstart+colspan] -
687 colxpos[child->colstart] - cols->spacing);
693 static gint columns_compute_height(Columns *cols, widget_dim_fn_t get_height)
697 gint i, ncols, colspan, *colypos, retheight, childheight;
699 retheight = cols->spacing;
702 colypos = g_new(gint, 1);
705 for (children = cols->children;
706 children && (child = children->data);
707 children = children->next) {
709 if (!child->widget) {
710 /* Column reconfiguration. */
711 for (i = 1; i < ncols; i++) {
712 if (colypos[0] < colypos[i])
713 colypos[0] = colypos[i];
715 ncols = child->ncols;
716 colypos = g_renew(gint, colypos, ncols);
717 for (i = 1; i < ncols; i++)
718 colypos[i] = colypos[0];
722 /* Only take visible widgets into account. */
723 if (!gtk_widget_get_visible(child->widget))
726 childheight = get_height(child);
727 colspan = child->colspan ? child->colspan : ncols-child->colstart;
730 * To compute height: the widget's top will be positioned at
731 * the largest y value so far reached in any of the columns it
732 * crosses. Then it will go down by childheight plus padding;
733 * and the point it reaches at the bottom is the new y value
734 * in all those columns, and minus the padding it is also a
735 * lower bound on our own height.
741 for (i = 0; i < colspan; i++) {
742 if (topy < colypos[child->colstart+i])
743 topy = colypos[child->colstart+i];
745 boty = topy + childheight + cols->spacing;
746 for (i = 0; i < colspan; i++) {
747 colypos[child->colstart+i] = boty;
750 if (retheight < boty - cols->spacing)
751 retheight = boty - cols->spacing;
755 retheight += 2*gtk_container_get_border_width(GTK_CONTAINER(cols));
762 static void columns_alloc_vert(Columns *cols, gint ourheight,
763 widget_dim_fn_t get_height)
767 gint i, ncols, colspan, *colypos, childheight;
770 /* As in size_request, colypos is the lowest y reached in each column. */
771 colypos = g_new(gint, 1);
774 for (children = cols->children;
775 children && (child = children->data);
776 children = children->next) {
777 if (!child->widget) {
778 /* Column reconfiguration. */
779 for (i = 1; i < ncols; i++) {
780 if (colypos[0] < colypos[i])
781 colypos[0] = colypos[i];
783 ncols = child->ncols;
784 colypos = g_renew(gint, colypos, ncols);
785 for (i = 1; i < ncols; i++)
786 colypos[i] = colypos[0];
790 /* Only take visible widgets into account. */
791 if (!gtk_widget_get_visible(child->widget))
794 childheight = get_height(child);
795 colspan = child->colspan ? child->colspan : ncols-child->colstart;
798 * To compute height: the widget's top will be positioned
799 * at the largest y value so far reached in any of the
800 * columns it crosses. Then it will go down by creq.height
801 * plus padding; and the point it reaches at the bottom is
802 * the new y value in all those columns.
808 for (i = 0; i < colspan; i++) {
809 if (topy < colypos[child->colstart+i])
810 topy = colypos[child->colstart+i];
813 child->h = childheight;
814 boty = topy + childheight + cols->spacing;
815 for (i = 0; i < colspan; i++) {
816 colypos[child->colstart+i] = boty;
825 * Now here comes the interesting bit. The actual layout part is
826 * done in the following two functions:
828 * columns_size_request() examines the list of widgets held in the
829 * Columns, and returns a requisition stating the absolute minimum
830 * size it can bear to be.
832 * columns_size_allocate() is given an allocation telling it what
833 * size the whole container is going to be, and it calls
834 * gtk_widget_size_allocate() on all of its (visible) children to
835 * set their size and position relative to the top left of the
839 #if !GTK_CHECK_VERSION(3,0,0)
841 static gint columns_gtk2_get_width(ColumnsChild *child)
844 gtk_widget_size_request(child->widget, &creq);
848 static gint columns_gtk2_get_height(ColumnsChild *child)
851 gtk_widget_size_request(child->widget, &creq);
855 static void columns_size_request(GtkWidget *widget, GtkRequisition *req)
859 g_return_if_fail(widget != NULL);
860 g_return_if_fail(IS_COLUMNS(widget));
861 g_return_if_fail(req != NULL);
863 cols = COLUMNS(widget);
865 req->width = columns_compute_width(cols, columns_gtk2_get_width);
866 req->height = columns_compute_height(cols, columns_gtk2_get_height);
869 static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc)
876 g_return_if_fail(widget != NULL);
877 g_return_if_fail(IS_COLUMNS(widget));
878 g_return_if_fail(alloc != NULL);
880 cols = COLUMNS(widget);
881 gtk_widget_set_allocation(widget, alloc);
883 border = gtk_container_get_border_width(GTK_CONTAINER(cols));
885 columns_alloc_horiz(cols, alloc->width, columns_gtk2_get_width);
886 columns_alloc_vert(cols, alloc->height, columns_gtk2_get_height);
888 for (children = cols->children;
889 children && (child = children->data);
890 children = children->next) {
891 if (child->widget && gtk_widget_get_visible(child->widget)) {
893 call.x = alloc->x + border + child->x;
894 call.y = alloc->y + border + child->y;
895 call.width = child->w;
896 call.height = child->h;
897 gtk_widget_size_allocate(child->widget, &call);
902 #else /* GTK_CHECK_VERSION(3,0,0) */
904 static gint columns_gtk3_get_min_width(ColumnsChild *child)
907 gtk_widget_get_preferred_width(child->widget, &ret, NULL);
911 static gint columns_gtk3_get_nat_width(ColumnsChild *child)
915 if (GTK_IS_LABEL(child->widget) &&
916 gtk_label_get_line_wrap(GTK_LABEL(child->widget))) {
918 * We treat wrapping GtkLabels as a special case in this
919 * layout class, because the whole point of those is that I
920 * _don't_ want them to take up extra horizontal space for
921 * long text, but instead to wrap it to whatever size is used
922 * by the rest of the layout.
924 gtk_widget_get_preferred_width(child->widget, &ret, NULL);
926 gtk_widget_get_preferred_width(child->widget, NULL, &ret);
931 static gint columns_gtk3_get_minfh_width(ColumnsChild *child)
934 gtk_widget_get_preferred_width_for_height(child->widget, child->h,
939 static gint columns_gtk3_get_natfh_width(ColumnsChild *child)
942 gtk_widget_get_preferred_width_for_height(child->widget, child->h,
947 static gint columns_gtk3_get_min_height(ColumnsChild *child)
950 gtk_widget_get_preferred_height(child->widget, &ret, NULL);
954 static gint columns_gtk3_get_nat_height(ColumnsChild *child)
957 gtk_widget_get_preferred_height(child->widget, NULL, &ret);
961 static gint columns_gtk3_get_minfw_height(ColumnsChild *child)
964 gtk_widget_get_preferred_height_for_width(child->widget, child->w,
969 static gint columns_gtk3_get_natfw_height(ColumnsChild *child)
972 gtk_widget_get_preferred_height_for_width(child->widget, child->w,
977 static void columns_get_preferred_width(GtkWidget *widget,
978 gint *min, gint *nat)
982 g_return_if_fail(widget != NULL);
983 g_return_if_fail(IS_COLUMNS(widget));
985 cols = COLUMNS(widget);
988 *min = columns_compute_width(cols, columns_gtk3_get_min_width);
990 *nat = columns_compute_width(cols, columns_gtk3_get_nat_width);
993 static void columns_get_preferred_height(GtkWidget *widget,
994 gint *min, gint *nat)
998 g_return_if_fail(widget != NULL);
999 g_return_if_fail(IS_COLUMNS(widget));
1001 cols = COLUMNS(widget);
1004 *min = columns_compute_height(cols, columns_gtk3_get_min_height);
1006 *nat = columns_compute_height(cols, columns_gtk3_get_nat_height);
1009 static void columns_get_preferred_width_for_height(GtkWidget *widget,
1011 gint *min, gint *nat)
1015 g_return_if_fail(widget != NULL);
1016 g_return_if_fail(IS_COLUMNS(widget));
1018 cols = COLUMNS(widget);
1020 /* FIXME: which one should the get-height function here be? */
1021 columns_alloc_vert(cols, height, columns_gtk3_get_nat_height);
1024 *min = columns_compute_width(cols, columns_gtk3_get_minfh_width);
1026 *nat = columns_compute_width(cols, columns_gtk3_get_natfh_width);
1029 static void columns_get_preferred_height_for_width(GtkWidget *widget,
1031 gint *min, gint *nat)
1035 g_return_if_fail(widget != NULL);
1036 g_return_if_fail(IS_COLUMNS(widget));
1038 cols = COLUMNS(widget);
1040 /* FIXME: which one should the get-height function here be? */
1041 columns_alloc_horiz(cols, width, columns_gtk3_get_nat_width);
1044 *min = columns_compute_height(cols, columns_gtk3_get_minfw_height);
1046 *nat = columns_compute_height(cols, columns_gtk3_get_natfw_height);
1049 static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc)
1052 ColumnsChild *child;
1056 g_return_if_fail(widget != NULL);
1057 g_return_if_fail(IS_COLUMNS(widget));
1058 g_return_if_fail(alloc != NULL);
1060 cols = COLUMNS(widget);
1061 gtk_widget_set_allocation(widget, alloc);
1063 border = gtk_container_get_border_width(GTK_CONTAINER(cols));
1065 columns_alloc_horiz(cols, alloc->width, columns_gtk3_get_min_width);
1066 columns_alloc_vert(cols, alloc->height, columns_gtk3_get_minfw_height);
1068 for (children = cols->children;
1069 children && (child = children->data);
1070 children = children->next) {
1071 if (child->widget && gtk_widget_get_visible(child->widget)) {
1073 call.x = alloc->x + border + child->x;
1074 call.y = alloc->y + border + child->y;
1075 call.width = child->w;
1076 call.height = child->h;
1077 gtk_widget_size_allocate(child->widget, &call);