]> Pileus Git - ~andy/gtk/blob - gtk/gtktable.c
Translation updated by Ivar Smolin.
[~andy/gtk] / gtk / gtktable.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser 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.
8  *
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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <config.h>
28 #include "gtktable.h"
29 #include "gtkprivate.h"
30 #include "gtkintl.h"
31 #include "gtkalias.h"
32
33 enum
34 {
35   PROP_0,
36   PROP_N_ROWS,
37   PROP_N_COLUMNS,
38   PROP_COLUMN_SPACING,
39   PROP_ROW_SPACING,
40   PROP_HOMOGENEOUS
41 };
42
43 enum
44 {
45   CHILD_PROP_0,
46   CHILD_PROP_LEFT_ATTACH,
47   CHILD_PROP_RIGHT_ATTACH,
48   CHILD_PROP_TOP_ATTACH,
49   CHILD_PROP_BOTTOM_ATTACH,
50   CHILD_PROP_X_OPTIONS,
51   CHILD_PROP_Y_OPTIONS,
52   CHILD_PROP_X_PADDING,
53   CHILD_PROP_Y_PADDING
54 };
55   
56
57 static void gtk_table_finalize      (GObject        *object);
58 static void gtk_table_size_request  (GtkWidget      *widget,
59                                      GtkRequisition *requisition);
60 static void gtk_table_size_allocate (GtkWidget      *widget,
61                                      GtkAllocation  *allocation);
62 static void gtk_table_add           (GtkContainer   *container,
63                                      GtkWidget      *widget);
64 static void gtk_table_remove        (GtkContainer   *container,
65                                      GtkWidget      *widget);
66 static void gtk_table_forall        (GtkContainer   *container,
67                                      gboolean        include_internals,
68                                      GtkCallback     callback,
69                                      gpointer        callback_data);
70 static void gtk_table_get_property  (GObject         *object,
71                                      guint            prop_id,
72                                      GValue          *value,
73                                      GParamSpec      *pspec);
74 static void gtk_table_set_property  (GObject         *object,
75                                      guint            prop_id,
76                                      const GValue    *value,
77                                      GParamSpec      *pspec);
78 static void gtk_table_set_child_property (GtkContainer    *container,
79                                           GtkWidget       *child,
80                                           guint            property_id,
81                                           const GValue    *value,
82                                           GParamSpec      *pspec);
83 static void gtk_table_get_child_property (GtkContainer    *container,
84                                           GtkWidget       *child,
85                                           guint            property_id,
86                                           GValue          *value,
87                                           GParamSpec      *pspec);
88 static GType gtk_table_child_type   (GtkContainer   *container);
89
90
91 static void gtk_table_size_request_init  (GtkTable *table);
92 static void gtk_table_size_request_pass1 (GtkTable *table);
93 static void gtk_table_size_request_pass2 (GtkTable *table);
94 static void gtk_table_size_request_pass3 (GtkTable *table);
95
96 static void gtk_table_size_allocate_init  (GtkTable *table);
97 static void gtk_table_size_allocate_pass1 (GtkTable *table);
98 static void gtk_table_size_allocate_pass2 (GtkTable *table);
99
100
101 G_DEFINE_TYPE (GtkTable, gtk_table, GTK_TYPE_CONTAINER)
102
103 static void
104 gtk_table_class_init (GtkTableClass *class)
105 {
106   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
107   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
108   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
109   
110   gobject_class->finalize = gtk_table_finalize;
111
112   gobject_class->get_property = gtk_table_get_property;
113   gobject_class->set_property = gtk_table_set_property;
114   
115   widget_class->size_request = gtk_table_size_request;
116   widget_class->size_allocate = gtk_table_size_allocate;
117   
118   container_class->add = gtk_table_add;
119   container_class->remove = gtk_table_remove;
120   container_class->forall = gtk_table_forall;
121   container_class->child_type = gtk_table_child_type;
122   container_class->set_child_property = gtk_table_set_child_property;
123   container_class->get_child_property = gtk_table_get_child_property;
124   
125
126   g_object_class_install_property (gobject_class,
127                                    PROP_N_ROWS,
128                                    g_param_spec_uint ("n-rows",
129                                                      P_("Rows"),
130                                                      P_("The number of rows in the table"),
131                                                      0,
132                                                      G_MAXUINT,
133                                                      0,
134                                                      GTK_PARAM_READWRITE));
135   g_object_class_install_property (gobject_class,
136                                    PROP_N_COLUMNS,
137                                    g_param_spec_uint ("n-columns",
138                                                      P_("Columns"),
139                                                      P_("The number of columns in the table"),
140                                                      0,
141                                                      G_MAXUINT,
142                                                      0,
143                                                      GTK_PARAM_READWRITE));
144   g_object_class_install_property (gobject_class,
145                                    PROP_ROW_SPACING,
146                                    g_param_spec_uint ("row-spacing",
147                                                      P_("Row spacing"),
148                                                      P_("The amount of space between two consecutive rows"),
149                                                      0,
150                                                      G_MAXUINT,
151                                                      0,
152                                                      GTK_PARAM_READWRITE));
153   g_object_class_install_property (gobject_class,
154                                    PROP_COLUMN_SPACING,
155                                    g_param_spec_uint ("column-spacing",
156                                                      P_("Column spacing"),
157                                                      P_("The amount of space between two consecutive columns"),
158                                                      0,
159                                                      G_MAXUINT,
160                                                      0,
161                                                      GTK_PARAM_READWRITE));
162   g_object_class_install_property (gobject_class,
163                                    PROP_HOMOGENEOUS,
164                                    g_param_spec_boolean ("homogeneous",
165                                                          P_("Homogeneous"),
166                                                          P_("If TRUE, the table cells are all the same width/height"),
167                                                          FALSE,
168                                                          GTK_PARAM_READWRITE));
169
170   gtk_container_class_install_child_property (container_class,
171                                               CHILD_PROP_LEFT_ATTACH,
172                                               g_param_spec_uint ("left-attach", 
173                                                                  P_("Left attachment"), 
174                                                                  P_("The column number to attach the left side of the child to"),
175                                                                  0, 65535, 0,
176                                                                  GTK_PARAM_READWRITE));
177   gtk_container_class_install_child_property (container_class,
178                                               CHILD_PROP_RIGHT_ATTACH,
179                                               g_param_spec_uint ("right-attach", 
180                                                                  P_("Right attachment"), 
181                                                                  P_("The column number to attach the right side of a child widget to"),
182                                                                  1, 65535, 1,
183                                                                  GTK_PARAM_READWRITE));
184   gtk_container_class_install_child_property (container_class,
185                                               CHILD_PROP_TOP_ATTACH,
186                                               g_param_spec_uint ("top-attach", 
187                                                                  P_("Top attachment"), 
188                                                                  P_("The row number to attach the top of a child widget to"),
189                                                                  0, 65535, 0,
190                                                                  GTK_PARAM_READWRITE));
191   gtk_container_class_install_child_property (container_class,
192                                               CHILD_PROP_BOTTOM_ATTACH,
193                                               g_param_spec_uint ("bottom-attach",
194                                                                  P_("Bottom attachment"), 
195                                                                  P_("The row number to attach the bottom of the child to"),
196                                                                  1, 65535, 1,
197                                                                  GTK_PARAM_READWRITE));
198   gtk_container_class_install_child_property (container_class,
199                                               CHILD_PROP_X_OPTIONS,
200                                               g_param_spec_flags ("x-options", 
201                                                                   P_("Horizontal options"), 
202                                                                   P_("Options specifying the horizontal behaviour of the child"),
203                                                                   GTK_TYPE_ATTACH_OPTIONS, GTK_EXPAND | GTK_FILL,
204                                                                   GTK_PARAM_READWRITE));
205   gtk_container_class_install_child_property (container_class,
206                                               CHILD_PROP_Y_OPTIONS,
207                                               g_param_spec_flags ("y-options", 
208                                                                   P_("Vertical options"), 
209                                                                   P_("Options specifying the vertical behaviour of the child"),
210                                                                   GTK_TYPE_ATTACH_OPTIONS, GTK_EXPAND | GTK_FILL,
211                                                                   GTK_PARAM_READWRITE));
212   gtk_container_class_install_child_property (container_class,
213                                               CHILD_PROP_X_PADDING,
214                                               g_param_spec_uint ("x-padding", 
215                                                                  P_("Horizontal padding"), 
216                                                                  P_("Extra space to put between the child and its left and right neighbors, in pixels"),
217                                                                  0, 65535, 0,
218                                                                  GTK_PARAM_READWRITE));
219   gtk_container_class_install_child_property (container_class,
220                                               CHILD_PROP_Y_PADDING,
221                                               g_param_spec_uint ("y-padding", 
222                                                                  P_("Vertical padding"), 
223                                                                  P_("Extra space to put between the child and its upper and lower neighbors, in pixels"),
224                                                                  0, 65535, 0,
225                                                                  GTK_PARAM_READWRITE));
226 }
227
228 static GType
229 gtk_table_child_type (GtkContainer   *container)
230 {
231   return GTK_TYPE_WIDGET;
232 }
233
234 static void
235 gtk_table_get_property (GObject      *object,
236                         guint         prop_id,
237                         GValue       *value,
238                         GParamSpec   *pspec)
239 {
240   GtkTable *table;
241
242   table = GTK_TABLE (object);
243
244   switch (prop_id)
245     {
246     case PROP_N_ROWS:
247       g_value_set_uint (value, table->nrows);
248       break;
249     case PROP_N_COLUMNS:
250       g_value_set_uint (value, table->ncols);
251       break;
252     case PROP_ROW_SPACING:
253       g_value_set_uint (value, table->row_spacing);
254       break;
255     case PROP_COLUMN_SPACING:
256       g_value_set_uint (value, table->column_spacing);
257       break;
258     case PROP_HOMOGENEOUS:
259       g_value_set_boolean (value, table->homogeneous);
260       break;
261     default:
262       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
263       break;
264     }
265 }
266
267 static void
268 gtk_table_set_property (GObject      *object,
269                         guint         prop_id,
270                         const GValue *value,
271                         GParamSpec   *pspec)
272 {
273   GtkTable *table;
274
275   table = GTK_TABLE (object);
276
277   switch (prop_id)
278     {
279     case PROP_N_ROWS:
280       gtk_table_resize (table, g_value_get_uint (value), table->ncols);
281       break;
282     case PROP_N_COLUMNS:
283       gtk_table_resize (table, table->nrows, g_value_get_uint (value));
284       break;
285     case PROP_ROW_SPACING:
286       gtk_table_set_row_spacings (table, g_value_get_uint (value));
287       break;
288     case PROP_COLUMN_SPACING:
289       gtk_table_set_col_spacings (table, g_value_get_uint (value));
290       break;
291     case PROP_HOMOGENEOUS:
292       gtk_table_set_homogeneous (table, g_value_get_boolean (value));
293       break;
294     default:
295       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
296       break;
297     }
298 }
299
300 static void
301 gtk_table_set_child_property (GtkContainer    *container,
302                               GtkWidget       *child,
303                               guint            property_id,
304                               const GValue    *value,
305                               GParamSpec      *pspec)
306 {
307   GtkTable *table = GTK_TABLE (container);
308   GtkTableChild *table_child;
309   GList *list;
310
311   table_child = NULL;
312   for (list = table->children; list; list = list->next)
313     {
314       table_child = list->data;
315
316       if (table_child->widget == child)
317         break;
318     }
319   if (!list)
320     {
321       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
322       return;
323     }
324
325   switch (property_id)
326     {
327     case CHILD_PROP_LEFT_ATTACH:
328       table_child->left_attach = g_value_get_uint (value);
329       if (table_child->right_attach <= table_child->left_attach)
330         table_child->right_attach = table_child->left_attach + 1;
331       if (table_child->right_attach >= table->ncols)
332         gtk_table_resize (table, table->nrows, table_child->right_attach);
333       break;
334     case CHILD_PROP_RIGHT_ATTACH:
335       table_child->right_attach = g_value_get_uint (value);
336       if (table_child->right_attach <= table_child->left_attach)
337         table_child->left_attach = table_child->right_attach - 1;
338       if (table_child->right_attach >= table->ncols)
339         gtk_table_resize (table, table->nrows, table_child->right_attach);
340       break;
341     case CHILD_PROP_TOP_ATTACH:
342       table_child->top_attach = g_value_get_uint (value);
343       if (table_child->bottom_attach <= table_child->top_attach)
344         table_child->bottom_attach = table_child->top_attach + 1;
345       if (table_child->bottom_attach >= table->nrows)
346         gtk_table_resize (table, table_child->bottom_attach, table->ncols);
347       break;
348     case CHILD_PROP_BOTTOM_ATTACH:
349       table_child->bottom_attach = g_value_get_uint (value);
350       if (table_child->bottom_attach <= table_child->top_attach)
351         table_child->top_attach = table_child->bottom_attach - 1;
352       if (table_child->bottom_attach >= table->nrows)
353         gtk_table_resize (table, table_child->bottom_attach, table->ncols);
354       break;
355     case CHILD_PROP_X_OPTIONS:
356       table_child->xexpand = (g_value_get_flags (value) & GTK_EXPAND) != 0;
357       table_child->xshrink = (g_value_get_flags (value) & GTK_SHRINK) != 0;
358       table_child->xfill = (g_value_get_flags (value) & GTK_FILL) != 0;
359       break;
360     case CHILD_PROP_Y_OPTIONS:
361       table_child->yexpand = (g_value_get_flags (value) & GTK_EXPAND) != 0;
362       table_child->yshrink = (g_value_get_flags (value) & GTK_SHRINK) != 0;
363       table_child->yfill = (g_value_get_flags (value) & GTK_FILL) != 0;
364       break;
365     case CHILD_PROP_X_PADDING:
366       table_child->xpadding = g_value_get_uint (value);
367       break;
368     case CHILD_PROP_Y_PADDING:
369       table_child->ypadding = g_value_get_uint (value);
370       break;
371     default:
372       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
373       break;
374     }
375   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (table))
376     gtk_widget_queue_resize (child);
377 }
378
379 static void
380 gtk_table_get_child_property (GtkContainer    *container,
381                               GtkWidget       *child,
382                               guint            property_id,
383                               GValue          *value,
384                               GParamSpec      *pspec)
385 {
386   GtkTable *table = GTK_TABLE (container);
387   GtkTableChild *table_child;
388   GList *list;
389
390   table_child = NULL;
391   for (list = table->children; list; list = list->next)
392     {
393       table_child = list->data;
394
395       if (table_child->widget == child)
396         break;
397     }
398   if (!list)
399     {
400       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
401       return;
402     }
403
404   switch (property_id)
405     {
406     case CHILD_PROP_LEFT_ATTACH:
407       g_value_set_uint (value, table_child->left_attach);
408       break;
409     case CHILD_PROP_RIGHT_ATTACH:
410       g_value_set_uint (value, table_child->right_attach);
411       break;
412     case CHILD_PROP_TOP_ATTACH:
413       g_value_set_uint (value, table_child->top_attach);
414       break;
415     case CHILD_PROP_BOTTOM_ATTACH:
416       g_value_set_uint (value, table_child->bottom_attach);
417       break;
418     case CHILD_PROP_X_OPTIONS:
419       g_value_set_flags (value, (table_child->xexpand * GTK_EXPAND |
420                                  table_child->xshrink * GTK_SHRINK |
421                                  table_child->xfill * GTK_FILL));
422       break;
423     case CHILD_PROP_Y_OPTIONS:
424       g_value_set_flags (value, (table_child->yexpand * GTK_EXPAND |
425                                  table_child->yshrink * GTK_SHRINK |
426                                  table_child->yfill * GTK_FILL));
427       break;
428     case CHILD_PROP_X_PADDING:
429       g_value_set_uint (value, table_child->xpadding);
430       break;
431     case CHILD_PROP_Y_PADDING:
432       g_value_set_uint (value, table_child->ypadding);
433       break;
434     default:
435       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
436       break;
437     }
438 }
439
440 static void
441 gtk_table_init (GtkTable *table)
442 {
443   GTK_WIDGET_SET_FLAGS (table, GTK_NO_WINDOW);
444   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (table), FALSE);
445   
446   table->children = NULL;
447   table->rows = NULL;
448   table->cols = NULL;
449   table->nrows = 0;
450   table->ncols = 0;
451   table->column_spacing = 0;
452   table->row_spacing = 0;
453   table->homogeneous = FALSE;
454
455   gtk_table_resize (table, 1, 1);
456 }
457
458 GtkWidget*
459 gtk_table_new (guint    rows,
460                guint    columns,
461                gboolean homogeneous)
462 {
463   GtkTable *table;
464
465   if (rows == 0)
466     rows = 1;
467   if (columns == 0)
468     columns = 1;
469   
470   table = g_object_new (GTK_TYPE_TABLE, NULL);
471   
472   table->homogeneous = (homogeneous ? TRUE : FALSE);
473
474   gtk_table_resize (table, rows, columns);
475   
476   return GTK_WIDGET (table);
477 }
478
479 void
480 gtk_table_resize (GtkTable *table,
481                   guint     n_rows,
482                   guint     n_cols)
483 {
484   g_return_if_fail (GTK_IS_TABLE (table));
485   g_return_if_fail (n_rows > 0 && n_rows < 65536);
486   g_return_if_fail (n_cols > 0 && n_cols < 65536);
487
488   n_rows = MAX (n_rows, 1);
489   n_cols = MAX (n_cols, 1);
490
491   if (n_rows != table->nrows ||
492       n_cols != table->ncols)
493     {
494       GList *list;
495       
496       for (list = table->children; list; list = list->next)
497         {
498           GtkTableChild *child;
499           
500           child = list->data;
501           
502           n_rows = MAX (n_rows, child->bottom_attach);
503           n_cols = MAX (n_cols, child->right_attach);
504         }
505       
506       if (n_rows != table->nrows)
507         {
508           guint i;
509
510           i = table->nrows;
511           table->nrows = n_rows;
512           table->rows = g_realloc (table->rows, table->nrows * sizeof (GtkTableRowCol));
513           
514           for (; i < table->nrows; i++)
515             {
516               table->rows[i].requisition = 0;
517               table->rows[i].allocation = 0;
518               table->rows[i].spacing = table->row_spacing;
519               table->rows[i].need_expand = 0;
520               table->rows[i].need_shrink = 0;
521               table->rows[i].expand = 0;
522               table->rows[i].shrink = 0;
523             }
524
525           g_object_notify (G_OBJECT (table), "n-rows");
526         }
527
528       if (n_cols != table->ncols)
529         {
530           guint i;
531
532           i = table->ncols;
533           table->ncols = n_cols;
534           table->cols = g_realloc (table->cols, table->ncols * sizeof (GtkTableRowCol));
535           
536           for (; i < table->ncols; i++)
537             {
538               table->cols[i].requisition = 0;
539               table->cols[i].allocation = 0;
540               table->cols[i].spacing = table->column_spacing;
541               table->cols[i].need_expand = 0;
542               table->cols[i].need_shrink = 0;
543               table->cols[i].expand = 0;
544               table->cols[i].shrink = 0;
545             }
546
547           g_object_notify (G_OBJECT (table), "n-columns");
548         }
549     }
550 }
551
552 void
553 gtk_table_attach (GtkTable        *table,
554                   GtkWidget       *child,
555                   guint            left_attach,
556                   guint            right_attach,
557                   guint            top_attach,
558                   guint            bottom_attach,
559                   GtkAttachOptions xoptions,
560                   GtkAttachOptions yoptions,
561                   guint            xpadding,
562                   guint            ypadding)
563 {
564   GtkTableChild *table_child;
565   
566   g_return_if_fail (GTK_IS_TABLE (table));
567   g_return_if_fail (GTK_IS_WIDGET (child));
568   g_return_if_fail (child->parent == NULL);
569   
570   /* g_return_if_fail (left_attach >= 0); */
571   g_return_if_fail (left_attach < right_attach);
572   /* g_return_if_fail (top_attach >= 0); */
573   g_return_if_fail (top_attach < bottom_attach);
574   
575   if (right_attach >= table->ncols)
576     gtk_table_resize (table, table->nrows, right_attach);
577   
578   if (bottom_attach >= table->nrows)
579     gtk_table_resize (table, bottom_attach, table->ncols);
580   
581   table_child = g_new (GtkTableChild, 1);
582   table_child->widget = child;
583   table_child->left_attach = left_attach;
584   table_child->right_attach = right_attach;
585   table_child->top_attach = top_attach;
586   table_child->bottom_attach = bottom_attach;
587   table_child->xexpand = (xoptions & GTK_EXPAND) != 0;
588   table_child->xshrink = (xoptions & GTK_SHRINK) != 0;
589   table_child->xfill = (xoptions & GTK_FILL) != 0;
590   table_child->xpadding = xpadding;
591   table_child->yexpand = (yoptions & GTK_EXPAND) != 0;
592   table_child->yshrink = (yoptions & GTK_SHRINK) != 0;
593   table_child->yfill = (yoptions & GTK_FILL) != 0;
594   table_child->ypadding = ypadding;
595   
596   table->children = g_list_prepend (table->children, table_child);
597   
598   gtk_widget_set_parent (child, GTK_WIDGET (table));
599 }
600
601 void
602 gtk_table_attach_defaults (GtkTable  *table,
603                            GtkWidget *widget,
604                            guint      left_attach,
605                            guint      right_attach,
606                            guint      top_attach,
607                            guint      bottom_attach)
608 {
609   gtk_table_attach (table, widget,
610                     left_attach, right_attach,
611                     top_attach, bottom_attach,
612                     GTK_EXPAND | GTK_FILL,
613                     GTK_EXPAND | GTK_FILL,
614                     0, 0);
615 }
616
617 void
618 gtk_table_set_row_spacing (GtkTable *table,
619                            guint     row,
620                            guint     spacing)
621 {
622   g_return_if_fail (GTK_IS_TABLE (table));
623   g_return_if_fail (row < table->nrows);
624   
625   if (table->rows[row].spacing != spacing)
626     {
627       table->rows[row].spacing = spacing;
628       
629       if (GTK_WIDGET_VISIBLE (table))
630         gtk_widget_queue_resize (GTK_WIDGET (table));
631     }
632 }
633
634 /**
635  * gtk_table_get_row_spacing:
636  * @table: a #GtkTable
637  * @row: a row in the table, 0 indicates the first row
638  *
639  * Gets the amount of space between row @row, and
640  * row @row + 1. See gtk_table_set_row_spacing().
641  *
642  * Return value: the row spacing
643  **/
644 guint
645 gtk_table_get_row_spacing (GtkTable *table,
646                            guint     row)
647 {
648   g_return_val_if_fail (GTK_IS_TABLE (table), 0);
649   g_return_val_if_fail (row < table->nrows - 1, 0);
650  
651   return table->rows[row].spacing;
652 }
653
654 void
655 gtk_table_set_col_spacing (GtkTable *table,
656                            guint     column,
657                            guint     spacing)
658 {
659   g_return_if_fail (GTK_IS_TABLE (table));
660   g_return_if_fail (column < table->ncols);
661   
662   if (table->cols[column].spacing != spacing)
663     {
664       table->cols[column].spacing = spacing;
665       
666       if (GTK_WIDGET_VISIBLE (table))
667         gtk_widget_queue_resize (GTK_WIDGET (table));
668     }
669 }
670
671 /**
672  * gtk_table_get_col_spacing:
673  * @table: a #GtkTable
674  * @column: a column in the table, 0 indicates the first column
675  *
676  * Gets the amount of space between column @col, and
677  * column @col + 1. See gtk_table_set_col_spacing().
678  *
679  * Return value: the column spacing
680  **/
681 guint
682 gtk_table_get_col_spacing (GtkTable *table,
683                            guint     column)
684 {
685   g_return_val_if_fail (GTK_IS_TABLE (table), 0);
686   g_return_val_if_fail (column < table->ncols, 0);
687
688   return table->cols[column].spacing;
689 }
690
691 void
692 gtk_table_set_row_spacings (GtkTable *table,
693                             guint     spacing)
694 {
695   guint row;
696   
697   g_return_if_fail (GTK_IS_TABLE (table));
698   
699   table->row_spacing = spacing;
700   for (row = 0; row < table->nrows; row++)
701     table->rows[row].spacing = spacing;
702   
703   if (GTK_WIDGET_VISIBLE (table))
704     gtk_widget_queue_resize (GTK_WIDGET (table));
705
706   g_object_notify (G_OBJECT (table), "row-spacing");
707 }
708
709 /**
710  * gtk_table_get_default_row_spacing:
711  * @table: a #GtkTable
712  *
713  * Gets the default row spacing for the table. This is
714  * the spacing that will be used for newly added rows.
715  * (See gtk_table_set_row_spacings())
716  *
717  * Returns value: the default row spacing
718  **/
719 guint
720 gtk_table_get_default_row_spacing (GtkTable *table)
721 {
722   g_return_val_if_fail (GTK_IS_TABLE (table), 0);
723
724   return table->row_spacing;
725 }
726
727 void
728 gtk_table_set_col_spacings (GtkTable *table,
729                             guint     spacing)
730 {
731   guint col;
732   
733   g_return_if_fail (GTK_IS_TABLE (table));
734   
735   table->column_spacing = spacing;
736   for (col = 0; col < table->ncols; col++)
737     table->cols[col].spacing = spacing;
738   
739   if (GTK_WIDGET_VISIBLE (table))
740     gtk_widget_queue_resize (GTK_WIDGET (table));
741
742   g_object_notify (G_OBJECT (table), "column-spacing");
743 }
744
745 /**
746  * gtk_table_get_default_col_spacing:
747  * @table: a #GtkTable
748  *
749  * Gets the default column spacing for the table. This is
750  * the spacing that will be used for newly added columns.
751  * (See gtk_table_set_col_spacings())
752  *
753  * Returns value: the default column spacing
754  **/
755 guint
756 gtk_table_get_default_col_spacing (GtkTable *table)
757 {
758   g_return_val_if_fail (GTK_IS_TABLE (table), 0);
759
760   return table->column_spacing;
761 }
762
763 void
764 gtk_table_set_homogeneous (GtkTable *table,
765                            gboolean  homogeneous)
766 {
767   g_return_if_fail (GTK_IS_TABLE (table));
768
769   homogeneous = (homogeneous != 0);
770   if (homogeneous != table->homogeneous)
771     {
772       table->homogeneous = homogeneous;
773       
774       if (GTK_WIDGET_VISIBLE (table))
775         gtk_widget_queue_resize (GTK_WIDGET (table));
776
777       g_object_notify (G_OBJECT (table), "homogeneous");
778     }
779 }
780
781 /**
782  * gtk_table_get_homogeneous:
783  * @table: a #GtkTable
784  *
785  * Returns whether the table cells are all constrained to the same
786  * width and height. (See gtk_table_set_homogenous ())
787  *
788  * Return value: %TRUE if the cells are all constrained to the same size
789  **/
790 gboolean
791 gtk_table_get_homogeneous (GtkTable *table)
792 {
793   g_return_val_if_fail (GTK_IS_TABLE (table), FALSE);
794
795   return table->homogeneous;
796 }
797
798 static void
799 gtk_table_finalize (GObject *object)
800 {
801   GtkTable *table;
802   
803   g_return_if_fail (GTK_IS_TABLE (object));
804   
805   table = GTK_TABLE (object);
806   
807   g_free (table->rows);
808   g_free (table->cols);
809   
810   G_OBJECT_CLASS (gtk_table_parent_class)->finalize (object);
811 }
812
813 static void
814 gtk_table_size_request (GtkWidget      *widget,
815                         GtkRequisition *requisition)
816 {
817   GtkTable *table;
818   gint row, col;
819   
820   g_return_if_fail (GTK_IS_TABLE (widget));
821   g_return_if_fail (requisition != NULL);
822   
823   table = GTK_TABLE (widget);
824   
825   requisition->width = 0;
826   requisition->height = 0;
827   
828   gtk_table_size_request_init (table);
829   gtk_table_size_request_pass1 (table);
830   gtk_table_size_request_pass2 (table);
831   gtk_table_size_request_pass3 (table);
832   gtk_table_size_request_pass2 (table);
833   
834   for (col = 0; col < table->ncols; col++)
835     requisition->width += table->cols[col].requisition;
836   for (col = 0; col + 1 < table->ncols; col++)
837     requisition->width += table->cols[col].spacing;
838   
839   for (row = 0; row < table->nrows; row++)
840     requisition->height += table->rows[row].requisition;
841   for (row = 0; row + 1 < table->nrows; row++)
842     requisition->height += table->rows[row].spacing;
843   
844   requisition->width += GTK_CONTAINER (table)->border_width * 2;
845   requisition->height += GTK_CONTAINER (table)->border_width * 2;
846 }
847
848 static void
849 gtk_table_size_allocate (GtkWidget     *widget,
850                          GtkAllocation *allocation)
851 {
852   GtkTable *table;
853   
854   g_return_if_fail (GTK_IS_TABLE (widget));
855   g_return_if_fail (allocation != NULL);
856   
857   widget->allocation = *allocation;
858   table = GTK_TABLE (widget);
859   
860   gtk_table_size_allocate_init (table);
861   gtk_table_size_allocate_pass1 (table);
862   gtk_table_size_allocate_pass2 (table);
863 }
864
865 static void
866 gtk_table_add (GtkContainer *container,
867                GtkWidget    *widget)
868 {
869   g_return_if_fail (GTK_IS_TABLE (container));
870   g_return_if_fail (widget != NULL);
871   
872   gtk_table_attach_defaults (GTK_TABLE (container), widget, 0, 1, 0, 1);
873 }
874
875 static void
876 gtk_table_remove (GtkContainer *container,
877                   GtkWidget    *widget)
878 {
879   GtkTable *table;
880   GtkTableChild *child;
881   GList *children;
882   
883   g_return_if_fail (GTK_IS_TABLE (container));
884   g_return_if_fail (widget != NULL);
885   
886   table = GTK_TABLE (container);
887   children = table->children;
888   
889   while (children)
890     {
891       child = children->data;
892       children = children->next;
893       
894       if (child->widget == widget)
895         {
896           gboolean was_visible = GTK_WIDGET_VISIBLE (widget);
897           
898           gtk_widget_unparent (widget);
899           
900           table->children = g_list_remove (table->children, child);
901           g_free (child);
902           
903           if (was_visible && GTK_WIDGET_VISIBLE (container))
904             gtk_widget_queue_resize (GTK_WIDGET (container));
905           break;
906         }
907     }
908 }
909
910 static void
911 gtk_table_forall (GtkContainer *container,
912                   gboolean      include_internals,
913                   GtkCallback   callback,
914                   gpointer      callback_data)
915 {
916   GtkTable *table;
917   GtkTableChild *child;
918   GList *children;
919   
920   g_return_if_fail (GTK_IS_TABLE (container));
921   g_return_if_fail (callback != NULL);
922   
923   table = GTK_TABLE (container);
924   children = table->children;
925   
926   while (children)
927     {
928       child = children->data;
929       children = children->next;
930       
931       (* callback) (child->widget, callback_data);
932     }
933 }
934
935 static void
936 gtk_table_size_request_init (GtkTable *table)
937 {
938   GtkTableChild *child;
939   GList *children;
940   gint row, col;
941   
942   for (row = 0; row < table->nrows; row++)
943     {
944       table->rows[row].requisition = 0;
945       table->rows[row].expand = FALSE;
946     }
947   for (col = 0; col < table->ncols; col++)
948     {
949       table->cols[col].requisition = 0;
950       table->cols[col].expand = FALSE;
951     }
952   
953   children = table->children;
954   while (children)
955     {
956       child = children->data;
957       children = children->next;
958       
959       if (GTK_WIDGET_VISIBLE (child->widget))
960         gtk_widget_size_request (child->widget, NULL);
961
962       if (child->left_attach == (child->right_attach - 1) && child->xexpand)
963         table->cols[child->left_attach].expand = TRUE;
964       
965       if (child->top_attach == (child->bottom_attach - 1) && child->yexpand)
966         table->rows[child->top_attach].expand = TRUE;
967     }
968 }
969
970 static void
971 gtk_table_size_request_pass1 (GtkTable *table)
972 {
973   GtkTableChild *child;
974   GList *children;
975   gint width;
976   gint height;
977   
978   children = table->children;
979   while (children)
980     {
981       child = children->data;
982       children = children->next;
983       
984       if (GTK_WIDGET_VISIBLE (child->widget))
985         {
986           GtkRequisition child_requisition;
987           gtk_widget_get_child_requisition (child->widget, &child_requisition);
988
989           /* Child spans a single column.
990            */
991           if (child->left_attach == (child->right_attach - 1))
992             {
993               width = child_requisition.width + child->xpadding * 2;
994               table->cols[child->left_attach].requisition = MAX (table->cols[child->left_attach].requisition, width);
995             }
996           
997           /* Child spans a single row.
998            */
999           if (child->top_attach == (child->bottom_attach - 1))
1000             {
1001               height = child_requisition.height + child->ypadding * 2;
1002               table->rows[child->top_attach].requisition = MAX (table->rows[child->top_attach].requisition, height);
1003             }
1004         }
1005     }
1006 }
1007
1008 static void
1009 gtk_table_size_request_pass2 (GtkTable *table)
1010 {
1011   gint max_width;
1012   gint max_height;
1013   gint row, col;
1014   
1015   if (table->homogeneous)
1016     {
1017       max_width = 0;
1018       max_height = 0;
1019       
1020       for (col = 0; col < table->ncols; col++)
1021         max_width = MAX (max_width, table->cols[col].requisition);
1022       for (row = 0; row < table->nrows; row++)
1023         max_height = MAX (max_height, table->rows[row].requisition);
1024       
1025       for (col = 0; col < table->ncols; col++)
1026         table->cols[col].requisition = max_width;
1027       for (row = 0; row < table->nrows; row++)
1028         table->rows[row].requisition = max_height;
1029     }
1030 }
1031
1032 static void
1033 gtk_table_size_request_pass3 (GtkTable *table)
1034 {
1035   GtkTableChild *child;
1036   GList *children;
1037   gint width, height;
1038   gint row, col;
1039   gint extra;
1040   
1041   children = table->children;
1042   while (children)
1043     {
1044       child = children->data;
1045       children = children->next;
1046       
1047       if (GTK_WIDGET_VISIBLE (child->widget))
1048         {
1049           /* Child spans multiple columns.
1050            */
1051           if (child->left_attach != (child->right_attach - 1))
1052             {
1053               GtkRequisition child_requisition;
1054
1055               gtk_widget_get_child_requisition (child->widget, &child_requisition);
1056               
1057               /* Check and see if there is already enough space
1058                *  for the child.
1059                */
1060               width = 0;
1061               for (col = child->left_attach; col < child->right_attach; col++)
1062                 {
1063                   width += table->cols[col].requisition;
1064                   if ((col + 1) < child->right_attach)
1065                     width += table->cols[col].spacing;
1066                 }
1067               
1068               /* If we need to request more space for this child to fill
1069                *  its requisition, then divide up the needed space amongst the
1070                *  columns it spans, favoring expandable columns if any.
1071                */
1072               if (width < child_requisition.width + child->xpadding * 2)
1073                 {
1074                   gint n_expand = 0;
1075                   gboolean force_expand = FALSE;
1076                   
1077                   width = child_requisition.width + child->xpadding * 2 - width;
1078
1079                   for (col = child->left_attach; col < child->right_attach; col++)
1080                     if (table->cols[col].expand)
1081                       n_expand++;
1082
1083                   if (n_expand == 0)
1084                     {
1085                       n_expand = (child->right_attach - child->left_attach);
1086                       force_expand = TRUE;
1087                     }
1088                     
1089                   for (col = child->left_attach; col < child->right_attach; col++)
1090                     if (force_expand || table->cols[col].expand)
1091                       {
1092                         extra = width / n_expand;
1093                         table->cols[col].requisition += extra;
1094                         width -= extra;
1095                         n_expand--;
1096                       }
1097                 }
1098             }
1099           
1100           /* Child spans multiple rows.
1101            */
1102           if (child->top_attach != (child->bottom_attach - 1))
1103             {
1104               GtkRequisition child_requisition;
1105
1106               gtk_widget_get_child_requisition (child->widget, &child_requisition);
1107
1108               /* Check and see if there is already enough space
1109                *  for the child.
1110                */
1111               height = 0;
1112               for (row = child->top_attach; row < child->bottom_attach; row++)
1113                 {
1114                   height += table->rows[row].requisition;
1115                   if ((row + 1) < child->bottom_attach)
1116                     height += table->rows[row].spacing;
1117                 }
1118               
1119               /* If we need to request more space for this child to fill
1120                *  its requisition, then divide up the needed space amongst the
1121                *  rows it spans, favoring expandable rows if any.
1122                */
1123               if (height < child_requisition.height + child->ypadding * 2)
1124                 {
1125                   gint n_expand = 0;
1126                   gboolean force_expand = FALSE;
1127                   
1128                   height = child_requisition.height + child->ypadding * 2 - height;
1129                   
1130                   for (row = child->top_attach; row < child->bottom_attach; row++)
1131                     {
1132                       if (table->rows[row].expand)
1133                         n_expand++;
1134                     }
1135
1136                   if (n_expand == 0)
1137                     {
1138                       n_expand = (child->bottom_attach - child->top_attach);
1139                       force_expand = TRUE;
1140                     }
1141                     
1142                   for (row = child->top_attach; row < child->bottom_attach; row++)
1143                     if (force_expand || table->rows[row].expand)
1144                       {
1145                         extra = height / n_expand;
1146                         table->rows[row].requisition += extra;
1147                         height -= extra;
1148                         n_expand--;
1149                       }
1150                 }
1151             }
1152         }
1153     }
1154 }
1155
1156 static void
1157 gtk_table_size_allocate_init (GtkTable *table)
1158 {
1159   GtkTableChild *child;
1160   GList *children;
1161   gint row, col;
1162   gint has_expand;
1163   gint has_shrink;
1164   
1165   /* Initialize the rows and cols.
1166    *  By default, rows and cols do not expand and do shrink.
1167    *  Those values are modified by the children that occupy
1168    *  the rows and cols.
1169    */
1170   for (col = 0; col < table->ncols; col++)
1171     {
1172       table->cols[col].allocation = table->cols[col].requisition;
1173       table->cols[col].need_expand = FALSE;
1174       table->cols[col].need_shrink = TRUE;
1175       table->cols[col].expand = FALSE;
1176       table->cols[col].shrink = TRUE;
1177       table->cols[col].empty = TRUE;
1178     }
1179   for (row = 0; row < table->nrows; row++)
1180     {
1181       table->rows[row].allocation = table->rows[row].requisition;
1182       table->rows[row].need_expand = FALSE;
1183       table->rows[row].need_shrink = TRUE;
1184       table->rows[row].expand = FALSE;
1185       table->rows[row].shrink = TRUE;
1186       table->rows[row].empty = TRUE;
1187     }
1188   
1189   /* Loop over all the children and adjust the row and col values
1190    *  based on whether the children want to be allowed to expand
1191    *  or shrink. This loop handles children that occupy a single
1192    *  row or column.
1193    */
1194   children = table->children;
1195   while (children)
1196     {
1197       child = children->data;
1198       children = children->next;
1199       
1200       if (GTK_WIDGET_VISIBLE (child->widget))
1201         {
1202           if (child->left_attach == (child->right_attach - 1))
1203             {
1204               if (child->xexpand)
1205                 table->cols[child->left_attach].expand = TRUE;
1206               
1207               if (!child->xshrink)
1208                 table->cols[child->left_attach].shrink = FALSE;
1209               
1210               table->cols[child->left_attach].empty = FALSE;
1211             }
1212           
1213           if (child->top_attach == (child->bottom_attach - 1))
1214             {
1215               if (child->yexpand)
1216                 table->rows[child->top_attach].expand = TRUE;
1217               
1218               if (!child->yshrink)
1219                 table->rows[child->top_attach].shrink = FALSE;
1220
1221               table->rows[child->top_attach].empty = FALSE;
1222             }
1223         }
1224     }
1225   
1226   /* Loop over all the children again and this time handle children
1227    *  which span multiple rows or columns.
1228    */
1229   children = table->children;
1230   while (children)
1231     {
1232       child = children->data;
1233       children = children->next;
1234       
1235       if (GTK_WIDGET_VISIBLE (child->widget))
1236         {
1237           if (child->left_attach != (child->right_attach - 1))
1238             {
1239               for (col = child->left_attach; col < child->right_attach; col++)
1240                 table->cols[col].empty = FALSE;
1241
1242               if (child->xexpand)
1243                 {
1244                   has_expand = FALSE;
1245                   for (col = child->left_attach; col < child->right_attach; col++)
1246                     if (table->cols[col].expand)
1247                       {
1248                         has_expand = TRUE;
1249                         break;
1250                       }
1251                   
1252                   if (!has_expand)
1253                     for (col = child->left_attach; col < child->right_attach; col++)
1254                       table->cols[col].need_expand = TRUE;
1255                 }
1256               
1257               if (!child->xshrink)
1258                 {
1259                   has_shrink = TRUE;
1260                   for (col = child->left_attach; col < child->right_attach; col++)
1261                     if (!table->cols[col].shrink)
1262                       {
1263                         has_shrink = FALSE;
1264                         break;
1265                       }
1266                   
1267                   if (has_shrink)
1268                     for (col = child->left_attach; col < child->right_attach; col++)
1269                       table->cols[col].need_shrink = FALSE;
1270                 }
1271             }
1272           
1273           if (child->top_attach != (child->bottom_attach - 1))
1274             {
1275               for (row = child->top_attach; row < child->bottom_attach; row++)
1276                 table->rows[row].empty = FALSE;
1277
1278               if (child->yexpand)
1279                 {
1280                   has_expand = FALSE;
1281                   for (row = child->top_attach; row < child->bottom_attach; row++)
1282                     if (table->rows[row].expand)
1283                       {
1284                         has_expand = TRUE;
1285                         break;
1286                       }
1287                   
1288                   if (!has_expand)
1289                     for (row = child->top_attach; row < child->bottom_attach; row++)
1290                       table->rows[row].need_expand = TRUE;
1291                 }
1292               
1293               if (!child->yshrink)
1294                 {
1295                   has_shrink = TRUE;
1296                   for (row = child->top_attach; row < child->bottom_attach; row++)
1297                     if (!table->rows[row].shrink)
1298                       {
1299                         has_shrink = FALSE;
1300                         break;
1301                       }
1302                   
1303                   if (has_shrink)
1304                     for (row = child->top_attach; row < child->bottom_attach; row++)
1305                       table->rows[row].need_shrink = FALSE;
1306                 }
1307             }
1308         }
1309     }
1310   
1311   /* Loop over the columns and set the expand and shrink values
1312    *  if the column can be expanded or shrunk.
1313    */
1314   for (col = 0; col < table->ncols; col++)
1315     {
1316       if (table->cols[col].empty)
1317         {
1318           table->cols[col].expand = FALSE;
1319           table->cols[col].shrink = FALSE;
1320         }
1321       else
1322         {
1323           if (table->cols[col].need_expand)
1324             table->cols[col].expand = TRUE;
1325           if (!table->cols[col].need_shrink)
1326             table->cols[col].shrink = FALSE;
1327         }
1328     }
1329   
1330   /* Loop over the rows and set the expand and shrink values
1331    *  if the row can be expanded or shrunk.
1332    */
1333   for (row = 0; row < table->nrows; row++)
1334     {
1335       if (table->rows[row].empty)
1336         {
1337           table->rows[row].expand = FALSE;
1338           table->rows[row].shrink = FALSE;
1339         }
1340       else
1341         {
1342           if (table->rows[row].need_expand)
1343             table->rows[row].expand = TRUE;
1344           if (!table->rows[row].need_shrink)
1345             table->rows[row].shrink = FALSE;
1346         }
1347     }
1348 }
1349
1350 static void
1351 gtk_table_size_allocate_pass1 (GtkTable *table)
1352 {
1353   gint real_width;
1354   gint real_height;
1355   gint width, height;
1356   gint row, col;
1357   gint nexpand;
1358   gint nshrink;
1359   gint extra;
1360   
1361   /* If we were allocated more space than we requested
1362    *  then we have to expand any expandable rows and columns
1363    *  to fill in the extra space.
1364    */
1365   
1366   real_width = GTK_WIDGET (table)->allocation.width - GTK_CONTAINER (table)->border_width * 2;
1367   real_height = GTK_WIDGET (table)->allocation.height - GTK_CONTAINER (table)->border_width * 2;
1368   
1369   if (table->homogeneous)
1370     {
1371       if (!table->children)
1372         nexpand = 1;
1373       else
1374         {
1375           nexpand = 0;
1376           for (col = 0; col < table->ncols; col++)
1377             if (table->cols[col].expand)
1378               {
1379                 nexpand += 1;
1380                 break;
1381               }
1382         }
1383       if (nexpand)
1384         {
1385           width = real_width;
1386           for (col = 0; col + 1 < table->ncols; col++)
1387             width -= table->cols[col].spacing;
1388           
1389           for (col = 0; col < table->ncols; col++)
1390             {
1391               extra = width / (table->ncols - col);
1392               table->cols[col].allocation = MAX (1, extra);
1393               width -= extra;
1394             }
1395         }
1396     }
1397   else
1398     {
1399       width = 0;
1400       nexpand = 0;
1401       nshrink = 0;
1402       
1403       for (col = 0; col < table->ncols; col++)
1404         {
1405           width += table->cols[col].requisition;
1406           if (table->cols[col].expand)
1407             nexpand += 1;
1408           if (table->cols[col].shrink)
1409             nshrink += 1;
1410         }
1411       for (col = 0; col + 1 < table->ncols; col++)
1412         width += table->cols[col].spacing;
1413       
1414       /* Check to see if we were allocated more width than we requested.
1415        */
1416       if ((width < real_width) && (nexpand >= 1))
1417         {
1418           width = real_width - width;
1419           
1420           for (col = 0; col < table->ncols; col++)
1421             if (table->cols[col].expand)
1422               {
1423                 extra = width / nexpand;
1424                 table->cols[col].allocation += extra;
1425                 
1426                 width -= extra;
1427                 nexpand -= 1;
1428               }
1429         }
1430       
1431       /* Check to see if we were allocated less width than we requested,
1432        * then shrink until we fit the size give.
1433        */
1434       if (width > real_width)
1435         {
1436           gint total_nshrink = nshrink;
1437
1438           extra = width - real_width;
1439           while (total_nshrink > 0 && extra > 0)
1440             {
1441               nshrink = total_nshrink;
1442               for (col = 0; col < table->ncols; col++)
1443                 if (table->cols[col].shrink)
1444                   {
1445                     gint allocation = table->cols[col].allocation;
1446
1447                     table->cols[col].allocation = MAX (1, (gint) table->cols[col].allocation - extra / nshrink);
1448                     extra -= allocation - table->cols[col].allocation;
1449                     nshrink -= 1;
1450                     if (table->cols[col].allocation < 2)
1451                       {
1452                         total_nshrink -= 1;
1453                         table->cols[col].shrink = FALSE;
1454                       }
1455                   }
1456             }
1457         }
1458     }
1459   
1460   if (table->homogeneous)
1461     {
1462       if (!table->children)
1463         nexpand = 1;
1464       else
1465         {
1466           nexpand = 0;
1467           for (row = 0; row < table->nrows; row++)
1468             if (table->rows[row].expand)
1469               {
1470                 nexpand += 1;
1471                 break;
1472               }
1473         }
1474       if (nexpand)
1475         {
1476           height = real_height;
1477           
1478           for (row = 0; row + 1 < table->nrows; row++)
1479             height -= table->rows[row].spacing;
1480           
1481           
1482           for (row = 0; row < table->nrows; row++)
1483             {
1484               extra = height / (table->nrows - row);
1485               table->rows[row].allocation = MAX (1, extra);
1486               height -= extra;
1487             }
1488         }
1489     }
1490   else
1491     {
1492       height = 0;
1493       nexpand = 0;
1494       nshrink = 0;
1495       
1496       for (row = 0; row < table->nrows; row++)
1497         {
1498           height += table->rows[row].requisition;
1499           if (table->rows[row].expand)
1500             nexpand += 1;
1501           if (table->rows[row].shrink)
1502             nshrink += 1;
1503         }
1504       for (row = 0; row + 1 < table->nrows; row++)
1505         height += table->rows[row].spacing;
1506       
1507       /* Check to see if we were allocated more height than we requested.
1508        */
1509       if ((height < real_height) && (nexpand >= 1))
1510         {
1511           height = real_height - height;
1512           
1513           for (row = 0; row < table->nrows; row++)
1514             if (table->rows[row].expand)
1515               {
1516                 extra = height / nexpand;
1517                 table->rows[row].allocation += extra;
1518                 
1519                 height -= extra;
1520                 nexpand -= 1;
1521               }
1522         }
1523       
1524       /* Check to see if we were allocated less height than we requested.
1525        * then shrink until we fit the size give.
1526        */
1527       if (height > real_height)
1528         {
1529           gint total_nshrink = nshrink;
1530           
1531           extra = height - real_height;
1532           while (total_nshrink > 0 && extra > 0)
1533             {
1534               nshrink = total_nshrink;
1535               for (row = 0; row < table->nrows; row++)
1536                 if (table->rows[row].shrink)
1537                   {
1538                     gint allocation = table->rows[row].allocation;
1539                     
1540                     table->rows[row].allocation = MAX (1, (gint) table->rows[row].allocation - extra / nshrink);
1541                     extra -= allocation - table->rows[row].allocation;
1542                     nshrink -= 1;
1543                     if (table->rows[row].allocation < 2)
1544                       {
1545                         total_nshrink -= 1;
1546                         table->rows[row].shrink = FALSE;
1547                       }
1548                   }
1549             }
1550         }
1551     }
1552 }
1553
1554 static void
1555 gtk_table_size_allocate_pass2 (GtkTable *table)
1556 {
1557   GtkTableChild *child;
1558   GList *children;
1559   gint max_width;
1560   gint max_height;
1561   gint x, y;
1562   gint row, col;
1563   GtkAllocation allocation;
1564   GtkWidget *widget = GTK_WIDGET (table);
1565   
1566   children = table->children;
1567   while (children)
1568     {
1569       child = children->data;
1570       children = children->next;
1571       
1572       if (GTK_WIDGET_VISIBLE (child->widget))
1573         {
1574           GtkRequisition child_requisition;
1575           gtk_widget_get_child_requisition (child->widget, &child_requisition);
1576
1577           x = GTK_WIDGET (table)->allocation.x + GTK_CONTAINER (table)->border_width;
1578           y = GTK_WIDGET (table)->allocation.y + GTK_CONTAINER (table)->border_width;
1579           max_width = 0;
1580           max_height = 0;
1581           
1582           for (col = 0; col < child->left_attach; col++)
1583             {
1584               x += table->cols[col].allocation;
1585               x += table->cols[col].spacing;
1586             }
1587           
1588           for (col = child->left_attach; col < child->right_attach; col++)
1589             {
1590               max_width += table->cols[col].allocation;
1591               if ((col + 1) < child->right_attach)
1592                 max_width += table->cols[col].spacing;
1593             }
1594           
1595           for (row = 0; row < child->top_attach; row++)
1596             {
1597               y += table->rows[row].allocation;
1598               y += table->rows[row].spacing;
1599             }
1600           
1601           for (row = child->top_attach; row < child->bottom_attach; row++)
1602             {
1603               max_height += table->rows[row].allocation;
1604               if ((row + 1) < child->bottom_attach)
1605                 max_height += table->rows[row].spacing;
1606             }
1607           
1608           if (child->xfill)
1609             {
1610               allocation.width = MAX (1, max_width - (gint)child->xpadding * 2);
1611               allocation.x = x + (max_width - allocation.width) / 2;
1612             }
1613           else
1614             {
1615               allocation.width = child_requisition.width;
1616               allocation.x = x + (max_width - allocation.width) / 2;
1617             }
1618           
1619           if (child->yfill)
1620             {
1621               allocation.height = MAX (1, max_height - (gint)child->ypadding * 2);
1622               allocation.y = y + (max_height - allocation.height) / 2;
1623             }
1624           else
1625             {
1626               allocation.height = child_requisition.height;
1627               allocation.y = y + (max_height - allocation.height) / 2;
1628             }
1629
1630           if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1631             allocation.x = widget->allocation.x + widget->allocation.width
1632               - (allocation.x - widget->allocation.x) - allocation.width;
1633           
1634           gtk_widget_size_allocate (child->widget, &allocation);
1635         }
1636     }
1637 }
1638
1639 #define __GTK_TABLE_C__
1640 #include "gtkaliasdef.c"