~ubuntu-branches/ubuntu/gutsy/goocanvas/gutsy

« back to all changes in this revision

Viewing changes to src/goocanvastable.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-02-20 18:25:58 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20070220182558-tjofc7wdzkzlxzor
Tags: 0.6-0ubuntu1
* New upstream version (UVF exception #86533):
  - Major rewrite to make the model optional, so people can choose to have
    either a simple canvas or a model/view canvas. The standard items can be
    used in either scenario.
  - Added support for cascading style properties (things like fill color, 
    stroke width, font etc.). Properties use a GQuark for a unique 
    identifier, and a GValue for the property value, so they are very 
    flexible.
  - Added GooCanvasTable item to layout child items.
  - Made it much easier to create new items, by subclassing 
    GooCanvasItemSimple which handles most of the work. See demo/demo-item.c 
    for a simple item.
  - Added support for different units - pixels, points, inches or 
    millimeters, and allow setting of vertical 
    and horizontal resolution (dpi).
  - Added workaround for cairo's 16-bit limit, to support large canvases.
  - Added demo/scalability-demo which creates 100,000 items over a large 
    canvas. It takes a few seconds to create all the items, but once created 
    it seems to work fast enough.
  - Improved the animation code, supporting relative or absolute values for
    the x, y, scale and rotation.
  - Added "clip-path" and "clip-fill-rule" to specify a clip path 
    for an item.
* debian/control:
  - updated GTK requirement to 2.10
* debian/control, debian/libgoocanvas0.install, debian/libgoocanvas1.install,
  debian/rules:
  - updated for soname change

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * GooCanvas. Copyright (C) 2005-6 Damon Chaplin.
 
3
 * Released under the GNU LGPL license. See COPYING for details.
 
4
 *
 
5
 * goocanvastable.c - table item.
 
6
 */
 
7
 
 
8
/**
 
9
 * SECTION:goocanvastable
 
10
 * @Title: GooCanvasTable
 
11
 * @Short_Description: a table container to layout items.
 
12
 *
 
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
 
15
 * GTK+ widgets.
 
16
 *
 
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
 
21
 * shrink).
 
22
 *
 
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
 
27
 * property setting).
 
28
 *
 
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
 
32
 * "pointer-events".
 
33
 *
 
34
 * To create a #GooCanvasTable use goo_canvas_table_new().
 
35
 *
 
36
 * To get or set the properties of an existing #GooCanvasTable, use
 
37
 * g_object_get() and g_object_set().
 
38
 */
 
39
#include <config.h>
 
40
#include <string.h>
 
41
#include <glib/gi18n-lib.h>
 
42
#include <gtk/gtk.h>
 
43
#include "goocanvastable.h"
 
44
#include "goocanvas.h"
 
45
 
 
46
 
 
47
enum
 
48
{
 
49
  PROP_0,
 
50
  PROP_WIDTH,
 
51
  PROP_HEIGHT,
 
52
  PROP_ROW_SPACING,
 
53
  PROP_COLUMN_SPACING,
 
54
  PROP_HOMOGENEOUS_ROWS,
 
55
  PROP_HOMOGENEOUS_COLUMNS
 
56
};
 
57
 
 
58
enum
 
59
{
 
60
  CHILD_PROP_0,
 
61
  CHILD_PROP_LEFT_PADDING,
 
62
  CHILD_PROP_RIGHT_PADDING,
 
63
  CHILD_PROP_TOP_PADDING,
 
64
  CHILD_PROP_BOTTOM_PADDING,
 
65
  CHILD_PROP_X_ALIGN,
 
66
  CHILD_PROP_Y_ALIGN,
 
67
  CHILD_PROP_ROW,
 
68
  CHILD_PROP_COLUMN,
 
69
  CHILD_PROP_ROWS,
 
70
  CHILD_PROP_COLUMNS,
 
71
  CHILD_PROP_X_EXPAND,
 
72
  CHILD_PROP_X_FILL,
 
73
  CHILD_PROP_X_SHRINK,
 
74
  CHILD_PROP_Y_EXPAND,
 
75
  CHILD_PROP_Y_FILL,
 
76
  CHILD_PROP_Y_SHRINK
 
77
};
 
78
 
 
79
#define HORZ 0
 
80
#define VERT 1
 
81
 
 
82
typedef enum
 
83
{
 
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;
 
88
 
 
89
typedef struct _GooCanvasTableChild  GooCanvasTableChild;
 
90
struct _GooCanvasTableChild
 
91
{
 
92
  gdouble position[2];
 
93
  gdouble start_pad[2], end_pad[2];
 
94
  gdouble align[2];
 
95
  guint16 start[2], size[2];
 
96
  guint8 flags[2];                      /* GooCanvasTableChildFlags. */
 
97
};
 
98
 
 
99
typedef struct _GooCanvasTableDimensionLayoutData GooCanvasTableDimensionLayoutData;
 
100
struct _GooCanvasTableDimensionLayoutData
 
101
{
 
102
  gdouble spacing;
 
103
  gdouble requisition;
 
104
  gdouble allocation;
 
105
  gdouble start;
 
106
  gdouble end;
 
107
  guint need_expand : 1;
 
108
  guint need_shrink : 1;
 
109
  guint expand : 1;
 
110
  guint shrink : 1;
 
111
  guint empty : 1;
 
112
};
 
113
 
 
114
typedef struct _GooCanvasTableChildLayoutData GooCanvasTableChildLayoutData;
 
115
struct _GooCanvasTableChildLayoutData
 
116
{
 
117
  gdouble requested_position[2];
 
118
  gdouble requested_size[2];
 
119
};
 
120
 
 
121
struct _GooCanvasTableLayoutData
 
122
{
 
123
  GooCanvasTableDimensionLayoutData *dldata[2];
 
124
  GooCanvasTableChildLayoutData *children;
 
125
 
 
126
  /* These are in the table's coordinate space. */
 
127
  gdouble requested_size[2];
 
128
  gdouble allocated_size[2];
 
129
};
 
130
 
 
131
 
 
132
 
 
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,
 
136
                                           guint               param_id,
 
137
                                           GValue             *value,
 
138
                                           GParamSpec         *pspec);
 
139
static void goo_canvas_table_set_property (GObject            *object,
 
140
                                           guint               param_id,
 
141
                                           const GValue       *value,
 
142
                                           GParamSpec         *pspec);
 
143
 
 
144
static void goo_canvas_table_free_layout_data (GooCanvasTableData *table_data);
 
145
 
 
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))
 
150
 
 
151
typedef void (*InstallChildPropertyFunc) (GObjectClass*, guint, GParamSpec*);
 
152
 
 
153
static void
 
154
goo_canvas_table_install_common_properties (GObjectClass *gobject_class,
 
155
                                            InstallChildPropertyFunc install_child_property)
 
156
{
 
157
  g_object_class_install_property (gobject_class, PROP_WIDTH,
 
158
                                   g_param_spec_double ("width",
 
159
                                                        _("Width"),
 
160
                                                        _("The requested width of the table, or -1 to use the default width"),
 
161
                                                        -G_MAXDOUBLE,
 
162
                                                        G_MAXDOUBLE, -1.0,
 
163
                                                        G_PARAM_READWRITE));
 
164
  g_object_class_install_property (gobject_class, PROP_HEIGHT,
 
165
                                   g_param_spec_double ("height",
 
166
                                                        _("Height"),
 
167
                                                        _("The requested height of the table, or -1 to use the default height"),
 
168
                                                        -G_MAXDOUBLE,
 
169
                                                        G_MAXDOUBLE, -1.0,
 
170
                                                        G_PARAM_READWRITE));
 
171
 
 
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",
 
175
                                                        _("Row spacing"),
 
176
                                                        _("The default space between rows"),
 
177
                                                        0.0, G_MAXDOUBLE, 0.0,
 
178
                                                        G_PARAM_READWRITE));
 
179
 
 
180
  g_object_class_install_property (gobject_class, PROP_COLUMN_SPACING,
 
181
                                   g_param_spec_double ("column-spacing",
 
182
                                                        _("Column spacing"),
 
183
                                                        _("The default space between columns"),
 
184
                                                        0.0, G_MAXDOUBLE, 0.0,
 
185
                                                        G_PARAM_READWRITE));
 
186
 
 
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"),
 
191
                                                         FALSE,
 
192
                                                         G_PARAM_READWRITE));
 
193
 
 
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"),
 
198
                                                         FALSE,
 
199
                                                         G_PARAM_READWRITE));
 
200
 
 
201
  /*
 
202
   * Child properties.
 
203
   */
 
204
  install_child_property (gobject_class, CHILD_PROP_LEFT_PADDING,
 
205
                          g_param_spec_double ("left-padding", 
 
206
                                               _("Left Padding"), 
 
207
                                               _("Extra space to add to the left of the item"),
 
208
                                               0.0, G_MAXDOUBLE, 0.0,
 
209
                                               G_PARAM_READWRITE));
 
210
  install_child_property (gobject_class, CHILD_PROP_RIGHT_PADDING,
 
211
                          g_param_spec_double ("right-padding", 
 
212
                                               _("Right Padding"), 
 
213
                                               _("Extra space to add to the right of the item"),
 
214
                                               0.0, G_MAXDOUBLE, 0.0,
 
215
                                               G_PARAM_READWRITE));
 
216
  install_child_property (gobject_class, CHILD_PROP_TOP_PADDING,
 
217
                          g_param_spec_double ("top-padding", 
 
218
                                               _("Top Padding"), 
 
219
                                               _("Extra space to add above the item"),
 
220
                                               0.0, G_MAXDOUBLE, 0.0,
 
221
                                               G_PARAM_READWRITE));
 
222
  install_child_property (gobject_class, CHILD_PROP_BOTTOM_PADDING,
 
223
                          g_param_spec_double ("bottom-padding", 
 
224
                                               _("Bottom Padding"), 
 
225
                                               _("Extra space to add below the item"),
 
226
                                               0.0, G_MAXDOUBLE, 0.0,
 
227
                                               G_PARAM_READWRITE));
 
