~ubuntu-branches/ubuntu/lucid/giggle/lucid

« back to all changes in this revision

Viewing changes to src/giggle-graph-renderer.c

  • Committer: Bazaar Package Importer
  • Author(s): Andrea Corradi
  • Date: 2007-05-09 21:16:35 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20070509211635-p0wst0b2b7qdns12
Tags: 0.3-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
#define PATH_SPACE(font_size) (font_size + 3)
32
32
#define DOT_RADIUS(font_size) (font_size / 2)
33
33
#define LINE_WIDTH(font_size) ((font_size / 6) << 1) /* we want the closest even number <= size/3 */
34
 
#define NEXT_COLOR(n_color)   ((n_color + 1) % G_N_ELEMENTS (colors))
 
34
#define NEXT_COLOR(n_color)   ((n_color % G_N_ELEMENTS (colors)) + 1)
 
35
#define INVALID_COLOR         0
35
36
 
36
37
typedef struct GiggleGraphRendererPrivate GiggleGraphRendererPrivate;
37
38
 
44
45
typedef struct GiggleGraphRendererPathState GiggleGraphRendererPathState;
45
46
 
46
47
struct GiggleGraphRendererPathState {
47
 
        GdkColor *upper_color;
48
 
        GdkColor *lower_color;
 
48
        gushort upper_n_color : 8;
 
49
        gushort lower_n_color : 8;
 
50
        gushort n_path;
49
51
};
50
52
 
51
53
enum {
54
56
};
55
57
 
56
58
static GdkColor colors[] = {
 
59
        /* invalid color */
 
60
        { 0x0, 0x0000, 0x0000, 0x0000 },
57
61
        /* light palette */
58
62
        { 0x0, 0xfc00, 0xe900, 0x4f00 }, /* butter */
59
63
        { 0x0, 0xfc00, 0xaf00, 0x3e00 }, /* orange */
239
243
}
240
244
 
241
245
static void
242
 
get_list_foreach (gpointer  key,
243
 
                  gpointer  value,
244
 
                  GList    **list)
245
 
{
246
 
        *list = g_list_prepend (*list, key);
247
 
}
248
 
 
249
 
static GList*
250
 
get_list (GHashTable *table)
251
 
{
252
 
        GList *list = NULL;
253
 
 
254
 
        g_hash_table_foreach (table, (GHFunc) get_list_foreach, &list);
255
 
        return list;
256
 
}
257
 
 
258
 
