]> Pileus Git - ~andy/gtk/blob - gtk/gtktable.c
d90b47b965e09b67bfbac2747025597f84af7d81
[~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 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.
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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include "gtktable.h"
19
20
21 static void gtk_table_class_init    (GtkTableClass  *klass);
22 static void gtk_table_init          (GtkTable       *table);
23 static void gtk_table_finalize      (GtkObject      *object);
24 static void gtk_table_map           (GtkWidget      *widget);
25 static void gtk_table_unmap         (GtkWidget      *widget);
26 static void gtk_table_draw          (GtkWidget      *widget,
27                                      GdkRectangle   *area);
28 static gint gtk_table_expose        (GtkWidget      *widget,
29                                      GdkEventExpose *event);
30 static void gtk_table_size_request  (GtkWidget      *widget,
31                                      GtkRequisition *requisition);
32 static void gtk_table_size_allocate (GtkWidget      *widget,
33                                      GtkAllocation  *allocation);
34 static void gtk_table_add           (GtkContainer   *container,
35                                      GtkWidget      *widget);
36 static void gtk_table_remove        (GtkContainer   *container,
37                                      GtkWidget      *widget);
38 static void gtk_table_foreach       (GtkContainer   *container,
39                                      GtkCallback     callback,
40                                      gpointer        callback_data);
41
42 static void gtk_table_size_request_init  (GtkTable *table);
43 static void gtk_table_size_request_pass1 (GtkTable *table);
44 static void gtk_table_size_request_pass2 (GtkTable *table);
45 static void gtk_table_size_request_pass3 (GtkTable *table);
46
47 static void gtk_table_size_allocate_init  (GtkTable *table);
48 static void gtk_table_size_allocate_pass1 (GtkTable *table);
49 static void gtk_table_size_allocate_pass2 (GtkTable *table);
50
51
52 static GtkContainerClass *parent_class = NULL;
53
54
55 guint
56 gtk_table_get_type ()
57 {
58   static guint table_type = 0;
59
60   if (!table_type)
61     {
62       GtkTypeInfo table_info =
63       {
64         "GtkTable",
65         sizeof (GtkTable),
66         sizeof (GtkTableClass),
67         (GtkClassInitFunc) gtk_table_class_init,
68         (GtkObjectInitFunc) gtk_table_init,
69         (GtkArgSetFunc) NULL,
70         (GtkArgGetFunc) NULL,
71       };
72
73       table_type = gtk_type_unique (gtk_container_get_type (), &table_info);
74     }
75
76   return table_type;
77 }
78
79 static void
80 gtk_table_class_init (GtkTableClass *class)
81 {
82   GtkObjectClass *object_class;
83   GtkWidgetClass *widget_class;
84   GtkContainerClass *container_class;
85
86   object_class = (GtkObjectClass*) class;
87   widget_class = (GtkWidgetClass*) class;
88   container_class = (GtkContainerClass*) class;
89
90   parent_class = gtk_type_class (gtk_container_get_type ());
91
92   object_class->finalize = gtk_table_finalize;
93
94   widget_class->map = gtk_table_map;
95   widget_class->unmap = gtk_table_unmap;
96   widget_class->draw = gtk_table_draw;
97   widget_class->expose_event = gtk_table_expose;
98   widget_class->size_request = gtk_table_size_request;
99   widget_class->size_allocate = gtk_table_size_allocate;
100
101   container_class->add = gtk_table_add;
102   container_class->remove = gtk_table_remove;
103   container_class->foreach = gtk_table_foreach;
104 }
105
106 static void
107 gtk_table_init (GtkTable *table)
108 {
109   GTK_WIDGET_SET_FLAGS (table, GTK_NO_WINDOW | GTK_BASIC);
110
111   table->children = NULL;
112   table->rows = NULL;
113   table->cols = NULL;
114   table->nrows = 0;
115   table->ncols = 0;
116   table->homogeneous = FALSE;
117 }
118
119 static void
120 gtk_table_init_rows (GtkTable *table, int start, int end)
121 {
122   const int spacing = table->row_spacing;
123   int row;
124
125   for (row = start; row < end; row++)
126     {
127       table->rows[row].requisition = 0;
128       table->rows[row].allocation = 0;
129       table->rows[row].spacing = spacing;
130       table->rows[row].need_expand = 0;
131       table->rows[row].need_shrink = 0;
132       table->rows[row].expand = 0;
133       table->rows[row].shrink = 0;
134     }
135 }
136
137 static void
138 gtk_table_init_cols (GtkTable *table, int start, int end)
139 {
140   const int spacing = table->column_spacing;
141   int col;
142   
143   for (col = start; col < end; col++)
144     {
145       table->cols[col].requisition = 0;
146       table->cols[col].allocation = 0;
147       table->cols[col].spacing = spacing;
148       table->cols[col].need_expand = 0;
149       table->cols[col].need_shrink = 0;
150       table->cols[col].expand = 0;
151       table->cols[col].shrink = 0;
152     }
153 }
154
155 GtkWidget*
156 gtk_table_new (gint rows,
157                gint columns,
158                gint homogeneous)
159 {
160   GtkTable *table;
161
162   table = gtk_type_new (gtk_table_get_type ());
163
164   table->nrows = rows;
165   table->ncols = columns;
166   table->homogeneous = (homogeneous ? TRUE : FALSE);
167   table->column_spacing = 0;
168   table->row_spacing = 0;
169   
170   table->rows = g_new (GtkTableRowCol, table->nrows);
171   table->cols = g_new (GtkTableRowCol, table->ncols);
172
173   gtk_table_init_rows (table, 0, table->nrows);
174   gtk_table_init_cols (table, 0, table->ncols);
175
176   return GTK_WIDGET (table);
177 }
178
179 static void
180 gtk_table_expand_cols (GtkTable *table, int new_max)
181 {
182   table->cols = g_realloc (table->cols, new_max * sizeof (GtkTableRowCol));
183   gtk_table_init_cols (table, table->ncols, new_max);
184   table->ncols = new_max;
185 }
186
187 static void
188 gtk_table_expand_rows (GtkTable *table, int new_max)
189 {
190   table->rows = g_realloc (table->rows, new_max * sizeof (GtkTableRowCol));
191   gtk_table_init_rows (table, table->nrows, new_max);
192   table->nrows = new_max;
193 }
194
195 void
196 gtk_table_attach (GtkTable  *table,
197                   GtkWidget *child,
198                   gint       left_attach,
199                   gint       right_attach,
200                   gint       top_attach,
201                   gint       bottom_attach,
202                   gint       xoptions,
203                   gint       yoptions,
204                   gint       xpadding,
205                   gint       ypadding)
206 {
207   GtkTableChild *table_child;
208   
209   g_return_if_fail (table != NULL);
210   g_return_if_fail (GTK_IS_TABLE (table));
211   g_return_if_fail (child != NULL);
212
213   g_return_if_fail (left_attach >= 0);
214   g_return_if_fail (left_attach < right_attach);
215   g_return_if_fail (top_attach >= 0);
216   g_return_if_fail (top_attach < bottom_attach);
217
218   if (right_attach >= table->ncols)
219           gtk_table_expand_cols (table, right_attach);
220
221   if (bottom_attach >= table->nrows)
222           gtk_table_expand_rows (table, bottom_attach);
223
224   table_child = g_new (GtkTableChild, 1);
225   table_child->widget = child;
226   table_child->left_attach = left_attach;
227   table_child->right_attach = right_attach;
228   table_child->top_attach = top_attach;
229   table_child->bottom_attach = bottom_attach;
230   table_child->xexpand = (xoptions & GTK_EXPAND) != 0;
231   table_child->xshrink = (xoptions & GTK_SHRINK) != 0;
232   table_child->xfill = (xoptions & GTK_FILL) != 0;
233   table_child->xpadding = xpadding;
234   table_child->yexpand = (yoptions & GTK_EXPAND) != 0;
235   table_child->yshrink = (yoptions & GTK_SHRINK) != 0;
236   table_child->yfill = (yoptions & GTK_FILL) != 0;
237   table_child->ypadding = ypadding;
238
239   table->children = g_list_prepend (table->children, table_child);
240
241   gtk_widget_set_parent (child, GTK_WIDGET (table));
242
243   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (table)))
244     {
245       if (GTK_WIDGET_REALIZED (GTK_WIDGET (table)) &&
246           !GTK_WIDGET_REALIZED (child))
247         gtk_widget_realize (child);
248       
249       if (GTK_WIDGET_MAPPED (GTK_WIDGET (table)) &&
250           !GTK_WIDGET_MAPPED (child))
251         gtk_widget_map (child);
252     }
253
254   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (table))
255     gtk_widget_queue_resize (child);
256 }
257
258 void
259 gtk_table_attach_defaults (GtkTable  *table,
260                            GtkWidget *widget,
261                            gint       left_attach,
262                            gint       right_attach,
263                            gint       top_attach,
264                            gint       bottom_attach)
265 {
266   gtk_table_attach (table, widget,
267                     left_attach, right_attach,
268                     top_attach, bottom_attach,
269                     GTK_EXPAND | GTK_FILL,
270                     GTK_EXPAND | GTK_FILL,
271                     0, 0);
272 }
273
274 void
275 gtk_table_set_row_spacing (GtkTable *table,
276                            gint      row,
277                            gint      spacing)
278 {
279   g_return_if_fail (table != NULL);
280   g_return_if_fail (GTK_IS_TABLE (table));
281   g_return_if_fail ((row >= 0) && (row < (table->nrows - 1)));
282
283   if (table->rows[row].spacing != spacing)
284     {
285       table->rows[row].spacing = spacing;
286
287       if (GTK_WIDGET_VISIBLE (table))
288         gtk_widget_queue_resize (GTK_WIDGET (table));
289     }
290 }
291
292 void
293 gtk_table_set_col_spacing (GtkTable *table,
294                            gint      column,
295                            gint      spacing)
296 {
297   g_return_if_fail (table != NULL);
298   g_return_if_fail (GTK_IS_TABLE (table));
299   g_return_if_fail ((column >= 0) && (column < (table->ncols - 1)));
300
301   if (table->cols[column].spacing != spacing)
302     {
303       table->cols[column].spacing = spacing;
304
305       if (GTK_WIDGET_VISIBLE (table))
306         gtk_widget_queue_resize (GTK_WIDGET (table));
307     }
308 }
309
310 void
311 gtk_table_set_row_spacings (GtkTable *table,
312                             gint      spacing)
313 {
314   gint row;
315
316   g_return_if_fail (table != NULL);
317   g_return_if_fail (GTK_IS_TABLE (table));
318
319   table->row_spacing = spacing;
320   for (row = 0; row < table->nrows - 1; row++)
321     table->rows[row].spacing = spacing;
322
323   if (GTK_WIDGET_VISIBLE (table))
324     gtk_widget_queue_resize (GTK_WIDGET (table));
325 }
326
327 void
328 gtk_table_set_col_spacings (GtkTable *table,
329                             gint      spacing)
330 {
331   gint col;
332
333   g_return_if_fail (table != NULL);
334   g_return_if_fail (GTK_IS_TABLE (table));
335
336   table->column_spacing = spacing;
337   for (col = 0; col < table->ncols - 1; col++)
338     table->cols[col].spacing = spacing;
339
340   if (GTK_WIDGET_VISIBLE (table))
341     gtk_widget_queue_resize (GTK_WIDGET (table));
342 }
343
344 void
345 gtk_table_set_homogeneous (GtkTable *table,
346                            gint      homogeneous)
347 {
348   g_return_if_fail (table != NULL);
349   g_return_if_fail (GTK_IS_TABLE (table));
350
351   table->homogeneous = (homogeneous != 0);
352
353   if (GTK_WIDGET_VISIBLE (table))
354     gtk_widget_queue_resize (GTK_WIDGET (table));
355 }
356
357
358 static void
359 gtk_table_finalize (GtkObject *object)
360 {
361   GtkTable *table;
362
363   g_return_if_fail (object != NULL);
364   g_return_if_fail (GTK_IS_TABLE (object));
365
366   table = GTK_TABLE (object);
367
368   g_free (table->rows);
369   g_free (table->cols);
370
371   (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
372 }
373
374 static void
375 gtk_table_map (GtkWidget *widget)
376 {
377   GtkTable *table;
378   GtkTableChild *child;
379   GList *children;
380
381   g_return_if_fail (widget != NULL);
382   g_return_if_fail (GTK_IS_TABLE (widget));
383
384   table = GTK_TABLE (widget);
385   GTK_WIDGET_SET_FLAGS (table, GTK_MAPPED);
386
387   children = table->children;
388   while (children)
389     {
390       child = children->data;
391       children = children->next;
392
393       if (GTK_WIDGET_VISIBLE (child->widget) &&
394           !GTK_WIDGET_MAPPED (child->widget))
395         gtk_widget_map (child->widget);
396     }
397 }
398
399 static void
400 gtk_table_unmap (GtkWidget *widget)
401 {
402   GtkTable *table;
403   GtkTableChild *child;
404   GList *children;
405
406   g_return_if_fail (widget != NULL);
407   g_return_if_fail (GTK_IS_TABLE (widget));
408
409   table = GTK_TABLE (widget);
410   GTK_WIDGET_UNSET_FLAGS (table, GTK_MAPPED);
411
412   children = table->children;
413   while (children)
414     {
415       child = children->data;
416       children = children->next;
417
418       if (GTK_WIDGET_VISIBLE (child->widget) &&
419           GTK_WIDGET_MAPPED (child->widget))
420         gtk_widget_unmap (child->widget);
421     }
422 }
423
424 static void
425 gtk_table_draw (GtkWidget    *widget,
426                 GdkRectangle *area)
427 {
428   GtkTable *table;
429   GtkTableChild *child;
430   GList *children;
431   GdkRectangle child_area;
432
433   g_return_if_fail (widget != NULL);
434   g_return_if_fail (GTK_IS_TABLE (widget));
435
436   if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
437     {
438       table = GTK_TABLE (widget);
439
440       children = table->children;
441       while (children)
442         {
443           child = children->data;
444           children = children->next;
445
446           if (gtk_widget_intersect (child->widget, area, &child_area))
447             gtk_widget_draw (child->widget, &child_area);
448         }
449     }
450 }
451
452 static gint
453 gtk_table_expose (GtkWidget      *widget,
454                   GdkEventExpose *event)
455 {
456   GtkTable *table;
457   GtkTableChild *child;
458   GList *children;
459   GdkEventExpose child_event;
460
461   g_return_val_if_fail (widget != NULL, FALSE);
462   g_return_val_if_fail (GTK_IS_TABLE (widget), FALSE);
463
464   if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
465     {
466       table = GTK_TABLE (widget);
467
468       child_event = *event;
469
470       children = table->children;
471       while (children)
472         {
473           child = children->data;
474           children = children->next;
475
476           if (GTK_WIDGET_NO_WINDOW (child->widget) &&
477               gtk_widget_intersect (child->widget, &event->area, &child_event.area))
478             gtk_widget_event (child->widget, (GdkEvent*) &child_event);
479         }
480     }
481
482   return FALSE;
483 }
484
485 static void
486 gtk_table_size_request (GtkWidget      *widget,
487                         GtkRequisition *requisition)
488 {
489   GtkTable *table;
490   gint row, col;
491
492   g_return_if_fail (widget != NULL);
493   g_return_if_fail (GTK_IS_TABLE (widget));
494   g_return_if_fail (requisition != NULL);
495
496   table = GTK_TABLE (widget);
497
498   requisition->width = 0;
499   requisition->height = 0;
500
501   gtk_table_size_request_init (table);
502   gtk_table_size_request_pass1 (table);
503   gtk_table_size_request_pass2 (table);
504   gtk_table_size_request_pass3 (table);
505   gtk_table_size_request_pass2 (table);
506
507   for (col = 0; col < table->ncols; col++)
508     requisition->width += table->cols[col].requisition;
509   for (col = 0; col < table->ncols - 1; col++)
510     requisition->width += table->cols[col].spacing;
511
512   for (row = 0; row < table->nrows; row++)
513     requisition->height += table->rows[row].requisition;
514   for (row = 0; row < table->nrows - 1; row++)
515     requisition->height += table->rows[row].spacing;
516
517   requisition->width += GTK_CONTAINER (table)->border_width * 2;
518   requisition->height += GTK_CONTAINER (table)->border_width * 2;
519 }
520
521 static void
522 gtk_table_size_allocate (GtkWidget     *widget,
523                          GtkAllocation *allocation)
524 {
525   GtkTable *table;
526
527   g_return_if_fail (widget != NULL);
528   g_return_if_fail (GTK_IS_TABLE (widget));
529   g_return_if_fail (allocation != NULL);
530
531   widget->allocation = *allocation;
532   table = GTK_TABLE (widget);
533
534   gtk_table_size_allocate_init (table);
535   gtk_table_size_allocate_pass1 (table);
536   gtk_table_size_allocate_pass2 (table);
537 }
538
539 static void
540 gtk_table_add (GtkContainer *container,
541                GtkWidget    *widget)
542 {
543   g_return_if_fail (container != NULL);
544   g_return_if_fail (GTK_IS_TABLE (container));
545   g_return_if_fail (widget != NULL);
546
547   gtk_table_attach_defaults (GTK_TABLE (container), widget, 0, 1, 0, 1);
548 }
549
550 static void
551 gtk_table_remove (GtkContainer *container,
552                   GtkWidget    *widget)
553 {
554   GtkTable *table;
555   GtkTableChild *child;
556   GList *children;
557
558   g_return_if_fail (container != NULL);
559   g_return_if_fail (GTK_IS_TABLE (container));
560   g_return_if_fail (widget != NULL);
561
562   table = GTK_TABLE (container);
563   children = table->children;
564
565   while (children)
566     {
567       child = children->data;
568       children = children->next;
569
570       if (child->widget == widget)
571         {
572           gtk_widget_unparent (widget);
573
574           table->children = g_list_remove (table->children, child);
575           g_free (child);
576
577           if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container))
578             gtk_widget_queue_resize (GTK_WIDGET (container));
579           break;
580         }
581     }
582 }
583
584 static void
585 gtk_table_foreach (GtkContainer *container,
586                    GtkCallback     callback,
587                    gpointer        callback_data)
588 {
589   GtkTable *table;
590   GtkTableChild *child;
591   GList *children;
592
593   g_return_if_fail (container != NULL);
594   g_return_if_fail (GTK_IS_TABLE (container));
595   g_return_if_fail (callback != NULL);
596
597   table = GTK_TABLE (container);
598   children = table->children;
599
600   while (children)
601     {
602       child = children->data;
603       children = children->next;
604
605       (* callback) (child->widget, callback_data);
606     }
607 }
608
609 static void
610 gtk_table_size_request_init (GtkTable *table)
611 {
612   GtkTableChild *child;
613   GList *children;
614   gint row, col;
615
616   for (row = 0; row < table->nrows; row++)
617     table->rows[row].requisition = 0;
618   for (col = 0; col < table->ncols; col++)
619     table->cols[col].requisition = 0;
620
621   children = table->children;
622   while (children)
623     {
624       child = children->data;
625       children = children->next;
626
627       if (GTK_WIDGET_VISIBLE (child->widget))
628         gtk_widget_size_request (child->widget, &child->widget->requisition);
629     }
630 }
631
632 static void
633 gtk_table_size_request_pass1 (GtkTable *table)
634 {
635   GtkTableChild *child;
636   GList *children;
637   gint width;
638   gint height;
639
640   children = table->children;
641   while (children)
642     {
643       child = children->data;
644       children = children->next;
645
646       if (GTK_WIDGET_VISIBLE (child->widget))
647         {
648           /* Child spans a single column.
649            */
650           if (child->left_attach == (child->right_attach - 1))
651             {
652               width = child->widget->requisition.width + child->xpadding * 2;
653               table->cols[child->left_attach].requisition = MAX (table->cols[child->left_attach].requisition, width);
654             }
655
656           /* Child spans a single row.
657            */
658           if (child->top_attach == (child->bottom_attach - 1))
659             {
660               height = child->widget->requisition.height + child->ypadding * 2;
661               table->rows[child->top_attach].requisition = MAX (table->rows[child->top_attach].requisition, height);
662             }
663         }
664     }
665 }
666
667 static void
668 gtk_table_size_request_pass2 (GtkTable *table)
669 {
670   gint max_width;
671   gint max_height;
672   gint row, col;
673
674   if (table->homogeneous)
675     {
676       max_width = 0;
677       max_height = 0;
678
679       for (col = 0; col < table->ncols; col++)
680         max_width = MAX (max_width, table->cols[col].requisition);
681       for (row = 0; row < table->nrows; row++)
682         max_height = MAX (max_height, table->rows[row].requisition);
683
684       for (col = 0; col < table->ncols; col++)
685         table->cols[col].requisition = max_width;
686       for (row = 0; row < table->nrows; row++)
687         table->rows[row].requisition = max_height;
688     }
689 }
690
691 static void
692 gtk_table_size_request_pass3 (GtkTable *table)
693 {
694   GtkTableChild *child;
695   GList *children;
696   gint width, height;
697   gint row, col;
698   gint extra;
699
700   children = table->children;
701   while (children)
702     {
703       child = children->data;
704       children = children->next;
705
706       if (GTK_WIDGET_VISIBLE (child->widget))
707         {
708           /* Child spans multiple columns.
709            */
710           if (child->left_attach != (child->right_attach - 1))
711             {
712               /* Check and see if there is already enough space
713                *  for the child.
714                */
715               width = 0;
716               for (col = child->left_attach; col < child->right_attach; col++)
717                 {
718                   width += table->cols[col].requisition;
719                   if ((col + 1) < child->right_attach)
720                     width += table->cols[col].spacing;
721                 }
722
723               /* If we need to request more space for this child to fill
724                *  its requisition, then divide up the needed space evenly
725                *  amongst the columns it spans.
726                */
727               if (width < child->widget->requisition.width)
728                 {
729                   width = child->widget->requisition.width - width;
730
731                   for (col = child->left_attach; col < child->right_attach; col++)
732                     {
733                       extra = width / (child->right_attach - col);
734                       table->cols[col].requisition += extra;
735                       width -= extra;
736                     }
737                 }
738             }
739
740           /* Child spans multiple rows.
741            */
742           if (child->top_attach != (child->bottom_attach - 1))
743             {
744               /* Check and see if there is already enough space
745                *  for the child.
746                */
747               height = 0;
748               for (row = child->top_attach; row < child->bottom_attach; row++)
749                 {
750                   height += table->rows[row].requisition;
751                   if ((row + 1) < child->bottom_attach)
752                     height += table->rows[row].spacing;
753                 }
754
755               /* If we need to request more space for this child to fill
756                *  its requisition, then divide up the needed space evenly
757                *  amongst the columns it spans.
758                */
759               if (height < child->widget->requisition.height)
760                 {
761                   height = child->widget->requisition.height - height;
762
763                   for (row = child->top_attach; row < child->bottom_attach; row++)
764                     {
765                       extra = height / (child->bottom_attach - row);
766                       table->rows[row].requisition += extra;
767                       height -= extra;
768                     }
769                 }
770             }
771         }
772     }
773 }
774
775 static void
776 gtk_table_size_allocate_init (GtkTable *table)
777 {
778   GtkTableChild *child;
779   GList *children;
780   gint row, col;
781   gint has_expand;
782   gint has_shrink;
783
784   /* Initialize the rows and cols.
785    *  By default, rows and cols do not expand and do shrink.
786    *  Those values are modified by the children that occupy
787    *  the rows and cols.
788    */
789   for (col = 0; col < table->ncols; col++)
790     {
791       table->cols[col].allocation = table->cols[col].requisition;
792       table->cols[col].need_expand = FALSE;
793       table->cols[col].need_shrink = TRUE;
794       table->cols[col].expand = FALSE;
795       table->cols[col].shrink = TRUE;
796     }
797   for (row = 0; row < table->nrows; row++)
798     {
799       table->rows[row].allocation = table->rows[row].requisition;
800       table->rows[row].need_expand = FALSE;
801       table->rows[row].need_shrink = TRUE;
802       table->rows[row].expand = FALSE;
803       table->rows[row].shrink = TRUE;
804     }
805
806   /* Loop over all the children and adjust the row and col values
807    *  based on whether the children want to be allowed to expand
808    *  or shrink. This loop handles children that occupy a single
809    *  row or column.
810    */
811   children = table->children;
812   while (children)
813     {
814       child = children->data;
815       children = children->next;
816
817       if (GTK_WIDGET_VISIBLE (child->widget))
818         {
819           if (child->left_attach == (child->right_attach - 1))
820             {
821               if (child->xexpand)
822                 table->cols[child->left_attach].expand = TRUE;
823
824               if (!child->xshrink)
825                 table->cols[child->left_attach].shrink = FALSE;
826             }
827
828           if (child->top_attach == (child->bottom_attach - 1))
829             {
830               if (child->yexpand)
831                 table->rows[child->top_attach].expand = TRUE;
832
833               if (!child->yshrink)
834                 table->rows[child->top_attach].shrink = FALSE;
835             }
836         }
837     }
838
839   /* Loop over all the children again and this time handle children
840    *  which span multiple rows or columns.
841    */
842   children = table->children;
843   while (children)
844     {
845       child = children->data;
846       children = children->next;
847
848       if (GTK_WIDGET_VISIBLE (child->widget))
849         {
850           if (child->left_attach != (child->right_attach - 1))
851             {
852               if (child->xexpand)
853                 {
854                   has_expand = FALSE;
855                   for (col = child->left_attach; col < child->right_attach; col++)
856                     if (table->cols[col].expand)
857                       {
858                         has_expand = TRUE;
859                         break;
860                       }
861
862                   if (!has_expand)
863                     for (col = child->left_attach; col < child->right_attach; col++)
864                       table->cols[col].need_expand = TRUE;
865                 }
866
867               if (!child->xshrink)
868                 {
869                   has_shrink = TRUE;
870                   for (col = child->left_attach; col < child->right_attach; col++)
871                     if (!table->cols[col].shrink)
872                       {
873                         has_shrink = FALSE;
874                         break;
875                       }
876
877                   if (has_shrink)
878                     for (col = child->left_attach; col < child->right_attach; col++)
879                       table->cols[col].need_shrink = FALSE;
880                 }
881             }
882
883           if (child->top_attach != (child->bottom_attach - 1))
884             {
885               if (child->yexpand)
886                 {
887                   has_expand = FALSE;
888                   for (row = child->top_attach; row < child->bottom_attach; row++)
889                     if (table->rows[row].expand)
890                       {
891                         has_expand = TRUE;
892                         break;
893                       }
894
895                   if (!has_expand)
896                     for (row = child->top_attach; row < child->bottom_attach; row++)
897                       table->rows[row].need_expand = TRUE;
898                 }
899
900               if (!child->yshrink)
901                 {
902                   has_shrink = TRUE;
903                   for (row = child->top_attach; row < child->bottom_attach; row++)
904                     if (!table->rows[row].shrink)
905                       {
906                         has_shrink = FALSE;
907                         break;
908                       }
909
910                   if (has_shrink)
911                     for (row = child->top_attach; row < child->bottom_attach; row++)
912                       table->rows[row].need_shrink = FALSE;
913                 }
914             }
915         }
916     }
917
918   /* Loop over the columns and set the expand and shrink values
919    *  if the column can be expanded or shrunk.
920    */
921   for (col = 0; col < table->ncols; col++)
922     {
923       if (table->cols[col].need_expand)
924         table->cols[col].expand = TRUE;
925       if (!table->cols[col].need_shrink)
926         table->cols[col].shrink = FALSE;
927     }
928
929   /* Loop over the rows and set the expand and shrink values
930    *  if the row can be expanded or shrunk.
931    */
932   for (row = 0; row < table->nrows; row++)
933     {
934       if (table->rows[row].need_expand)
935         table->rows[row].expand = TRUE;
936       if (!table->rows[row].need_shrink)
937         table->rows[row].shrink = FALSE;
938     }
939 }
940
941 static void
942 gtk_table_size_allocate_pass1 (GtkTable *table)
943 {
944   gint real_width;
945   gint real_height;
946   gint width, height;
947   gint row, col;
948   gint nexpand;
949   gint nshrink;
950   gint extra;
951
952   /* If we were allocated more space than we requested
953    *  then we have to expand any expandable rows and columns
954    *  to fill in the extra space.
955    */
956
957   real_width = GTK_WIDGET (table)->allocation.width - GTK_CONTAINER (table)->border_width * 2;
958   real_height = GTK_WIDGET (table)->allocation.height - GTK_CONTAINER (table)->border_width * 2;
959
960   if (table->homogeneous)
961     {
962       nexpand = 0;
963       for (col = 0; col < table->ncols; col++)
964         if (table->cols[col].expand)
965           {
966             nexpand += 1;
967             break;
968           }
969
970       if (nexpand > 0)
971         {
972           width = real_width;
973
974           for (col = 0; col < table->ncols - 1; col++)
975             width -= table->cols[col].spacing;
976
977           for (col = 0; col < table->ncols; col++)
978             {
979               extra = width / (table->ncols - col);
980               table->cols[col].allocation = MAX (1, extra);
981               width -= extra;
982             }
983         }
984     }
985   else
986     {
987       width = 0;
988       nexpand = 0;
989       nshrink = 0;
990
991       for (col = 0; col < table->ncols; col++)
992         {
993           width += table->cols[col].requisition;
994           if (table->cols[col].expand)
995             nexpand += 1;
996           if (table->cols[col].shrink)
997             nshrink += 1;
998         }
999       for (col = 0; col < table->ncols - 1; col++)
1000         width += table->cols[col].spacing;
1001
1002       /* Check to see if we were allocated more width than we requested.
1003        */
1004       if ((width < real_width) && (nexpand >= 1))
1005         {
1006           width = real_width - width;
1007
1008           for (col = 0; col < table->ncols; col++)
1009             if (table->cols[col].expand)
1010               {
1011                 extra = width / nexpand;
1012                 table->cols[col].allocation += extra;
1013
1014                 width -= extra;
1015                 nexpand -= 1;
1016               }
1017         }
1018
1019       /* Check to see if we were allocated less width than we requested.
1020        */
1021       if ((width > real_width) && (nshrink >= 1))
1022         {
1023           width = width - real_width;
1024
1025           for (col = 0; col < table->ncols; col++)
1026             if (table->cols[col].shrink)
1027               {
1028                 extra = width / nshrink;
1029                 table->cols[col].allocation = MAX (1, table->cols[col].allocation - extra);
1030
1031                 width -= extra;
1032                 nshrink -= 1;
1033               }
1034         }
1035     }
1036
1037   if (table->homogeneous)
1038     {
1039       nexpand = 0;
1040       for (row = 0; row < table->nrows; row++)
1041         if (table->rows[row].expand)
1042           {
1043             nexpand += 1;
1044             break;
1045           }
1046
1047       if (nexpand > 0)
1048         {
1049           height = real_height;
1050
1051           for (row = 0; row < table->nrows - 1; row++)
1052             height -= table->rows[row].spacing;
1053
1054
1055           for (row = 0; row < table->nrows; row++)
1056             {
1057               extra = height / (table->nrows - row);
1058               table->rows[row].allocation = MAX (1, extra);
1059               height -= extra;
1060             }
1061         }
1062     }
1063   else
1064     {
1065       height = 0;
1066       nexpand = 0;
1067       nshrink = 0;
1068
1069       for (row = 0; row < table->nrows; row++)
1070         {
1071           height += table->rows[row].requisition;
1072           if (table->rows[row].expand)
1073             nexpand += 1;
1074           if (table->rows[row].shrink)
1075             nshrink += 1;
1076         }
1077       for (row = 0; row < table->nrows - 1; row++)
1078         height += table->rows[row].spacing;
1079
1080       /* Check to see if we were allocated more height than we requested.
1081        */
1082       if ((height < real_height) && (nexpand >= 1))
1083         {
1084           height = real_height - height;
1085
1086           for (row = 0; row < table->nrows; row++)
1087             if (table->rows[row].expand)
1088               {
1089                 extra = height / nexpand;
1090                 table->rows[row].allocation += extra;
1091
1092                 height -= extra;
1093                 nexpand -= 1;
1094               }
1095         }
1096
1097       /* Check to see if we were allocated less height than we requested.
1098        */
1099       if ((height > real_height) && (nshrink >= 1))
1100         {
1101           height = height - real_height;
1102
1103           for (row = 0; row < table->nrows; row++)
1104             if (table->rows[row].shrink)
1105               {
1106                 extra = height / nshrink;
1107                 table->rows[row].allocation = MAX (1, table->rows[row].allocation - extra);
1108
1109                 height -= extra;
1110                 nshrink -= 1;
1111               }
1112         }
1113     }
1114 }
1115
1116 static void
1117 gtk_table_size_allocate_pass2 (GtkTable *table)
1118 {
1119   GtkTableChild *child;
1120   GList *children;
1121   gint max_width;
1122   gint max_height;
1123   gint x, y;
1124   gint row, col;
1125   GtkAllocation allocation;
1126
1127   children = table->children;
1128   while (children)
1129     {
1130       child = children->data;
1131       children = children->next;
1132
1133       if (GTK_WIDGET_VISIBLE (child->widget))
1134         {
1135           x = GTK_WIDGET (table)->allocation.x + GTK_CONTAINER (table)->border_width;
1136           y = GTK_WIDGET (table)->allocation.y + GTK_CONTAINER (table)->border_width;
1137           max_width = 0;
1138           max_height = 0;
1139
1140           for (col = 0; col < child->left_attach; col++)
1141             {
1142               x += table->cols[col].allocation;
1143               x += table->cols[col].spacing;
1144             }
1145
1146           for (col = child->left_attach; col < child->right_attach; col++)
1147             {
1148               max_width += table->cols[col].allocation;
1149               if ((col + 1) < child->right_attach)
1150                 max_width += table->cols[col].spacing;
1151             }
1152
1153           for (row = 0; row < child->top_attach; row++)
1154             {
1155               y += table->rows[row].allocation;
1156               y += table->rows[row].spacing;
1157             }
1158
1159           for (row = child->top_attach; row < child->bottom_attach; row++)
1160             {
1161               max_height += table->rows[row].allocation;
1162               if ((row + 1) < child->bottom_attach)
1163                 max_height += table->rows[row].spacing;
1164             }
1165
1166           if (child->xfill)
1167             {
1168               allocation.width = MAX (1, max_width - child->xpadding * 2);
1169               allocation.x = x + (max_width - allocation.width) / 2;
1170             }
1171           else
1172             {
1173               allocation.width = child->widget->requisition.width;
1174               allocation.x = x + (max_width - allocation.width) / 2;
1175             }
1176
1177           if (child->yfill)
1178             {
1179               allocation.height = MAX (1, max_height - child->ypadding * 2);
1180               allocation.y = y + (max_height - allocation.height) / 2;
1181             }
1182           else
1183             {
1184               allocation.height = child->widget->requisition.height;
1185               allocation.y = y + (max_height - allocation.height) / 2;
1186             }
1187
1188           gtk_widget_size_allocate (child->widget, &allocation);
1189         }
1190     }
1191 }
1192