228
 
 
229
  install_child_property (gobject_class, CHILD_PROP_X_ALIGN,
 
230
                          g_param_spec_double ("x-align", 
 
231
                                               _("X Align"), 
 
232
                                               _("The horizontal position of the item within its allocated space. 0.0 is left-aligned, 1.0 is right-aligned"),
 
233
                                               0.0, 1.0, 0.5,
 
234
                                               G_PARAM_READWRITE));
 
235
  install_child_property (gobject_class, CHILD_PROP_Y_ALIGN,
 
236
                          g_param_spec_double ("y-align", 
 
237
                                               _("Y Align"), 
 
238
                                               _("The vertical position of the item within its allocated space. 0.0 is top-aligned, 1.0 is bottom-aligned"),
 
239
                                               0.0, 1.0, 0.5,
 
240
                                               G_PARAM_READWRITE));
 
241
 
 
242
  install_child_property (gobject_class, CHILD_PROP_ROW,
 
243
                          g_param_spec_uint ("row", 
 
244
                                             _("Row"), 
 
245
                                             _("The row to place the item in"),
 
246
                                             0, 65535, 0,
 
247
                                             G_PARAM_READWRITE));
 
248
  install_child_property (gobject_class, CHILD_PROP_COLUMN,
 
249
                          g_param_spec_uint ("column", 
 
250
                                             _("Column"), 
 
251
                                             _("The column to place the item in"),
 
252
                                             0, 65535, 0,
 
253
                                             G_PARAM_READWRITE));
 
254
  install_child_property (gobject_class, CHILD_PROP_ROWS,
 
255
                          g_param_spec_uint ("rows", 
 
256
                                             _("Rows"), 
 
257
                                             _("The number of rows that the item spans"),
 
258
                                             0, 65535, 1,
 
259
                                             G_PARAM_READWRITE));
 
260
  install_child_property (gobject_class, CHILD_PROP_COLUMNS,
 
261
                          g_param_spec_uint ("columns", 
 
262
                                             _("Columns"), 
 
263
                                             _("The number of columns that the item spans"),
 
264
                                             0, 65535, 1,
 
265
                                             G_PARAM_READWRITE));
 
266
 
 
267
  install_child_property (gobject_class, CHILD_PROP_X_EXPAND,
 
268
                          g_param_spec_boolean ("x-expand", 
 
269
                                                _("X Expand"), 
 
270
                                                _("If the item expands horizontally as the table expands"),
 
271
                                                FALSE,
 
272
                                                G_PARAM_READWRITE));
 
273
  install_child_property (gobject_class, CHILD_PROP_X_FILL,
 
274
                          g_param_spec_boolean ("x-fill", 
 
275
                                                _("X Fill"), 
 
276
                                                _("If the item fills all horizontal allocated space"),
 
277
                                                FALSE,
 
278
                                                G_PARAM_READWRITE));
 
279
  install_child_property (gobject_class, CHILD_PROP_X_SHRINK,
 
280
                          g_param_spec_boolean ("x-shrink", 
 
281
                                                _("X Shrink"), 
 
282
                                                _("If the item can shrink smaller than its requested size horizontally"),
 
283
                                                FALSE,
 
284
                                                G_PARAM_READWRITE));
 
285
  install_child_property (gobject_class, CHILD_PROP_Y_EXPAND,
 
286
                          g_param_spec_boolean ("y-expand", 
 
287
                                                _("Y Expand"), 
 
288
                                                _("If the item expands vertically as the table expands"),
 
289
                                                FALSE,
 
290
                                                G_PARAM_READWRITE));
 
291
  install_child_property (gobject_class, CHILD_PROP_Y_FILL,
 
292
                          g_param_spec_boolean ("y-fill", 
 
293
                                                _("Y Fill"), 
 
294
                                                _("If the item fills all vertical allocated space"),
 
295
                                                FALSE,
 
296
                                                G_PARAM_READWRITE));
 
297
  install_child_property (gobject_class, CHILD_PROP_Y_SHRINK,
 
298
                          g_param_spec_boolean ("y-shrink", 
 
299
                                                _("Y Shrink"), 
 
300
                                                _("If the item can shrink smaller than its requested size vertically"),
 
301
                                                FALSE,
 
302
                                                G_PARAM_READWRITE));
 
303
}
 
304
 
 
305
 
 
306
static void
 
307
goo_canvas_table_class_init (GooCanvasTableClass *klass)
 
308
{
 
309
  GObjectClass *gobject_class = (GObjectClass*) klass;
 
310
 
 
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;
 
314
 
 
315
  goo_canvas_table_install_common_properties (gobject_class, goo_canvas_item_class_install_child_property);
 
316
}
 
317
 
 
318
 
 
319
/* This frees the contents of the table data, but not the struct itself. */
 
320
static void
 
321
goo_canvas_table_init_data (GooCanvasTableData *table_data)
 
322
{
 
323
  gint d;
 
324
 
 
325
  table_data->width = -1.0;
 
326
  table_data->height = -1.0;
 
327
 
 
328
  for (d = 0; d < 2; d++)
 
329
    {
 
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;
 
334
    }
 
335
 
 
336
  table_data->border_width = 0.0;
 
337
 
 
338
  table_data->children = g_array_new (0, 0, sizeof (GooCanvasTableChild));
 
339
}
 
340
 
 
341
 
 
342
/* This frees the contents of the table data, but not the struct itself. */
 
343
static void
 
344
goo_canvas_table_free_data (GooCanvasTableData *table_data)
 
345
{
 
346
  gint d;
 
347
 
 
348
  g_array_free (table_data->children, TRUE);
 
349
 
 
350
  for (d = 0; d < 2; d++)
 
351
    {
 
352
      g_free (table_data->dimensions[d].spacings);
 
353
      table_data->dimensions[d].spacings = NULL;
 
354
    }
 
355
 
 
356
  goo_canvas_table_free_layout_data (table_data);
 
357
}
 
358
 
 
359
 
 
360
static void
 
361
goo_canvas_table_init (GooCanvasTable *table)
 
362
{
 
363
  table->table_data = g_slice_new0 (GooCanvasTableData);
 
364
  goo_canvas_table_init_data (table->table_data);
 
365
}
 
366
 
 
367
 
 
368
/**
 
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.
 
374
 * 
 
375
 * Creates a new table item.
 
376
 *
 
377
 * <!--PARAMETERS-->
 
378
 *
 
379
 * Here's an example showing how to create a table with a square, a circle and
 
380
 * a triangle in it:
 
381
 *
 
382
 * <informalexample><programlisting>
 
383
 *  GooCanvasItem *table, *square, *circle, *triangle;
 
384
 *  
 
385
 *  table = goo_canvas_table_new (root,
 
386
 *                                "row-spacing", 4.0,
 
387
 *                                "column-spacing", 4.0,
 
388
 *                                NULL);
 
389
 *  goo_canvas_item_translate (table, 400, 200);
 
390
 *  
 
391
 *  square = goo_canvas_rect_new (table, 0.0, 0.0, 50.0, 50.0,
 
392
 *                                "fill-color", "red",
 
393
 *                                NULL);
 
394
 *  goo_canvas_item_set_child_properties (table, square,
 
395
 *                                        "row", 0,
 
396
 *                                        "column", 0,
 
397
 *                                        NULL);
 
398
 *  
 
399
 *  circle = goo_canvas_ellipse_new (table, 0.0, 0.0, 25.0, 25.0,
 
400
 *                                   "fill-color", "blue",
 
401
 *                                   NULL);
 
402
 *  goo_canvas_item_set_child_properties (table, circle,
 
403
 *                                        "row", 0,
 
404
 *                                        "column", 1,
 
405
 *                                        NULL);
 
406
 *  
 
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",
 
410
 *                                      NULL);
 
411
 *  goo_canvas_item_set_child_properties (table, triangle,
 
412
 *                                        "row", 0,
 
413
 *                                        "column", 2,
 
414
 *                                        NULL);
 
415
 * </programlisting></informalexample>
 
416
 * 
 
417
 * Returns: a new table item.
 
418
 **/
 
419
GooCanvasItem*
 
420
goo_canvas_table_new (GooCanvasItem  *parent,
 
421
                      ...)
 
422
{
 
423
  GooCanvasItem *item;
 
424
  va_list var_args;
 
425
  const char *first_property;
 
426
 
 
427
  item = g_object_new (GOO_TYPE_CANVAS_TABLE, NULL);
 
428
 
 
429
  va_start (var_args, parent);
 
430
  first_property = va_arg (var_args, char*);
 
431
  if (first_property)
 
432
    g_object_set_valist (G_OBJECT (item), first_property, var_args);
 
433
  va_end (var_args);
 
434
 
 
435
  if (parent)
 
436
    {
 
437
      goo_canvas_item_add_child (parent, item, -1);
 
438
      g_object_unref (item);
 
439
    }
 
440
 
 
441
  return item;
 
442
}
 
443
 
 
444
 
 
445
static void
 
446
goo_canvas_table_finalize (GObject *object)
 
447
{
 
448
  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
 
449
  GooCanvasTable *table = (GooCanvasTable*) object;
 
450
 
 
451
  if (!simple->model)
 
452
    {
 
453
      goo_canvas_table_free_data (table->table_data);
 
454
      g_slice_free (GooCanvasTableData, table->table_data);
 
455
    }
 
456
  table->table_data = NULL;
 
457
 
 
458
  G_OBJECT_CLASS (goo_canvas_table_parent_class)->finalize (object);
 
459
}
 
460
 
 
461
 
 
462
static void
 
463
goo_canvas_table_get_common_property (GObject              *object,
 
464
                                      GooCanvasTableData   *table_data,
 
465
                                      guint                 prop_id,
 
466
                                      GValue               *value,
 
467
                                      GParamSpec           *pspec)
 
