2
* GooCanvas. Copyright (C) 2005-6 Damon Chaplin.
3
* Released under the GNU LGPL license. See COPYING for details.
5
* goocanvastable.c - table item.
9
* SECTION:goocanvastable
10
* @Title: GooCanvasTable
11
* @Short_Description: a table container to layout items.
13
* #GooCanvasTable is a table container used to lay out other canvas items.
14
* It is used in a similar way to how the GtkTable widget is used to lay out
17
* Items are added to the table using the normal methods, then
18
* goo_canvas_item_set_child_properties() is used to specify how each child
19
* item is to be positioned within the table (i.e. which row and column it is
20
* in, how much padding it should have and whether it should expand or
23
* #GooCanvasTable is a subclass of #GooCanvasItemSimple and so
24
* inherits all of the style properties such as "stroke-color", "fill-color"
25
* and "line-width". Setting a style property on a #GooCanvasTable will affect
26
* all children of the #GooCanvasTable (unless the children override the
29
* #GooCanvasTable implements the #GooCanvasItem interface, so you can use
30
* the #GooCanvasItem functions such as goo_canvas_item_raise() and
31
* goo_canvas_item_rotate(), and the properties such as "visibility" and
34
* To create a #GooCanvasTable use goo_canvas_table_new().
36
* To get or set the properties of an existing #GooCanvasTable, use
37
* g_object_get() and g_object_set().
41
#include <glib/gi18n-lib.h>
43
#include "goocanvastable.h"
44
#include "goocanvas.h"
54
PROP_HOMOGENEOUS_ROWS,
55
PROP_HOMOGENEOUS_COLUMNS
61
CHILD_PROP_LEFT_PADDING,
62
CHILD_PROP_RIGHT_PADDING,
63
CHILD_PROP_TOP_PADDING,
64
CHILD_PROP_BOTTOM_PADDING,
84
GOO_CANVAS_TABLE_CHILD_EXPAND = 1 << 0,
85
GOO_CANVAS_TABLE_CHILD_FILL = 1 << 1,
86
GOO_CANVAS_TABLE_CHILD_SHRINK = 1 << 2
87
} GooCanvasTableChildFlags;
89
typedef struct _GooCanvasTableChild GooCanvasTableChild;
90
struct _GooCanvasTableChild
93
gdouble start_pad[2], end_pad[2];
95
guint16 start[2], size[2];
96
guint8 flags[2]; /* GooCanvasTableChildFlags. */
99
typedef struct _GooCanvasTableDimensionLayoutData GooCanvasTableDimensionLayoutData;
100
struct _GooCanvasTableDimensionLayoutData
107
guint need_expand : 1;
108
guint need_shrink : 1;
114
typedef struct _GooCanvasTableChildLayoutData GooCanvasTableChildLayoutData;
115
struct _GooCanvasTableChildLayoutData
117
gdouble requested_position[2];
118
gdouble requested_size[2];
121
struct _GooCanvasTableLayoutData
123
GooCanvasTableDimensionLayoutData *dldata[2];
124
GooCanvasTableChildLayoutData *children;
126
/* These are in the table's coordinate space. */
127
gdouble requested_size[2];
128
gdouble allocated_size[2];
133
static void item_interface_init (GooCanvasItemIface *iface);
134
static void goo_canvas_table_finalize (GObject *object);
135
static void goo_canvas_table_get_property (GObject *object,
139
static void goo_canvas_table_set_property (GObject *object,
144
static void goo_canvas_table_free_layout_data (GooCanvasTableData *table_data);
146
G_DEFINE_TYPE_WITH_CODE (GooCanvasTable, goo_canvas_table,
147
GOO_TYPE_CANVAS_GROUP,
148
G_IMPLEMENT_INTERFACE (GOO_TYPE_CANVAS_ITEM,
149
item_interface_init))
151
typedef void (*InstallChildPropertyFunc) (GObjectClass*, guint, GParamSpec*);
154
goo_canvas_table_install_common_properties (GObjectClass *gobject_class,
155
InstallChildPropertyFunc install_child_property)
157
g_object_class_install_property (gobject_class, PROP_WIDTH,
158
g_param_spec_double ("width",
160
_("The requested width of the table, or -1 to use the default width"),
164
g_object_class_install_property (gobject_class, PROP_HEIGHT,
165
g_param_spec_double ("height",
167
_("The requested height of the table, or -1 to use the default height"),
172
/* FIXME: Support setting individual row/col spacing. */
173
g_object_class_install_property (gobject_class, PROP_ROW_SPACING,
174
g_param_spec_double ("row-spacing",
176
_("The default space between rows"),
177
0.0, G_MAXDOUBLE, 0.0,
180
g_object_class_install_property (gobject_class, PROP_COLUMN_SPACING,
181
g_param_spec_double ("column-spacing",
183
_("The default space between columns"),
184
0.0, G_MAXDOUBLE, 0.0,
187
g_object_class_install_property (gobject_class, PROP_HOMOGENEOUS_ROWS,
188
g_param_spec_boolean ("homogeneous-rows",
189
_("Homogenous Rows"),
190
_("If all rows are the same height"),
194
g_object_class_install_property (gobject_class, PROP_HOMOGENEOUS_COLUMNS,
195
g_param_spec_boolean ("homogeneous-columns",
196
_("Homogenous Columns"),
197
_("If all columns are the same width"),
204
install_child_property (gobject_class, CHILD_PROP_LEFT_PADDING,
205
g_param_spec_double ("left-padding",
207
_("Extra space to add to the left of the item"),
208
0.0, G_MAXDOUBLE, 0.0,
210
install_child_property (gobject_class, CHILD_PROP_RIGHT_PADDING,
211
g_param_spec_double ("right-padding",
213
_("Extra space to add to the right of the item"),
214
0.0, G_MAXDOUBLE, 0.0,
216
install_child_property (gobject_class, CHILD_PROP_TOP_PADDING,
217
g_param_spec_double ("top-padding",
219
_("Extra space to add above the item"),
220
0.0, G_MAXDOUBLE, 0.0,
222
install_child_property (gobject_class, CHILD_PROP_BOTTOM_PADDING,
223
g_param_spec_double ("bottom-padding",
225
_("Extra space to add below the item"),
226
0.0, G_MAXDOUBLE, 0.0,
229
install_child_property (gobject_class, CHILD_PROP_X_ALIGN,
230
g_param_spec_double ("x-align",
232
_("The horizontal position of the item within its allocated space. 0.0 is left-aligned, 1.0 is right-aligned"),
235
install_child_property (gobject_class, CHILD_PROP_Y_ALIGN,
236
g_param_spec_double ("y-align",
238
_("The vertical position of the item within its allocated space. 0.0 is top-aligned, 1.0 is bottom-aligned"),
242
install_child_property (gobject_class, CHILD_PROP_ROW,
243
g_param_spec_uint ("row",
245
_("The row to place the item in"),
248
install_child_property (gobject_class, CHILD_PROP_COLUMN,
249
g_param_spec_uint ("column",
251
_("The column to place the item in"),
254
install_child_property (gobject_class, CHILD_PROP_ROWS,
255
g_param_spec_uint ("rows",
257
_("The number of rows that the item spans"),
260
install_child_property (gobject_class, CHILD_PROP_COLUMNS,
261
g_param_spec_uint ("columns",
263
_("The number of columns that the item spans"),
267
install_child_property (gobject_class, CHILD_PROP_X_EXPAND,
268
g_param_spec_boolean ("x-expand",
270
_("If the item expands horizontally as the table expands"),
273
install_child_property (gobject_class, CHILD_PROP_X_FILL,
274
g_param_spec_boolean ("x-fill",
276
_("If the item fills all horizontal allocated space"),
279
install_child_property (gobject_class, CHILD_PROP_X_SHRINK,
280
g_param_spec_boolean ("x-shrink",
282
_("If the item can shrink smaller than its requested size horizontally"),
285
install_child_property (gobject_class, CHILD_PROP_Y_EXPAND,
286
g_param_spec_boolean ("y-expand",
288
_("If the item expands vertically as the table expands"),
291
install_child_property (gobject_class, CHILD_PROP_Y_FILL,
292
g_param_spec_boolean ("y-fill",
294
_("If the item fills all vertical allocated space"),
297
install_child_property (gobject_class, CHILD_PROP_Y_SHRINK,
298
g_param_spec_boolean ("y-shrink",
300
_("If the item can shrink smaller than its requested size vertically"),
307
goo_canvas_table_class_init (GooCanvasTableClass *klass)
309
GObjectClass *gobject_class = (GObjectClass*) klass;
311
gobject_class->finalize = goo_canvas_table_finalize;
312
gobject_class->get_property = goo_canvas_table_get_property;
313
gobject_class->set_property = goo_canvas_table_set_property;
315
goo_canvas_table_install_common_properties (gobject_class, goo_canvas_item_class_install_child_property);
319
/* This frees the contents of the table data, but not the struct itself. */
321
goo_canvas_table_init_data (GooCanvasTableData *table_data)
325
table_data->width = -1.0;
326
table_data->height = -1.0;
328
for (d = 0; d < 2; d++)
330
table_data->dimensions[d].size = 0;
331
table_data->dimensions[d].default_spacing = 0.0;
332
table_data->dimensions[d].spacings = NULL;
333
table_data->dimensions[d].homogeneous = FALSE;
336
table_data->border_width = 0.0;
338
table_data->children = g_array_new (0, 0, sizeof (GooCanvasTableChild));
342
/* This frees the contents of the table data, but not the struct itself. */
344
goo_canvas_table_free_data (GooCanvasTableData *table_data)
348
g_array_free (table_data->children, TRUE);
350
for (d = 0; d < 2; d++)
352
g_free (table_data->dimensions[d].spacings);
353
table_data->dimensions[d].spacings = NULL;
356
goo_canvas_table_free_layout_data (table_data);
361
goo_canvas_table_init (GooCanvasTable *table)
363
table->table_data = g_slice_new0 (GooCanvasTableData);
364
goo_canvas_table_init_data (table->table_data);
369
* goo_canvas_table_new:
370
* @parent: the parent item, or %NULL. If a parent is specified, it will assume
371
* ownership of the item, and the item will automatically be freed when it is
372
* removed from the parent. Otherwise call g_object_unref() to free it.
373
* @...: optional pairs of property names and values, and a terminating %NULL.
375
* Creates a new table item.
379
* Here's an example showing how to create a table with a square, a circle and
382
* <informalexample><programlisting>
383
* GooCanvasItem *table, *square, *circle, *triangle;
385
* table = goo_canvas_table_new (root,
386
* "row-spacing", 4.0,
387
* "column-spacing", 4.0,
389
* goo_canvas_item_translate (table, 400, 200);
391
* square = goo_canvas_rect_new (table, 0.0, 0.0, 50.0, 50.0,
392
* "fill-color", "red",
394
* goo_canvas_item_set_child_properties (table, square,
399
* circle = goo_canvas_ellipse_new (table, 0.0, 0.0, 25.0, 25.0,
400
* "fill-color", "blue",
402
* goo_canvas_item_set_child_properties (table, circle,
407
* triangle = goo_canvas_polyline_new (table, TRUE, 3,
408
* 25.0, 0.0, 0.0, 50.0, 50.0, 50.0,
409
* "fill-color", "yellow",
411
* goo_canvas_item_set_child_properties (table, triangle,
415
* </programlisting></informalexample>
417
* Returns: a new table item.
420
goo_canvas_table_new (GooCanvasItem *parent,
425
const char *first_property;
427
item = g_object_new (GOO_TYPE_CANVAS_TABLE, NULL);
429
va_start (var_args, parent);
430
first_property = va_arg (var_args, char*);
432
g_object_set_valist (G_OBJECT (item), first_property, var_args);
437
goo_canvas_item_add_child (parent, item, -1);
438
g_object_unref (item);
446
goo_canvas_table_finalize (GObject *object)
448
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
449
GooCanvasTable *table = (GooCanvasTable*) object;
453
goo_canvas_table_free_data (table->table_data);
454
g_slice_free (GooCanvasTableData, table->table_data);
456
table->table_data = NULL;
458
G_OBJECT_CLASS (goo_canvas_table_parent_class)->finalize (object);
463
goo_canvas_table_get_common_property (GObject *object,
464
GooCanvasTableData *table_data,
472
g_value_set_double (value, table_data->width);
475
g_value_set_double (value, table_data->height);
477
case PROP_ROW_SPACING:
478
g_value_set_double (value, table_data->dimensions[VERT].default_spacing);
480
case PROP_COLUMN_SPACING:
481
g_value_set_double (value, table_data->dimensions[HORZ].default_spacing);
483
case PROP_HOMOGENEOUS_ROWS:
484
g_value_set_boolean (value, table_data->dimensions[VERT].homogeneous);
486
case PROP_HOMOGENEOUS_COLUMNS:
487
g_value_set_boolean (value, table_data->dimensions[HORZ].homogeneous);
490
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
497
goo_canvas_table_get_property (GObject *object,
502
GooCanvasTable *table = (GooCanvasTable*) object;
504
goo_canvas_table_get_common_property (object, table->table_data,
505
prop_id, value, pspec);
510
goo_canvas_table_set_common_property (GObject *object,
511
GooCanvasTableData *table_data,
516
gboolean recompute_bounds = TRUE;
521
table_data->width = g_value_get_double (value);
524
table_data->height = g_value_get_double (value);
526
case PROP_ROW_SPACING:
527
table_data->dimensions[VERT].default_spacing = g_value_get_double (value);
529
case PROP_COLUMN_SPACING:
530
table_data->dimensions[HORZ].default_spacing = g_value_get_double (value);
532
case PROP_HOMOGENEOUS_ROWS:
533
table_data->dimensions[VERT].homogeneous = g_value_get_boolean (value);
535
case PROP_HOMOGENEOUS_COLUMNS:
536
table_data->dimensions[HORZ].homogeneous = g_value_get_boolean (value);
539
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
543
return recompute_bounds;
548
goo_canvas_table_set_property (GObject *object,
553
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
554
GooCanvasTable *table = (GooCanvasTable*) object;
555
gboolean recompute_bounds;
559
g_warning ("Can't set property of a canvas item with a model - set the model property instead");
563
recompute_bounds = goo_canvas_table_set_common_property (object,
567
goo_canvas_item_simple_changed (simple, recompute_bounds);
572
goo_canvas_table_update_dimensions (GooCanvasTableData *table_data,
573
GooCanvasTableChild *table_child)
577
for (d = 0; d < 2; d++)
579
size = table_child->start[d] + table_child->size[d];
581
if (size > table_data->dimensions[d].size)
583
table_data->dimensions[d].spacings = g_realloc (table_data->dimensions[d].spacings, size * sizeof (gdouble));
585
/* Initialize new spacings to -1.0 so the default is used. */
586
for (i = table_data->dimensions[d].size; i < size; i++)
587
table_data->dimensions[d].spacings[i] = -1.0;
589
table_data->dimensions[d].size = size;
596
goo_canvas_table_add_child_internal (GooCanvasTableData *table_data,
599
GooCanvasTableChild table_child;
602
/* Initialize a table child struct. */
603
for (d = 0; d < 2; d++)
605
table_child.start_pad[d] = 0.0;
606
table_child.end_pad[d] = 0.0;
607
table_child.align[d] = 0.5;
608
table_child.start[d] = 0;
609
table_child.size[d] = 1;
611
/* Unlike GtkTable our children do not expand & fill by default,
612
as that makes more sense with the builtin simple items. */
613
table_child.flags[d] = 0;
617
position = table_data->children->len;
618
g_array_insert_val (table_data->children, position, table_child);
620
goo_canvas_table_update_dimensions (table_data, &table_child);
625
goo_canvas_table_add_child (GooCanvasItem *item,
626
GooCanvasItem *child,
629
GooCanvasItemIface *iface = GOO_CANVAS_ITEM_GET_IFACE (item);
630
GooCanvasItemIface *parent_iface = g_type_interface_peek_parent (iface);
631
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
632
GooCanvasTable *table = (GooCanvasTable*) item;
635
goo_canvas_table_add_child_internal (table->table_data, position);
637
/* Let the parent GooCanvasGroup code do the rest. */
638
parent_iface->add_child (item, child, position);
643
goo_canvas_table_move_child_internal (GooCanvasTableData *table_data,
647
GooCanvasTableChild *table_child, tmp_child;
649
/* Copy the child temporarily. */
650
table_child = &g_array_index (table_data->children, GooCanvasTableChild,
652
tmp_child = *table_child;
654
/* Move the array data up or down. */
655
if (new_position > old_position)
657
/* Move the items down one place. */
658
g_memmove (table_child,
659
&g_array_index (table_data->children, GooCanvasTableChild,
661
sizeof (GooCanvasTableChild) * (new_position - old_position));
665
/* Move the items up one place. */
666
g_memmove (&g_array_index (table_data->children, GooCanvasTableChild,
668
&g_array_index (table_data->children, GooCanvasTableChild,
670
sizeof (GooCanvasTableChild) * (old_position - new_position));
673
/* Copy the child into its new position. */
674
table_child = &g_array_index (table_data->children, GooCanvasTableChild,
676
*table_child = tmp_child;
681
goo_canvas_table_move_child (GooCanvasItem *item,
685
GooCanvasItemIface *iface = GOO_CANVAS_ITEM_GET_IFACE (item);
686
GooCanvasItemIface *parent_iface = g_type_interface_peek_parent (iface);
687
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
688
GooCanvasTable *table = (GooCanvasTable*) item;
691
goo_canvas_table_move_child_internal (table->table_data, old_position,
694
/* Let the parent GooCanvasGroup code do the rest. */
695
parent_iface->move_child (item, old_position, new_position);
700
goo_canvas_table_remove_child (GooCanvasItem *item,
703
GooCanvasItemIface *iface = GOO_CANVAS_ITEM_GET_IFACE (item);
704
GooCanvasItemIface *parent_iface = g_type_interface_peek_parent (iface);
705
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
706
GooCanvasTable *table = (GooCanvasTable*) item;
709
g_array_remove_index (table->table_data->children, child_num);
711
/* Let the parent GooCanvasGroup code do the rest. */
712
parent_iface->remove_child (item, child_num);
717
goo_canvas_table_get_common_child_property (GObject *object,
718
GooCanvasTableChild *table_child,
725
case CHILD_PROP_LEFT_PADDING:
726
g_value_set_double (value, table_child->start_pad[HORZ]);
728
case CHILD_PROP_RIGHT_PADDING:
729
g_value_set_double (value, table_child->end_pad[HORZ]);
731
case CHILD_PROP_TOP_PADDING:
732
g_value_set_double (value, table_child->start_pad[VERT]);
734
case CHILD_PROP_BOTTOM_PADDING:
735
g_value_set_double (value, table_child->end_pad[VERT]);
737
case CHILD_PROP_X_ALIGN:
738
g_value_set_double (value, table_child->align[HORZ]);
740
case CHILD_PROP_Y_ALIGN:
741
g_value_set_double (value, table_child->align[VERT]);
744
g_value_set_uint (value, table_child->start[VERT]);
746
case CHILD_PROP_COLUMN:
747
g_value_set_uint (value, table_child->start[HORZ]);
749
case CHILD_PROP_ROWS:
750
g_value_set_uint (value, table_child->size[VERT]);
752
case CHILD_PROP_COLUMNS:
753
g_value_set_uint (value, table_child->size[HORZ]);
755
case CHILD_PROP_X_EXPAND:
756
g_value_set_boolean (value, table_child->flags[HORZ] & GOO_CANVAS_TABLE_CHILD_EXPAND);
758
case CHILD_PROP_X_FILL:
759
g_value_set_boolean (value, table_child->flags[HORZ] & GOO_CANVAS_TABLE_CHILD_FILL);
761
case CHILD_PROP_X_SHRINK:
762
g_value_set_boolean (value, table_child->flags[HORZ] & GOO_CANVAS_TABLE_CHILD_SHRINK);
764
case CHILD_PROP_Y_EXPAND:
765
g_value_set_boolean (value, table_child->flags[VERT] & GOO_CANVAS_TABLE_CHILD_EXPAND);
767
case CHILD_PROP_Y_FILL:
768
g_value_set_boolean (value, table_child->flags[VERT] & GOO_CANVAS_TABLE_CHILD_FILL);
770
case CHILD_PROP_Y_SHRINK:
771
g_value_set_boolean (value, table_child->flags[VERT] & GOO_CANVAS_TABLE_CHILD_SHRINK);
774
G_OBJECT_WARN_INVALID_PSPEC ((object), "child property id",
775
(property_id), (pspec));
782
goo_canvas_table_get_child_property (GooCanvasItem *item,
783
GooCanvasItem *child,
788
GooCanvasGroup *group = (GooCanvasGroup*) item;
789
GooCanvasTable *table = (GooCanvasTable*) item;
790
GooCanvasTableChild *table_child;
793
for (child_num = 0; child_num < group->items->len; child_num++)
795
if (group->items->pdata[child_num] == child)
797
table_child = &g_array_index (table->table_data->children,
798
GooCanvasTableChild, child_num);
799
goo_canvas_table_get_common_child_property ((GObject*) table,
810
goo_canvas_table_set_common_child_property (GObject *object,
811
GooCanvasTableData *table_data,
812
GooCanvasTableChild *table_child,
819
case CHILD_PROP_LEFT_PADDING:
820
table_child->start_pad[HORZ] = g_value_get_double (value);
822
case CHILD_PROP_RIGHT_PADDING:
823
table_child->end_pad[HORZ] = g_value_get_double (value);
825
case CHILD_PROP_TOP_PADDING:
826
table_child->start_pad[VERT] = g_value_get_double (value);
828
case CHILD_PROP_BOTTOM_PADDING:
829
table_child->end_pad[VERT] = g_value_get_double (value);
831
case CHILD_PROP_X_ALIGN:
832
table_child->align[HORZ] = g_value_get_double (value);
834
case CHILD_PROP_Y_ALIGN:
835
table_child->align[VERT] = g_value_get_double (value);
838
table_child->start[VERT] = g_value_get_uint (value);
840
case CHILD_PROP_COLUMN:
841
table_child->start[HORZ] = g_value_get_uint (value);
843
case CHILD_PROP_ROWS:
844
table_child->size[VERT] = g_value_get_uint (value);
846
case CHILD_PROP_COLUMNS:
847
table_child->size[HORZ] = g_value_get_uint (value);
850
case CHILD_PROP_X_EXPAND:
851
if (g_value_get_boolean (value))
852
table_child->flags[HORZ] |= GOO_CANVAS_TABLE_CHILD_EXPAND;
854
table_child->flags[HORZ] &= ~GOO_CANVAS_TABLE_CHILD_EXPAND;
856
case CHILD_PROP_X_FILL:
857
if (g_value_get_boolean (value))
858
table_child->flags[HORZ] |= GOO_CANVAS_TABLE_CHILD_FILL;
860
table_child->flags[HORZ] &= ~GOO_CANVAS_TABLE_CHILD_FILL;
862
case CHILD_PROP_X_SHRINK:
863
if (g_value_get_boolean (value))
864
table_child->flags[HORZ] |= GOO_CANVAS_TABLE_CHILD_SHRINK;
866
table_child->flags[HORZ] &= ~GOO_CANVAS_TABLE_CHILD_SHRINK;
869
case CHILD_PROP_Y_EXPAND:
870
if (g_value_get_boolean (value))
871
table_child->flags[VERT] |= GOO_CANVAS_TABLE_CHILD_EXPAND;
873
table_child->flags[VERT] &= ~GOO_CANVAS_TABLE_CHILD_EXPAND;
875
case CHILD_PROP_Y_FILL:
876
if (g_value_get_boolean (value))
877
table_child->flags[VERT] |= GOO_CANVAS_TABLE_CHILD_FILL;
879
table_child->flags[VERT] &= ~GOO_CANVAS_TABLE_CHILD_FILL;
881
case CHILD_PROP_Y_SHRINK:
882
if (g_value_get_boolean (value))
883
table_child->flags[VERT] |= GOO_CANVAS_TABLE_CHILD_SHRINK;
885
table_child->flags[VERT] &= ~GOO_CANVAS_TABLE_CHILD_SHRINK;
889
G_OBJECT_WARN_INVALID_PSPEC ((object), "child property id",
890
(property_id), (pspec));
894
goo_canvas_table_update_dimensions (table_data, table_child);
899
goo_canvas_table_set_child_property (GooCanvasItem *item,
900
GooCanvasItem *child,
905
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
906
GooCanvasGroup *group = (GooCanvasGroup*) item;
907
GooCanvasTable *table = (GooCanvasTable*) item;
908
GooCanvasTableChild *table_child;
911
for (child_num = 0; child_num < group->items->len; child_num++)
913
if (group->items->pdata[child_num] == child)
915
table_child = &g_array_index (table->table_data->children,
916
GooCanvasTableChild, child_num);
917
goo_canvas_table_set_common_child_property ((GObject*) table,
926
goo_canvas_item_simple_changed (simple, TRUE);
931
goo_canvas_table_set_model (GooCanvasItem *item,
932
GooCanvasItemModel *model)
934
GooCanvasItemIface *iface = GOO_CANVAS_ITEM_GET_IFACE (item);
935
GooCanvasItemIface *parent_iface = g_type_interface_peek_parent (iface);
936
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
937
GooCanvasTable *table = (GooCanvasTable*) item;
938
GooCanvasTableModel *tmodel = (GooCanvasTableModel*) model;
940
/* If our table_data was allocated, free it. */
943
goo_canvas_table_free_data (table->table_data);
944
g_slice_free (GooCanvasTableData, table->table_data);
947
/* Now use the new model's table_data instead. */
948
table->table_data = &tmodel->table_data;
950
/* Let the parent GooCanvasGroup code do the rest. */
951
parent_iface->set_model (item, model);
956
* Size requisition/allocation code.
960
goo_canvas_table_free_layout_data (GooCanvasTableData *table_data)
962
if (table_data->layout_data)
964
g_free (table_data->layout_data->dldata[HORZ]);
965
g_free (table_data->layout_data->dldata[VERT]);
966
g_free (table_data->layout_data->children);
967
g_slice_free (GooCanvasTableLayoutData, table_data->layout_data);
968
table_data->layout_data = NULL;
973
/* This allocates the layout data, and initializes the row and column data. */
975
goo_canvas_table_init_layout_data (GooCanvasTable *table)
977
GooCanvasTableData *table_data = table->table_data;
978
GooCanvasTableDimension *dimension;
979
GooCanvasTableLayoutData *layout_data;
980
GooCanvasTableDimensionLayoutData *dldata;
983
/* Free any previous data, just in case it hasn't been freed. */
984
goo_canvas_table_free_layout_data (table->table_data);
986
layout_data = g_slice_new (GooCanvasTableLayoutData);
988
table_data->layout_data = layout_data;
989
layout_data->dldata[VERT] = g_new (GooCanvasTableDimensionLayoutData,
990
table_data->dimensions[VERT].size);
991
layout_data->children = g_new (GooCanvasTableChildLayoutData,
992
table_data->children->len);
994
for (d = 0; d < 2; d++)
996
dimension = &table_data->dimensions[d];
998
layout_data->dldata[d] = g_new (GooCanvasTableDimensionLayoutData,
1000
dldata = layout_data->dldata[d];
1002
for (i = 0; i < dimension->size; i++)
1004
/* Calculate the actual spacings. If -ve use the default. */
1005
if (dimension->spacings[i] > 0)
1006
dldata[i].spacing = dimension->spacings[i];
1008
dldata[i].spacing = dimension->default_spacing;
1010
dldata[i].requisition = 0.0;
1011
dldata[i].need_expand = FALSE;
1012
dldata[i].need_shrink = TRUE;
1013
dldata[i].expand = FALSE;
1014
dldata[i].shrink = TRUE;
1015
dldata[i].empty = TRUE;
1021
/* This gets the requested size of all child items, and sets the expand
1022
flag for the row or column for items in a single row or column. */
1024
goo_canvas_table_size_request_init (GooCanvasTable *table,
1027
GooCanvasGroup *group = (GooCanvasGroup*) table;
1028
GooCanvasTableData *table_data = table->table_data;
1029
GooCanvasTableLayoutData *layout_data = table_data->layout_data;
1030
GooCanvasTableDimensionLayoutData *dldata;
1031
GooCanvasTableChild *child;
1032
GooCanvasItem *child_item;
1033
GooCanvasBounds bounds;
1034
gboolean allocate, has_expand, has_shrink;
1035
gint i, j, d, start, end;
1038
for (i = 0; i < table_data->children->len; i++)
1040
child = &g_array_index (table_data->children, GooCanvasTableChild, i);
1041
child_item = group->items->pdata[i];
1043
/* Children will return FALSE if they don't need space allocated. */
1044
allocate = goo_canvas_item_get_requested_area (child_item, cr, &bounds);
1046
layout_data->children[i].requested_position[HORZ] = bounds.x1;
1047
layout_data->children[i].requested_position[VERT] = bounds.y1;
1051
layout_data->children[i].requested_size[HORZ] = -1.0;
1052
layout_data->children[i].requested_size[VERT] = -1.0;
1056
layout_data->children[i].requested_size[HORZ] = bounds.x2 - bounds.x1;
1057
layout_data->children[i].requested_size[VERT] = bounds.y2 - bounds.y1;
1059
for (d = 0; d < 2; d++)
1061
dldata = layout_data->dldata[d];
1062
start = child->start[d];
1063
flags = child->flags[d];
1065
if (child->size[d] == 1)
1067
if (flags & GOO_CANVAS_TABLE_CHILD_EXPAND)
1068
dldata[start].expand = TRUE;
1069
if (!(flags & GOO_CANVAS_TABLE_CHILD_SHRINK))
1070
dldata[start].shrink = FALSE;
1071
dldata[start].empty = FALSE;
1077
for (i = 0; i < table_data->children->len; i++)
1079
child = &g_array_index (table_data->children, GooCanvasTableChild, i);
1081
if (layout_data->children[i].requested_size[HORZ] < 0.0)
1084
for (d = 0; d < 2; d++)
1086
dldata = layout_data->dldata[d];
1087
start = child->start[d];
1088
end = start + child->size[d] - 1;
1089
flags = child->flags[d];
1091
if (child->size[d] != 1)
1096
for (j = start; j <= end; j++)
1098
dldata[j].empty = FALSE;
1099
if (dldata[j].expand)
1101
if (!dldata[j].shrink)
1105
if (!has_expand && (flags & GOO_CANVAS_TABLE_CHILD_EXPAND))
1107
for (j = start; j <= end; j++)
1108
dldata[j].need_expand = TRUE;
1111
if (has_shrink && !(flags & GOO_CANVAS_TABLE_CHILD_SHRINK))
1113
for (j = start; j <= end; j++)
1114
dldata[j].need_shrink = FALSE;
1122
/* This calculates the initial size request for each row & column, which is
1123
the maximum size of all items that are in that row or column. (It skips
1124
items that span more than one row or column.) */
1126
goo_canvas_table_size_request_pass1 (GooCanvasTable *table)
1128
GooCanvasTableData *table_data = table->table_data;
1129
GooCanvasTableLayoutData *layout_data = table_data->layout_data;
1130
GooCanvasTableDimensionLayoutData *rows = layout_data->dldata[VERT];
1131
GooCanvasTableDimensionLayoutData *columns = layout_data->dldata[HORZ];
1132
GooCanvasTableDimensionLayoutData *row, *column;
1133
GooCanvasTableChild *child;
1134
gdouble requested_width, requested_height;
1137
for (i = 0; i < table_data->children->len; i++)
1139
child = &g_array_index (table_data->children, GooCanvasTableChild, i);
1141
requested_width = layout_data->children[i].requested_size[HORZ];
1142
requested_height = layout_data->children[i].requested_size[VERT];
1144
/* Child needs allocation & spans a single row or column. */
1145
if (requested_width >= 0.0 && child->size[HORZ] == 1)
1147
requested_width += child->start_pad[HORZ] + child->end_pad[HORZ];
1148
column = &columns[child->start[HORZ]];
1149
column->requisition = MAX (column->requisition, requested_width);
1152
if (requested_height >= 0.0 && child->size[VERT] == 1)
1154
requested_height += child->start_pad[VERT] + child->end_pad[VERT];
1155
row = &rows[child->start[VERT]];
1156
row->requisition = MAX (row->requisition, requested_height);
1162
/* This ensures that homogeneous tables have all rows/columns the same size. */
1164
goo_canvas_table_size_request_pass2 (GooCanvasTable *table)
1166
GooCanvasTableData *table_data = table->table_data;
1167
GooCanvasTableLayoutData *layout_data = table_data->layout_data;
1168
GooCanvasTableDimensionLayoutData *rows = layout_data->dldata[VERT];
1169
GooCanvasTableDimensionLayoutData *columns = layout_data->dldata[HORZ];
1170
gdouble max_width = 0.0, max_height = 0.0;
1173
if (table_data->dimensions[VERT].homogeneous)
1175
/* Calculate the max height and use that for all rows. */
1176
for (row = 0; row < table_data->dimensions[VERT].size; row++)
1177
max_height = MAX (max_height, rows[row].requisition);
1178
for (row = 0; row < table_data->dimensions[VERT].size; row++)
1179
rows[row].requisition = max_height;
1182
if (table_data->dimensions[HORZ].homogeneous)
1184
/* Calculate the max width and use that for all columns. */
1185
for (column = 0; column < table_data->dimensions[HORZ].size; column++)
1186
max_width = MAX (max_width, columns[column].requisition);
1187
for (column = 0; column < table_data->dimensions[HORZ].size; column++)
1188
columns[column].requisition = max_width;
1193
/* This handles items that span more than one row or column, by making sure
1194
there is enough space for them and expanding the row/column size request
1197
goo_canvas_table_size_request_pass3 (GooCanvasTable *table)
1199
GooCanvasTableData *table_data = table->table_data;
1200
GooCanvasTableLayoutData *layout_data = table_data->layout_data;
1201
GooCanvasTableDimensionLayoutData *dldata;
1202
GooCanvasTableChild *child;
1205
for (i = 0; i < table_data->children->len; i++)
1207
child = &g_array_index (table_data->children, GooCanvasTableChild, i);
1209
if (layout_data->children[i].requested_size[HORZ] <= 0.0)
1212
for (d = 0; d < 2; d++)
1214
/* Child spans multiple rows/columns. */
1215
if (child->size[d] != 1)
1217
gint start = child->start[d];
1218
gint end = start + child->size[d] - 1;
1219
gdouble total_space = 0.0, space_needed;
1221
dldata = layout_data->dldata[d];
1223
/* Check if there is already enough space for the child. */
1224
for (j = start; j <= end; j++)
1226
total_space += dldata[j].requisition;
1228
total_space += dldata[j].spacing;
1231
/* If we need to request more space for this child to fill
1232
its requisition, then divide up the needed space amongst the
1233
columns it spans, favoring expandable columns if any. */
1234
space_needed = layout_data->children[i].requested_size[d]
1235
+ child->start_pad[d] + child->end_pad[d];
1237
if (total_space < space_needed)
1240
gboolean force_expand = FALSE;
1241
gdouble expand = space_needed - total_space;
1244
for (j = start; j <= end; j++)
1246
if (dldata[j].expand)
1252
n_expand = child->size[d];
1253
force_expand = TRUE;
1256
/* FIXME: Integer mode for widgets? */
1257
extra = expand / n_expand;
1258
for (j = start; j <= end; j++)
1260
if (force_expand || dldata[j].expand)
1261
dldata[j].requisition += extra;
1270
/* Returns FALSE if item shouldn't be allocated. */
1272
goo_canvas_table_get_requested_area (GooCanvasItem *item,
1274
GooCanvasBounds *requested_area)
1276
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
1277
GooCanvasItemSimpleData *simple_data = simple->simple_data;
1278
GooCanvasTable *table = (GooCanvasTable*) item;
1279
GooCanvasTableData *table_data = table->table_data;
1280
GooCanvasTableLayoutData *layout_data;
1281
GooCanvasTableDimensionLayoutData *rows, *columns;
1282
gdouble width = 0.0, height = 0.0;
1283
gint row, column, end;
1285
simple->bounds.x1 = simple->bounds.x2 = 0.0;
1286
simple->bounds.y1 = simple->bounds.y2 = 0.0;
1288
simple->need_update = FALSE;
1290
goo_canvas_item_simple_check_style (simple);
1292
if (simple_data->visibility == GOO_CANVAS_ITEM_HIDDEN)
1296
if (simple_data->transform)
1297
cairo_transform (cr, simple_data->transform);
1299
goo_canvas_table_init_layout_data (table);
1300
goo_canvas_table_size_request_init (table, cr);
1301
goo_canvas_table_size_request_pass1 (table);
1302
goo_canvas_table_size_request_pass2 (table);
1303
goo_canvas_table_size_request_pass3 (table);
1304
goo_canvas_table_size_request_pass2 (table);
1306
layout_data = table_data->layout_data;
1307
rows = layout_data->dldata[VERT];
1308
columns = layout_data->dldata[HORZ];
1310
end = table_data->dimensions[HORZ].size - 1;
1311
for (column = 0; column <= end; column++)
1313
width += columns[column].requisition;
1315
width += columns[column].spacing;
1318
end = table_data->dimensions[VERT].size - 1;
1319
for (row = 0; row <= end; row++)
1321
height += rows[row].requisition;
1323
height += rows[row].spacing;
1326
width += table_data->border_width * 2;
1327
height += table_data->border_width * 2;
1329
/* If the width or height has been set, that overrides the calculations. */
1330
if (table_data->width > 0.0)
1331
width = table_data->width;
1332
if (table_data->height > 0.0)
1333
height = table_data->height;
1335
layout_data->requested_size[HORZ] = simple->bounds.x2 = width;
1336
layout_data->requested_size[VERT] = simple->bounds.y2 = height;
1338
/* Copy the user bounds to the requested area. */
1339
*requested_area = simple->bounds;
1341
/* Convert to the parent's coordinate space. */
1342
goo_canvas_item_simple_user_bounds_to_parent (simple, cr, requested_area);
1344
/* Convert the item's bounds to device space. */
1345
goo_canvas_item_simple_user_bounds_to_device (simple, cr, &simple->bounds);
1354
goo_canvas_table_size_allocate_init (GooCanvasTable *table)
1356
GooCanvasTableData *table_data = table->table_data;
1357
GooCanvasTableLayoutData *layout_data = table_data->layout_data;
1358
GooCanvasTableDimension *dimension;
1359
GooCanvasTableDimensionLayoutData *dldata;
1362
/* Set the initial allocation, by copying over the requisition.
1363
Also set the final expand & shrink flags. */
1364
for (d = 0; d < 2; d++)
1366
dimension = &table_data->dimensions[d];
1367
dldata = layout_data->dldata[d];
1369
for (i = 0; i < dimension->size; i++)
1371
dldata[i].allocation = dldata[i].requisition;
1373
if (dldata[i].empty)
1375
dldata[i].expand = FALSE;
1376
dldata[i].shrink = FALSE;
1380
if (dldata[i].need_expand)
1381
dldata[i].expand = TRUE;
1382
if (!dldata[i].need_shrink)
1383
dldata[i].shrink = FALSE;
1391
goo_canvas_table_size_allocate_pass1 (GooCanvasTable *table)
1393
GooCanvasTableData *table_data = table->table_data;
1394
GooCanvasTableLayoutData *layout_data = table_data->layout_data;
1395
GooCanvasTableDimension *dimension;
1396
GooCanvasTableDimensionLayoutData *dldata;
1397
gdouble total_size, size_to_allocate, natural_size, extra;
1398
gint d, i, nexpand, nshrink;
1400
/* If we were allocated more space than we requested
1401
* then we have to expand any expandable rows and columns
1402
* to fill in the extra space.
1404
for (d = 0; d < 2; d++)
1406
dimension = &table_data->dimensions[d];
1407
dldata = layout_data->dldata[d];
1409
total_size = layout_data->allocated_size[d] - table_data->border_width * 2;
1411
if (dimension->homogeneous)
1413
/* If the table is homogeneous in this dimension we check if any of
1414
the children expand. If they do we expand all rows/columns to
1415
fit the total_size. */
1416
/* FIXME: Should we try shrinking as well here? */
1417
if (table_data->children->len == 0)
1422
for (i = 0; i < dimension->size; i++)
1423
if (dldata[i].expand)
1431
size_to_allocate = total_size;
1432
for (i = 0; i + 1 < dimension->size; i++)
1433
size_to_allocate -= dldata[i].spacing;
1435
/* FIXME: Integer mode for widgets? */
1436
size_to_allocate /= dimension->size;
1437
for (i = 0; i < dimension->size; i++)
1438
dldata[i].allocation = size_to_allocate;
1447
for (i = 0; i < dimension->size; i++)
1449
natural_size += dldata[i].requisition;
1450
if (dldata[i].expand)
1452
if (dldata[i].shrink)
1455
for (i = 0; i + 1 < dimension->size; i++)
1456
natural_size += dldata[i].spacing;
1458
/* Check to see if we were allocated more width than we requested.
1460
if ((natural_size < total_size) && (nexpand >= 1))
1462
/* FIXME: Integer mode for widgets? */
1463
extra = (total_size - natural_size) / nexpand;
1464
for (i = 0; i < dimension->size; i++)
1466
if (dldata[i].expand)
1467
dldata[i].allocation += extra;
1471
/* Check to see if we were allocated less width than we requested,
1472
* then shrink until we fit the size give.
1474
if (natural_size > total_size)
1476
gint total_nshrink = nshrink;
1478
extra = natural_size - total_size;
1479
/* FIXME: Integer mode for widgets? */
1480
while (total_nshrink > 0 && extra > 0)
1482
nshrink = total_nshrink;
1483
for (i = 0; i < dimension->size; i++)
1485
if (dldata[i].shrink)
1487
gdouble old_allocation = dldata[i].allocation;
1489
dldata[i].allocation = MAX (0.0, dldata[i].allocation - extra / nshrink);
1490
extra -= old_allocation - dldata[i].allocation;
1492
if (dldata[i].allocation <= 0.0)
1495
dldata[i].shrink = FALSE;
1506
/* Calculates the start and end position of each row/column. */
1508
goo_canvas_table_size_allocate_pass2 (GooCanvasTable *table)
1510
GooCanvasTableData *table_data = table->table_data;
1511
GooCanvasTableLayoutData *layout_data = table_data->layout_data;
1512
GooCanvasTableDimension *dimension;
1513
GooCanvasTableDimensionLayoutData *dldata;
1517
for (d = 0; d < 2; d++)
1519
dimension = &table_data->dimensions[d];
1520
dldata = layout_data->dldata[d];
1522
pos = table_data->border_width;
1523
for (i = 0; i < dimension->size; i++)
1525
dldata[i].start = pos;
1526
pos += dldata[i].allocation;
1527
dldata[i].end = pos;
1528
pos += dldata[i].spacing;
1534
/* This does the actual allocation of each child, calculating its size and
1535
position according to the rows & columns it spans. */
1537
goo_canvas_table_size_allocate_pass3 (GooCanvasTable *table,
1539
gdouble table_x_offset,
1540
gdouble table_y_offset)
1542
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) table;
1543
GooCanvasGroup *group = (GooCanvasGroup*) table;
1544
GooCanvasTableData *table_data = table->table_data;
1545
GooCanvasTableLayoutData *layout_data = table_data->layout_data;
1546
GooCanvasTableDimensionLayoutData *rows = layout_data->dldata[VERT];
1547
GooCanvasTableDimensionLayoutData *columns = layout_data->dldata[HORZ];
1548
GooCanvasTableChild *child;
1549
GooCanvasItem *child_item;
1550
GooCanvasTableChildLayoutData *child_data;
1551
GooCanvasBounds requested_area, allocated_area;
1552
GtkTextDirection direction = GTK_TEXT_DIR_NONE;
1553
gint start_column, end_column, start_row, end_row, i;
1554
gdouble x, y, max_width, max_height, width, height;
1555
gdouble requested_width, requested_height;
1556
gdouble x_offset, y_offset;
1559
direction = gtk_widget_get_direction (GTK_WIDGET (simple->canvas));
1561
for (i = 0; i < table_data->children->len; i++)
1563
child = &g_array_index (table_data->children, GooCanvasTableChild, i);
1564
child_item = group->items->pdata[i];
1565
child_data = &layout_data->children[i];
1567
requested_width = child_data->requested_size[HORZ];
1568
requested_height = child_data->requested_size[VERT];
1570
if (requested_width <= 0.0)
1573
start_column = child->start[HORZ];
1574
end_column = child->start[HORZ] + child->size[HORZ] - 1;
1575
x = columns[start_column].start + child->start_pad[HORZ];
1576
max_width = columns[end_column].end - child->end_pad[HORZ] - x;
1578
start_row = child->start[VERT];
1579
end_row = child->start[VERT] + child->size[VERT] - 1;
1580
y = rows[start_row].start + child->start_pad[VERT];
1581
max_height = rows[end_row].end - child->end_pad[VERT] - y;
1583
width = max_width = MAX (0.0, max_width);
1584
height = max_height = MAX (0.0, max_height);
1586
if (!(child->flags[HORZ] & GOO_CANVAS_TABLE_CHILD_FILL))
1588
width = MIN (max_width, requested_width);
1589
x += (max_width - width) * child->align[HORZ];
1592
if (!(child->flags[VERT] & GOO_CANVAS_TABLE_CHILD_FILL))
1594
height = MIN (max_height, requested_height);
1595
y += (max_height - height) * child->align[VERT];
1598
if (direction == GTK_TEXT_DIR_RTL)
1599
x = layout_data->allocated_size[HORZ] - width;
1601
child->position[HORZ] = x - layout_data->children[i].requested_position[HORZ];
1602
child->position[VERT] = y - layout_data->children[i].requested_position[VERT];
1604
requested_area.x1 = layout_data->children[i].requested_position[HORZ];
1605
requested_area.y1 = layout_data->children[i].requested_position[VERT];
1606
requested_area.x2 = requested_area.x1 + requested_width;
1607
requested_area.y2 = requested_area.y1 + requested_height;
1609
allocated_area.x1 = x;
1610
allocated_area.y1 = y;
1611
allocated_area.x2 = allocated_area.x1 + width;
1612
allocated_area.y2 = allocated_area.y1 + height;
1614
/* Translate the cairo context so the item's user space is correct. */
1615
cairo_translate (cr, child->position[HORZ], child->position[VERT]);
1617
x_offset = allocated_area.x1 - requested_area.x1;
1618
y_offset = allocated_area.y1 - requested_area.y1;
1619
cairo_user_to_device_distance (cr, &x_offset, &y_offset);
1620
x_offset += table_x_offset;
1621
y_offset += table_y_offset;
1623
goo_canvas_item_allocate_area (child_item, cr, &requested_area,
1624
&allocated_area, x_offset, y_offset);
1626
cairo_translate (cr, -child->position[HORZ], -child->position[VERT]);
1632
goo_canvas_table_allocate_area (GooCanvasItem *item,
1634
GooCanvasBounds *requested_area,
1635
GooCanvasBounds *allocated_area,
1639
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
1640
GooCanvasItemSimpleData *simple_data = simple->simple_data;
1641
GooCanvasTable *table = (GooCanvasTable*) item;
1642
GooCanvasTableData *table_data = table->table_data;
1643
GooCanvasTableLayoutData *layout_data = table_data->layout_data;
1644
gdouble requested_width, requested_height, allocated_width, allocated_height;
1645
gdouble width_proportion, height_proportion, min_proportion;
1648
if (simple_data->transform)
1649
cairo_transform (cr, simple_data->transform);
1651
requested_width = requested_area->x2 - requested_area->x1;
1652
requested_height = requested_area->y2 - requested_area->y1;
1653
allocated_width = allocated_area->x2 - allocated_area->x1;
1654
allocated_height = allocated_area->y2 - allocated_area->y1;
1656
/* Calculate what proportion of our requested size we were allocated. */
1657
width_proportion = allocated_width / requested_width;
1658
height_proportion = allocated_height / requested_height;
1660
/* If the table is rotated we have to scale it to make sure it fits in the
1662
if (simple_data->transform && (simple_data->transform->xy != 0.0
1663
|| simple_data->transform->yx != 0.0))
1665
/* Calculate the minimum proportion, which we'll use to scale our
1666
original width & height requests. */
1667
min_proportion = MIN (width_proportion, height_proportion);
1669
layout_data->allocated_size[HORZ] = layout_data->requested_size[HORZ] * min_proportion;
1670
layout_data->allocated_size[VERT] = layout_data->requested_size[VERT] * min_proportion;
1674
/* If the table isn't rotated we can just scale according to the
1675
allocated proportions. */
1676
layout_data->allocated_size[HORZ] = layout_data->requested_size[HORZ] * width_proportion;
1677
layout_data->allocated_size[VERT] = layout_data->requested_size[VERT] * height_proportion;
1680
/* Recalculate the bounds. */
1681
simple->bounds.x1 = simple->bounds.y1 = 0.0;
1682
simple->bounds.x2 = layout_data->allocated_size[HORZ];
1683
simple->bounds.y2 = layout_data->allocated_size[VERT];
1684
goo_canvas_item_simple_user_bounds_to_device (simple, cr, &simple->bounds);
1686
goo_canvas_table_size_allocate_init (table);
1687
goo_canvas_table_size_allocate_pass1 (table);
1688
goo_canvas_table_size_allocate_pass2 (table);
1689
goo_canvas_table_size_allocate_pass3 (table, cr, x_offset, y_offset);
1691
goo_canvas_table_free_layout_data (table_data);
1698
goo_canvas_table_update (GooCanvasItem *item,
1699
gboolean entire_tree,
1701
GooCanvasBounds *bounds)
1703
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
1704
GooCanvasBounds tmp_bounds;
1706
if (entire_tree || simple->need_update)
1708
simple->need_update = FALSE;
1709
simple->need_entire_subtree_update = FALSE;
1711
goo_canvas_item_simple_check_style (simple);
1713
/* We just allocate exactly what is requested. */
1714
if (goo_canvas_table_get_requested_area (item, cr, &tmp_bounds))
1715
goo_canvas_table_allocate_area (item, cr, &tmp_bounds, &tmp_bounds,
1719
*bounds = simple->bounds;
1724
goo_canvas_table_paint (GooCanvasItem *item,
1726
GooCanvasBounds *bounds,
1729
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
1730
GooCanvasItemSimpleData *simple_data = simple->simple_data;
1731
GooCanvasGroup *group = (GooCanvasGroup*) item;
1732
GooCanvasTable *table = (GooCanvasTable*) item;
1733
GooCanvasTableData *table_data = table->table_data;
1734
GArray *children = table_data->children;
1735
GooCanvasTableChild *table_child;
1736
GooCanvasItem *child;
1739
/* Check if the item should be visible. */
1740
if (simple_data->visibility <= GOO_CANVAS_ITEM_INVISIBLE
1741
|| (simple_data->visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD
1742
&& simple->canvas->scale < simple_data->visibility_threshold))
1745
/* Paint all the items in the group. */
1747
if (simple_data->transform)
1748
cairo_transform (cr, simple_data->transform);
1750
for (i = 0; i < group->items->len; i++)
1752
child = group->items->pdata[i];
1754
table_child = &g_array_index (children, GooCanvasTableChild, i);
1755
cairo_translate (cr, table_child->position[HORZ],
1756
table_child->position[VERT]);
1758
/* FIXME: Clip the child to make sure it doesn't go outside its area? */
1759
goo_canvas_item_paint (child, cr, bounds, scale);
1761
cairo_translate (cr, -table_child->position[HORZ],
1762
-table_child->position[VERT]);
1768
static GooCanvasItem*
1769
goo_canvas_table_get_item_at (GooCanvasItem *item,
1773
gboolean is_pointer_event,
1774
gboolean parent_visible)
1776
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
1777
GooCanvasItemSimpleData *simple_data = simple->simple_data;
1778
GooCanvasGroup *group = (GooCanvasGroup*) item;
1779
GooCanvasTable *table = (GooCanvasTable*) item;
1780
GooCanvasTableData *table_data = table->table_data;
1781
GArray *children = table_data->children;
1782
GooCanvasTableChild *table_child;
1783
GooCanvasItem *child;
1784
GooCanvasItem *found_item = NULL;
1785
gboolean visible = parent_visible;
1788
if (simple->need_update)
1789
goo_canvas_item_ensure_updated (item);
1791
if (simple_data->visibility <= GOO_CANVAS_ITEM_INVISIBLE
1792
|| (simple_data->visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD
1793
&& simple->canvas->scale < simple_data->visibility_threshold))
1796
/* Check if the group should receive events. */
1797
if (is_pointer_event
1798
&& (simple_data->pointer_events == GOO_CANVAS_EVENTS_NONE
1799
|| ((simple_data->pointer_events & GOO_CANVAS_EVENTS_VISIBLE_MASK)
1803
/* Step down from the top item to the bottom in the stack/layer, and return
1804
the first item found that contains the given point. */
1806
if (simple_data->transform)
1807
cairo_transform (cr, simple_data->transform);
1809
for (i = group->items->len - 1; i >= 0; i--)
1811
child = group->items->pdata[i];
1813
table_child = &g_array_index (children, GooCanvasTableChild, i);
1814
cairo_translate (cr, table_child->position[HORZ],
1815
table_child->position[VERT]);
1817
found_item = goo_canvas_item_get_item_at (child, x, y, cr,
1818
is_pointer_event, visible);
1822
cairo_translate (cr, -table_child->position[HORZ],
1823
-table_child->position[VERT]);
1832
goo_canvas_table_get_transform_for_child (GooCanvasItem *item,
1833
GooCanvasItem *child,
1834
cairo_matrix_t *transform)
1836
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
1837
GooCanvasGroup *group = (GooCanvasGroup*) item;
1838
GooCanvasTable *table = (GooCanvasTable*) item;
1839
GooCanvasTableChild *table_child;
1840
gboolean has_transform = FALSE;
1844
if (simple->simple_data->transform)
1846
*transform = *simple->simple_data->transform;
1847
has_transform = TRUE;
1851
cairo_matrix_init_identity (transform);
1854
for (child_num = 0; child_num < group->items->len; child_num++)
1856
if (group->items->pdata[child_num] == child)
1858
table_child = &g_array_index (table->table_data->children,
1859
GooCanvasTableChild, child_num);
1860
cairo_matrix_translate (transform, table_child->position[HORZ],
1861
table_child->position[VERT]);
1862
has_transform = TRUE;
1867
return has_transform;
1872
item_interface_init (GooCanvasItemIface *iface)
1874
iface->add_child = goo_canvas_table_add_child;
1875
iface->move_child = goo_canvas_table_move_child;
1876
iface->remove_child = goo_canvas_table_remove_child;
1877
iface->get_child_property = goo_canvas_table_get_child_property;
1878
iface->set_child_property = goo_canvas_table_set_child_property;
1879
iface->get_transform_for_child = goo_canvas_table_get_transform_for_child;
1881
iface->update = goo_canvas_table_update;
1882
iface->get_requested_area = goo_canvas_table_get_requested_area;
1883
iface->allocate_area = goo_canvas_table_allocate_area;
1884
iface->paint = goo_canvas_table_paint;
1885
iface->get_item_at = goo_canvas_table_get_item_at;
1887
iface->set_model = goo_canvas_table_set_model;
1893
* SECTION:goocanvastablemodel
1894
* @Title: GooCanvasTableModel
1895
* @Short_Description: a model for a table container to layout items.
1897
* #GooCanvasTableModel is a model for a table container used to lay out other
1898
* canvas items. It is used in a similar way to how the GtkTable widget is used
1899
* to lay out GTK+ widgets.
1901
* Item models are added to the table using the normal methods, then
1902
* goo_canvas_item_model_set_child_properties() is used to specify how each
1903
* child item is to be positioned within the table (i.e. which row and column
1904
* it is in, how much padding it should have and whether it should expand or
1907
* #GooCanvasTableModel is a subclass of #GooCanvasItemModelSimple and so
1908
* inherits all of the style properties such as "stroke-color", "fill-color"
1909
* and "line-width". Setting a style property on a #GooCanvasTableModel will
1910
* affect all children of the #GooCanvasTableModel (unless the children
1911
* override the property setting).
1913
* #GooCanvasTableModel implements the #GooCanvasItemModel interface, so you
1914
* can use the #GooCanvasItemModel functions such as
1915
* goo_canvas_item_model_raise() and goo_canvas_item_rotate(), and the
1916
* properties such as "visibility" and "pointer-events".
1918
* To create a #GooCanvasTableModel use goo_canvas_table_model_new().
1920
* To get or set the properties of an existing #GooCanvasTableModel, use
1921
* g_object_get() and g_object_set().
1924
static void item_model_interface_init (GooCanvasItemModelIface *iface);
1925
static void goo_canvas_table_model_finalize (GObject *object);
1926
static void goo_canvas_table_model_get_property (GObject *object,
1930
static void goo_canvas_table_model_set_property (GObject *object,
1932
const GValue *value,
1935
G_DEFINE_TYPE_WITH_CODE (GooCanvasTableModel, goo_canvas_table_model,
1936
GOO_TYPE_CANVAS_GROUP_MODEL,
1937
G_IMPLEMENT_INTERFACE (GOO_TYPE_CANVAS_ITEM_MODEL,
1938
item_model_interface_init))
1942
goo_canvas_table_model_class_init (GooCanvasTableModelClass *klass)
1944
GObjectClass *gobject_class = (GObjectClass*) klass;
1946
gobject_class->finalize = goo_canvas_table_model_finalize;
1948
gobject_class->get_property = goo_canvas_table_model_get_property;
1949
gobject_class->set_property = goo_canvas_table_model_set_property;
1951
goo_canvas_table_install_common_properties (gobject_class, goo_canvas_item_model_class_install_child_property);
1956
goo_canvas_table_model_init (GooCanvasTableModel *tmodel)
1958
goo_canvas_table_init_data (&tmodel->table_data);
1963
* goo_canvas_table_model_new:
1964
* @parent: the parent model, or %NULL. If a parent is specified, it will
1965
* assume ownership of the item, and the item will automatically be freed when
1966
* it is removed from the parent. Otherwise call g_object_unref() to free it.
1967
* @...: optional pairs of property names and values, and a terminating %NULL.
1969
* Creates a new table model.
1973
* Here's an example showing how to create a table with a square, a circle and
1976
* <informalexample><programlisting>
1977
* GooCanvasItemModel *table, *square, *circle, *triangle;
1979
* table = goo_canvas_table_model_new (root,
1980
* "row-spacing", 4.0,
1981
* "column-spacing", 4.0,
1983
* goo_canvas_item_model_translate (table, 400, 200);
1985
* square = goo_canvas_rect_model_new (table, 0.0, 0.0, 50.0, 50.0,
1986
* "fill-color", "red",
1988
* goo_canvas_item_model_set_child_properties (table, square,
1993
* circle = goo_canvas_ellipse_model_new (table, 0.0, 0.0, 25.0, 25.0,
1994
* "fill-color", "blue",
1996
* goo_canvas_item_model_set_child_properties (table, circle,
2001
* triangle = goo_canvas_polyline_model_new (table, TRUE, 3,
2002
* 25.0, 0.0, 0.0, 50.0, 50.0, 50.0,
2003
* "fill-color", "yellow",
2005
* goo_canvas_item_model_set_child_properties (table, triangle,
2009
* </programlisting></informalexample>
2011
* Returns: a new table model.
2014
goo_canvas_table_model_new (GooCanvasItemModel *parent,
2017
GooCanvasItemModel *model;
2019
const char *first_property;
2021
model = g_object_new (GOO_TYPE_CANVAS_TABLE_MODEL, NULL);
2023
va_start (var_args, parent);
2024
first_property = va_arg (var_args, char*);
2026
g_object_set_valist (G_OBJECT (model), first_property, var_args);
2031
goo_canvas_item_model_add_child (parent, model, -1);
2032
g_object_unref (model);
2040
goo_canvas_table_model_finalize (GObject *object)
2042
GooCanvasTableModel *tmodel = (GooCanvasTableModel*) object;
2044
goo_canvas_table_free_data (&tmodel->table_data);
2046
G_OBJECT_CLASS (goo_canvas_table_model_parent_class)->finalize (object);
2051
goo_canvas_table_model_get_property (GObject *object,
2056
GooCanvasTableModel *emodel = (GooCanvasTableModel*) object;
2058
goo_canvas_table_get_common_property (object, &emodel->table_data,
2059
prop_id, value, pspec);
2064
goo_canvas_table_model_set_property (GObject *object,
2066
const GValue *value,
2069
GooCanvasTableModel *emodel = (GooCanvasTableModel*) object;
2070
gboolean recompute_bounds;
2072
recompute_bounds = goo_canvas_table_set_common_property (object,
2073
&emodel->table_data,
2076
g_signal_emit_by_name (emodel, "changed", recompute_bounds);
2081
goo_canvas_table_model_add_child (GooCanvasItemModel *model,
2082
GooCanvasItemModel *child,
2085
GooCanvasItemModelIface *iface = GOO_CANVAS_ITEM_MODEL_GET_IFACE (model);
2086
GooCanvasItemModelIface *parent_iface = g_type_interface_peek_parent (iface);
2087
GooCanvasTableModel *tmodel = (GooCanvasTableModel*) model;
2089
goo_canvas_table_add_child_internal (&tmodel->table_data, position);
2091
/* Let the parent GooCanvasGroupModel code do the rest. */
2092
parent_iface->add_child (model, child, position);
2097
goo_canvas_table_model_move_child (GooCanvasItemModel *model,
2101
GooCanvasItemModelIface *iface = GOO_CANVAS_ITEM_MODEL_GET_IFACE (model);
2102
GooCanvasItemModelIface *parent_iface = g_type_interface_peek_parent (iface);
2103
GooCanvasTableModel *tmodel = (GooCanvasTableModel*) model;
2105
goo_canvas_table_move_child_internal (&tmodel->table_data, old_position,
2108
/* Let the parent GooCanvasGroupModel code do the rest. */
2109
parent_iface->move_child (model, old_position, new_position);
2114
goo_canvas_table_model_remove_child (GooCanvasItemModel *model,
2117
GooCanvasItemModelIface *iface = GOO_CANVAS_ITEM_MODEL_GET_IFACE (model);
2118
GooCanvasItemModelIface *parent_iface = g_type_interface_peek_parent (iface);
2119
GooCanvasTableModel *tmodel = (GooCanvasTableModel*) model;
2121
g_array_remove_index (tmodel->table_data.children, child_num);
2123
/* Let the parent GooCanvasGroupModel code do the rest. */
2124
parent_iface->remove_child (model, child_num);
2129
goo_canvas_table_model_get_child_property (GooCanvasItemModel *model,
2130
GooCanvasItemModel *child,
2135
GooCanvasGroupModel *gmodel = (GooCanvasGroupModel*) model;
2136
GooCanvasTableModel *tmodel = (GooCanvasTableModel*) model;
2137
GooCanvasTableChild *table_child;
2140
for (child_num = 0; child_num < gmodel->children->len; child_num++)
2142
if (gmodel->children->pdata[child_num] == child)
2144
table_child = &g_array_index (tmodel->table_data.children,
2145
GooCanvasTableChild, child_num);
2146
goo_canvas_table_get_common_child_property ((GObject*) tmodel,
2157
goo_canvas_table_model_set_child_property (GooCanvasItemModel *model,
2158
GooCanvasItemModel *child,
2160
const GValue *value,
2163
GooCanvasGroupModel *gmodel = (GooCanvasGroupModel*) model;
2164
GooCanvasTableModel *tmodel = (GooCanvasTableModel*) model;
2165
GooCanvasTableChild *table_child;
2168
for (child_num = 0; child_num < gmodel->children->len; child_num++)
2170
if (gmodel->children->pdata[child_num] == child)
2172
table_child = &g_array_index (tmodel->table_data.children,
2173
GooCanvasTableChild, child_num);
2174
goo_canvas_table_set_common_child_property ((GObject*) tmodel,
2175
&tmodel->table_data,
2183
g_signal_emit_by_name (tmodel, "changed", TRUE);
2187
static GooCanvasItem*
2188
goo_canvas_table_model_create_item (GooCanvasItemModel *model,
2191
GooCanvasItem *item;
2193
item = goo_canvas_table_new (NULL, NULL);
2194
/* Note that we set the canvas before the model, since we may need the
2195
canvas to create any child items. */
2196
goo_canvas_item_set_canvas (item, canvas);
2197
goo_canvas_item_set_model (item, model);
2204
item_model_interface_init (GooCanvasItemModelIface *iface)
2206
iface->add_child = goo_canvas_table_model_add_child;
2207
iface->move_child = goo_canvas_table_model_move_child;
2208
iface->remove_child = goo_canvas_table_model_remove_child;
2209
iface->get_child_property = goo_canvas_table_model_get_child_property;
2210
iface->set_child_property = goo_canvas_table_model_set_child_property;
2212
iface->create_item = goo_canvas_table_model_create_item;