static void
259
246
giggle_graph_renderer_render (GtkCellRenderer *cell,
260
247
                              GdkWindow       *window,
261
248
                              GtkWidget       *widget,
267
254
        GiggleGraphRendererPrivate   *priv;
268
255
        GiggleGraphRendererPathState *path_state;
269
256
        GiggleRevision               *revision;
270
 
        GHashTable                   *paths_state;
 
257
        GArray                       *paths_state;
 
258
        GHashTable                   *table;
271
259
        cairo_t                      *cr;
272
260
        gint                          x, y, h;
273
261
        gint                          cur_pos, pos;
274
 
        GList                        *children, *paths, *path;
275
 
        gint                          size;
 
262
        GList                        *children;
 
263
        gint                          size, i;
276
264
 
277
265
        priv = GIGGLE_GRAPH_RENDERER (cell)->_priv;
278
266
 
279
 
        g_return_if_fail (priv->revision != NULL);
 
267
        if (!priv->revision) {
 
268
                return;
 
269
        }
280
270
 
281
271
        cr = gdk_cairo_create (window);
282
272
        x = cell_area->x;
285
275
        revision = priv->revision;
286
276
        size = PANGO_PIXELS (pango_font_description_get_size (widget->style->font_desc));
287
277
 
 
278
        table = g_hash_table_new (g_direct_hash, g_direct_equal);
288
279
        paths_state = g_object_get_qdata (G_OBJECT (revision), revision_paths_state_quark);
289
280
        children = giggle_revision_get_children (revision);
290
281
        cur_pos = GPOINTER_TO_INT (g_hash_table_lookup (priv->paths_info, revision));
291
 
        path_state = g_hash_table_lookup (paths_state, GINT_TO_POINTER (cur_pos));
292
 
        paths = path = get_list (paths_state);
293
282
        cairo_set_line_width (cr, LINE_WIDTH (size));
294
283
 
295
284
        /* paint paths */
296
 
        while (path) {
297
 
                pos = GPOINTER_TO_INT (path->data);
298
 
                path_state = g_hash_table_lookup (paths_state, GINT_TO_POINTER (pos));
 
285
        for (i = 0; i < paths_state->len; i++) {
 
286
                path_state = & g_array_index (paths_state, GiggleGraphRendererPathState, i);
 
287
                g_hash_table_insert (table, GINT_TO_POINTER ((gint) path_state->n_path), path_state);
 
288
                pos = path_state->n_path;
299
289
 
300
 
                if (path_state->lower_color &&
 
290
                if (path_state->lower_n_color != INVALID_COLOR &&
301
291
                    (pos != cur_pos || giggle_revision_get_parents (revision))) {
302
 
                        gdk_cairo_set_source_color (cr, path_state->lower_color);
 
292
                        gdk_cairo_set_source_color (cr, &colors[path_state->lower_n_color]);
303
293
                        cairo_move_to (cr, x + (pos * PATH_SPACE (size)), y + (h / 2));
304
294
                        cairo_line_to (cr, x + (pos * PATH_SPACE (size)), y + h);
305
295
                        cairo_stroke  (cr);
306
296
                }
307
297
 
308
 
                if (path_state->upper_color) {
309
 
                        gdk_cairo_set_source_color (cr, path_state->upper_color);
 
298
                if (path_state->upper_n_color != INVALID_COLOR) {
 
299
                        gdk_cairo_set_source_color (cr, &colors[path_state->upper_n_color]);
310
300
                        cairo_move_to (cr, x + (pos * PATH_SPACE (size)), y);
311
301
                        cairo_line_to (cr, x + (pos * PATH_SPACE (size)), y + (h / 2));
312
302
                        cairo_stroke  (cr);
313
303
                }
314
 
 
315
 
                path = path->next;
316
304
        }
317
305
 
318
306
        /* paint connections between paths */
319
307
        while (children) {
320
308
                pos = GPOINTER_TO_INT (g_hash_table_lookup (priv->paths_info, children->data));
321
 
                path_state = g_hash_table_lookup (paths_state, GINT_TO_POINTER (pos));
 
309
                path_state = g_hash_table_lookup (table, GINT_TO_POINTER (pos));
322
310
 
323
 
                if (path_state->upper_color) {
324
 
                        gdk_cairo_set_source_color (cr, path_state->upper_color);
 
311
                if (path_state->upper_n_color != INVALID_COLOR) {
 
312
                        gdk_cairo_set_source_color (cr, &colors[path_state->upper_n_color]);
325
313
                        cairo_move_to (cr,
326
314
                                       x + (cur_pos * PATH_SPACE (size)),
327
315
                                       y + (h / 2));
343
331
        cairo_stroke (cr);
344
332
 
345
333
        /* paint internal circle */
346
 
        path_state = g_hash_table_lookup (paths_state, GINT_TO_POINTER (cur_pos));
347
 
        gdk_cairo_set_source_color (cr, path_state->lower_color);
 
334
        path_state = g_hash_table_lookup (table, GINT_TO_POINTER (cur_pos));
 
335
        gdk_cairo_set_source_color (cr, &colors[path_state->lower_n_color]);
348
336
        cairo_arc (cr,
349
337
                   x + (cur_pos * PATH_SPACE (size)),
350
338
                   y + (h / 2),
353
341
        cairo_stroke (cr);
354
342
 
355
343
        cairo_destroy (cr);
356
 
        g_list_free (paths);
 
344
        g_hash_table_destroy (table);
357
345
}
358
346
 
359
347
GtkCellRenderer *
387
375
                            gpointer value,
388
376
                            gpointer user_data)
389
377
{
390
 
        GiggleGraphRendererPathState *path_state;
391
 
        GHashTable *table = (GHashTable *) user_data;
392
 
 
393
 
        path_state = g_new0 (GiggleGraphRendererPathState, 1);
394
 
        path_state->lower_color = value;
395
 
        path_state->upper_color = value;
396
 
        g_hash_table_insert (table, key, path_state);
 
378
        GiggleGraphRendererPathState  path_state;
 
379
        GArray                       *array;
 
380
        gint                          n_color, n_path;
 
381
 
 
382
        array = (GArray *) user_data;
 
383
        n_color = GPOINTER_TO_INT (value);
 
384
        n_path = GPOINTER_TO_INT (key);
 
385
 
 
386
        path_state.n_path = n_path;
 
387
        path_state.lower_n_color = n_color;
 
388
        path_state.upper_n_color = n_color;
 
389
 
 
390
        g_array_append_val (array, path_state);
 
391
}
 
392
 
 
393
static GArray *
 
394
get_initial_status (GHashTable *visible_paths)
 
395
{
 
396
        GArray *array;
 
397
        guint      size;
 
398
 
 
399
        size = g_hash_table_size (visible_paths);
 
400
        array = g_array_sized_new (FALSE, TRUE, sizeof (GiggleGraphRendererPathState), size);
 
401
 
 
402
        g_hash_table_foreach (visible_paths, (GHFunc) get_initial_status_foreach, array);
 
403
 
 
404
        return array;
397
405
}
398
406
 
399
407
static void
400
 
get_initial_status (GHashTable *paths,
401
 
                    GHashTable *visible_paths)
 
408
free_paths_state (GArray *array)
402
409
{
403
 
        g_hash_table_foreach (visible_paths, (GHFunc) get_initial_status_foreach, paths);
 
410
        g_array_free (array, FALSE);
404
411
}
405
412
 
406
413
static void
409
416
                                                GHashTable          *visible_paths,
410
417
                                                gint                *n_color)
411
418
{
412
 
        GiggleGraphRendererPathState *path_state;
 
419
        GiggleGraphRendererPathState  path_state;
413
420
        GiggleGraphRendererPrivate   *priv;
414
 
        GHashTable                   *paths_state;
 
421
        GiggleRevision               *rev;
 
422
        GArray                       *paths_state;
415
423
        GList                        *children;
416
424
        gboolean                      current_path_reused = FALSE;
417
425
        gboolean                      update_color;
418
 
        gint                          n_path;
 
426
        gint                          n_path, i;
419
427
 
420
428
        priv = renderer->_priv;
421
429
        children = giggle_revision_get_children (revision);
422
430
        update_color = (g_list_length (children) > 1);
423
 
        paths_state = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
424
 
        get_initial_status (paths_state, visible_paths);
 
431
        paths_state = get_initial_status (visible_paths);
425
432
 
426
433
        while (children) {
427
 
                path_state = g_new0 (GiggleGraphRendererPathState, 1);
428
 
                n_path = GPOINTER_TO_INT (g_hash_table_lookup (priv->paths_info, children->data));
 
434
                rev = GIGGLE_REVISION (children->data);
 
435
                n_path = GPOINTER_TO_INT (g_hash_table_lookup (priv->paths_info, rev));
429
436
 
430
437
                if (!n_path) {
431
438
                        /* there wasn't a path for this revision, choose one */
436
443
                                find_free_path (visible_paths, &priv->n_paths, &n_path);
437
444
                        }
438
445
 
439
 
                        g_hash_table_insert (priv->paths_info, children->data, GINT_TO_POINTER (n_path));
440
 
                        path_state->lower_color = g_hash_table_lookup (visible_paths, GINT_TO_POINTER (n_path));
 
446
                        g_hash_table_insert (priv->paths_info, rev, GINT_TO_POINTER (n_path));
 
447
                        path_state.lower_n_color =
 
448
                                GPOINTER_TO_INT (g_hash_table_lookup (visible_paths, GINT_TO_POINTER (n_path)));
441
449
 
442
450
                        if (update_color) {
443
 
                                *n_color = NEXT_COLOR (*n_color);
444
 
                                path_state->upper_color = &colors[*n_color];
 
451
                                path_state.upper_n_color = *n_color = NEXT_COLOR (*n_color);
445
452
                        } else {
446
 
                                path_state->upper_color = path_state->lower_color;
 
453
                                path_state.upper_n_color = path_state.lower_n_color;
447
454
                        }
448
455
                } else {
449
 
                        path_state->lower_color = g_hash_table_lookup (visible_paths, GINT_TO_POINTER (n_path));
450
 
                        path_state->upper_color = path_state->lower_color;
 
456
                        path_state.lower_n_color =
 
457
                                GPOINTER_TO_INT (g_hash_table_lookup (visible_paths, GINT_TO_POINTER (n_path)));
 
458
 
 
459
                        path_state.upper_n_color = path_state.lower_n_color;
451
460
                }
452
461
 
453
 
                g_hash_table_insert (visible_paths, GINT_TO_POINTER (n_path), path_state->upper_color);
454
 
                g_hash_table_insert (paths_state, GINT_TO_POINTER (n_path), path_state);
 
462
                path_state.n_path = n_path;
 
463
                g_hash_table_insert (visible_paths, GINT_TO_POINTER (n_path), GINT_TO_POINTER ((gint) path_state.upper_n_color));
 
464
                g_array_append_val (paths_state, path_state);
455
465
 
456
466
                children = children->next;
457
467
        }
460
470
                /* current path is a dead end, remove it from the visible paths table */
461
471
                n_path = GPOINTER_TO_INT (g_hash_table_lookup (priv->paths_info, revision));
462
472
                g_hash_table_remove (visible_paths, GINT_TO_POINTER (n_path));
463
 
                path_state = g_hash_table_lookup (paths_state, GINT_TO_POINTER (n_path));
464
 
                path_state->upper_color = NULL;
 
473
 
 
474
                for (i = 0; i < paths_state->len; i++) {
 
475
                        path_state = g_array_index (paths_state, GiggleGraphRendererPathState, i);
 
476
 
 
477
                        if (path_state.n_path == n_path) {
 
478
                                path_state.upper_n_color = INVALID_COLOR;
 
479
                                ((GiggleGraphRendererPathState *) paths_state->data)[i] = path_state;
 
480
                                break;
 
481
                        }
 
482
                }
465
483
        }
466
484
 
467
485
        g_object_set_qdata_full (G_OBJECT (revision), revision_paths_state_quark,
468
 
                                 paths_state, (GDestroyNotify) g_hash_table_destroy);
 
486
                                 paths_state, (GDestroyNotify) free_paths_state);
469
487
}
470
488
 
471
489
void
505
523
                gtk_tree_model_iter_nth_child (model, &iter, NULL, n_children);
506
524
                gtk_tree_model_get (model, &iter, column, &revision, -1);
507
525
 
508
 
                if (!giggle_revision_get_parents (revision)) {
509
 
                        n_color = NEXT_COLOR (n_color);
510
 
                        find_free_path (visible_paths, &priv->n_paths, &n_path);
511
 
                        g_hash_table_insert (priv->paths_info, revision, GINT_TO_POINTER (n_path));
512
 
                        g_hash_table_insert (visible_paths, GINT_TO_POINTER (n_path), &colors[n_color]);
 
526
                if (revision) {
 
527
                        if (!giggle_revision_get_parents (revision)) {
 
528
                                n_color = NEXT_COLOR (n_color);
 
529
                                find_free_path (visible_paths, &priv->n_paths, &n_path);
 
530
                                g_hash_table_insert (priv->paths_info, revision, GINT_TO_POINTER (n_path));
 
531
                                g_hash_table_insert (visible_paths, GINT_TO_POINTER (n_path), GINT_TO_POINTER (n_color));
 
532
                        }
 
533
 
 
534
                        giggle_graph_renderer_calculate_revision_state (renderer, revision, visible_paths, &n_color);
 
535
                        g_object_unref (revision);
513
536
                }
514
 
 
515
 
                giggle_graph_renderer_calculate_revision_state (renderer, revision, visible_paths, &n_color);
516
 
                g_object_unref (revision);
517
537
        }
518
538
 
519
539
        g_hash_table_destroy (visible_paths);