468
{
 
469
  switch (prop_id)
 
470
    {
 
471
    case PROP_WIDTH:
 
472
      g_value_set_double (value, table_data->width);
 
473
      break;
 
474
    case PROP_HEIGHT:
 
475
      g_value_set_double (value, table_data->height);
 
476
      break;
 
477
    case PROP_ROW_SPACING:
 
478
      g_value_set_double (value, table_data->dimensions[VERT].default_spacing);
 
479
      break;
 
480
    case PROP_COLUMN_SPACING:
 
481
      g_value_set_double (value, table_data->dimensions[HORZ].default_spacing);
 
482
      break;
 
483
    case PROP_HOMOGENEOUS_ROWS:
 
484
      g_value_set_boolean (value, table_data->dimensions[VERT].homogeneous);
 
485
      break;
 
486
    case PROP_HOMOGENEOUS_COLUMNS:
 
487
      g_value_set_boolean (value, table_data->dimensions[HORZ].homogeneous);
 
488
      break;
 
489
    default:
 
490
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
491
      break;
 
492
    }
 
493
}
 
494
 
 
495
 
 
496
static void
 
497
goo_canvas_table_get_property (GObject              *object,
 
498
                               guint                 prop_id,
 
499
                               GValue               *value,
 
500
                               GParamSpec           *pspec)
 
501
{
 
502
  GooCanvasTable *table = (GooCanvasTable*) object;
 
503
 
 
504
  goo_canvas_table_get_common_property (object, table->table_data,
 
505
                                        prop_id, value, pspec);
 
506
}
 
507
 
 
508
 
 
509
static gboolean
 
510
goo_canvas_table_set_common_property (GObject              *object,
 
511
                                      GooCanvasTableData   *table_data,
 
512
                                      guint                 prop_id,
 
513
                                      const GValue         *value,
 
514
                                      GParamSpec           *pspec)
 
515
{
 
516
  gboolean recompute_bounds = TRUE;
 
517
 
 
518
  switch (prop_id)
 
519
    {
 
520
    case PROP_WIDTH:
 
521
      table_data->width = g_value_get_double (value);
 
522
      break;
 
523
    case PROP_HEIGHT:
 
524
      table_data->height = g_value_get_double (value);
 
525
      break;
 
526
    case PROP_ROW_SPACING:
 
527
      table_data->dimensions[VERT].default_spacing = g_value_get_double (value);
 
528
      break;
 
529
    case PROP_COLUMN_SPACING:
 
530
      table_data->dimensions[HORZ].default_spacing = g_value_get_double (value);
 
531
      break;
 
532
    case PROP_HOMOGENEOUS_ROWS:
 
533
      table_data->dimensions[VERT].homogeneous = g_value_get_boolean (value);
 
534
      break;
 
535
    case PROP_HOMOGENEOUS_COLUMNS:
 
536
      table_data->dimensions[HORZ].homogeneous = g_value_get_boolean (value);
 
537
      break;
 
538
    default:
 
539
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
540
      break;
 
541
    }
 
542
 
 
543
  return recompute_bounds;
 
544
}
 
545
 
 
546
 
 
547
static void
 
548
goo_canvas_table_set_property (GObject              *object,
 
549
                               guint                 prop_id,
 
550
                               const GValue         *value,
 
551
                               GParamSpec           *pspec)
 
552
{
 
553
  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
 
554
  GooCanvasTable *table = (GooCanvasTable*) object;
 
555
  gboolean recompute_bounds;
 
556
 
 
557
  if (simple->model)
 
558
    {
 
559
      g_warning ("Can't set property of a canvas item with a model - set the model property instead");
 
560
      return;
 
561
    }
 
562
 
 
563
  recompute_bounds = goo_canvas_table_set_common_property (object,
 
564
                                                           table->table_data,
 
565
                                                           prop_id, value,
 
566
                                                           pspec);
 
567
  goo_canvas_item_simple_changed (simple, recompute_bounds);
 
568
}
 
569
 
 
570
 
 
571
static void
 
572
goo_canvas_table_update_dimensions (GooCanvasTableData    *table_data,
 
573
                                    GooCanvasTableChild   *table_child)
 
574
{
 
575
  gint d, size, i;
 
576
 
 
577
  for (d = 0; d < 2; d++)
 
578
    {
 
579
      size = table_child->start[d] + table_child->size[d];
 
580
 
 
581
      if (size > table_data->dimensions[d].size)
 
582
        {
 
583
          table_data->dimensions[d].spacings = g_realloc (table_data->dimensions[d].spacings, size * sizeof (gdouble));
 
584
 
 
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;
 
588
 
 
589
          table_data->dimensions[d].size = size;
 
590
        }
 
591
    }
 
592
}
 
593
 
 
594
 
 
595
static void
 
596
goo_canvas_table_add_child_internal (GooCanvasTableData *table_data,
 
597
                                     gint                position)
 
598
{
 
599
  GooCanvasTableChild table_child;
 
600
  gint d;
 
601
 
 
602
  /* Initialize a table child struct. */
 
603
  for (d = 0; d < 2; d++)
 
604
    {
 
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;
 
610
 
 
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;
 
614
    }
 
615
 
 
616
  if (position < 0)
 
617
    position = table_data->children->len;
 
618
  g_array_insert_val (table_data->children, position, table_child);
 
619
 
 
620
  goo_canvas_table_update_dimensions (table_data, &table_child);
 
621
}
 
622
 
 
623
 
 
624
static void
 
625
goo_canvas_table_add_child     (GooCanvasItem  *item,
 
626
                                GooCanvasItem  *child,
 
627
                                gint            position)
 
628
{
 
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;
 
633
 
 
634
  if (!simple->model)
 
635
    goo_canvas_table_add_child_internal (table->table_data, position);
 
636
 
 
637
  /* Let the parent GooCanvasGroup code do the rest. */
 
638
  parent_iface->add_child (item, child, position);
 
639
}
 
640
 
 
641
 
 
642
static void
 
643
goo_canvas_table_move_child_internal    (GooCanvasTableData *table_data,
 
644
                                         gint                old_position,
 
645
                                         gint                new_position)
 
646
{
 
647
  GooCanvasTableChild *table_child, tmp_child;
 
648
 
 
649
  /* Copy the child temporarily. */
 
650
  table_child = &g_array_index (table_data->children, GooCanvasTableChild,
 
651
                                old_position);
 
652
  tmp_child = *table_child;
 
653
 
 
654
  /* Move the array data up or down. */
 
655
  if (new_position > old_position)
 
656
    {
 
657
      /* Move the items down one place. */
 
658
      g_memmove (table_child,
 
659
                 &g_array_index (table_data->children, GooCanvasTableChild,
 
660
                                 old_position + 1),
 
661
                 sizeof (GooCanvasTableChild) * (new_position - old_position));
 
662
    }
 
663
  else
 
664
    {
 
665
      /* Move the items up one place. */
 
666
      g_memmove (&g_array_index (table_data->children, GooCanvasTableChild,
 
667
                                 new_position + 1),
 
668
                 &g_array_index (table_data->children, GooCanvasTableChild,
 
669
                                 new_position),
 
670
                 sizeof (GooCanvasTableChild) * (old_position - new_position));
 
671
    }
 
672
 
 
673
  /* Copy the child into its new position. */
 
674
  table_child = &g_array_index (table_data->children, GooCanvasTableChild,
 
675
                                new_position);
 
676
  *table_child = tmp_child;
 
677
}
 
678
 
 
679
 
 
680
static void
 
681
goo_canvas_table_move_child    (GooCanvasItem  *item,
 
682
                                gint            old_position,
 
683
                                gint            new_position)
 
684
{
 
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;
 
689
 
 
690
  if (!simple->model)
 
691
    goo_canvas_table_move_child_internal (table->table_data, old_position,
 
692
                                          new_position);
 
693
 
 
694
  /* Let the parent GooCanvasGroup code do the rest. */
 
695
  parent_iface->move_child (item, old_position, new_position);
 
696
}
 
697
 
 
698
 
 
699
static void
 
700
goo_canvas_table_remove_child  (GooCanvasItem  *item,
 
701
                                gint            child_num)
 
702
{
 
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;
 
707
 
 
708
  if (!simple->model)
 
709
    g_array_remove_index (table->table_data->children, child_num);
 
710
 
 
711
  /* Let the parent GooCanvasGroup code do the rest. */
 
712
  parent_iface->remove_child (item, child_num);
 
713
}
 
714
 
 
715
 
 
716
static void
 
717
goo_canvas_table_get_common_child_property (GObject             *object,
 
718
                                            GooCanvasTableChild *table_child,
 
719
                                            guint                property_id,
 
720
                                            GValue              *value,
 
721
                                            GParamSpec          *pspec)
 
