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_forall (GtkContainer *container,
63 gboolean include_internals,
65 gpointer callback_data);
66 static void gtk_table_get_arg (GtkObject *object,
69 static void gtk_table_set_arg (GtkObject *object,
72 static void gtk_table_set_child_arg (GtkContainer *container,
76 static void gtk_table_get_child_arg (GtkContainer *container,
80 static GtkType gtk_table_child_type (GtkContainer *container);
83 static void gtk_table_size_request_init (GtkTable *table);
84 static void gtk_table_size_request_pass1 (GtkTable *table);
85 static void gtk_table_size_request_pass2 (GtkTable *table);
86 static void gtk_table_size_request_pass3 (GtkTable *table);
88 static void gtk_table_size_allocate_init (GtkTable *table);
89 static void gtk_table_size_allocate_pass1 (GtkTable *table);
90 static void gtk_table_size_allocate_pass2 (GtkTable *table);
93 static GtkContainerClass *parent_class = NULL;
97 gtk_table_get_type (void)
99 static GtkType table_type = 0;
103 GtkTypeInfo table_info =
107 sizeof (GtkTableClass),
108 (GtkClassInitFunc) gtk_table_class_init,
109 (GtkObjectInitFunc) gtk_table_init,
110 /* reserved_1 */ NULL,
111 /* reserved_2 */ NULL,
112 (GtkClassInitFunc) NULL,
115 table_type = gtk_type_unique (gtk_container_get_type (), &table_info);
122 gtk_table_class_init (GtkTableClass *class)
124 GtkObjectClass *object_class;
125 GtkWidgetClass *widget_class;
126 GtkContainerClass *container_class;
128 object_class = (GtkObjectClass*) class;
129 widget_class = (GtkWidgetClass*) class;
130 container_class = (GtkContainerClass*) class;
132 parent_class = gtk_type_class (gtk_container_get_type ());
134 gtk_object_add_arg_type ("GtkTable::n_rows", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_N_ROWS);
135 gtk_object_add_arg_type ("GtkTable::n_columns", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_N_COLUMNS);
136 gtk_object_add_arg_type ("GtkTable::row_spacing", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_ROW_SPACING);
137 gtk_object_add_arg_type ("GtkTable::column_spacing", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_COLUMN_SPACING);
138 gtk_object_add_arg_type ("GtkTable::homogeneous", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HOMOGENEOUS);
139 gtk_container_add_child_arg_type ("GtkTable::left_attach", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_LEFT_ATTACH);
140 gtk_container_add_child_arg_type ("GtkTable::right_attach", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_RIGHT_ATTACH);
141 gtk_container_add_child_arg_type ("GtkTable::top_attach", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_TOP_ATTACH);
142 gtk_container_add_child_arg_type ("GtkTable::bottom_attach", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_BOTTOM_ATTACH);
143 gtk_container_add_child_arg_type ("GtkTable::x_options", GTK_TYPE_ATTACH_OPTIONS, GTK_ARG_READWRITE, CHILD_ARG_X_OPTIONS);
144 gtk_container_add_child_arg_type ("GtkTable::y_options", GTK_TYPE_ATTACH_OPTIONS, GTK_ARG_READWRITE, CHILD_ARG_Y_OPTIONS);
145 gtk_container_add_child_arg_type ("GtkTable::x_padding", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_X_PADDING);
146 gtk_container_add_child_arg_type ("GtkTable::y_padding", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_Y_PADDING);
148 object_class->get_arg = gtk_table_get_arg;
149 object_class->set_arg = gtk_table_set_arg;
150 object_class->finalize = gtk_table_finalize;
152 widget_class->map = gtk_table_map;
153 widget_class->unmap = gtk_table_unmap;
154 widget_class->draw = gtk_table_draw;
155 widget_class->expose_event = gtk_table_expose;
156 widget_class->size_request = gtk_table_size_request;
157 widget_class->size_allocate = gtk_table_size_allocate;
159 container_class->add = gtk_table_add;
160 container_class->remove = gtk_table_remove;
161 container_class->forall = gtk_table_forall;
162 container_class->child_type = gtk_table_child_type;
163 container_class->set_child_arg = gtk_table_set_child_arg;
164 container_class->get_child_arg = gtk_table_get_child_arg;
168 gtk_table_child_type (GtkContainer *container)
170 return GTK_TYPE_WIDGET;
174 gtk_table_get_arg (GtkObject *object,
180 table = GTK_TABLE (object);
185 GTK_VALUE_UINT (*arg) = table->nrows;
188 GTK_VALUE_UINT (*arg) = table->ncols;
190 case ARG_ROW_SPACING:
191 GTK_VALUE_UINT (*arg) = table->row_spacing;
193 case ARG_COLUMN_SPACING:
194 GTK_VALUE_UINT (*arg) = table->column_spacing;
196 case ARG_HOMOGENEOUS:
197 GTK_VALUE_BOOL (*arg) = table->homogeneous;
200 arg->type = GTK_TYPE_INVALID;
206 gtk_table_set_arg (GtkObject *object,
212 table = GTK_TABLE (object);
217 gtk_table_resize (table, GTK_VALUE_UINT (*arg), table->ncols);
220 gtk_table_resize (table, table->nrows, GTK_VALUE_UINT (*arg));
222 case ARG_ROW_SPACING:
223 gtk_table_set_row_spacings (table, GTK_VALUE_UINT (*arg));
225 case ARG_COLUMN_SPACING:
226 gtk_table_set_col_spacings (table, GTK_VALUE_UINT (*arg));
228 case ARG_HOMOGENEOUS:
229 gtk_table_set_homogeneous (table, GTK_VALUE_BOOL (*arg));
237 gtk_table_set_child_arg (GtkContainer *container,
243 GtkTableChild *table_child;
246 table = GTK_TABLE (container);
248 for (list = table->children; list; list = list->next)
250 table_child = list->data;
252 if (table_child->widget == child)
260 case CHILD_ARG_LEFT_ATTACH:
261 table_child->left_attach = GTK_VALUE_UINT (*arg);
262 if (table_child->right_attach <= table_child->left_attach)
263 table_child->right_attach = table_child->left_attach + 1;
264 if (table_child->right_attach >= table->ncols)
265 gtk_table_resize (table, table->ncols, table_child->right_attach);
267 case CHILD_ARG_RIGHT_ATTACH:
268 if (GTK_VALUE_UINT (*arg) > 0)
270 table_child->right_attach = GTK_VALUE_UINT (*arg);
271 if (table_child->right_attach <= table_child->left_attach)
272 table_child->left_attach = table_child->right_attach - 1;
273 if (table_child->right_attach >= table->ncols)
274 gtk_table_resize (table, table->ncols, table_child->right_attach);
277 case CHILD_ARG_TOP_ATTACH:
278 table_child->top_attach = GTK_VALUE_UINT (*arg);
279 if (table_child->bottom_attach <= table_child->top_attach)
280 table_child->bottom_attach = table_child->top_attach + 1;
281 if (table_child->bottom_attach >= table->nrows)
282 gtk_table_resize (table, table_child->bottom_attach, table->ncols);
284 case CHILD_ARG_BOTTOM_ATTACH:
285 if (GTK_VALUE_UINT (*arg) > 0)
287 table_child->bottom_attach = GTK_VALUE_UINT (*arg);
288 if (table_child->bottom_attach <= table_child->top_attach)
289 table_child->top_attach = table_child->bottom_attach - 1;
290 if (table_child->bottom_attach >= table->nrows)
291 gtk_table_resize (table, table_child->bottom_attach, table->ncols);
294 case CHILD_ARG_X_OPTIONS:
295 table_child->xexpand = (GTK_VALUE_FLAGS (*arg) & GTK_EXPAND) != 0;
296 table_child->xshrink = (GTK_VALUE_FLAGS (*arg) & GTK_SHRINK) != 0;
297 table_child->xfill = (GTK_VALUE_FLAGS (*arg) & GTK_FILL) != 0;
299 case CHILD_ARG_Y_OPTIONS:
300 table_child->yexpand = (GTK_VALUE_FLAGS (*arg) & GTK_EXPAND) != 0;
301 table_child->yshrink = (GTK_VALUE_FLAGS (*arg) & GTK_SHRINK) != 0;
302 table_child->yfill = (GTK_VALUE_FLAGS (*arg) & GTK_FILL) != 0;
304 case CHILD_ARG_X_PADDING:
305 table_child->xpadding = GTK_VALUE_UINT (*arg);
307 case CHILD_ARG_Y_PADDING:
308 table_child->ypadding = GTK_VALUE_UINT (*arg);
313 if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (table))
314 gtk_widget_queue_resize (child);
318 gtk_table_get_child_arg (GtkContainer *container,
324 GtkTableChild *table_child;
327 table = GTK_TABLE (container);
329 for (list = table->children; list; list = list->next)
331 table_child = list->data;
333 if (table_child->widget == child)
341 case CHILD_ARG_LEFT_ATTACH:
342 GTK_VALUE_UINT (*arg) = table_child->left_attach;
344 case CHILD_ARG_RIGHT_ATTACH:
345 GTK_VALUE_UINT (*arg) = table_child->right_attach;
347 case CHILD_ARG_TOP_ATTACH:
348 GTK_VALUE_UINT (*arg) = table_child->top_attach;
350 case CHILD_ARG_BOTTOM_ATTACH:
351 GTK_VALUE_UINT (*arg) = table_child->bottom_attach;
353 case CHILD_ARG_X_OPTIONS:
354 GTK_VALUE_FLAGS (*arg) = (table_child->xexpand * GTK_EXPAND |
355 table_child->xshrink * GTK_SHRINK |
356 table_child->xfill * GTK_FILL);
358 case CHILD_ARG_Y_OPTIONS:
359 GTK_VALUE_FLAGS (*arg) = (table_child->yexpand * GTK_EXPAND |
360 table_child->yshrink * GTK_SHRINK |
361 table_child->yfill * GTK_FILL);
363 case CHILD_ARG_X_PADDING:
364 GTK_VALUE_UINT (*arg) = table_child->xpadding;
366 case CHILD_ARG_Y_PADDING:
367 GTK_VALUE_UINT (*arg) = table_child->ypadding;
370 arg->type = GTK_TYPE_INVALID;
376 gtk_table_init (GtkTable *table)
378 GTK_WIDGET_SET_FLAGS (table, GTK_NO_WINDOW);
380 table->children = NULL;
385 table->column_spacing = 0;
386 table->row_spacing = 0;
387 table->homogeneous = FALSE;
389 gtk_table_resize (table, 1, 1);
393 gtk_table_new (guint rows,
395 gboolean homogeneous)
404 table = gtk_type_new (gtk_table_get_type ());
406 table->homogeneous = (homogeneous ? TRUE : FALSE);
408 gtk_table_resize (table, rows, columns);
410 return GTK_WIDGET (table);
414 gtk_table_resize (GtkTable *table,
418 g_return_if_fail (table != NULL);
419 g_return_if_fail (GTK_IS_TABLE (table));
421 n_rows = MAX (n_rows, 1);
422 n_cols = MAX (n_cols, 1);
424 if (n_rows != table->nrows ||
425 n_cols != table->ncols)
429 for (list = table->children; list; list = list->next)
431 GtkTableChild *child;
435 n_rows = MAX (n_rows, child->bottom_attach);
436 n_cols = MAX (n_cols, child->right_attach);
439 if (n_rows != table->nrows)
444 table->nrows = n_rows;
445 table->rows = g_realloc (table->rows, table->nrows * sizeof (GtkTableRowCol));
447 for (; i < table->nrows; i++)
449 table->rows[i].requisition = 0;
450 table->rows[i].allocation = 0;
451 table->rows[i].spacing = table->row_spacing;
452 table->rows[i].need_expand = 0;
453 table->rows[i].need_shrink = 0;
454 table->rows[i].expand = 0;
455 table->rows[i].shrink = 0;
459 if (n_cols != table->ncols)
464 table->ncols = n_cols;
465 table->cols = g_realloc (table->cols, table->ncols * sizeof (GtkTableRowCol));
467 for (; i < table->ncols; i++)
469 table->cols[i].requisition = 0;
470 table->cols[i].allocation = 0;
471 table->cols[i].spacing = table->column_spacing;
472 table->cols[i].need_expand = 0;
473 table->cols[i].need_shrink = 0;
474 table->cols[i].expand = 0;
475 table->cols[i].shrink = 0;
482 gtk_table_attach (GtkTable *table,
488 GtkAttachOptions xoptions,
489 GtkAttachOptions yoptions,
493 GtkTableChild *table_child;
495 g_return_if_fail (table != NULL);
496 g_return_if_fail (GTK_IS_TABLE (table));
497 g_return_if_fail (child != NULL);
498 g_return_if_fail (GTK_IS_WIDGET (child));
499 g_return_if_fail (child->parent == NULL);
501 /* g_return_if_fail (left_attach >= 0); */
502 g_return_if_fail (left_attach < right_attach);
503 /* g_return_if_fail (top_attach >= 0); */
504 g_return_if_fail (top_attach < bottom_attach);
506 if (right_attach >= table->ncols)
507 gtk_table_resize (table, table->nrows, right_attach);
509 if (bottom_attach >= table->nrows)
510 gtk_table_resize (table, bottom_attach, table->ncols);
512 table_child = g_new (GtkTableChild, 1);
513 table_child->widget = child;
514 table_child->left_attach = left_attach;
515 table_child->right_attach = right_attach;
516 table_child->top_attach = top_attach;
517 table_child->bottom_attach = bottom_attach;
518 table_child->xexpand = (xoptions & GTK_EXPAND) != 0;
519 table_child->xshrink = (xoptions & GTK_SHRINK) != 0;
520 table_child->xfill = (xoptions & GTK_FILL) != 0;
521 table_child->xpadding = xpadding;
522 table_child->yexpand = (yoptions & GTK_EXPAND) != 0;
523 table_child->yshrink = (yoptions & GTK_SHRINK) != 0;
524 table_child->yfill = (yoptions & GTK_FILL) != 0;
525 table_child->ypadding = ypadding;
527 table->children = g_list_prepend (table->children, table_child);
529 gtk_widget_set_parent (child, GTK_WIDGET (table));
531 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (table)))
533 if (GTK_WIDGET_REALIZED (GTK_WIDGET (table)) &&
534 !GTK_WIDGET_REALIZED (child))
535 gtk_widget_realize (child);
537 if (GTK_WIDGET_MAPPED (GTK_WIDGET (table)) &&
538 !GTK_WIDGET_MAPPED (child))
539 gtk_widget_map (child);
542 if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (table))
543 gtk_widget_queue_resize (child);
547 gtk_table_attach_defaults (GtkTable *table,
554 gtk_table_attach (table, widget,
555 left_attach, right_attach,
556 top_attach, bottom_attach,
557 GTK_EXPAND | GTK_FILL,
558 GTK_EXPAND | GTK_FILL,
563 gtk_table_set_row_spacing (GtkTable *table,
567 g_return_if_fail (table != NULL);
568 g_return_if_fail (GTK_IS_TABLE (table));
569 g_return_if_fail (row + 1 < table->nrows);
571 if (table->rows[row].spacing != spacing)
573 table->rows[row].spacing = spacing;
575 if (GTK_WIDGET_VISIBLE (table))
576 gtk_widget_queue_resize (GTK_WIDGET (table));
581 gtk_table_set_col_spacing (GtkTable *table,
585 g_return_if_fail (table != NULL);
586 g_return_if_fail (GTK_IS_TABLE (table));
587 g_return_if_fail (column + 1 < table->ncols);
589 if (table->cols[column].spacing != spacing)
591 table->cols[column].spacing = spacing;
593 if (GTK_WIDGET_VISIBLE (table))
594 gtk_widget_queue_resize (GTK_WIDGET (table));
599 gtk_table_set_row_spacings (GtkTable *table,
604 g_return_if_fail (table != NULL);
605 g_return_if_fail (GTK_IS_TABLE (table));
607 table->row_spacing = spacing;
608 for (row = 0; row + 1 < table->nrows; row++)
609 table->rows[row].spacing = spacing;
611 if (GTK_WIDGET_VISIBLE (table))
612 gtk_widget_queue_resize (GTK_WIDGET (table));
616 gtk_table_set_col_spacings (GtkTable *table,
621 g_return_if_fail (table != NULL);
622 g_return_if_fail (GTK_IS_TABLE (table));
624 table->column_spacing = spacing;
625 for (col = 0; col + 1 < table->ncols; col++)
626 table->cols[col].spacing = spacing;
628 if (GTK_WIDGET_VISIBLE (table))
629 gtk_widget_queue_resize (GTK_WIDGET (table));
633 gtk_table_set_homogeneous (GtkTable *table,
634 gboolean homogeneous)
636 g_return_if_fail (table != NULL);
637 g_return_if_fail (GTK_IS_TABLE (table));
639 homogeneous = (homogeneous != 0);
640 if (homogeneous != table->homogeneous)
642 table->homogeneous = homogeneous;
644 if (GTK_WIDGET_VISIBLE (table))
645 gtk_widget_queue_resize (GTK_WIDGET (table));
650 gtk_table_finalize (GtkObject *object)
654 g_return_if_fail (object != NULL);
655 g_return_if_fail (GTK_IS_TABLE (object));
657 table = GTK_TABLE (object);
659 g_free (table->rows);
660 g_free (table->cols);
662 (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
666 gtk_table_map (GtkWidget *widget)
669 GtkTableChild *child;
672 g_return_if_fail (widget != NULL);
673 g_return_if_fail (GTK_IS_TABLE (widget));
675 table = GTK_TABLE (widget);
676 GTK_WIDGET_SET_FLAGS (table, GTK_MAPPED);
678 children = table->children;
681 child = children->data;
682 children = children->next;
684 if (GTK_WIDGET_VISIBLE (child->widget) &&
685 !GTK_WIDGET_MAPPED (child->widget))
686 gtk_widget_map (child->widget);
691 gtk_table_unmap (GtkWidget *widget)
694 GtkTableChild *child;
697 g_return_if_fail (widget != NULL);
698 g_return_if_fail (GTK_IS_TABLE (widget));
700 table = GTK_TABLE (widget);
701 GTK_WIDGET_UNSET_FLAGS (table, GTK_MAPPED);
703 children = table->children;
706 child = children->data;
707 children = children->next;
709 if (GTK_WIDGET_VISIBLE (child->widget) &&
710 GTK_WIDGET_MAPPED (child->widget))
711 gtk_widget_unmap (child->widget);
716 gtk_table_draw (GtkWidget *widget,
720 GtkTableChild *child;
722 GdkRectangle child_area;
724 g_return_if_fail (widget != NULL);
725 g_return_if_fail (GTK_IS_TABLE (widget));
727 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
729 table = GTK_TABLE (widget);
731 children = table->children;
734 child = children->data;
735 children = children->next;
737 if (gtk_widget_intersect (child->widget, area, &child_area))
738 gtk_widget_draw (child->widget, &child_area);
744 gtk_table_expose (GtkWidget *widget,
745 GdkEventExpose *event)
748 GtkTableChild *child;
750 GdkEventExpose child_event;
752 g_return_val_if_fail (widget != NULL, FALSE);
753 g_return_val_if_fail (GTK_IS_TABLE (widget), FALSE);
755 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
757 table = GTK_TABLE (widget);
759 child_event = *event;
761 children = table->children;
764 child = children->data;
765 children = children->next;
767 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
768 gtk_widget_intersect (child->widget, &event->area, &child_event.area))
769 gtk_widget_event (child->widget, (GdkEvent*) &child_event);
777 gtk_table_size_request (GtkWidget *widget,
778 GtkRequisition *requisition)
783 g_return_if_fail (widget != NULL);
784 g_return_if_fail (GTK_IS_TABLE (widget));
785 g_return_if_fail (requisition != NULL);
787 table = GTK_TABLE (widget);
789 requisition->width = 0;
790 requisition->height = 0;
792 gtk_table_size_request_init (table);
793 gtk_table_size_request_pass1 (table);
794 gtk_table_size_request_pass2 (table);
795 gtk_table_size_request_pass3 (table);
796 gtk_table_size_request_pass2 (table);
798 for (col = 0; col < table->ncols; col++)
799 requisition->width += table->cols[col].requisition;
800 for (col = 0; col + 1 < table->ncols; col++)
801 requisition->width += table->cols[col].spacing;
803 for (row = 0; row < table->nrows; row++)
804 requisition->height += table->rows[row].requisition;
805 for (row = 0; row + 1 < table->nrows; row++)
806 requisition->height += table->rows[row].spacing;
808 requisition->width += GTK_CONTAINER (table)->border_width * 2;
809 requisition->height += GTK_CONTAINER (table)->border_width * 2;
813 gtk_table_size_allocate (GtkWidget *widget,
814 GtkAllocation *allocation)
818 g_return_if_fail (widget != NULL);
819 g_return_if_fail (GTK_IS_TABLE (widget));
820 g_return_if_fail (allocation != NULL);
822 widget->allocation = *allocation;
823 table = GTK_TABLE (widget);
825 gtk_table_size_allocate_init (table);
826 gtk_table_size_allocate_pass1 (table);
827 gtk_table_size_allocate_pass2 (table);
831 gtk_table_add (GtkContainer *container,
834 g_return_if_fail (container != NULL);
835 g_return_if_fail (GTK_IS_TABLE (container));
836 g_return_if_fail (widget != NULL);
838 gtk_table_attach_defaults (GTK_TABLE (container), widget, 0, 1, 0, 1);
842 gtk_table_remove (GtkContainer *container,
846 GtkTableChild *child;
849 g_return_if_fail (container != NULL);
850 g_return_if_fail (GTK_IS_TABLE (container));
851 g_return_if_fail (widget != NULL);
853 table = GTK_TABLE (container);
854 children = table->children;
858 child = children->data;
859 children = children->next;
861 if (child->widget == widget)
863 gboolean was_visible = GTK_WIDGET_VISIBLE (widget);
865 gtk_widget_unparent (widget);
867 table->children = g_list_remove (table->children, child);
870 if (was_visible && GTK_WIDGET_VISIBLE (container))
871 gtk_container_queue_resize (container);
878 gtk_table_forall (GtkContainer *container,
879 gboolean include_internals,
880 GtkCallback callback,
881 gpointer callback_data)
884 GtkTableChild *child;
887 g_return_if_fail (container != NULL);
888 g_return_if_fail (GTK_IS_TABLE (container));
889 g_return_if_fail (callback != NULL);
891 table = GTK_TABLE (container);
892 children = table->children;
896 child = children->data;
897 children = children->next;
899 (* callback) (child->widget, callback_data);
904 gtk_table_size_request_init (GtkTable *table)
906 GtkTableChild *child;
910 for (row = 0; row < table->nrows; row++)
911 table->rows[row].requisition = 0;
912 for (col = 0; col < table->ncols; col++)
913 table->cols[col].requisition = 0;
915 children = table->children;
918 child = children->data;
919 children = children->next;
921 if (GTK_WIDGET_VISIBLE (child->widget))
922 gtk_widget_size_request (child->widget, &child->widget->requisition);
927 gtk_table_size_request_pass1 (GtkTable *table)
929 GtkTableChild *child;
934 children = table->children;
937 child = children->data;
938 children = children->next;
940 if (GTK_WIDGET_VISIBLE (child->widget))
942 /* Child spans a single column.
944 if (child->left_attach == (child->right_attach - 1))
946 width = child->widget->requisition.width + child->xpadding * 2;
947 table->cols[child->left_attach].requisition = MAX (table->cols[child->left_attach].requisition, width);
950 /* Child spans a single row.
952 if (child->top_attach == (child->bottom_attach - 1))
954 height = child->widget->requisition.height + child->ypadding * 2;
955 table->rows[child->top_attach].requisition = MAX (table->rows[child->top_attach].requisition, height);
962 gtk_table_size_request_pass2 (GtkTable *table)
968 if (table->homogeneous)
973 for (col = 0; col < table->ncols; col++)
974 max_width = MAX (max_width, table->cols[col].requisition);
975 for (row = 0; row < table->nrows; row++)
976 max_height = MAX (max_height, table->rows[row].requisition);
978 for (col = 0; col < table->ncols; col++)
979 table->cols[col].requisition = max_width;
980 for (row = 0; row < table->nrows; row++)
981 table->rows[row].requisition = max_height;
986 gtk_table_size_request_pass3 (GtkTable *table)
988 GtkTableChild *child;
994 children = table->children;
997 child = children->data;
998 children = children->next;
1000 if (GTK_WIDGET_VISIBLE (child->widget))
1002 /* Child spans multiple columns.
1004 if (child->left_attach != (child->right_attach - 1))
1006 /* Check and see if there is already enough space
1010 for (col = child->left_attach; col < child->right_attach; col++)
1012 width += table->cols[col].requisition;
1013 if ((col + 1) < child->right_attach)
1014 width += table->cols[col].spacing;
1017 /* If we need to request more space for this child to fill
1018 * its requisition, then divide up the needed space evenly
1019 * amongst the columns it spans.
1021 if (width < child->widget->requisition.width + child->xpadding * 2)
1023 width = child->widget->requisition.width + child->xpadding * 2 - width;
1025 for (col = child->left_attach; col < child->right_attach; col++)
1027 extra = width / (child->right_attach - col);
1028 table->cols[col].requisition += extra;
1034 /* Child spans multiple rows.
1036 if (child->top_attach != (child->bottom_attach - 1))
1038 /* Check and see if there is already enough space
1042 for (row = child->top_attach; row < child->bottom_attach; row++)
1044 height += table->rows[row].requisition;
1045 if ((row + 1) < child->bottom_attach)
1046 height += table->rows[row].spacing;
1049 /* If we need to request more space for this child to fill
1050 * its requisition, then divide up the needed space evenly
1051 * amongst the columns it spans.
1053 if (height < child->widget->requisition.height + child->ypadding * 2)
1055 height = child->widget->requisition.height + child->ypadding * 2 - height;
1057 for (row = child->top_attach; row < child->bottom_attach; row++)
1059 extra = height / (child->bottom_attach - row);
1060 table->rows[row].requisition += extra;
1070 gtk_table_size_allocate_init (GtkTable *table)
1072 GtkTableChild *child;
1078 /* Initialize the rows and cols.
1079 * By default, rows and cols do not expand and do shrink.
1080 * Those values are modified by the children that occupy
1081 * the rows and cols.
1083 for (col = 0; col < table->ncols; col++)
1085 table->cols[col].allocation = table->cols[col].requisition;
1086 table->cols[col].need_expand = FALSE;
1087 table->cols[col].need_shrink = TRUE;
1088 table->cols[col].expand = FALSE;
1089 table->cols[col].shrink = TRUE;
1090 table->cols[col].empty = TRUE;
1092 for (row = 0; row < table->nrows; row++)
1094 table->rows[row].allocation = table->rows[row].requisition;
1095 table->rows[row].need_expand = FALSE;
1096 table->rows[row].need_shrink = TRUE;
1097 table->rows[row].expand = FALSE;
1098 table->rows[row].shrink = TRUE;
1099 table->rows[row].empty = TRUE;
1102 /* Loop over all the children and adjust the row and col values
1103 * based on whether the children want to be allowed to expand
1104 * or shrink. This loop handles children that occupy a single
1107 children = table->children;
1110 child = children->data;
1111 children = children->next;
1113 if (GTK_WIDGET_VISIBLE (child->widget))
1115 if (child->left_attach == (child->right_attach - 1))
1118 table->cols[child->left_attach].expand = TRUE;
1120 if (!child->xshrink)
1121 table->cols[child->left_attach].shrink = FALSE;
1123 table->cols[child->left_attach].empty = FALSE;
1126 if (child->top_attach == (child->bottom_attach - 1))
1129 table->rows[child->top_attach].expand = TRUE;
1131 if (!child->yshrink)
1132 table->rows[child->top_attach].shrink = FALSE;
1134 table->rows[child->top_attach].empty = FALSE;
1139 /* Loop over all the children again and this time handle children
1140 * which span multiple rows or columns.
1142 children = table->children;
1145 child = children->data;
1146 children = children->next;
1148 if (GTK_WIDGET_VISIBLE (child->widget))
1150 if (child->left_attach != (child->right_attach - 1))
1152 for (col = child->left_attach; col < child->right_attach; col++)
1153 table->cols[col].empty = FALSE;
1158 for (col = child->left_attach; col < child->right_attach; col++)
1159 if (table->cols[col].expand)
1166 for (col = child->left_attach; col < child->right_attach; col++)
1167 table->cols[col].need_expand = TRUE;
1170 if (!child->xshrink)
1173 for (col = child->left_attach; col < child->right_attach; col++)
1174 if (!table->cols[col].shrink)
1181 for (col = child->left_attach; col < child->right_attach; col++)
1182 table->cols[col].need_shrink = FALSE;
1186 if (child->top_attach != (child->bottom_attach - 1))
1188 for (row = child->top_attach; row < child->bottom_attach; row++)
1189 table->rows[row].empty = FALSE;
1194 for (row = child->top_attach; row < child->bottom_attach; row++)
1195 if (table->rows[row].expand)
1202 for (row = child->top_attach; row < child->bottom_attach; row++)
1203 table->rows[row].need_expand = TRUE;
1206 if (!child->yshrink)
1209 for (row = child->top_attach; row < child->bottom_attach; row++)
1210 if (!table->rows[row].shrink)
1217 for (row = child->top_attach; row < child->bottom_attach; row++)
1218 table->rows[row].need_shrink = FALSE;
1224 /* Loop over the columns and set the expand and shrink values
1225 * if the column can be expanded or shrunk.
1227 for (col = 0; col < table->ncols; col++)
1229 if (table->cols[col].empty)
1231 table->cols[col].expand = FALSE;
1232 table->cols[col].shrink = FALSE;
1236 if (table->cols[col].need_expand)
1237 table->cols[col].expand = TRUE;
1238 if (!table->cols[col].need_shrink)
1239 table->cols[col].shrink = FALSE;
1243 /* Loop over the rows and set the expand and shrink values
1244 * if the row can be expanded or shrunk.
1246 for (row = 0; row < table->nrows; row++)
1248 if (table->rows[row].empty)
1250 table->rows[row].expand = FALSE;
1251 table->rows[row].shrink = FALSE;
1255 if (table->rows[row].need_expand)
1256 table->rows[row].expand = TRUE;
1257 if (!table->rows[row].need_shrink)
1258 table->rows[row].shrink = FALSE;
1264 gtk_table_size_allocate_pass1 (GtkTable *table)
1274 /* If we were allocated more space than we requested
1275 * then we have to expand any expandable rows and columns
1276 * to fill in the extra space.
1279 real_width = GTK_WIDGET (table)->allocation.width - GTK_CONTAINER (table)->border_width * 2;
1280 real_height = GTK_WIDGET (table)->allocation.height - GTK_CONTAINER (table)->border_width * 2;
1282 if (table->homogeneous)
1285 for (col = 0; col < table->ncols; col++)
1286 if (table->cols[col].expand)
1296 for (col = 0; col + 1 < table->ncols; col++)
1297 width -= table->cols[col].spacing;
1299 for (col = 0; col < table->ncols; col++)
1301 extra = width / (table->ncols - col);
1302 table->cols[col].allocation = MAX (1, extra);
1313 for (col = 0; col < table->ncols; col++)
1315 width += table->cols[col].requisition;
1316 if (table->cols[col].expand)
1318 if (table->cols[col].shrink)
1321 for (col = 0; col + 1 < table->ncols; col++)
1322 width += table->cols[col].spacing;
1324 /* Check to see if we were allocated more width than we requested.
1326 if ((width < real_width) && (nexpand >= 1))
1328 width = real_width - width;
1330 for (col = 0; col < table->ncols; col++)
1331 if (table->cols[col].expand)
1333 extra = width / nexpand;
1334 table->cols[col].allocation += extra;
1341 /* Check to see if we were allocated less width than we requested.
1343 if ((width > real_width) && (nshrink >= 1))
1345 width = width - real_width;
1347 for (col = 0; col < table->ncols; col++)
1348 if (table->cols[col].shrink)
1350 extra = width / nshrink;
1351 table->cols[col].allocation = MAX (1, table->cols[col].allocation - extra);
1359 if (table->homogeneous)
1362 for (row = 0; row < table->nrows; row++)
1363 if (table->rows[row].expand)
1371 height = real_height;
1373 for (row = 0; row + 1 < table->nrows; row++)
1374 height -= table->rows[row].spacing;
1377 for (row = 0; row < table->nrows; row++)
1379 extra = height / (table->nrows - row);
1380 table->rows[row].allocation = MAX (1, extra);
1391 for (row = 0; row < table->nrows; row++)
1393 height += table->rows[row].requisition;
1394 if (table->rows[row].expand)
1396 if (table->rows[row].shrink)
1399 for (row = 0; row + 1 < table->nrows; row++)
1400 height += table->rows[row].spacing;
1402 /* Check to see if we were allocated more height than we requested.
1404 if ((height < real_height) && (nexpand >= 1))
1406 height = real_height - height;
1408 for (row = 0; row < table->nrows; row++)
1409 if (table->rows[row].expand)
1411 extra = height / nexpand;
1412 table->rows[row].allocation += extra;
1419 /* Check to see if we were allocated less height than we requested.
1421 if ((height > real_height) && (nshrink >= 1))
1423 height = height - real_height;
1425 for (row = 0; row < table->nrows; row++)
1426 if (table->rows[row].shrink)
1428 extra = height / nshrink;
1429 table->rows[row].allocation = MAX (1, table->rows[row].allocation - extra);
1439 gtk_table_size_allocate_pass2 (GtkTable *table)
1441 GtkTableChild *child;
1447 GtkAllocation allocation;
1449 children = table->children;
1452 child = children->data;
1453 children = children->next;
1455 if (GTK_WIDGET_VISIBLE (child->widget))
1457 x = GTK_WIDGET (table)->allocation.x + GTK_CONTAINER (table)->border_width;
1458 y = GTK_WIDGET (table)->allocation.y + GTK_CONTAINER (table)->border_width;
1462 for (col = 0; col < child->left_attach; col++)
1464 x += table->cols[col].allocation;
1465 x += table->cols[col].spacing;
1468 for (col = child->left_attach; col < child->right_attach; col++)
1470 max_width += table->cols[col].allocation;
1471 if ((col + 1) < child->right_attach)
1472 max_width += table->cols[col].spacing;
1475 for (row = 0; row < child->top_attach; row++)
1477 y += table->rows[row].allocation;
1478 y += table->rows[row].spacing;
1481 for (row = child->top_attach; row < child->bottom_attach; row++)
1483 max_height += table->rows[row].allocation;
1484 if ((row + 1) < child->bottom_attach)
1485 max_height += table->rows[row].spacing;
1490 allocation.width = MAX (1, max_width - child->xpadding * 2);
1491 allocation.x = x + (max_width - allocation.width) / 2;
1495 allocation.width = child->widget->requisition.width;
1496 allocation.x = x + (max_width - allocation.width) / 2;
1501 allocation.height = MAX (1, max_height - child->ypadding * 2);
1502 allocation.y = y + (max_height - allocation.height) / 2;
1506 allocation.height = child->widget->requisition.height;
1507 allocation.y = y + (max_height - allocation.height) / 2;
1510 gtk_widget_size_allocate (child->widget, &allocation);