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
G_DEFINE_TYPE(GtkTable,gtk_table,GTK_TYPE_CONTAINER)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 1,
132 65535,
133 1,
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 1,
141 65535,
142 1,
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 65535,
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 65535,
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
gtk_table_child_type(GtkContainer * container)229 gtk_table_child_type (GtkContainer *container)
230 {
231 return GTK_TYPE_WIDGET;
232 }
233
234 static void
gtk_table_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)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
gtk_table_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)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
gtk_table_set_child_property(GtkContainer * container,GtkWidget * child,guint property_id,const GValue * value,GParamSpec * pspec)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_get_visible (child) &&
376 gtk_widget_get_visible (GTK_WIDGET (table)))
377 gtk_widget_queue_resize (child);
378 }
379
380 static void
gtk_table_get_child_property(GtkContainer * container,GtkWidget * child,guint property_id,GValue * value,GParamSpec * pspec)381 gtk_table_get_child_property (GtkContainer *container,
382 GtkWidget *child,
383 guint property_id,
384 GValue *value,
385 GParamSpec *pspec)
386 {
387 GtkTable *table = GTK_TABLE (container);
388 GtkTableChild *table_child;
389 GList *list;
390
391 table_child = NULL;
392 for (list = table->children; list; list = list->next)
393 {
394 table_child = list->data;
395
396 if (table_child->widget == child)
397 break;
398 }
399 if (!list)
400 {
401 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
402 return;
403 }
404
405 switch (property_id)
406 {
407 case CHILD_PROP_LEFT_ATTACH:
408 g_value_set_uint (value, table_child->left_attach);
409 break;
410 case CHILD_PROP_RIGHT_ATTACH:
411 g_value_set_uint (value, table_child->right_attach);
412 break;
413 case CHILD_PROP_TOP_ATTACH:
414 g_value_set_uint (value, table_child->top_attach);
415 break;
416 case CHILD_PROP_BOTTOM_ATTACH:
417 g_value_set_uint (value, table_child->bottom_attach);
418 break;
419 case CHILD_PROP_X_OPTIONS:
420 g_value_set_flags (value, (table_child->xexpand * GTK_EXPAND |
421 table_child->xshrink * GTK_SHRINK |
422 table_child->xfill * GTK_FILL));
423 break;
424 case CHILD_PROP_Y_OPTIONS:
425 g_value_set_flags (value, (table_child->yexpand * GTK_EXPAND |
426 table_child->yshrink * GTK_SHRINK |
427 table_child->yfill * GTK_FILL));
428 break;
429 case CHILD_PROP_X_PADDING:
430 g_value_set_uint (value, table_child->xpadding);
431 break;
432 case CHILD_PROP_Y_PADDING:
433 g_value_set_uint (value, table_child->ypadding);
434 break;
435 default:
436 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
437 break;
438 }
439 }
440
441 static void
gtk_table_init(GtkTable * table)442 gtk_table_init (GtkTable *table)
443 {
444 gtk_widget_set_has_window (GTK_WIDGET (table), FALSE);
445 gtk_widget_set_redraw_on_allocate (GTK_WIDGET (table), FALSE);
446
447 table->children = NULL;
448 table->rows = NULL;
449 table->cols = NULL;
450 table->nrows = 0;
451 table->ncols = 0;
452 table->column_spacing = 0;
453 table->row_spacing = 0;
454 table->homogeneous = FALSE;
455
456 gtk_table_resize (table, 1, 1);
457 }
458
459 GtkWidget*
gtk_table_new(guint rows,guint columns,gboolean homogeneous)460 gtk_table_new (guint rows,
461 guint columns,
462 gboolean homogeneous)
463 {
464 GtkTable *table;
465
466 if (rows == 0)
467 rows = 1;
468 if (columns == 0)
469 columns = 1;
470
471 table = g_object_new (GTK_TYPE_TABLE, NULL);
472
473 table->homogeneous = (homogeneous ? TRUE : FALSE);
474
475 gtk_table_resize (table, rows, columns);
476
477 return GTK_WIDGET (table);
478 }
479
480 void
gtk_table_resize(GtkTable * table,guint n_rows,guint n_cols)481 gtk_table_resize (GtkTable *table,
482 guint n_rows,
483 guint n_cols)
484 {
485 g_return_if_fail (GTK_IS_TABLE (table));
486 g_return_if_fail (n_rows > 0 && n_rows <= 65535);
487 g_return_if_fail (n_cols > 0 && n_cols <= 65535);
488
489 n_rows = MAX (n_rows, 1);
490 n_cols = MAX (n_cols, 1);
491
492 if (n_rows != table->nrows ||
493 n_cols != table->ncols)
494 {
495 GList *list;
496
497 for (list = table->children; list; list = list->next)
498 {
499 GtkTableChild *child;
500
501 child = list->data;
502
503 n_rows = MAX (n_rows, child->bottom_attach);
504 n_cols = MAX (n_cols, child->right_attach);
505 }
506
507 if (n_rows != table->nrows)
508 {
509 guint i;
510
511 i = table->nrows;
512 table->nrows = n_rows;
513 table->rows = g_realloc (table->rows, table->nrows * sizeof (GtkTableRowCol));
514
515 for (; i < table->nrows; i++)
516 {
517 table->rows[i].requisition = 0;
518 table->rows[i].allocation = 0;
519 table->rows[i].spacing = table->row_spacing;
520 table->rows[i].need_expand = 0;
521 table->rows[i].need_shrink = 0;
522 table->rows[i].expand = 0;
523 table->rows[i].shrink = 0;
524 }
525
526 g_object_notify (G_OBJECT (table), "n-rows");
527 }
528
529 if (n_cols != table->ncols)
530 {
531 guint i;
532
533 i = table->ncols;
534 table->ncols = n_cols;
535 table->cols = g_realloc (table->cols, table->ncols * sizeof (GtkTableRowCol));
536
537 for (; i < table->ncols; i++)
538 {
539 table->cols[i].requisition = 0;
540 table->cols[i].allocation = 0;
541 table->cols[i].spacing = table->column_spacing;
542 table->cols[i].need_expand = 0;
543 table->cols[i].need_shrink = 0;
544 table->cols[i].expand = 0;
545 table->cols[i].shrink = 0;
546 }
547
548 g_object_notify (G_OBJECT (table), "n-columns");
549 }
550 }
551 }
552
553 void
gtk_table_attach(GtkTable * table,GtkWidget * child,guint left_attach,guint right_attach,guint top_attach,guint bottom_attach,GtkAttachOptions xoptions,GtkAttachOptions yoptions,guint xpadding,guint ypadding)554 gtk_table_attach (GtkTable *table,
555 GtkWidget *child,
556 guint left_attach,
557 guint right_attach,
558 guint top_attach,
559 guint bottom_attach,
560 GtkAttachOptions xoptions,
561 GtkAttachOptions yoptions,
562 guint xpadding,
563 guint ypadding)
564 {
565 GtkTableChild *table_child;
566
567 g_return_if_fail (GTK_IS_TABLE (table));
568 g_return_if_fail (GTK_IS_WIDGET (child));
569 g_return_if_fail (child->parent == NULL);
570
571 /* g_return_if_fail (left_attach >= 0); */
572 g_return_if_fail (left_attach < right_attach);
573 /* g_return_if_fail (top_attach >= 0); */
574 g_return_if_fail (top_attach < bottom_attach);
575
576 if (right_attach >= table->ncols)
577 gtk_table_resize (table, table->nrows, right_attach);
578
579 if (bottom_attach >= table->nrows)
580 gtk_table_resize (table, bottom_attach, table->ncols);
581
582 table_child = g_new (GtkTableChild, 1);
583 table_child->widget = child;
584 table_child->left_attach = left_attach;
585 table_child->right_attach = right_attach;
586 table_child->top_attach = top_attach;
587 table_child->bottom_attach = bottom_attach;
588 table_child->xexpand = (xoptions & GTK_EXPAND) != 0;
589 table_child->xshrink = (xoptions & GTK_SHRINK) != 0;
590 table_child->xfill = (xoptions & GTK_FILL) != 0;
591 table_child->xpadding = xpadding;
592 table_child->yexpand = (yoptions & GTK_EXPAND) != 0;
593 table_child->yshrink = (yoptions & GTK_SHRINK) != 0;
594 table_child->yfill = (yoptions & GTK_FILL) != 0;
595 table_child->ypadding = ypadding;
596
597 table->children = g_list_prepend (table->children, table_child);
598
599 gtk_widget_set_parent (child, GTK_WIDGET (table));
600 }
601
602 void
gtk_table_attach_defaults(GtkTable * table,GtkWidget * widget,guint left_attach,guint right_attach,guint top_attach,guint bottom_attach)603 gtk_table_attach_defaults (GtkTable *table,
604 GtkWidget *widget,
605 guint left_attach,
606 guint right_attach,
607 guint top_attach,
608 guint bottom_attach)
609 {
610 gtk_table_attach (table, widget,
611 left_attach, right_attach,
612 top_attach, bottom_attach,
613 GTK_EXPAND | GTK_FILL,
614 GTK_EXPAND | GTK_FILL,
615 0, 0);
616 }
617
618 void
gtk_table_set_row_spacing(GtkTable * table,guint row,guint spacing)619 gtk_table_set_row_spacing (GtkTable *table,
620 guint row,
621 guint spacing)
622 {
623 g_return_if_fail (GTK_IS_TABLE (table));
624 g_return_if_fail (row < table->nrows);
625
626 if (table->rows[row].spacing != spacing)
627 {
628 table->rows[row].spacing = spacing;
629
630 if (gtk_widget_get_visible (GTK_WIDGET (table)))
631 gtk_widget_queue_resize (GTK_WIDGET (table));
632 }
633 }
634
635 /**
636 * gtk_table_get_row_spacing:
637 * @table: a #GtkTable
638 * @row: a row in the table, 0 indicates the first row
639 *
640 * Gets the amount of space between row @row, and
641 * row @row + 1. See gtk_table_set_row_spacing().
642 *
643 * Return value: the row spacing
644 **/
645 guint
gtk_table_get_row_spacing(GtkTable * table,guint row)646 gtk_table_get_row_spacing (GtkTable *table,
647 guint row)
648 {
649 g_return_val_if_fail (GTK_IS_TABLE (table), 0);
650 g_return_val_if_fail (row < table->nrows - 1, 0);
651
652 return table->rows[row].spacing;
653 }
654
655 void
gtk_table_set_col_spacing(GtkTable * table,guint column,guint spacing)656 gtk_table_set_col_spacing (GtkTable *table,
657 guint column,
658 guint spacing)
659 {
660 g_return_if_fail (GTK_IS_TABLE (table));
661 g_return_if_fail (column < table->ncols);
662
663 if (table->cols[column].spacing != spacing)
664 {
665 table->cols[column].spacing = spacing;
666
667 if (gtk_widget_get_visible (GTK_WIDGET (table)))
668 gtk_widget_queue_resize (GTK_WIDGET (table));
669 }
670 }
671
672 /**
673 * gtk_table_get_col_spacing:
674 * @table: a #GtkTable
675 * @column: a column in the table, 0 indicates the first column
676 *
677 * Gets the amount of space between column @col, and
678 * column @col + 1. See gtk_table_set_col_spacing().
679 *
680 * Return value: the column spacing
681 **/
682 guint
gtk_table_get_col_spacing(GtkTable * table,guint column)683 gtk_table_get_col_spacing (GtkTable *table,
684 guint column)
685 {
686 g_return_val_if_fail (GTK_IS_TABLE (table), 0);
687 g_return_val_if_fail (column < table->ncols, 0);
688
689 return table->cols[column].spacing;
690 }
691
692 void
gtk_table_set_row_spacings(GtkTable * table,guint spacing)693 gtk_table_set_row_spacings (GtkTable *table,
694 guint spacing)
695 {
696 guint row;
697
698 g_return_if_fail (GTK_IS_TABLE (table));
699
700 table->row_spacing = spacing;
701 for (row = 0; row < table->nrows; row++)
702 table->rows[row].spacing = spacing;
703
704 if (gtk_widget_get_visible (GTK_WIDGET (table)))
705 gtk_widget_queue_resize (GTK_WIDGET (table));
706
707 g_object_notify (G_OBJECT (table), "row-spacing");
708 }
709
710 /**
711 * gtk_table_get_default_row_spacing:
712 * @table: a #GtkTable
713 *
714 * Gets the default row spacing for the table. This is
715 * the spacing that will be used for newly added rows.
716 * (See gtk_table_set_row_spacings())
717 *
718 * Return value: the default row spacing
719 **/
720 guint
gtk_table_get_default_row_spacing(GtkTable * table)721 gtk_table_get_default_row_spacing (GtkTable *table)
722 {
723 g_return_val_if_fail (GTK_IS_TABLE (table), 0);
724
725 return table->row_spacing;
726 }
727
728 void
gtk_table_set_col_spacings(GtkTable * table,guint spacing)729 gtk_table_set_col_spacings (GtkTable *table,
730 guint spacing)
731 {
732 guint col;
733
734 g_return_if_fail (GTK_IS_TABLE (table));
735
736 table->column_spacing = spacing;
737 for (col = 0; col < table->ncols; col++)
738 table->cols[col].spacing = spacing;
739
740 if (gtk_widget_get_visible (GTK_WIDGET (table)))
741 gtk_widget_queue_resize (GTK_WIDGET (table));
742
743 g_object_notify (G_OBJECT (table), "column-spacing");
744 }
745
746 /**
747 * gtk_table_get_default_col_spacing:
748 * @table: a #GtkTable
749 *
750 * Gets the default column spacing for the table. This is
751 * the spacing that will be used for newly added columns.
752 * (See gtk_table_set_col_spacings())
753 *
754 * Return value: the default column spacing
755 **/
756 guint
gtk_table_get_default_col_spacing(GtkTable * table)757 gtk_table_get_default_col_spacing (GtkTable *table)
758 {
759 g_return_val_if_fail (GTK_IS_TABLE (table), 0);
760
761 return table->column_spacing;
762 }
763
764 void
gtk_table_set_homogeneous(GtkTable * table,gboolean homogeneous)765 gtk_table_set_homogeneous (GtkTable *table,
766 gboolean homogeneous)
767 {
768 g_return_if_fail (GTK_IS_TABLE (table));
769
770 homogeneous = (homogeneous != 0);
771 if (homogeneous != table->homogeneous)
772 {
773 table->homogeneous = homogeneous;
774
775 if (gtk_widget_get_visible (GTK_WIDGET (table)))
776 gtk_widget_queue_resize (GTK_WIDGET (table));
777
778 g_object_notify (G_OBJECT (table), "homogeneous");
779 }
780 }
781
782 /**
783 * gtk_table_get_homogeneous:
784 * @table: a #GtkTable
785 *
786 * Returns whether the table cells are all constrained to the same
787 * width and height. (See gtk_table_set_homogenous ())
788 *
789 * Return value: %TRUE if the cells are all constrained to the same size
790 **/
791 gboolean
gtk_table_get_homogeneous(GtkTable * table)792 gtk_table_get_homogeneous (GtkTable *table)
793 {
794 g_return_val_if_fail (GTK_IS_TABLE (table), FALSE);
795
796 return table->homogeneous;
797 }
798
799 /**
800 * gtk_table_get_size:
801 * @table: a #GtkTable
802 * @rows: (out) (allow-none): return location for the number of
803 * rows, or %NULL
804 * @columns: (out) (allow-none): return location for the number
805 * of columns, or %NULL
806 *
807 * Returns the number of rows and columns in the table.
808 *
809 * Since: 2.22
810 **/
811 void
gtk_table_get_size(GtkTable * table,guint * rows,guint * columns)812 gtk_table_get_size (GtkTable *table,
813 guint *rows,
814 guint *columns)
815 {
816 g_return_if_fail (GTK_IS_TABLE (table));
817
818 if (rows)
819 *rows = table->nrows;
820
821 if (columns)
822 *columns = table->ncols;
823 }
824
825 static void
gtk_table_finalize(GObject * object)826 gtk_table_finalize (GObject *object)
827 {
828 GtkTable *table = GTK_TABLE (object);
829
830 g_free (table->rows);
831 g_free (table->cols);
832
833 G_OBJECT_CLASS (gtk_table_parent_class)->finalize (object);
834 }
835
836 static void
gtk_table_size_request(GtkWidget * widget,GtkRequisition * requisition)837 gtk_table_size_request (GtkWidget *widget,
838 GtkRequisition *requisition)
839 {
840 GtkTable *table = GTK_TABLE (widget);
841 gint row, col;
842
843 requisition->width = 0;
844 requisition->height = 0;
845
846 gtk_table_size_request_init (table);
847 gtk_table_size_request_pass1 (table);
848 gtk_table_size_request_pass2 (table);
849 gtk_table_size_request_pass3 (table);
850 gtk_table_size_request_pass2 (table);
851
852 for (col = 0; col < table->ncols; col++)
853 requisition->width += table->cols[col].requisition;
854 for (col = 0; col + 1 < table->ncols; col++)
855 requisition->width += table->cols[col].spacing;
856
857 for (row = 0; row < table->nrows; row++)
858 requisition->height += table->rows[row].requisition;
859 for (row = 0; row + 1 < table->nrows; row++)
860 requisition->height += table->rows[row].spacing;
861
862 requisition->width += GTK_CONTAINER (table)->border_width * 2;
863 requisition->height += GTK_CONTAINER (table)->border_width * 2;
864 }
865
866 static void
gtk_table_size_allocate(GtkWidget * widget,GtkAllocation * allocation)867 gtk_table_size_allocate (GtkWidget *widget,
868 GtkAllocation *allocation)
869 {
870 GtkTable *table = GTK_TABLE (widget);
871
872 widget->allocation = *allocation;
873
874 gtk_table_size_allocate_init (table);
875 gtk_table_size_allocate_pass1 (table);
876 gtk_table_size_allocate_pass2 (table);
877 }
878
879 static void
gtk_table_add(GtkContainer * container,GtkWidget * widget)880 gtk_table_add (GtkContainer *container,
881 GtkWidget *widget)
882 {
883 gtk_table_attach_defaults (GTK_TABLE (container), widget, 0, 1, 0, 1);
884 }
885
886 static void
gtk_table_remove(GtkContainer * container,GtkWidget * widget)887 gtk_table_remove (GtkContainer *container,
888 GtkWidget *widget)
889 {
890 GtkTable *table = GTK_TABLE (container);
891 GtkTableChild *child;
892 GtkWidget *widget_container = GTK_WIDGET (container);
893 GList *children;
894
895 children = table->children;
896
897 while (children)
898 {
899 child = children->data;
900 children = children->next;
901
902 if (child->widget == widget)
903 {
904 gboolean was_visible = gtk_widget_get_visible (widget);
905
906 gtk_widget_unparent (widget);
907
908 table->children = g_list_remove (table->children, child);
909 g_free (child);
910
911 if (was_visible && gtk_widget_get_visible (widget_container))
912 gtk_widget_queue_resize (widget_container);
913 break;
914 }
915 }
916 }
917
918 static void
gtk_table_forall(GtkContainer * container,gboolean include_internals,GtkCallback callback,gpointer callback_data)919 gtk_table_forall (GtkContainer *container,
920 gboolean include_internals,
921 GtkCallback callback,
922 gpointer callback_data)
923 {
924 GtkTable *table = GTK_TABLE (container);
925 GtkTableChild *child;
926 GList *children;
927
928 children = table->children;
929
930 while (children)
931 {
932 child = children->data;
933 children = children->next;
934
935 (* callback) (child->widget, callback_data);
936 }
937 }
938
939 static void
gtk_table_size_request_init(GtkTable * table)940 gtk_table_size_request_init (GtkTable *table)
941 {
942 GtkTableChild *child;
943 GList *children;
944 gint row, col;
945
946 for (row = 0; row < table->nrows; row++)
947 {
948 table->rows[row].requisition = 0;
949 table->rows[row].expand = FALSE;
950 }
951 for (col = 0; col < table->ncols; col++)
952 {
953 table->cols[col].requisition = 0;
954 table->cols[col].expand = FALSE;
955 }
956
957 children = table->children;
958 while (children)
959 {
960 child = children->data;
961 children = children->next;
962
963 if (gtk_widget_get_visible (child->widget))
964 gtk_widget_size_request (child->widget, NULL);
965
966 if (child->left_attach == (child->right_attach - 1) && child->xexpand)
967 table->cols[child->left_attach].expand = TRUE;
968
969 if (child->top_attach == (child->bottom_attach - 1) && child->yexpand)
970 table->rows[child->top_attach].expand = TRUE;
971 }
972 }
973
974 static void
gtk_table_size_request_pass1(GtkTable * table)975 gtk_table_size_request_pass1 (GtkTable *table)
976 {
977 GtkTableChild *child;
978 GList *children;
979 gint width;
980 gint height;
981
982 children = table->children;
983 while (children)
984 {
985 child = children->data;
986 children = children->next;
987
988 if (gtk_widget_get_visible (child->widget))
989 {
990 GtkRequisition child_requisition;
991 gtk_widget_get_child_requisition (child->widget, &child_requisition);
992
993 /* Child spans a single column.
994 */
995 if (child->left_attach == (child->right_attach - 1))
996 {
997 width = child_requisition.width + child->xpadding * 2;
998 table->cols[child->left_attach].requisition = MAX (table->cols[child->left_attach].requisition, width);
999 }
1000
1001 /* Child spans a single row.
1002 */
1003 if (child->top_attach == (child->bottom_attach - 1))
1004 {
1005 height = child_requisition.height + child->ypadding * 2;
1006 table->rows[child->top_attach].requisition = MAX (table->rows[child->top_attach].requisition, height);
1007 }
1008 }
1009 }
1010 }
1011
1012 static void
gtk_table_size_request_pass2(GtkTable * table)1013 gtk_table_size_request_pass2 (GtkTable *table)
1014 {
1015 gint max_width;
1016 gint max_height;
1017 gint row, col;
1018
1019 if (table->homogeneous)
1020 {
1021 max_width = 0;
1022 max_height = 0;
1023
1024 for (col = 0; col < table->ncols; col++)
1025 max_width = MAX (max_width, table->cols[col].requisition);
1026 for (row = 0; row < table->nrows; row++)
1027 max_height = MAX (max_height, table->rows[row].requisition);
1028
1029 for (col = 0; col < table->ncols; col++)
1030 table->cols[col].requisition = max_width;
1031 for (row = 0; row < table->nrows; row++)
1032 table->rows[row].requisition = max_height;
1033 }
1034 }
1035
1036 static void
gtk_table_size_request_pass3(GtkTable * table)1037 gtk_table_size_request_pass3 (GtkTable *table)
1038 {
1039 GtkTableChild *child;
1040 GList *children;
1041 gint width, height;
1042 gint row, col;
1043 gint extra;
1044
1045 children = table->children;
1046 while (children)
1047 {
1048 child = children->data;
1049 children = children->next;
1050
1051 if (gtk_widget_get_visible (child->widget))
1052 {
1053 /* Child spans multiple columns.
1054 */
1055 if (child->left_attach != (child->right_attach - 1))
1056 {
1057 GtkRequisition child_requisition;
1058
1059 gtk_widget_get_child_requisition (child->widget, &child_requisition);
1060
1061 /* Check and see if there is already enough space
1062 * for the child.
1063 */
1064 width = 0;
1065 for (col = child->left_attach; col < child->right_attach; col++)
1066 {
1067 width += table->cols[col].requisition;
1068 if ((col + 1) < child->right_attach)
1069 width += table->cols[col].spacing;
1070 }
1071
1072 /* If we need to request more space for this child to fill
1073 * its requisition, then divide up the needed space amongst the
1074 * columns it spans, favoring expandable columns if any.
1075 */
1076 if (width < child_requisition.width + child->xpadding * 2)
1077 {
1078 gint n_expand = 0;
1079 gboolean force_expand = FALSE;
1080
1081 width = child_requisition.width + child->xpadding * 2 - width;
1082
1083 for (col = child->left_attach; col < child->right_attach; col++)
1084 if (table->cols[col].expand)
1085 n_expand++;
1086
1087 if (n_expand == 0)
1088 {
1089 n_expand = (child->right_attach - child->left_attach);
1090 force_expand = TRUE;
1091 }
1092
1093 for (col = child->left_attach; col < child->right_attach; col++)
1094 if (force_expand || table->cols[col].expand)
1095 {
1096 extra = width / n_expand;
1097 table->cols[col].requisition += extra;
1098 width -= extra;
1099 n_expand--;
1100 }
1101 }
1102 }
1103
1104 /* Child spans multiple rows.
1105 */
1106 if (child->top_attach != (child->bottom_attach - 1))
1107 {
1108 GtkRequisition child_requisition;
1109
1110 gtk_widget_get_child_requisition (child->widget, &child_requisition);
1111
1112 /* Check and see if there is already enough space
1113 * for the child.
1114 */
1115 height = 0;
1116 for (row = child->top_attach; row < child->bottom_attach; row++)
1117 {
1118 height += table->rows[row].requisition;
1119 if ((row + 1) < child->bottom_attach)
1120 height += table->rows[row].spacing;
1121 }
1122
1123 /* If we need to request more space for this child to fill
1124 * its requisition, then divide up the needed space amongst the
1125 * rows it spans, favoring expandable rows if any.
1126 */
1127 if (height < child_requisition.height + child->ypadding * 2)
1128 {
1129 gint n_expand = 0;
1130 gboolean force_expand = FALSE;
1131
1132 height = child_requisition.height + child->ypadding * 2 - height;
1133
1134 for (row = child->top_attach; row < child->bottom_attach; row++)
1135 {
1136 if (table->rows[row].expand)
1137 n_expand++;
1138 }
1139
1140 if (n_expand == 0)
1141 {
1142 n_expand = (child->bottom_attach - child->top_attach);
1143 force_expand = TRUE;
1144 }
1145
1146 for (row = child->top_attach; row < child->bottom_attach; row++)
1147 if (force_expand || table->rows[row].expand)
1148 {
1149 extra = height / n_expand;
1150 table->rows[row].requisition += extra;
1151 height -= extra;
1152 n_expand--;
1153 }
1154 }
1155 }
1156 }
1157 }
1158 }
1159
1160 static void
gtk_table_size_allocate_init(GtkTable * table)1161 gtk_table_size_allocate_init (GtkTable *table)
1162 {
1163 GtkTableChild *child;
1164 GList *children;
1165 gint row, col;
1166 gint has_expand;
1167 gint has_shrink;
1168
1169 /* Initialize the rows and cols.
1170 * By default, rows and cols do not expand and do shrink.
1171 * Those values are modified by the children that occupy
1172 * the rows and cols.
1173 */
1174 for (col = 0; col < table->ncols; col++)
1175 {
1176 table->cols[col].allocation = table->cols[col].requisition;
1177 table->cols[col].need_expand = FALSE;
1178 table->cols[col].need_shrink = TRUE;
1179 table->cols[col].expand = FALSE;
1180 table->cols[col].shrink = TRUE;
1181 table->cols[col].empty = TRUE;
1182 }
1183 for (row = 0; row < table->nrows; row++)
1184 {
1185 table->rows[row].allocation = table->rows[row].requisition;
1186 table->rows[row].need_expand = FALSE;
1187 table->rows[row].need_shrink = TRUE;
1188 table->rows[row].expand = FALSE;
1189 table->rows[row].shrink = TRUE;
1190 table->rows[row].empty = TRUE;
1191 }
1192
1193 /* Loop over all the children and adjust the row and col values
1194 * based on whether the children want to be allowed to expand
1195 * or shrink. This loop handles children that occupy a single
1196 * row or column.
1197 */
1198 children = table->children;
1199 while (children)
1200 {
1201 child = children->data;
1202 children = children->next;
1203
1204 if (gtk_widget_get_visible (child->widget))
1205 {
1206 if (child->left_attach == (child->right_attach - 1))
1207 {
1208 if (child->xexpand)
1209 table->cols[child->left_attach].expand = TRUE;
1210
1211 if (!child->xshrink)
1212 table->cols[child->left_attach].shrink = FALSE;
1213
1214 table->cols[child->left_attach].empty = FALSE;
1215 }
1216
1217 if (child->top_attach == (child->bottom_attach - 1))
1218 {
1219 if (child->yexpand)
1220 table->rows[child->top_attach].expand = TRUE;
1221
1222 if (!child->yshrink)
1223 table->rows[child->top_attach].shrink = FALSE;
1224
1225 table->rows[child->top_attach].empty = FALSE;
1226 }
1227 }
1228 }
1229
1230 /* Loop over all the children again and this time handle children
1231 * which span multiple rows or columns.
1232 */
1233 children = table->children;
1234 while (children)
1235 {
1236 child = children->data;
1237 children = children->next;
1238
1239 if (gtk_widget_get_visible (child->widget))
1240 {
1241 if (child->left_attach != (child->right_attach - 1))
1242 {
1243 for (col = child->left_attach; col < child->right_attach; col++)
1244 table->cols[col].empty = FALSE;
1245
1246 if (child->xexpand)
1247 {
1248 has_expand = FALSE;
1249 for (col = child->left_attach; col < child->right_attach; col++)
1250 if (table->cols[col].expand)
1251 {
1252 has_expand = TRUE;
1253 break;
1254 }
1255
1256 if (!has_expand)
1257 for (col = child->left_attach; col < child->right_attach; col++)
1258 table->cols[col].need_expand = TRUE;
1259 }
1260
1261 if (!child->xshrink)
1262 {
1263 has_shrink = TRUE;
1264 for (col = child->left_attach; col < child->right_attach; col++)
1265 if (!table->cols[col].shrink)
1266 {
1267 has_shrink = FALSE;
1268 break;
1269 }
1270
1271 if (has_shrink)
1272 for (col = child->left_attach; col < child->right_attach; col++)
1273 table->cols[col].need_shrink = FALSE;
1274 }
1275 }
1276
1277 if (child->top_attach != (child->bottom_attach - 1))
1278 {
1279 for (row = child->top_attach; row < child->bottom_attach; row++)
1280 table->rows[row].empty = FALSE;
1281
1282 if (child->yexpand)
1283 {
1284 has_expand = FALSE;
1285 for (row = child->top_attach; row < child->bottom_attach; row++)
1286 if (table->rows[row].expand)
1287 {
1288 has_expand = TRUE;
1289 break;
1290 }
1291
1292 if (!has_expand)
1293 for (row = child->top_attach; row < child->bottom_attach; row++)
1294 table->rows[row].need_expand = TRUE;
1295 }
1296
1297 if (!child->yshrink)
1298 {
1299 has_shrink = TRUE;
1300 for (row = child->top_attach; row < child->bottom_attach; row++)
1301 if (!table->rows[row].shrink)
1302 {
1303 has_shrink = FALSE;
1304 break;
1305 }
1306
1307 if (has_shrink)
1308 for (row = child->top_attach; row < child->bottom_attach; row++)
1309 table->rows[row].need_shrink = FALSE;
1310 }
1311 }
1312 }
1313 }
1314
1315 /* Loop over the columns and set the expand and shrink values
1316 * if the column can be expanded or shrunk.
1317 */
1318 for (col = 0; col < table->ncols; col++)
1319 {
1320 if (table->cols[col].empty)
1321 {
1322 table->cols[col].expand = FALSE;
1323 table->cols[col].shrink = FALSE;
1324 }
1325 else
1326 {
1327 if (table->cols[col].need_expand)
1328 table->cols[col].expand = TRUE;
1329 if (!table->cols[col].need_shrink)
1330 table->cols[col].shrink = FALSE;
1331 }
1332 }
1333
1334 /* Loop over the rows and set the expand and shrink values
1335 * if the row can be expanded or shrunk.
1336 */
1337 for (row = 0; row < table->nrows; row++)
1338 {
1339 if (table->rows[row].empty)
1340 {
1341 table->rows[row].expand = FALSE;
1342 table->rows[row].shrink = FALSE;
1343 }
1344 else
1345 {
1346 if (table->rows[row].need_expand)
1347 table->rows[row].expand = TRUE;
1348 if (!table->rows[row].need_shrink)
1349 table->rows[row].shrink = FALSE;
1350 }
1351 }
1352 }
1353
1354 static void
gtk_table_size_allocate_pass1(GtkTable * table)1355 gtk_table_size_allocate_pass1 (GtkTable *table)
1356 {
1357 gint real_width;
1358 gint real_height;
1359 gint width, height;
1360 gint row, col;
1361 gint nexpand;
1362 gint nshrink;
1363 gint extra;
1364
1365 /* If we were allocated more space than we requested
1366 * then we have to expand any expandable rows and columns
1367 * to fill in the extra space.
1368 */
1369
1370 real_width = GTK_WIDGET (table)->allocation.width - GTK_CONTAINER (table)->border_width * 2;
1371 real_height = GTK_WIDGET (table)->allocation.height - GTK_CONTAINER (table)->border_width * 2;
1372
1373 if (table->homogeneous)
1374 {
1375 if (!table->children)
1376 nexpand = 1;
1377 else
1378 {
1379 nexpand = 0;
1380 for (col = 0; col < table->ncols; col++)
1381 if (table->cols[col].expand)
1382 {
1383 nexpand += 1;
1384 break;
1385 }
1386 }
1387 if (nexpand)
1388 {
1389 width = real_width;
1390 for (col = 0; col + 1 < table->ncols; col++)
1391 width -= table->cols[col].spacing;
1392
1393 for (col = 0; col < table->ncols; col++)
1394 {
1395 extra = width / (table->ncols - col);
1396 table->cols[col].allocation = MAX (1, extra);
1397 width -= extra;
1398 }
1399 }
1400 }
1401 else
1402 {
1403 width = 0;
1404 nexpand = 0;
1405 nshrink = 0;
1406
1407 for (col = 0; col < table->ncols; col++)
1408 {
1409 width += table->cols[col].requisition;
1410 if (table->cols[col].expand)
1411 nexpand += 1;
1412 if (table->cols[col].shrink)
1413 nshrink += 1;
1414 }
1415 for (col = 0; col + 1 < table->ncols; col++)
1416 width += table->cols[col].spacing;
1417
1418 /* Check to see if we were allocated more width than we requested.
1419 */
1420 if ((width < real_width) && (nexpand >= 1))
1421 {
1422 width = real_width - width;
1423
1424 for (col = 0; col < table->ncols; col++)
1425 if (table->cols[col].expand)
1426 {
1427 extra = width / nexpand;
1428 table->cols[col].allocation += extra;
1429
1430 width -= extra;
1431 nexpand -= 1;
1432 }
1433 }
1434
1435 /* Check to see if we were allocated less width than we requested,
1436 * then shrink until we fit the size give.
1437 */
1438 if (width > real_width)
1439 {
1440 gint total_nshrink = nshrink;
1441
1442 extra = width - real_width;
1443 while (total_nshrink > 0 && extra > 0)
1444 {
1445 nshrink = total_nshrink;
1446 for (col = 0; col < table->ncols; col++)
1447 if (table->cols[col].shrink)
1448 {
1449 gint allocation = table->cols[col].allocation;
1450
1451 table->cols[col].allocation = MAX (1, (gint) table->cols[col].allocation - extra / nshrink);
1452 extra -= allocation - table->cols[col].allocation;
1453 nshrink -= 1;
1454 if (table->cols[col].allocation < 2)
1455 {
1456 total_nshrink -= 1;
1457 table->cols[col].shrink = FALSE;
1458 }
1459 }
1460 }
1461 }
1462 }
1463
1464 if (table->homogeneous)
1465 {
1466 if (!table->children)
1467 nexpand = 1;
1468 else
1469 {
1470 nexpand = 0;
1471 for (row = 0; row < table->nrows; row++)
1472 if (table->rows[row].expand)
1473 {
1474 nexpand += 1;
1475 break;
1476 }
1477 }
1478 if (nexpand)
1479 {
1480 height = real_height;
1481
1482 for (row = 0; row + 1 < table->nrows; row++)
1483 height -= table->rows[row].spacing;
1484
1485
1486 for (row = 0; row < table->nrows; row++)
1487 {
1488 extra = height / (table->nrows - row);
1489 table->rows[row].allocation = MAX (1, extra);
1490 height -= extra;
1491 }
1492 }
1493 }
1494 else
1495 {
1496 height = 0;
1497 nexpand = 0;
1498 nshrink = 0;
1499
1500 for (row = 0; row < table->nrows; row++)
1501 {
1502 height += table->rows[row].requisition;
1503 if (table->rows[row].expand)
1504 nexpand += 1;
1505 if (table->rows[row].shrink)
1506 nshrink += 1;
1507 }
1508 for (row = 0; row + 1 < table->nrows; row++)
1509 height += table->rows[row].spacing;
1510
1511 /* Check to see if we were allocated more height than we requested.
1512 */
1513 if ((height < real_height) && (nexpand >= 1))
1514 {
1515 height = real_height - height;
1516
1517 for (row = 0; row < table->nrows; row++)
1518 if (table->rows[row].expand)
1519 {
1520 extra = height / nexpand;
1521 table->rows[row].allocation += extra;
1522
1523 height -= extra;
1524 nexpand -= 1;
1525 }
1526 }
1527
1528 /* Check to see if we were allocated less height than we requested.
1529 * then shrink until we fit the size give.
1530 */
1531 if (height > real_height)
1532 {
1533 gint total_nshrink = nshrink;
1534
1535 extra = height - real_height;
1536 while (total_nshrink > 0 && extra > 0)
1537 {
1538 nshrink = total_nshrink;
1539 for (row = 0; row < table->nrows; row++)
1540 if (table->rows[row].shrink)
1541 {
1542 gint allocation = table->rows[row].allocation;
1543
1544 table->rows[row].allocation = MAX (1, (gint) table->rows[row].allocation - extra / nshrink);
1545 extra -= allocation - table->rows[row].allocation;
1546 nshrink -= 1;
1547 if (table->rows[row].allocation < 2)
1548 {
1549 total_nshrink -= 1;
1550 table->rows[row].shrink = FALSE;
1551 }
1552 }
1553 }
1554 }
1555 }
1556 }
1557
1558 static void
gtk_table_size_allocate_pass2(GtkTable * table)1559 gtk_table_size_allocate_pass2 (GtkTable *table)
1560 {
1561 GtkTableChild *child;
1562 GList *children;
1563 gint max_width;
1564 gint max_height;
1565 gint x, y;
1566 gint row, col;
1567 GtkAllocation allocation;
1568 GtkWidget *widget = GTK_WIDGET (table);
1569
1570 children = table->children;
1571 while (children)
1572 {
1573 child = children->data;
1574 children = children->next;
1575
1576 if (gtk_widget_get_visible (child->widget))
1577 {
1578 GtkRequisition child_requisition;
1579 gtk_widget_get_child_requisition (child->widget, &child_requisition);
1580
1581 x = GTK_WIDGET (table)->allocation.x + GTK_CONTAINER (table)->border_width;
1582 y = GTK_WIDGET (table)->allocation.y + GTK_CONTAINER (table)->border_width;
1583 max_width = 0;
1584 max_height = 0;
1585
1586 for (col = 0; col < child->left_attach; col++)
1587 {
1588 x += table->cols[col].allocation;
1589 x += table->cols[col].spacing;
1590 }
1591
1592 for (col = child->left_attach; col < child->right_attach; col++)
1593 {
1594 max_width += table->cols[col].allocation;
1595 if ((col + 1) < child->right_attach)
1596 max_width += table->cols[col].spacing;
1597 }
1598
1599 for (row = 0; row < child->top_attach; row++)
1600 {
1601 y += table->rows[row].allocation;
1602 y += table->rows[row].spacing;
1603 }
1604
1605 for (row = child->top_attach; row < child->bottom_attach; row++)
1606 {
1607 max_height += table->rows[row].allocation;
1608 if ((row + 1) < child->bottom_attach)
1609 max_height += table->rows[row].spacing;
1610 }
1611
1612 if (child->xfill)
1613 {
1614 allocation.width = MAX (1, max_width - (gint)child->xpadding * 2);
1615 allocation.x = x + (max_width - allocation.width) / 2;
1616 }
1617 else
1618 {
1619 allocation.width = child_requisition.width;
1620 allocation.x = x + (max_width - allocation.width) / 2;
1621 }
1622
1623 if (child->yfill)
1624 {
1625 allocation.height = MAX (1, max_height - (gint)child->ypadding * 2);
1626 allocation.y = y + (max_height - allocation.height) / 2;
1627 }
1628 else
1629 {
1630 allocation.height = child_requisition.height;
1631 allocation.y = y + (max_height - allocation.height) / 2;
1632 }
1633
1634 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1635 allocation.x = widget->allocation.x + widget->allocation.width
1636 - (allocation.x - widget->allocation.x) - allocation.width;
1637
1638 gtk_widget_size_allocate (child->widget, &allocation);
1639 }
1640 }
1641 }
1642
1643 #define __GTK_TABLE_C__
1644 #include "gtkaliasdef.c"
1645