722
{
 
723
  switch (property_id)
 
724
    {
 
725
    case CHILD_PROP_LEFT_PADDING:
 
726
      g_value_set_double (value, table_child->start_pad[HORZ]);
 
727
      break;
 
728
    case CHILD_PROP_RIGHT_PADDING:
 
729
      g_value_set_double (value, table_child->end_pad[HORZ]);
 
730
      break;
 
731
    case CHILD_PROP_TOP_PADDING:
 
732
      g_value_set_double (value, table_child->start_pad[VERT]);
 
733
      break;
 
734
    case CHILD_PROP_BOTTOM_PADDING:
 
735
      g_value_set_double (value, table_child->end_pad[VERT]);
 
736
      break;
 
737
    case CHILD_PROP_X_ALIGN:
 
738
      g_value_set_double (value, table_child->align[HORZ]);
 
739
      break;
 
740
    case CHILD_PROP_Y_ALIGN:
 
741
      g_value_set_double (value, table_child->align[VERT]);
 
742
      break;
 
743
    case CHILD_PROP_ROW:
 
744
      g_value_set_uint (value, table_child->start[VERT]);
 
745
      break;
 
746
    case CHILD_PROP_COLUMN:
 
747
      g_value_set_uint (value, table_child->start[HORZ]);
 
748
      break;
 
749
    case CHILD_PROP_ROWS:
 
750
      g_value_set_uint (value, table_child->size[VERT]);
 
751
      break;
 
752
    case CHILD_PROP_COLUMNS:
 
753
      g_value_set_uint (value, table_child->size[HORZ]);
 
754
      break;
 
755
    case CHILD_PROP_X_EXPAND:
 
756
      g_value_set_boolean (value, table_child->flags[HORZ] & GOO_CANVAS_TABLE_CHILD_EXPAND);
 
757
      break;
 
758
    case CHILD_PROP_X_FILL:
 
759
      g_value_set_boolean (value, table_child->flags[HORZ] & GOO_CANVAS_TABLE_CHILD_FILL);
 
760
      break;
 
761
    case CHILD_PROP_X_SHRINK:
 
762
      g_value_set_boolean (value, table_child->flags[HORZ] & GOO_CANVAS_TABLE_CHILD_SHRINK);
 
763
      break;
 
764
    case CHILD_PROP_Y_EXPAND:
 
765
      g_value_set_boolean (value, table_child->flags[VERT] & GOO_CANVAS_TABLE_CHILD_EXPAND);
 
766
      break;
 
767
    case CHILD_PROP_Y_FILL:
 
768
      g_value_set_boolean (value, table_child->flags[VERT] & GOO_CANVAS_TABLE_CHILD_FILL);
 
769
      break;
 
770
    case CHILD_PROP_Y_SHRINK:
 
771
      g_value_set_boolean (value, table_child->flags[VERT] & GOO_CANVAS_TABLE_CHILD_SHRINK);
 
772
      break;
 
773
    default:
 
774
      G_OBJECT_WARN_INVALID_PSPEC ((object), "child property id",
 
775
                                   (property_id), (pspec));
 
776
      break;
 
777
    }
 
778
}
 
779
 
 
780
 
 
781
static void
 
782
goo_canvas_table_get_child_property (GooCanvasItem     *item,
 
783
                                     GooCanvasItem     *child,
 
784
                                     guint              property_id,
 
785
                                     GValue            *value,
 
786
                                     GParamSpec        *pspec)
 
787
{
 
788
  GooCanvasGroup *group = (GooCanvasGroup*) item;
 
789
  GooCanvasTable *table = (GooCanvasTable*) item;
 
790
  GooCanvasTableChild *table_child;
 
791
  gint child_num;
 
792
 
 
793
  for (child_num = 0; child_num < group->items->len; child_num++)
 
794
    {
 
795
      if (group->items->pdata[child_num] == child)
 
796
        {
 
797
          table_child = &g_array_index (table->table_data->children,
 
798
                                        GooCanvasTableChild, child_num);
 
799
          goo_canvas_table_get_common_child_property ((GObject*) table,
 
800
                                                      table_child,
 
801
                                                      property_id, value,
 
802
                                                      pspec);
 
803
          break;
 
804
        }
 
805
    }
 
806
}
 
807
 
 
808
 
 
809
static void
 
810
goo_canvas_table_set_common_child_property (GObject             *object,
 
811
                                            GooCanvasTableData  *table_data,
 
812
                                            GooCanvasTableChild *table_child,
 
813
                                            guint                property_id,
 
814
                                            const GValue        *value,
 
815
                                            GParamSpec          *pspec)
 
816
{
 
817
  switch (property_id)
 
818
    {
 
819
    case CHILD_PROP_LEFT_PADDING:
 
820
      table_child->start_pad[HORZ] = g_value_get_double (value);
 
821
      break;
 
822
    case CHILD_PROP_RIGHT_PADDING:
 
823
      table_child->end_pad[HORZ] = g_value_get_double (value);
 
824
      break;
 
825
    case CHILD_PROP_TOP_PADDING:
 
826
      table_child->start_pad[VERT] = g_value_get_double (value);
 
827
      break;
 
828
    case CHILD_PROP_BOTTOM_PADDING:
 
829
      table_child->end_pad[VERT] = g_value_get_double (value);
 
830
      break;
 
831
    case CHILD_PROP_X_ALIGN:
 
832
      table_child->align[HORZ] = g_value_get_double (value);
 
833
      break;
 
834
    case CHILD_PROP_Y_ALIGN:
 
835
      table_child->align[VERT] = g_value_get_double (value);
 
836
      break;
 
837
    case CHILD_PROP_ROW:
 
838
      table_child->start[VERT] = g_value_get_uint (value);
 
839
      break;
 
840
    case CHILD_PROP_COLUMN:
 
841
      table_child->start[HORZ] = g_value_get_uint (value);
 
842
      break;
 
843
    case CHILD_PROP_ROWS:
 
844
      table_child->size[VERT] = g_value_get_uint (value);
 
845
      break;
 
846
    case CHILD_PROP_COLUMNS:
 
847
      table_child->size[HORZ] = g_value_get_uint (value);
 
848
      break;
 
849
 
 
850
    case CHILD_PROP_X_EXPAND:
 
851
      if (g_value_get_boolean (value))
 
852
        table_child->flags[HORZ] |= GOO_CANVAS_TABLE_CHILD_EXPAND;
 
853
      else
 
854
        table_child->flags[HORZ] &= ~GOO_CANVAS_TABLE_CHILD_EXPAND;
 
855
      break;
 
856
    case CHILD_PROP_X_FILL:
 
857
      if (g_value_get_boolean (value))
 
858
        table_child->flags[HORZ] |= GOO_CANVAS_TABLE_CHILD_FILL;
 
859
      else
 
860
        table_child->flags[HORZ] &= ~GOO_CANVAS_TABLE_CHILD_FILL;
 
861
      break;
 
862
    case CHILD_PROP_X_SHRINK:
 
863
      if (g_value_get_boolean (value))
 
864
        table_child->flags[HORZ] |= GOO_CANVAS_TABLE_CHILD_SHRINK;
 
865
      else
 
866
        table_child->flags[HORZ] &= ~GOO_CANVAS_TABLE_CHILD_SHRINK;
 
867
      break;
 
868
 
 
869
    case CHILD_PROP_Y_EXPAND:
 
870
      if (g_value_get_boolean (value))
 
871
        table_child->flags[VERT] |= GOO_CANVAS_TABLE_CHILD_EXPAND;
 
872
      else
 
873
        table_child->flags[VERT] &= ~GOO_CANVAS_TABLE_CHILD_EXPAND;
 
874
      break;
 
875
    case CHILD_PROP_Y_FILL:
 
876
      if (g_value_get_boolean (value))
 
877
        table_child->flags[VERT] |= GOO_CANVAS_TABLE_CHILD_FILL;
 
878
      else
 
879
        table_child->flags[VERT] &= ~GOO_CANVAS_TABLE_CHILD_FILL;
 
880
      break;
 
881
    case CHILD_PROP_Y_SHRINK:
 
882
      if (g_value_get_boolean (value))
 
883
        table_child->flags[VERT] |= GOO_CANVAS_TABLE_CHILD_SHRINK;
 
884
      else
 
885
        table_child->flags[VERT] &= ~GOO_CANVAS_TABLE_CHILD_SHRINK;
 
886
      break;
 
887
 
 
888
    default:
 
889
      G_OBJECT_WARN_INVALID_PSPEC ((object), "child property id",
 
890
                                   (property_id), (pspec));
 
891
      break;
 
892
    }
 
893
 
 
894
  goo_canvas_table_update_dimensions (table_data, table_child);
 
895
}
 
896
 
 
897
 
 
898
static void
 
899
goo_canvas_table_set_child_property (GooCanvasItem     *item,
 
900
                                     GooCanvasItem     *child,
 
901
                                     guint              property_id,
 
902
                                     const GValue      *value,
 
903
                                     GParamSpec        *pspec)
 
904
{
 
905
  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
 
906
  GooCanvasGroup *group = (GooCanvasGroup*) item;
 
907
  GooCanvasTable *table = (GooCanvasTable*) item;
 
908
  GooCanvasTableChild *table_child;
 
909
  gint child_num;
 
910
 
 
911
  for (child_num = 0; child_num < group->items->len; child_num++)
 
912
    {
 
913
      if (group->items->pdata[child_num] == child)
 
914
        {
 
915
          table_child = &g_array_index (table->table_data->children,
 
916
                                        GooCanvasTableChild, child_num);
 
917
          goo_canvas_table_set_common_child_property ((GObject*) table,
 
918
                                                      table->table_data,
 
919
                                                      table_child,
 
920
                                                      property_id, value,
 
921
                                                      pspec);
 
922
          break;
 
923
        }
 
924
    }
 
925
 
 
926
  goo_canvas_item_simple_changed (simple, TRUE);
 
927
}
 
928
 
 
929
 
 
930
static void
 
931
goo_canvas_table_set_model    (GooCanvasItem      *item,
 
932
                               GooCanvasItemModel *model)
 
933
{
 
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;
 
939
 
 
940
  /* If our table_data was allocated, free it. */
 
941
  if (!simple->model)
 
942
    {
 
943
      goo_canvas_table_free_data (table->table_data);
 
944
      g_slice_free (GooCanvasTableData, table->table_data);
 
945
    }
 
946
 
 
947
  /* Now use the new model's table_data instead. */
 
948
  table->table_data = &tmodel->table_data;
 
949
 
 
950
  /* Let the parent GooCanvasGroup code do the rest. */
 
951
  parent_iface->set_model (item, model);
 
952
}
 
953
 
 
954
 
 
955
/*
 
956
 * Size requisition/allocation code.
 
957
 */
 
958
 
 
959
static void
 
960
goo_canvas_table_free_layout_data (GooCanvasTableData *table_data)
 
