1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
34 CHILD_ARG_LEFT_ATTACH,
35 CHILD_ARG_RIGHT_ATTACH,
37 CHILD_ARG_BOTTOM_ATTACH,
45 static void gtk_table_class_init (GtkTableClass *klass);
46 static void gtk_table_init (GtkTable *table);
47 static void gtk_table_finalize (GtkObject *object);
48 static void gtk_table_map (GtkWidget *widget);
49 static void gtk_table_unmap (GtkWidget *widget);
50 static void gtk_table_draw (GtkWidget *widget,
52 static gint gtk_table_expose (GtkWidget *widget,
53 GdkEventExpose *event);
54 static void gtk_table_size_request (GtkWidget *widget,
55 GtkRequisition *requisition);
56 static void gtk_table_size_allocate (GtkWidget *widget,
57 GtkAllocation *allocation);
58 static void gtk_table_add (GtkContainer *container,
60 static void gtk_table_remove (GtkContainer *container,
62 static void gtk_table_foreach (GtkContainer *container,
64 gpointer callback_data);
65 static void gtk_table_get_arg (GtkObject *object,
68 static void gtk_table_set_arg (GtkObject *object,
71 static void gtk_table_set_child_arg (GtkContainer *container,
75 static void gtk_table_get_child_arg (GtkContainer *container,
79 static GtkType gtk_table_child_type (GtkContainer *container);
82 static void gtk_table_size_request_init (GtkTable *table);
83 static void gtk_table_size_request_pass1 (GtkTable *table);
84 static void gtk_table_size_request_pass2 (GtkTable *table);
85 static void gtk_table_size_request_pass3 (GtkTable *table);
87 static void gtk_table_size_allocate_init (GtkTable *table);
88 static void gtk_table_size_allocate_pass1 (GtkTable *table);
89 static void gtk_table_size_allocate_pass2 (GtkTable *table);
92 static GtkContainerClass *parent_class = NULL;
96 gtk_table_get_type (void)
98 static GtkType table_type = 0;
102 GtkTypeInfo table_info =
106 sizeof (GtkTableClass),
107 (GtkClassInitFunc) gtk_table_class_init,
108 (GtkObjectInitFunc) gtk_table_init,
113 table_type = gtk_type_unique (gtk_container_get_type (), &table_info);
120 gtk_table_class_init (GtkTableClass *class)
122 GtkObjectClass *object_class;
123 GtkWidgetClass *widget_class;
124 GtkContainerClass *container_class;
126 object_class = (GtkObjectClass*) class;
127 widget_class = (GtkWidgetClass*) class;
128 container_class = (GtkContainerClass*) class;
130 parent_class = gtk_type_class (gtk_container_get_type ());
132 gtk_object_add_arg_type ("GtkTable::n_rows", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_N_ROWS);
133 gtk_object_add_arg_type ("GtkTable::n_columns", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_N_COLUMNS);
134 gtk_object_add_arg_type ("GtkTable::row_spacing", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_ROW_SPACING);
135 gtk_object_add_arg_type ("GtkTable::column_spacing", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_COLUMN_SPACING);
136 gtk_object_add_arg_type ("GtkTable::homogeneous", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HOMOGENEOUS);
137 gtk_container_add_child_arg_type ("GtkTable::left_attach", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_LEFT_ATTACH);
138 gtk_container_add_child_arg_type ("GtkTable::right_attach", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_RIGHT_ATTACH);
139 gtk_container_add_child_arg_type ("GtkTable::top_attach", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_TOP_ATTACH);
140 gtk_container_add_child_arg_type ("GtkTable::bottom_attach", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_BOTTOM_ATTACH);
141 gtk_container_add_child_arg_type ("GtkTable::x_options", GTK_TYPE_ATTACH_OPTIONS, GTK_ARG_READWRITE, CHILD_ARG_X_OPTIONS);
142 gtk_container_add_child_arg_type ("GtkTable::y_options", GTK_TYPE_ATTACH_OPTIONS, GTK_ARG_READWRITE, CHILD_ARG_Y_OPTIONS);
143 gtk_container_add_child_arg_type ("GtkTable::x_padding", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_X_PADDING);
144 gtk_container_add_child_arg_type ("GtkTable::y_padding", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_Y_PADDING);
146 object_class->finalize = gtk_table_finalize;
148 widget_class->map = gtk_table_map;
149 widget_class->unmap = gtk_table_unmap;
150 widget_class->draw = gtk_table_draw;
151 widget_class->expose_event = gtk_table_expose;
152 widget_class->size_request = gtk_table_size_request;
153 widget_class->size_allocate = gtk_table_size_allocate;
155 container_class->add = gtk_table_add;
156 container_class->remove = gtk_table_remove;
157 container_class->foreach = gtk_table_foreach;
158 container_class->child_type = gtk_table_child_type;
159 container_class->set_child_arg = gtk_table_set_child_arg;
160 container_class->get_child_arg = gtk_table_get_child_arg;
164 gtk_table_child_type (GtkContainer *container)
166 return GTK_TYPE_WIDGET;
170 gtk_table_get_arg (GtkObject *object,
176 table = GTK_TABLE (object);
181 GTK_VALUE_UINT (*arg) = table->nrows;
184 GTK_VALUE_UINT (*arg) = table->ncols;
186 case ARG_ROW_SPACING:
187 GTK_VALUE_UINT (*arg) = table->row_spacing;
189 case ARG_COLUMN_SPACING:
190 GTK_VALUE_UINT (*arg) = table->column_spacing;
192 case ARG_HOMOGENEOUS:
193 GTK_VALUE_BOOL (*arg) = table->homogeneous;
196 arg->type = GTK_TYPE_INVALID;
202 gtk_table_set_arg (GtkObject *object,
208 table = GTK_TABLE (object);
213 gtk_table_resize (table, GTK_VALUE_UINT (*arg), table->ncols);
216 gtk_table_resize (table, table->nrows, GTK_VALUE_UINT (*arg));
218 case ARG_ROW_SPACING:
219 gtk_table_set_row_spacings (table, GTK_VALUE_UINT (*arg));
221 case ARG_COLUMN_SPACING:
222 gtk_table_set_col_spacings (table, GTK_VALUE_UINT (*arg));
224 case ARG_HOMOGENEOUS:
225 gtk_table_set_homogeneous (table, GTK_VALUE_BOOL (*arg));
233 gtk_table_set_child_arg (GtkContainer *container,
239 GtkTableChild *table_child;
242 table = GTK_TABLE (container);
244 for (list = table->children; list; list = list->next)
246 table_child = list->data;
248 if (table_child->widget == child)
256 case CHILD_ARG_LEFT_ATTACH:
257 if (GTK_VALUE_UINT (*arg) < table_child->right_attach)
258 table_child->left_attach = GTK_VALUE_UINT (*arg);
260 case CHILD_ARG_RIGHT_ATTACH:
261 if (GTK_VALUE_UINT (*arg) > table_child->left_attach)
262 table_child->right_attach = GTK_VALUE_UINT (*arg);
263 if (table_child->right_attach >= table->ncols)
264 gtk_table_resize (table, table->ncols, table_child->right_attach);
266 case CHILD_ARG_TOP_ATTACH:
267 if (GTK_VALUE_UINT (*arg) < table_child->bottom_attach)
268 table_child->top_attach = GTK_VALUE_UINT (*arg);
270 case CHILD_ARG_BOTTOM_ATTACH:
271 if (GTK_VALUE_UINT (*arg) > table_child->top_attach)
272 table_child->bottom_attach = GTK_VALUE_UINT (*arg);
273 if (table_child->bottom_attach >= table->nrows)
274 gtk_table_resize (table, table_child->bottom_attach, table->ncols);
276 case CHILD_ARG_X_OPTIONS:
277 table_child->xexpand = (GTK_VALUE_FLAGS (*arg) & GTK_EXPAND) != 0;
278 table_child->xshrink = (GTK_VALUE_FLAGS (*arg) & GTK_SHRINK) != 0;
279 table_child->xfill = (GTK_VALUE_FLAGS (*arg) & GTK_FILL) != 0;
281 case CHILD_ARG_Y_OPTIONS:
282 table_child->yexpand = (GTK_VALUE_FLAGS (*arg) & GTK_EXPAND) != 0;
283 table_child->yshrink = (GTK_VALUE_FLAGS (*arg) & GTK_SHRINK) != 0;
284 table_child->yfill = (GTK_VALUE_FLAGS (*arg) & GTK_FILL) != 0;
286 case CHILD_ARG_X_PADDING:
287 table_child->xpadding = GTK_VALUE_UINT (*arg);
289 case CHILD_ARG_Y_PADDING:
290 table_child->ypadding = GTK_VALUE_UINT (*arg);
295 if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (table))
296 gtk_widget_queue_resize (GTK_WIDGET (table));
300 gtk_table_get_child_arg (GtkContainer *container,
306 GtkTableChild *table_child;
309 table = GTK_TABLE (container);
311 for (list = table->children; list; list = list->next)
313 table_child = list->data;
315 if (table_child->widget == child)
323 case CHILD_ARG_LEFT_ATTACH:
324 GTK_VALUE_UINT (*arg) = table_child->left_attach;
326 case CHILD_ARG_RIGHT_ATTACH:
327 GTK_VALUE_UINT (*arg) = table_child->right_attach;
329 case CHILD_ARG_TOP_ATTACH:
330 GTK_VALUE_UINT (*arg) = table_child->top_attach;
332 case CHILD_ARG_BOTTOM_ATTACH:
333 GTK_VALUE_UINT (*arg) = table_child->bottom_attach;
335 case CHILD_ARG_X_OPTIONS:
336 GTK_VALUE_FLAGS (*arg) = (table_child->xexpand * GTK_EXPAND |
337 table_child->xshrink * GTK_SHRINK |
338 table_child->xfill * GTK_FILL);
340 case CHILD_ARG_Y_OPTIONS:
341 GTK_VALUE_FLAGS (*arg) = (table_child->yexpand * GTK_EXPAND |
342 table_child->yshrink * GTK_SHRINK |
343 table_child->yfill * GTK_FILL);
345 case CHILD_ARG_X_PADDING:
346 GTK_VALUE_UINT (*arg) = table_child->xpadding;
348 case CHILD_ARG_Y_PADDING:
349 GTK_VALUE_UINT (*arg) = table_child->ypadding;
352 arg->type = GTK_TYPE_INVALID;
358 gtk_table_init (GtkTable *table)
360 GTK_WIDGET_SET_FLAGS (table, GTK_NO_WINDOW | GTK_BASIC);
362 table->children = NULL;
367 table->column_spacing = 0;
368 table->row_spacing = 0;
369 table->homogeneous = FALSE;
371 gtk_table_resize (table, 1, 1);
375 gtk_table_new (guint rows,
377 gboolean homogeneous)
381 g_return_val_if_fail (rows >= 1, NULL);
382 g_return_val_if_fail (columns >= 1, NULL);
384 table = gtk_type_new (gtk_table_get_type ());
386 table->homogeneous = (homogeneous ? TRUE : FALSE);
388 gtk_table_resize (table, rows, columns);
390 return GTK_WIDGET (table);
394 gtk_table_resize (GtkTable *table,
398 g_return_if_fail (table != NULL);
399 g_return_if_fail (GTK_IS_TABLE (table));
401 n_rows = MAX (n_rows, 1);
402 n_cols = MAX (n_cols, 1);
404 if (n_rows != table->nrows ||
405 n_cols != table->ncols)
409 for (list = table->children; list; list = list->next)
411 GtkTableChild *child;
415 n_rows = MAX (n_rows, child->bottom_attach);
416 n_cols = MAX (n_cols, child->right_attach);
419 if (n_rows != table->nrows)
424 table->nrows = n_rows;
425 table->rows = g_realloc (table->rows, table->nrows * sizeof (GtkTableRowCol));
427 for (; i < table->nrows; i++)
429 table->rows[i].requisition = 0;
430 table->rows[i].allocation = 0;
431 table->rows[i].spacing = table->row_spacing;
432 table->rows[i].need_expand = 0;
433 table->rows[i].need_shrink = 0;
434 table->rows[i].expand = 0;
435 table->rows[i].shrink = 0;
439 if (n_cols != table->ncols)
444 table->ncols = n_cols;
445 table->cols = g_realloc (table->cols, table->ncols * sizeof (GtkTableRowCol));
447 for (; i < table->ncols; i++)
449 table->cols[i].requisition = 0;
450 table->cols[i].allocation = 0;
451 table->cols[i].spacing = table->column_spacing;
452 table->cols[i].need_expand = 0;
453 table->cols[i].need_shrink = 0;
454 table->cols[i].expand = 0;
455 table->cols[i].shrink = 0;
462 gtk_table_attach (GtkTable *table,
468 GtkAttachOptions xoptions,
469 GtkAttachOptions yoptions,
473 GtkTableChild *table_child;
475 g_return_if_fail (table != NULL);
476 g_return_if_fail (GTK_IS_TABLE (table));
477 g_return_if_fail (child != NULL);
478 g_return_if_fail (GTK_IS_WIDGET (child));
479 g_return_if_fail (child->parent == NULL);
481 /* g_return_if_fail (left_attach >= 0); */
482 g_return_if_fail (left_attach < right_attach);
483 /* g_return_if_fail (top_attach >= 0); */
484 g_return_if_fail (top_attach < bottom_attach);
486 if (right_attach >= table->ncols)
487 gtk_table_resize (table, table->nrows, right_attach);
489 if (bottom_attach >= table->nrows)
490 gtk_table_resize (table, bottom_attach, table->ncols);
492 table_child = g_new (GtkTableChild, 1);
493 table_child->widget = child;
494 table_child->left_attach = left_attach;
495 table_child->right_attach = right_attach;
496 table_child->top_attach = top_attach;
497 table_child->bottom_attach = bottom_attach;
498 table_child->xexpand = (xoptions & GTK_EXPAND) != 0;
499 table_child->xshrink = (xoptions & GTK_SHRINK) != 0;
500 table_child->xfill = (xoptions & GTK_FILL) != 0;
501 table_child->xpadding = xpadding;
502 table_child->yexpand = (yoptions & GTK_EXPAND) != 0;
503 table_child->yshrink = (yoptions & GTK_SHRINK) != 0;
504 table_child->yfill = (yoptions & GTK_FILL) != 0;
505 table_child->ypadding = ypadding;
507 table->children = g_list_prepend (table->children, table_child);
509 gtk_widget_set_parent (child, GTK_WIDGET (table));
511 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (table)))
513 if (GTK_WIDGET_REALIZED (GTK_WIDGET (table)) &&
514 !GTK_WIDGET_REALIZED (child))
515 gtk_widget_realize (child);
517 if (GTK_WIDGET_MAPPED (GTK_WIDGET (table)) &&
518 !GTK_WIDGET_MAPPED (child))
519 gtk_widget_map (child);
522 if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (table))
523 gtk_widget_queue_resize (GTK_WIDGET (table));
527 gtk_table_attach_defaults (GtkTable *table,
534 gtk_table_attach (table, widget,
535 left_attach, right_attach,
536 top_attach, bottom_attach,
537 GTK_EXPAND | GTK_FILL,
538 GTK_EXPAND | GTK_FILL,
543 gtk_table_set_row_spacing (GtkTable *table,
547 g_return_if_fail (table != NULL);
548 g_return_if_fail (GTK_IS_TABLE (table));
549 g_return_if_fail (row + 1 < table->nrows);
551 if (table->rows[row].spacing != spacing)
553 table->rows[row].spacing = spacing;
555 if (GTK_WIDGET_VISIBLE (table))
556 gtk_widget_queue_resize (GTK_WIDGET (table));
561 gtk_table_set_col_spacing (GtkTable *table,
565 g_return_if_fail (table != NULL);
566 g_return_if_fail (GTK_IS_TABLE (table));
567 g_return_if_fail (column + 1 < table->ncols);
569 if (table->cols[column].spacing != spacing)
571 table->cols[column].spacing = spacing;
573 if (GTK_WIDGET_VISIBLE (table))
574 gtk_widget_queue_resize (GTK_WIDGET (table));
579 gtk_table_set_row_spacings (GtkTable *table,
584 g_return_if_fail (table != NULL);
585 g_return_if_fail (GTK_IS_TABLE (table));
587 table->row_spacing = spacing;
588 for (row = 0; row + 1 < table->nrows; row++)
589 table->rows[row].spacing = spacing;
591 if (GTK_WIDGET_VISIBLE (table))
592 gtk_widget_queue_resize (GTK_WIDGET (table));
596 gtk_table_set_col_spacings (GtkTable *table,
601 g_return_if_fail (table != NULL);
602 g_return_if_fail (GTK_IS_TABLE (table));
604 table->column_spacing = spacing;
605 for (col = 0; col + 1 < table->ncols; col++)
606 table->cols[col].spacing = spacing;
608 if (GTK_WIDGET_VISIBLE (table))
609 gtk_widget_queue_resize (GTK_WIDGET (table));
613 gtk_table_set_homogeneous (GtkTable *table,
614 gboolean homogeneous)
616 g_return_if_fail (table != NULL);
617 g_return_if_fail (GTK_IS_TABLE (table));
619 homogeneous = (homogeneous != 0);
620 if (homogeneous != table->homogeneous)
622 table->homogeneous = homogeneous;
624 if (GTK_WIDGET_VISIBLE (table))
625 gtk_widget_queue_resize (GTK_WIDGET (table));
630 gtk_table_finalize (GtkObject *object)
634 g_return_if_fail (object != NULL);
635 g_return_if_fail (GTK_IS_TABLE (object));
637 table = GTK_TABLE (object);
639 g_free (table->rows);
640 g_free (table->cols);
642 (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
646 gtk_table_map (GtkWidget *widget)
649 GtkTableChild *child;
652 g_return_if_fail (widget != NULL);
653 g_return_if_fail (GTK_IS_TABLE (widget));
655 table = GTK_TABLE (widget);
656 GTK_WIDGET_SET_FLAGS (table, GTK_MAPPED);
658 children = table->children;
661 child = children->data;
662 children = children->next;
664 if (GTK_WIDGET_VISIBLE (child->widget) &&
665 !GTK_WIDGET_MAPPED (child->widget))
666 gtk_widget_map (child->widget);
671 gtk_table_unmap (GtkWidget *widget)
674 GtkTableChild *child;
677 g_return_if_fail (widget != NULL);
678 g_return_if_fail (GTK_IS_TABLE (widget));
680 table = GTK_TABLE (widget);
681 GTK_WIDGET_UNSET_FLAGS (table, GTK_MAPPED);
683 children = table->children;
686 child = children->data;
687 children = children->next;
689 if (GTK_WIDGET_VISIBLE (child->widget) &&
690 GTK_WIDGET_MAPPED (child->widget))
691 gtk_widget_unmap (child->widget);
696 gtk_table_draw (GtkWidget *widget,
700 GtkTableChild *child;
702 GdkRectangle child_area;
704 g_return_if_fail (widget != NULL);
705 g_return_if_fail (GTK_IS_TABLE (widget));
707 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
709 table = GTK_TABLE (widget);
711 children = table->children;
714 child = children->data;
715 children = children->next;
717 if (gtk_widget_intersect (child->widget, area, &child_area))
718 gtk_widget_draw (child->widget, &child_area);
724 gtk_table_expose (GtkWidget *widget,
725 GdkEventExpose *event)
728 GtkTableChild *child;
730 GdkEventExpose child_event;
732 g_return_val_if_fail (widget != NULL, FALSE);
733 g_return_val_if_fail (GTK_IS_TABLE (widget), FALSE);
735 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
737 table = GTK_TABLE (widget);
739 child_event = *event;
741 children = table->children;
744 child = children->data;
745 children = children->next;
747 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
748 gtk_widget_intersect (child->widget, &event->area, &child_event.area))
749 gtk_widget_event (child->widget, (GdkEvent*) &child_event);
757 gtk_table_size_request (GtkWidget *widget,
758 GtkRequisition *requisition)
763 g_return_if_fail (widget != NULL);
764 g_return_if_fail (GTK_IS_TABLE (widget));
765 g_return_if_fail (requisition != NULL);
767 table = GTK_TABLE (widget);
769 requisition->width = 0;
770 requisition->height = 0;
772 gtk_table_size_request_init (table);
773 gtk_table_size_request_pass1 (table);
774 gtk_table_size_request_pass2 (table);
775 gtk_table_size_request_pass3 (table);
776 gtk_table_size_request_pass2 (table);
778 for (col = 0; col < table->ncols; col++)
779 requisition->width += table->cols[col].requisition;
780 for (col = 0; col + 1 < table->ncols; col++)
781 requisition->width += table->cols[col].spacing;
783 for (row = 0; row < table->nrows; row++)
784 requisition->height += table->rows[row].requisition;
785 for (row = 0; row + 1 < table->nrows; row++)
786 requisition->height += table->rows[row].spacing;
788 requisition->width += GTK_CONTAINER (table)->border_width * 2;
789 requisition->height += GTK_CONTAINER (table)->border_width * 2;
793 gtk_table_size_allocate (GtkWidget *widget,
794 GtkAllocation *allocation)
798 g_return_if_fail (widget != NULL);
799 g_return_if_fail (GTK_IS_TABLE (widget));
800 g_return_if_fail (allocation != NULL);
802 widget->allocation = *allocation;
803 table = GTK_TABLE (widget);
805 gtk_table_size_allocate_init (table);
806 gtk_table_size_allocate_pass1 (table);
807 gtk_table_size_allocate_pass2 (table);
811 gtk_table_add (GtkContainer *container,
814 g_return_if_fail (container != NULL);
815 g_return_if_fail (GTK_IS_TABLE (container));
816 g_return_if_fail (widget != NULL);
818 gtk_table_attach_defaults (GTK_TABLE (container), widget, 0, 1, 0, 1);
822 gtk_table_remove (GtkContainer *container,
826 GtkTableChild *child;
829 g_return_if_fail (container != NULL);
830 g_return_if_fail (GTK_IS_TABLE (container));
831 g_return_if_fail (widget != NULL);
833 table = GTK_TABLE (container);
834 children = table->children;
838 child = children->data;
839 children = children->next;
841 if (child->widget == widget)
843 gboolean was_visible = GTK_WIDGET_VISIBLE (widget);
845 gtk_widget_unparent (widget);
847 table->children = g_list_remove (table->children, child);
850 if (was_visible && GTK_WIDGET_VISIBLE (container))
851 gtk_widget_queue_resize (GTK_WIDGET (container));
858 gtk_table_foreach (GtkContainer *container,
859 GtkCallback callback,
860 gpointer callback_data)
863 GtkTableChild *child;
866 g_return_if_fail (container != NULL);
867 g_return_if_fail (GTK_IS_TABLE (container));
868 g_return_if_fail (callback != NULL);
870 table = GTK_TABLE (container);
871 children = table->children;
875 child = children->data;
876 children = children->next;
878 (* callback) (child->widget, callback_data);
883 gtk_table_size_request_init (GtkTable *table)
885 GtkTableChild *child;
889 for (row = 0; row < table->nrows; row++)
890 table->rows[row].requisition = 0;
891 for (col = 0; col < table->ncols; col++)
892 table->cols[col].requisition = 0;
894 children = table->children;
897 child = children->data;
898 children = children->next;
900 if (GTK_WIDGET_VISIBLE (child->widget))
901 gtk_widget_size_request (child->widget, &child->widget->requisition);
906 gtk_table_size_request_pass1 (GtkTable *table)
908 GtkTableChild *child;
913 children = table->children;
916 child = children->data;
917 children = children->next;
919 if (GTK_WIDGET_VISIBLE (child->widget))
921 /* Child spans a single column.
923 if (child->left_attach == (child->right_attach - 1))
925 width = child->widget->requisition.width + child->xpadding * 2;
926 table->cols[child->left_attach].requisition = MAX (table->cols[child->left_attach].requisition, width);
929 /* Child spans a single row.
931 if (child->top_attach == (child->bottom_attach - 1))
933 height = child->widget->requisition.height + child->ypadding * 2;
934 table->rows[child->top_attach].requisition = MAX (table->rows[child->top_attach].requisition, height);
941 gtk_table_size_request_pass2 (GtkTable *table)
947 if (table->homogeneous)
952 for (col = 0; col < table->ncols; col++)
953 max_width = MAX (max_width, table->cols[col].requisition);
954 for (row = 0; row < table->nrows; row++)
955 max_height = MAX (max_height, table->rows[row].requisition);
957 for (col = 0; col < table->ncols; col++)
958 table->cols[col].requisition = max_width;
959 for (row = 0; row < table->nrows; row++)
960 table->rows[row].requisition = max_height;
965 gtk_table_size_request_pass3 (GtkTable *table)
967 GtkTableChild *child;
973 children = table->children;
976 child = children->data;
977 children = children->next;
979 if (GTK_WIDGET_VISIBLE (child->widget))
981 /* Child spans multiple columns.
983 if (child->left_attach != (child->right_attach - 1))
985 /* Check and see if there is already enough space
989 for (col = child->left_attach; col < child->right_attach; col++)
991 width += table->cols[col].requisition;
992 if ((col + 1) < child->right_attach)
993 width += table->cols[col].spacing;
996 /* If we need to request more space for this child to fill
997 * its requisition, then divide up the needed space evenly
998 * amongst the columns it spans.
1000 if (width < child->widget->requisition.width + child->xpadding * 2)
1002 width = child->widget->requisition.width + child->xpadding * 2 - width;
1004 for (col = child->left_attach; col < child->right_attach; col++)
1006 extra = width / (child->right_attach - col);
1007 table->cols[col].requisition += extra;
1013 /* Child spans multiple rows.
1015 if (child->top_attach != (child->bottom_attach - 1))
1017 /* Check and see if there is already enough space
1021 for (row = child->top_attach; row < child->bottom_attach; row++)
1023 height += table->rows[row].requisition;
1024 if ((row + 1) < child->bottom_attach)
1025 height += table->rows[row].spacing;
1028 /* If we need to request more space for this child to fill
1029 * its requisition, then divide up the needed space evenly
1030 * amongst the columns it spans.
1032 if (height < child->widget->requisition.height + child->ypadding * 2)
1034 height = child->widget->requisition.height + child->ypadding * 2 - height;
1036 for (row = child->top_attach; row < child->bottom_attach; row++)
1038 extra = height / (child->bottom_attach - row);
1039 table->rows[row].requisition += extra;
1049 gtk_table_size_allocate_init (GtkTable *table)
1051 GtkTableChild *child;
1057 /* Initialize the rows and cols.
1058 * By default, rows and cols do not expand and do shrink.
1059 * Those values are modified by the children that occupy
1060 * the rows and cols.
1062 for (col = 0; col < table->ncols; col++)
1064 table->cols[col].allocation = table->cols[col].requisition;
1065 table->cols[col].need_expand = FALSE;
1066 table->cols[col].need_shrink = TRUE;
1067 table->cols[col].expand = FALSE;
1068 table->cols[col].shrink = TRUE;
1070 for (row = 0; row < table->nrows; row++)
1072 table->rows[row].allocation = table->rows[row].requisition;
1073 table->rows[row].need_expand = FALSE;
1074 table->rows[row].need_shrink = TRUE;
1075 table->rows[row].expand = FALSE;
1076 table->rows[row].shrink = TRUE;
1079 /* Loop over all the children and adjust the row and col values
1080 * based on whether the children want to be allowed to expand
1081 * or shrink. This loop handles children that occupy a single
1084 children = table->children;
1087 child = children->data;
1088 children = children->next;
1090 if (GTK_WIDGET_VISIBLE (child->widget))
1092 if (child->left_attach == (child->right_attach - 1))
1095 table->cols[child->left_attach].expand = TRUE;
1097 if (!child->xshrink)
1098 table->cols[child->left_attach].shrink = FALSE;
1101 if (child->top_attach == (child->bottom_attach - 1))
1104 table->rows[child->top_attach].expand = TRUE;
1106 if (!child->yshrink)
1107 table->rows[child->top_attach].shrink = FALSE;
1112 /* Loop over all the children again and this time handle children
1113 * which span multiple rows or columns.
1115 children = table->children;
1118 child = children->data;
1119 children = children->next;
1121 if (GTK_WIDGET_VISIBLE (child->widget))
1123 if (child->left_attach != (child->right_attach - 1))
1128 for (col = child->left_attach; col < child->right_attach; col++)
1129 if (table->cols[col].expand)
1136 for (col = child->left_attach; col < child->right_attach; col++)
1137 table->cols[col].need_expand = TRUE;
1140 if (!child->xshrink)
1143 for (col = child->left_attach; col < child->right_attach; col++)
1144 if (!table->cols[col].shrink)
1151 for (col = child->left_attach; col < child->right_attach; col++)
1152 table->cols[col].need_shrink = FALSE;
1156 if (child->top_attach != (child->bottom_attach - 1))
1161 for (row = child->top_attach; row < child->bottom_attach; row++)
1162 if (table->rows[row].expand)
1169 for (row = child->top_attach; row < child->bottom_attach; row++)
1170 table->rows[row].need_expand = TRUE;
1173 if (!child->yshrink)
1176 for (row = child->top_attach; row < child->bottom_attach; row++)
1177 if (!table->rows[row].shrink)
1184 for (row = child->top_attach; row < child->bottom_attach; row++)
1185 table->rows[row].need_shrink = FALSE;
1191 /* Loop over the columns and set the expand and shrink values
1192 * if the column can be expanded or shrunk.
1194 for (col = 0; col < table->ncols; col++)
1196 if (table->cols[col].need_expand)
1197 table->cols[col].expand = TRUE;
1198 if (!table->cols[col].need_shrink)
1199 table->cols[col].shrink = FALSE;
1202 /* Loop over the rows and set the expand and shrink values
1203 * if the row can be expanded or shrunk.
1205 for (row = 0; row < table->nrows; row++)
1207 if (table->rows[row].need_expand)
1208 table->rows[row].expand = TRUE;
1209 if (!table->rows[row].need_shrink)
1210 table->rows[row].shrink = FALSE;
1215 gtk_table_size_allocate_pass1 (GtkTable *table)
1225 /* If we were allocated more space than we requested
1226 * then we have to expand any expandable rows and columns
1227 * to fill in the extra space.
1230 real_width = GTK_WIDGET (table)->allocation.width - GTK_CONTAINER (table)->border_width * 2;
1231 real_height = GTK_WIDGET (table)->allocation.height - GTK_CONTAINER (table)->border_width * 2;
1233 if (table->homogeneous)
1236 for (col = 0; col < table->ncols; col++)
1237 if (table->cols[col].expand)
1247 for (col = 0; col + 1 < table->ncols; col++)
1248 width -= table->cols[col].spacing;
1250 for (col = 0; col < table->ncols; col++)
1252 extra = width / (table->ncols - col);
1253 table->cols[col].allocation = MAX (1, extra);
1264 for (col = 0; col < table->ncols; col++)
1266 width += table->cols[col].requisition;
1267 if (table->cols[col].expand)
1269 if (table->cols[col].shrink)
1272 for (col = 0; col + 1 < table->ncols; col++)
1273 width += table->cols[col].spacing;
1275 /* Check to see if we were allocated more width than we requested.
1277 if ((width < real_width) && (nexpand >= 1))
1279 width = real_width - width;
1281 for (col = 0; col < table->ncols; col++)
1282 if (table->cols[col].expand)
1284 extra = width / nexpand;
1285 table->cols[col].allocation += extra;
1292 /* Check to see if we were allocated less width than we requested.
1294 if ((width > real_width) && (nshrink >= 1))
1296 width = width - real_width;
1298 for (col = 0; col < table->ncols; col++)
1299 if (table->cols[col].shrink)
1301 extra = width / nshrink;
1302 table->cols[col].allocation = MAX (1, table->cols[col].allocation - extra);
1310 if (table->homogeneous)
1313 for (row = 0; row < table->nrows; row++)
1314 if (table->rows[row].expand)
1322 height = real_height;
1324 for (row = 0; row + 1 < table->nrows; row++)
1325 height -= table->rows[row].spacing;
1328 for (row = 0; row < table->nrows; row++)
1330 extra = height / (table->nrows - row);
1331 table->rows[row].allocation = MAX (1, extra);
1342 for (row = 0; row < table->nrows; row++)
1344 height += table->rows[row].requisition;
1345 if (table->rows[row].expand)
1347 if (table->rows[row].shrink)
1350 for (row = 0; row + 1 < table->nrows; row++)
1351 height += table->rows[row].spacing;
1353 /* Check to see if we were allocated more height than we requested.
1355 if ((height < real_height) && (nexpand >= 1))
1357 height = real_height - height;
1359 for (row = 0; row < table->nrows; row++)
1360 if (table->rows[row].expand)
1362 extra = height / nexpand;
1363 table->rows[row].allocation += extra;
1370 /* Check to see if we were allocated less height than we requested.
1372 if ((height > real_height) && (nshrink >= 1))
1374 height = height - real_height;
1376 for (row = 0; row < table->nrows; row++)
1377 if (table->rows[row].shrink)
1379 extra = height / nshrink;
1380 table->rows[row].allocation = MAX (1, table->rows[row].allocation - extra);
1390 gtk_table_size_allocate_pass2 (GtkTable *table)
1392 GtkTableChild *child;
1398 GtkAllocation allocation;
1400 children = table->children;
1403 child = children->data;
1404 children = children->next;
1406 if (GTK_WIDGET_VISIBLE (child->widget))
1408 x = GTK_WIDGET (table)->allocation.x + GTK_CONTAINER (table)->border_width;
1409 y = GTK_WIDGET (table)->allocation.y + GTK_CONTAINER (table)->border_width;
1413 for (col = 0; col < child->left_attach; col++)
1415 x += table->cols[col].allocation;
1416 x += table->cols[col].spacing;
1419 for (col = child->left_attach; col < child->right_attach; col++)
1421 max_width += table->cols[col].allocation;
1422 if ((col + 1) < child->right_attach)
1423 max_width += table->cols[col].spacing;
1426 for (row = 0; row < child->top_attach; row++)
1428 y += table->rows[row].allocation;
1429 y += table->rows[row].spacing;
1432 for (row = child->top_attach; row < child->bottom_attach; row++)
1434 max_height += table->rows[row].allocation;
1435 if ((row + 1) < child->bottom_attach)
1436 max_height += table->rows[row].spacing;
1441 allocation.width = MAX (1, max_width - child->xpadding * 2);
1442 allocation.x = x + (max_width - allocation.width) / 2;
1446 allocation.width = child->widget->requisition.width;
1447 allocation.x = x + (max_width - allocation.width) / 2;
1452 allocation.height = MAX (1, max_height - child->ypadding * 2);
1453 allocation.y = y + (max_height - allocation.height) / 2;
1457 allocation.height = child->widget->requisition.height;
1458 allocation.y = y + (max_height - allocation.height) / 2;
1461 gtk_widget_size_allocate (child->widget, &allocation);