961
{
 
962
  if (table_data->layout_data)
 
963
    {
 
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;
 
969
    }
 
970
}
 
971
 
 
972
 
 
973
/* This allocates the layout data, and initializes the row and column data. */
 
974
static void
 
975
goo_canvas_table_init_layout_data (GooCanvasTable *table)
 
976
{
 
977
  GooCanvasTableData *table_data = table->table_data;
 
978
  GooCanvasTableDimension *dimension;
 
979
  GooCanvasTableLayoutData *layout_data;
 
980
  GooCanvasTableDimensionLayoutData *dldata;
 
981
  gint d, i;
 
982
 
 
983
  /* Free any previous data, just in case it hasn't been freed. */
 
984
  goo_canvas_table_free_layout_data (table->table_data);
 
985
 
 
986
  layout_data = g_slice_new (GooCanvasTableLayoutData);
 
987
 
 
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);
 
993
 
 
994
  for (d = 0; d < 2; d++)
 
995
    {
 
996
      dimension = &table_data->dimensions[d];
 
997
 
 
998
      layout_data->dldata[d] = g_new (GooCanvasTableDimensionLayoutData,
 
999
                                      dimension->size);
 
1000
      dldata = layout_data->dldata[d];
 
1001
 
 
1002
      for (i = 0; i < dimension->size; i++)
 
1003
        {
 
1004
          /* Calculate the actual spacings. If -ve use the default. */
 
1005
          if (dimension->spacings[i] > 0)
 
1006
            dldata[i].spacing = dimension->spacings[i];
 
1007
          else
 
1008
            dldata[i].spacing = dimension->default_spacing;
 
1009
 
 
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;
 
1016
        }
 
1017
    }
 
1018
}
 
1019
 
 
1020
 
 
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. */
 
1023
static void
 
1024
goo_canvas_table_size_request_init (GooCanvasTable *table,
 
1025
                                    cairo_t        *cr)
 
1026
{
 
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;
 
1036
  guint8 flags;
 
1037
 
 
1038
  for (i = 0; i < table_data->children->len; i++)
 
1039
    {
 
1040
      child = &g_array_index (table_data->children, GooCanvasTableChild, i);
 
1041
      child_item = group->items->pdata[i];
 
1042
 
 
1043
      /* Children will return FALSE if they don't need space allocated. */
 
1044
      allocate = goo_canvas_item_get_requested_area (child_item, cr, &bounds);
 
1045
 
 
1046
      layout_data->children[i].requested_position[HORZ] = bounds.x1;
 
1047
      layout_data->children[i].requested_position[VERT] = bounds.y1;
 
1048
 
 
1049
      if (!allocate)
 
1050
        {
 
1051
          layout_data->children[i].requested_size[HORZ] = -1.0;
 
1052
          layout_data->children[i].requested_size[VERT] = -1.0;
 
1053
          continue;
 
1054
        }
 
1055
 
 
1056
      layout_data->children[i].requested_size[HORZ] = bounds.x2 - bounds.x1;
 
1057
      layout_data->children[i].requested_size[VERT] = bounds.y2 - bounds.y1;
 
1058
 
 
1059
      for (d = 0; d < 2; d++)
 
1060
        {
 
1061
          dldata = layout_data->dldata[d];
 
1062
          start = child->start[d];
 
1063
          flags = child->flags[d];
 
1064
 
 
1065
          if (child->size[d] == 1)
 
1066
            {
 
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;
 
1072
            }
 
1073
        }
 
1074
    }
 
1075
 
 
1076
 
 
1077
  for (i = 0; i < table_data->children->len; i++)
 
1078
    {
 
1079
      child = &g_array_index (table_data->children, GooCanvasTableChild, i);
 
1080
 
 
1081
      if (layout_data->children[i].requested_size[HORZ] < 0.0)
 
1082
        continue;
 
1083
 
 
1084
      for (d = 0; d < 2; d++)
 
1085
        {
 
1086
          dldata = layout_data->dldata[d];
 
1087
          start = child->start[d];
 
1088
          end = start + child->size[d] - 1;
 
1089
          flags = child->flags[d];
 
1090
 
 
1091
          if (child->size[d] != 1)
 
1092
            {
 
1093
              has_expand = FALSE;
 
1094
              has_shrink = TRUE;
 
1095
 
 
1096
              for (j = start; j <= end; j++)
 
1097
                {
 
1098
                  dldata[j].empty = FALSE;
 
1099
                  if (dldata[j].expand)
 
1100
                    has_expand = TRUE;
 
1101
                  if (!dldata[j].shrink)
 
1102
                    has_shrink = FALSE;
 
1103
                }
 
1104
 
 
1105
              if (!has_expand && (flags & GOO_CANVAS_TABLE_CHILD_EXPAND))
 
1106
                {
 
1107
                  for (j = start; j <= end; j++)
 
1108
                    dldata[j].need_expand = TRUE;
 
1109
                }
 
1110
 
 
1111
              if (has_shrink && !(flags & GOO_CANVAS_TABLE_CHILD_SHRINK))
 
1112
                {
 
1113
                  for (j = start; j <= end; j++)
 
1114
                    dldata[j].need_shrink = FALSE;
 
1115
                }
 
1116
            }
 
1117
        }
 
1118
    }
 
1119
}
 
1120
 
 
1121
 
 
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.) */
 
1125
static void
 
1126
goo_canvas_table_size_request_pass1 (GooCanvasTable *table)
 
1127
{
 
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;
 
1135
  gint i;
 
1136
  
 
1137
  for (i = 0; i < table_data->children->len; i++)
 
1138
    {
 
1139
      child = &g_array_index (table_data->children, GooCanvasTableChild, i);
 
1140
 
 
1141
      requested_width = layout_data->children[i].requested_size[HORZ];
 
1142
      requested_height = layout_data->children[i].requested_size[VERT];
 
1143
 
 
1144
      /* Child needs allocation & spans a single row or column. */
 
1145
      if (requested_width >= 0.0 && child->size[HORZ] == 1)
 
1146
        {
 
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);
 
1150
        }
 
1151
 
 
1152
      if (requested_height >= 0.0 && child->size[VERT] == 1)
 
1153
        {
 
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);
 
1157
        }
 
1158
    }
 
1159
}
 
1160
 
 
1161
 
 
1162
/* This ensures that homogeneous tables have all rows/columns the same size. */
 
1163
static void
 
1164
goo_canvas_table_size_request_pass2 (GooCanvasTable *table)
 
1165
{
 
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;
 
1171
  gint row, column;
 
1172
  
 
1173
  if (table_data->dimensions[VERT].homogeneous)
 
1174
    {
 
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;
 
1180
    }
 
1181
 
 
1182
  if (table_data->dimensions[HORZ].homogeneous)
 
1183
    {
 
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;
 
1189
    }
 
1190
}
 
1191
 
 
1192
 
 
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
 
1195
   if needed. */
 
1196
static void
 
1197
goo_canvas_table_size_request_pass3 (GooCanvasTable *table)
 
1198
{
 
1199
  GooCanvasTableData *table_data = table->table_data;
 
1200
  GooCanvasTableLayoutData *layout_data = table_data->layout_data;
 
1201
  GooCanvasTableDimensionLayoutData *dldata;
 
1202
  GooCanvasTableChild *child;
 
1203
  gint i, j, d;
 
1204
  
 
1205
  for (i = 0; i < table_data->children->len; i++)
 
1206
    {
 
1207
      child = &g_array_index (table_data->children, GooCanvasTableChild, i);
 
1208
      
 
1209
      if (layout_data->children[i].requested_size[HORZ] <= 0.0)
 
1210
        continue;
 
1211
 
 
1212
      for (d = 0; d < 2; d++)
 
1213
        {
 
1214
          /* Child spans multiple rows/columns. */
 
1215
          if (child->size[d] != 1)
 
1216
            {
 
1217
              gint start = child->start[d];
 
1218
              gint end = start + child->size[d] - 1;
 
1219
              gdouble total_space = 0.0, space_needed;
 
1220
 
 
1221
              dldata = layout_data->dldata[d];
 
1222
 
 
1223
              /* Check if there is already enough space for the child. */
 
1224
              for (j = start; j <= end; j++)
 
1225
                {
 
1226
                  total_space += dldata[j].requisition;
 
1227
                  if (j < end)
 
1228
                    total_space += dldata[j].spacing;
 
1229
                }
 
1230
              
 
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];
 
1236
 
 
1237
              if (total_space < space_needed)
 
1238
                {
 
1239
                  gint n_expand = 0;
 
1240
                  gboolean force_expand = FALSE;
 
1241
                  gdouble expand = space_needed - total_space;
 
1242
                  gdouble extra;
 
1243
 
 
1244
                  for (j = start; j <= end; j++)
 
1245
                    {
 
1246
                      if (dldata[j].expand)
 
1247
                        n_expand++;
 
1248
                    }
 
1249
 
 
1250
                  if (n_expand == 0)
 
1251
                    {
 
1252
                      n_expand = child->size[d];
 
1253
                      force_expand = TRUE;
 
1254
                    }
 
1255
                    
 
1256
                  /* FIXME: Integer mode for widgets? */
 
1257
                  extra = expand / n_expand;
 
1258
                  for (j = start; j <= end; j++)
 
1259
                    {
 
1260
                      if (force_expand || dldata[j].expand)
 
1261
                        dldata[j].requisition += extra;
 
1262
                    }
 
1263
                }
 
1264
            }
 
1265
        }
 
1266
    }
 
1267
}
 
1268
 
 
1269
 
 
1270
/* Returns FALSE if item shouldn't be allocated. */
 
1271
static gboolean
 
1272
goo_canvas_table_get_requested_area (GooCanvasItem        *item,
 
1273
                                     cairo_t              *cr,
 
1274
                                     GooCanvasBounds      *requested_area)
 
1275
{
 
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;
 
1284
  
 
1285
  simple->bounds.x1 = simple->bounds.x2 = 0.0;
 
1286
  simple->bounds.y1 = simple->bounds.y2 = 0.0;
 
1287
 
 
1288
  simple->need_update = FALSE;
 
1289
 
 
1290
  goo_canvas_item_simple_check_style (simple);
 
1291
 
 
1292
  if (simple_data->visibility == GOO_CANVAS_ITEM_HIDDEN)
 
1293
    return FALSE;
 
1294
 
 
1295
  cairo_save (cr);
 
1296
  if (simple_data->transform)
 
1297
    cairo_transform (cr, simple_data->transform);
 
1298
 
 
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);
 
1305
  
 
1306
  layout_data = table_data->layout_data;
 
1307
  rows = layout_data->dldata[VERT];
 
1308
  columns = layout_data->dldata[HORZ];
 
1309
 
 
1310
  end = table_data->dimensions[HORZ].size - 1;
 
1311
  for (column = 0; column <= end; column++)
 
1312
    {
 
1313
      width += columns[column].requisition;
 
1314
      if (column < end)
 
1315
        width += columns[column].spacing;
 
1316
    }
 
1317
  
 
1318
  end = table_data->dimensions[VERT].size - 1;
 
1319
  for (row = 0; row <= end; row++)
 
1320
    {
 
1321
      height += rows[row].requisition;
 
1322
      if (row < end)
 
1323
        height += rows[row].spacing;
 
1324
    }
 
1325
 
 
1326
  width += table_data->border_width * 2;
 
1327
  height += table_data->border_width * 2;
 
1328
 
 
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;
 
1334
 
 
1335
  layout_data->requested_size[HORZ] = simple->bounds.x2 = width;
 
1336
  layout_data->requested_size[VERT] = simple->bounds.y2 = height;
 
1337
 
 
1338
  /* Copy the user bounds to the requested area. */
 
1339
  *requested_area = simple->bounds;
 
1340
 
 
1341
  /* Convert to the parent's coordinate space. */
 
1342
  goo_canvas_item_simple_user_bounds_to_parent (simple, cr, requested_area);
 
1343
 
 
1344
  /* Convert the item's bounds to device space. */
 
1345
  goo_canvas_item_simple_user_bounds_to_device (simple, cr, &simple->bounds);
 
1346
 
 
1347
  cairo_restore (cr);
 
1348
 
 
1349
  return TRUE;
 
1350
}
 
1351
 
 
1352
 
 
1353
static void
 
1354
goo_canvas_table_size_allocate_init (GooCanvasTable *table)
 
1355
{
 
1356
  GooCanvasTableData *table_data = table->table_data;
 
1357
  GooCanvasTableLayoutData *layout_data = table_data->layout_data;
 
1358
  GooCanvasTableDimension *dimension;
 
1359
  GooCanvasTableDimensionLayoutData *dldata;
 
1360
  gint d, i;
 
1361
  
 
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++)
 
1365
    {
 
1366
      dimension = &table_data->dimensions[d];
 
1367
      dldata = layout_data->dldata[d];
 
1368
 
 
1369
      for (i = 0; i < dimension->size; i++)
 
1370
        {
 
1371
          dldata[i].allocation = dldata[i].requisition;
 
1372
 
 
1373
          if (dldata[i].empty)
 
1374
            {
 
1375
              dldata[i].expand = FALSE;
 
1376
              dldata[i].shrink = FALSE;
 
1377
            }
 
1378
          else
 
1379
            {
 
1380
              if (dldata[i].need_expand)
 
1381
                dldata[i].expand = TRUE;
 
1382
              if (!dldata[i].need_shrink)
 
1383
                dldata[i].shrink = FALSE;
 
1384
            }
 
1385
        }
 
1386
    }
 
1387
}
 
1388
 
 
1389
 
 
1390
static void
 
1391
goo_canvas_table_size_allocate_pass1 (GooCanvasTable *table)
 
1392
{
 
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;
 
1399
  
 
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.
 
1403
   */
 
1404
  for (d = 0; d < 2; d++)
 
1405
    {
 
1406
      dimension = &table_data->dimensions[d];
 
1407
      dldata = layout_data->dldata[d];
 
1408
 
 
1409
      total_size = layout_data->allocated_size[d] - table_data->border_width * 2;
 
1410
 
 
1411
      if (dimension->homogeneous)
 
1412
        {
 
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)
 
1418
            nexpand = 1;
 
1419
          else
 
1420
            {
 
1421
              nexpand = 0;
 
1422
              for (i = 0; i < dimension->size; i++)
 
1423
                if (dldata[i].expand)
 
1424
                  {
 
1425
                    nexpand += 1;
 
1426
                    break;
 
1427
                  }
 
1428
            }
 
1429
          if (nexpand)
 
1430
            {
 
1431
              size_to_allocate = total_size;
 
1432
              for (i = 0; i + 1 < dimension->size; i++)
 
1433
                size_to_allocate -= dldata[i].spacing;
 
1434
          
 
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;
 
1439
            }
 
1440
        }
 
1441
      else
 
1442
        {
 
1443
          natural_size = 0;
 
1444
          nexpand = 0;
 
1445
          nshrink = 0;
 
1446
 
 
1447
          for (i = 0; i < dimension->size; i++)
 
1448
            {
 
1449
              natural_size += dldata[i].requisition;
 
1450
              if (dldata[i].expand)
 
1451
                nexpand += 1;
 
1452
              if (dldata[i].shrink)
 
1453
                nshrink += 1;
 
1454
            }
 
1455
          for (i = 0; i + 1 < dimension->size; i++)
 
1456
            natural_size += dldata[i].spacing;
 
1457
      
 
1458
          /* Check to see if we were allocated more width than we requested.
 
1459
           */
 
1460
          if ((natural_size < total_size) && (nexpand >= 1))
 
1461
            {
 
1462
              /* FIXME: Integer mode for widgets? */
 
1463
              extra = (total_size - natural_size) / nexpand;
 
1464
              for (i = 0; i < dimension->size; i++)
 
1465
                {
 
1466
                  if (dldata[i].expand)
 
1467
                    dldata[i].allocation += extra;
 
1468
                }
 
1469
            }
 
1470
          
 
1471
          /* Check to see if we were allocated less width than we requested,
 
1472
           * then shrink until we fit the size give.
 
1473
           */
 
1474
          if (natural_size > total_size)
 
1475
            {
 
1476
              gint total_nshrink = nshrink;
 
1477
              
 
1478
              extra = natural_size - total_size;
 
1479
              /* FIXME: Integer mode for widgets? */
 
1480
              while (total_nshrink > 0 && extra > 0)
 
1481
                {
 
1482
                  nshrink = total_nshrink;
 
1483
                  for (i = 0; i < dimension->size; i++)
 
1484
                    {
 
1485
                      if (dldata[i].shrink)
 
1486
                        {
 
1487
                          gdouble old_allocation = dldata[i].allocation;
 
1488
                        
 
1489
                          dldata[i].allocation = MAX (0.0, dldata[i].allocation - extra / nshrink);
 
1490
                          extra -= old_allocation - dldata[i].allocation;
 
1491
                          nshrink -= 1;
 
1492
                          if (dldata[i].allocation <= 0.0)
 
1493
                            {
 
1494
                              total_nshrink -= 1;
 
1495
                              dldata[i].shrink = FALSE;
 
1496
                            }
 
1497
                        }
 
1498
                    }
 
1499
                }
 
1500
            }
 
1501
        }
 
1502
    }
 
1503
}
 
1504
 
 
1505
 
 
1506
/* Calculates the start and end position of each row/column. */
 
1507
static void
 
1508
goo_canvas_table_size_allocate_pass2 (GooCanvasTable *table)
 
1509
{
 
1510
  GooCanvasTableData *table_data = table->table_data;
 
1511
  GooCanvasTableLayoutData *layout_data = table_data->layout_data;
 
1512
  GooCanvasTableDimension *dimension;
 
1513
  GooCanvasTableDimensionLayoutData *dldata;
 
1514
  gdouble pos;
 
1515
  gint d, i;
 
1516
 
 
1517
  for (d = 0; d < 2; d++)
 
1518
    {
 
1519
      dimension = &table_data->dimensions[d];
 
1520
      dldata = layout_data->dldata[d];
 
1521
 
 
1522
      pos = table_data->border_width;
 
1523
      for (i = 0; i < dimension->size; i++)
 
1524
        {
 
1525
          dldata[i].start = pos;
 
1526
          pos += dldata[i].allocation;
 
1527
          dldata[i].end = pos;
 
1528
          pos += dldata[i].spacing;
 
1529
        }
 
1530
    }
 
1531
}
 
1532
 
 
1533
 
 
1534
/* This does the actual allocation of each child, calculating its size and
 
1535
   position according to the rows & columns it spans. */
 
1536
static void
 
1537
goo_canvas_table_size_allocate_pass3 (GooCanvasTable *table,
 
1538
                                      cairo_t        *cr,
 
1539
                                      gdouble         table_x_offset,
 
1540
                                      gdouble         table_y_offset)
 
1541
{
 
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;
 
1557
 
 
1558
  if (simple->canvas)
 
1559
    direction = gtk_widget_get_direction (GTK_WIDGET (simple->canvas));
 
1560
 
 
1561
  for (i = 0; i < table_data->children->len; i++)
 
1562
    {
 
1563
      child = &g_array_index (table_data->children, GooCanvasTableChild, i);
 
1564
      child_item = group->items->pdata[i];
 
1565
      child_data = &layout_data->children[i];
 
1566
 
 
1567
      requested_width = child_data->requested_size[HORZ];
 
1568
      requested_height = child_data->requested_size[VERT];
 
1569
 
 
1570
      if (requested_width <= 0.0)
 
1571
        continue;
 
1572
      
 
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;
 
1577
 
 
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;
 
1582
 
 
1583
      width = max_width = MAX (0.0, max_width);
 
1584
      height = max_height = MAX (0.0, max_height);
 
1585
 
 
1586
      if (!(child->flags[HORZ] & GOO_CANVAS_TABLE_CHILD_FILL))
 
1587
        {
 
1588
          width = MIN (max_width, requested_width);
 
1589
          x += (max_width - width) * child->align[HORZ];
 
1590
        }
 
1591
          
 
1592
      if (!(child->flags[VERT] & GOO_CANVAS_TABLE_CHILD_FILL))
 
1593
        {
 
1594
          height = MIN (max_height, requested_height);
 
1595
          y += (max_height - height) * child->align[VERT];
 
1596
        }
 
1597
 
 
1598
      if (direction == GTK_TEXT_DIR_RTL)
 
1599
        x = layout_data->allocated_size[HORZ] - width;
 
1600
 
 
1601
      child->position[HORZ] = x - layout_data->children[i].requested_position[HORZ];
 
1602
      child->position[VERT] = y - layout_data->children[i].requested_position[VERT];
 
1603
 
 
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;
 
1608
 
 
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;
 
1613
 
 
1614
      /* Translate the cairo context so the item's user space is correct. */
 
1615
      cairo_translate (cr, child->position[HORZ], child->position[VERT]);
 
1616
 
 
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;
 
1622
 
 
1623
      goo_canvas_item_allocate_area (child_item, cr, &requested_area,
 
1624
                                     &allocated_area, x_offset, y_offset);
 
1625
 
 
1626
      cairo_translate (cr, -child->position[HORZ], -child->position[VERT]);
 
1627
    }
 
1628
}
 
1629
 
 
1630
 
 
1631
static void
 
1632
goo_canvas_table_allocate_area (GooCanvasItem    *item,
 
1633
                                cairo_t          *cr,
 
1634
                                GooCanvasBounds  *requested_area,
 
1635
                                GooCanvasBounds  *allocated_area,
 
1636
                                gdouble           x_offset,
 
1637
                                gdouble           y_offset)
 
1638
{
 
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;
 
1646
 
 
1647
  cairo_save (cr);
 
1648
  if (simple_data->transform)
 
1649
    cairo_transform (cr, simple_data->transform);
 
1650
 
 
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;
 
1655
 
 
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;
 
1659
 
 
1660
  /* If the table is rotated we have to scale it to make sure it fits in the
 
1661
     allocated area. */
 
1662
  if (simple_data->transform && (simple_data->transform->xy != 0.0
 
1663
                                 || simple_data->transform->yx != 0.0))
 
1664
    {
 
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);
 
1668
 
 
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;
 
1671
    }
 
1672
  else
 
1673
    {
 
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;
 
1678
    }
 
1679
 
 
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);
 
1685
 
 
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);
 
1690
 
 
1691
  goo_canvas_table_free_layout_data (table_data);
 
1692
 
 
1693
  cairo_restore (cr);
 
1694
}
 
1695
 
 
1696
 
 
1697
static void
 
1698
goo_canvas_table_update  (GooCanvasItem   *item,
 
1699
                          gboolean         entire_tree,
 
1700
                          cairo_t         *cr,
 
1701
                          GooCanvasBounds *bounds)
 
1702
{
 
1703
  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
 
1704
  GooCanvasBounds tmp_bounds;
 
1705
 
 
1706
  if (entire_tree || simple->need_update)
 
1707
    {
 
1708
      simple->need_update = FALSE;
 
1709
      simple->need_entire_subtree_update = FALSE;
 
1710
 
 
1711
      goo_canvas_item_simple_check_style (simple);
 
1712
 
 
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,
 
1716
                                        0, 0);
 
1717
    }
 
1718
 
 
1719
  *bounds = simple->bounds;
 
1720
}
 
1721
 
 
1722
 
 
1723
static void
 
1724
goo_canvas_table_paint (GooCanvasItem     *item,
 
1725
                        cairo_t           *cr,
 
1726
                        GooCanvasBounds   *bounds,
 
1727
                        gdouble            scale)
 
1728
{
 
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;
 
1737
  gint i;
 
1738
 
 
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))
 
1743
    return;
 
1744
 
 
1745
  /* Paint all the items in the group. */
 
1746
  cairo_save (cr);
 
1747
  if (simple_data->transform)
 
1748
    cairo_transform (cr, simple_data->transform);
 
1749
 
 
1750
  for (i = 0; i < group->items->len; i++)
 
1751
    {
 
1752
      child = group->items->pdata[i];
 
1753
 
 
1754
      table_child = &g_array_index (children, GooCanvasTableChild, i);
 
1755
      cairo_translate (cr, table_child->position[HORZ],
 
1756
                       table_child->position[VERT]);
 
1757
 
 
1758
      /* FIXME: Clip the child to make sure it doesn't go outside its area? */
 
1759
      goo_canvas_item_paint (child, cr, bounds, scale);
 
1760
 
 
1761
      cairo_translate (cr, -table_child->position[HORZ],
 
1762
                       -table_child->position[VERT]);
 
1763
    }
 
1764
  cairo_restore (cr);
 
1765
}
 
1766
 
 
1767
 
 
1768
static GooCanvasItem*
 
1769
goo_canvas_table_get_item_at (GooCanvasItem  *item,
 
1770
                              gdouble         x,
 
1771
                              gdouble         y,
 
1772
                              cairo_t        *cr,
 
1773
                              gboolean        is_pointer_event,
 
1774
                              gboolean        parent_visible)
 
1775
{
 
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;
 
1786
  int i;
 
1787
 
 
1788
  if (simple->need_update)
 
1789
    goo_canvas_item_ensure_updated (item);
 
1790
 
 
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))
 
1794
    visible = FALSE;
 
1795
 
 
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)
 
1800
              && !visible)))
 
1801
    return NULL;
 
1802
 
 
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. */
 
1805
  cairo_save (cr);
 
1806
  if (simple_data->transform)
 
1807
    cairo_transform (cr, simple_data->transform);
 
1808
 
 
1809
  for (i = group->items->len - 1; i >= 0; i--)
 
1810
    {
 
1811
      child = group->items->pdata[i];
 
1812
 
 
1813
      table_child = &g_array_index (children, GooCanvasTableChild, i);
 
1814
      cairo_translate (cr, table_child->position[HORZ],
 
1815
                       table_child->position[VERT]);
 
1816
 
 
1817
      found_item = goo_canvas_item_get_item_at (child, x, y, cr,
 
1818
                                                is_pointer_event, visible);
 
1819
      if (found_item)
 
1820
        break;
 
1821
 
 
1822
      cairo_translate (cr, -table_child->position[HORZ],
 
1823
                       -table_child->position[VERT]);
 
1824
    }
 
1825
  cairo_restore (cr);
 
1826
 
 
1827
  return found_item;
 
1828
}
 
1829
 
 
1830
 
 
1831
gboolean
 
1832
goo_canvas_table_get_transform_for_child  (GooCanvasItem  *item,
 
1833
                                           GooCanvasItem  *child,
 
1834
                                           cairo_matrix_t *transform)
 
1835
{
 
1836
  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
 
1837
  GooCanvasGroup *group = (GooCanvasGroup*) item;
 
1838
  GooCanvasTable *table = (GooCanvasTable*) item;
 
1839
  GooCanvasTableChild *table_child;
 
1840
  gboolean has_transform = FALSE;
 
1841
  gint child_num;
 
1842
 
 
1843
 
 
1844
  if (simple->simple_data->transform)
 
1845
    {
 
1846
      *transform = *simple->simple_data->transform;
 
1847
      has_transform = TRUE;
 
1848
    }
 
1849
  else
 
1850
    {
 
1851
      cairo_matrix_init_identity (transform);
 
1852
    }
 
1853
 
 
1854
  for (child_num = 0; child_num < group->items->len; child_num++)
 
1855
    {
 
1856
      if (group->items->pdata[child_num] == child)
 
1857
        {
 
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;
 
1863
          break;
 
1864
        }
 
1865
    }
 
1866
 
 
1867
  return has_transform;
 
1868
}
 
1869
 
 
1870
 
 
1871
static void
 
1872
item_interface_init (GooCanvasItemIface *iface)
 
1873
{
 
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;
 
1880
 
 
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;
 
1886
 
 
1887
  iface->set_model               = goo_canvas_table_set_model;
 
1888
}
 
1889
 
 
1890
 
 
1891
 
 
1892
/**
 
1893
 * SECTION:goocanvastablemodel
 
1894
 * @Title: GooCanvasTableModel
 
1895
 * @Short_Description: a model for a table container to layout items.
 
1896
 *
 
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.
 
1900
 *
 
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
 
1905
 * shrink).
 
1906
 *
 
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).
 
1912
 *
 
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".
 
1917
 *
 
1918
 * To create a #GooCanvasTableModel use goo_canvas_table_model_new().
 
1919
 *
 
1920
 * To get or set the properties of an existing #GooCanvasTableModel, use
 
1921
 * g_object_get() and g_object_set().
 
1922
 */
 
1923
 
 
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,
 
1927
                                                 guint               param_id,
 
1928
                                                 GValue             *value,
 
1929
                                                 GParamSpec         *pspec);
 
1930
static void goo_canvas_table_model_set_property (GObject            *object,
 
1931
                                                 guint               param_id,
 
1932
                                                 const GValue       *value,
 
1933
                                                 GParamSpec         *pspec);
 
1934
 
 
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))
 
1939
 
 
1940
 
 
1941
static void
 
1942
goo_canvas_table_model_class_init (GooCanvasTableModelClass *klass)
 
1943
{
 
1944
  GObjectClass *gobject_class = (GObjectClass*) klass;
 
1945
 
 
1946
  gobject_class->finalize = goo_canvas_table_model_finalize;
 
1947
 
 
1948
  gobject_class->get_property = goo_canvas_table_model_get_property;
 
1949
  gobject_class->set_property = goo_canvas_table_model_set_property;
 
1950
 
 
1951
  goo_canvas_table_install_common_properties (gobject_class, goo_canvas_item_model_class_install_child_property);
 
1952
}
 
1953
 
 
1954
 
 
1955
static void
 
1956
goo_canvas_table_model_init (GooCanvasTableModel *tmodel)
 
1957
{
 
1958
  goo_canvas_table_init_data (&tmodel->table_data);
 
1959
}
 
1960
 
 
1961
 
 
1962
/**
 
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.
 
1968
 * 
 
1969
 * Creates a new table model.
 
1970
 *
 
1971
 * <!--PARAMETERS-->
 
1972
 *
 
1973
 * Here's an example showing how to create a table with a square, a circle and
 
1974
 * a triangle in it:
 
1975
 *
 
1976
 * <informalexample><programlisting>
 
1977
 *  GooCanvasItemModel *table, *square, *circle, *triangle;
 
1978
 *
 
1979
 *  table = goo_canvas_table_model_new (root,
 
1980
 *                                      "row-spacing", 4.0,
 
1981
 *                                      "column-spacing", 4.0,
 
1982
 *                                      NULL);
 
1983
 *  goo_canvas_item_model_translate (table, 400, 200);
 
1984
 *
 
1985
 *  square = goo_canvas_rect_model_new (table, 0.0, 0.0, 50.0, 50.0,
 
1986
 *                                      "fill-color", "red",
 
1987
 *                                      NULL);
 
1988
 *  goo_canvas_item_model_set_child_properties (table, square,
 
1989
 *                                              "row", 0,
 
1990
 *                                              "column", 0,
 
1991
 *                                              NULL);
 
1992
 *
 
1993
 *  circle = goo_canvas_ellipse_model_new (table, 0.0, 0.0, 25.0, 25.0,
 
1994
 *                                         "fill-color", "blue",
 
1995
 *                                         NULL);
 
1996
 *  goo_canvas_item_model_set_child_properties (table, circle,
 
1997
 *                                              "row", 0,
 
1998
 *                                              "column", 1,
 
1999
 *                                              NULL);
 
2000
 *
 
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",
 
2004
 *                                            NULL);
 
2005
 *  goo_canvas_item_model_set_child_properties (table, triangle,
 
2006
 *                                              "row", 0,
 
2007
 *                                              "column", 2,
 
2008
 *                                              NULL);
 
2009
 * </programlisting></informalexample>
 
2010
 * 
 
2011
 * Returns: a new table model.
 
2012
 **/
 
2013
GooCanvasItemModel*
 
2014
goo_canvas_table_model_new (GooCanvasItemModel *parent,
 
2015
                            ...)
 
2016
{
 
2017
  GooCanvasItemModel *model;
 
2018
  va_list var_args;
 
2019
  const char *first_property;
 
2020
 
 
2021
  model = g_object_new (GOO_TYPE_CANVAS_TABLE_MODEL, NULL);
 
2022
 
 
2023
  va_start (var_args, parent);
 
2024
  first_property = va_arg (var_args, char*);
 
2025
  if (first_property)
 
2026
    g_object_set_valist (G_OBJECT (model), first_property, var_args);
 
2027
  va_end (var_args);
 
2028
 
 
2029
  if (parent)
 
2030
    {
 
2031
      goo_canvas_item_model_add_child (parent, model, -1);
 
2032
      g_object_unref (model);
 
2033
    }
 
2034
 
 
2035
  return model;
 
2036
}
 
2037
 
 
2038
 
 
2039
static void
 
2040
goo_canvas_table_model_finalize (GObject *object)
 
2041
{
 
2042
  GooCanvasTableModel *tmodel = (GooCanvasTableModel*) object;
 
2043
 
 
2044
  goo_canvas_table_free_data (&tmodel->table_data);
 
2045
 
 
2046
  G_OBJECT_CLASS (goo_canvas_table_model_parent_class)->finalize (object);
 
2047
}
 
2048
 
 
2049
 
 
2050
static void
 
2051
goo_canvas_table_model_get_property (GObject              *object,
 
2052
                                     guint                 prop_id,
 
2053
                                     GValue               *value,
 
2054
                                     GParamSpec           *pspec)
 
2055
{
 
2056
  GooCanvasTableModel *emodel = (GooCanvasTableModel*) object;
 
2057
 
 
2058
  goo_canvas_table_get_common_property (object, &emodel->table_data,
 
2059
                                        prop_id, value, pspec);
 
2060
}
 
2061
 
 
2062
 
 
2063
static void
 
2064
goo_canvas_table_model_set_property (GObject              *object,
 
2065
                                     guint                 prop_id,
 
2066
                                     const GValue         *value,
 
2067
                                     GParamSpec           *pspec)
 
2068
{
 
2069
  GooCanvasTableModel *emodel = (GooCanvasTableModel*) object;
 
2070
  gboolean recompute_bounds;
 
2071
 
 
2072
  recompute_bounds = goo_canvas_table_set_common_property (object,
 
2073
                                                           &emodel->table_data,
 
2074
                                                           prop_id, value,
 
2075
                                                           pspec);
 
2076
  g_signal_emit_by_name (emodel, "changed", recompute_bounds);
 
2077
}
 
2078
 
 
2079
 
 
2080
static void
 
2081
goo_canvas_table_model_add_child     (GooCanvasItemModel *model,
 
2082
                                      GooCanvasItemModel *child,
 
2083
                                      gint                position)
 
2084
{
 
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;
 
2088
 
 
2089
  goo_canvas_table_add_child_internal (&tmodel->table_data, position);
 
2090
 
 
2091
  /* Let the parent GooCanvasGroupModel code do the rest. */
 
2092
  parent_iface->add_child (model, child, position);
 
2093
}
 
2094
 
 
2095
 
 
2096
static void
 
2097
goo_canvas_table_model_move_child    (GooCanvasItemModel *model,
 
2098
                                      gint                old_position,
 
2099
                                      gint                new_position)
 
2100
{
 
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;
 
2104
 
 
2105
  goo_canvas_table_move_child_internal (&tmodel->table_data, old_position,
 
2106
                                        new_position);
 
2107
 
 
2108
  /* Let the parent GooCanvasGroupModel code do the rest. */
 
2109
  parent_iface->move_child (model, old_position, new_position);
 
2110
}
 
2111
 
 
2112
 
 
2113
static void
 
2114
goo_canvas_table_model_remove_child  (GooCanvasItemModel *model,
 
2115
                                      gint                child_num)
 
2116
{
 
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;
 
2120
 
 
2121
  g_array_remove_index (tmodel->table_data.children, child_num);
 
2122
 
 
2123
  /* Let the parent GooCanvasGroupModel code do the rest. */
 
2124
  parent_iface->remove_child (model, child_num);
 
2125
}
 
2126
 
 
2127
 
 
2128
static void
 
2129
goo_canvas_table_model_get_child_property (GooCanvasItemModel *model,
 
2130
                                           GooCanvasItemModel *child,
 
2131
                                           guint               property_id,
 
2132
                                           GValue             *value,
 
2133
                                           GParamSpec         *pspec)
 
2134
{
 
2135
  GooCanvasGroupModel *gmodel = (GooCanvasGroupModel*) model;
 
2136
  GooCanvasTableModel *tmodel = (GooCanvasTableModel*) model;
 
2137
  GooCanvasTableChild *table_child;
 
2138
  gint child_num;
 
2139
 
 
2140
  for (child_num = 0; child_num < gmodel->children->len; child_num++)
 
2141
    {
 
2142
      if (gmodel->children->pdata[child_num] == child)
 
2143
        {
 
2144
          table_child = &g_array_index (tmodel->table_data.children,
 
2145
                                        GooCanvasTableChild, child_num);
 
2146
          goo_canvas_table_get_common_child_property ((GObject*) tmodel,
 
2147
                                                      table_child,
 
2148
                                                      property_id, value,
 
2149
                                                      pspec);
 
2150
          break;
 
2151
        }
 
2152
    }
 
2153
}
 
2154
 
 
2155
 
 
2156
static void
 
2157
goo_canvas_table_model_set_child_property (GooCanvasItemModel *model,
 
2158
                                           GooCanvasItemModel *child,
 
2159
                                           guint               property_id,
 
2160
                                           const GValue       *value,
 
2161
                                           GParamSpec         *pspec)
 
2162
{
 
2163
  GooCanvasGroupModel *gmodel = (GooCanvasGroupModel*) model;
 
2164
  GooCanvasTableModel *tmodel = (GooCanvasTableModel*) model;
 
2165
  GooCanvasTableChild *table_child;
 
2166
  gint child_num;
 
2167
 
 
2168
  for (child_num = 0; child_num < gmodel->children->len; child_num++)
 
2169
    {
 
2170
      if (gmodel->children->pdata[child_num] == child)
 
2171
        {
 
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,
 
2176
                                                      table_child,
 
2177
                                                      property_id, value,
 
2178
                                                      pspec);
 
2179
          break;
 
2180
        }
 
2181
    }
 
2182
 
 
2183
  g_signal_emit_by_name (tmodel, "changed", TRUE);
 
2184
}
 
2185
 
 
2186
 
 
2187
static GooCanvasItem*
 
2188
goo_canvas_table_model_create_item (GooCanvasItemModel *model,
 
2189
                                    GooCanvas          *canvas)
 
2190
{
 
2191
  GooCanvasItem *item;
 
2192
 
 
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);
 
2198
 
 
2199
  return item;
 
2200
}
 
2201
 
 
2202
 
 
2203
static void
 
2204
item_model_interface_init (GooCanvasItemModelIface *iface)
 
2205
{
 
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;
 
2211
 
 
2212
  iface->create_item        = goo_canvas_table_model_create_item;
 
2213
}