2
* GooCanvas. Copyright (C) 2005 Damon Chaplin.
3
* Released under the GNU LGPL license. See COPYING for details.
5
* goocanvasgroupview.c - view for group item.
9
* SECTION:goocanvasgroupview
10
* @Title: GooCanvasGroupView
11
* @Short_Description: a view for a group #GooCanvasItem.
13
* #GooCanvasGroupView represents a view of a group #GooCanvasItem (typically
16
* It implements the #GooCanvasItemView interface, so you can use the
17
* #GooCanvasItemView functions such as goo_canvas_item_view_get_item()
18
* and goo_canvas_item_view_get_bounds().
20
* Applications do not normally need to create item views themselves, as
21
* they are created automatically by #GooCanvasView when needed.
23
* To respond to events such as mouse clicks in the ellipse view you can
24
* connect to one of the #GooCanvasItemView signals such as
25
* #GooCanvasItemView::button-press-event. You can connect to these signals
26
* when the view is created. (See goo_canvas_view_get_item_view() and
27
* #GooCanvasView::item-view-created.)
31
#include "goocanvasprivate.h"
32
#include "goocanvasgroupview.h"
33
#include "goocanvasgroup.h"
34
#include "goocanvasview.h"
35
#include "goocanvasutils.h"
36
#include "goocanvasatk.h"
46
static void canvas_item_view_interface_init (GooCanvasItemViewIface *iface);
47
static void goo_canvas_group_view_finalize (GObject *object);
48
static void goo_canvas_group_view_get_property (GObject *object,
52
static void goo_canvas_group_view_set_property (GObject *object,
56
static void add_child_views_recursively (GooCanvasGroupView *group_view);
57
static void connect_group_signals (GooCanvasGroupView *group_view);
58
static void on_group_changed (GooCanvasItem *group,
59
gboolean recompute_bounds,
60
GooCanvasGroupView *view);
62
G_DEFINE_TYPE_WITH_CODE (GooCanvasGroupView, goo_canvas_group_view,
64
G_IMPLEMENT_INTERFACE (GOO_TYPE_CANVAS_ITEM_VIEW,
65
canvas_item_view_interface_init))
69
goo_canvas_group_view_class_init (GooCanvasGroupViewClass *klass)
71
GObjectClass *gobject_class = (GObjectClass*) klass;
73
gobject_class->finalize = goo_canvas_group_view_finalize;
75
gobject_class->get_property = goo_canvas_group_view_get_property;
76
gobject_class->set_property = goo_canvas_group_view_set_property;
78
atk_registry_set_factory_type (atk_get_default_registry (),
79
GOO_TYPE_CANVAS_GROUP_VIEW,
80
goo_canvas_item_view_accessible_factory_get_type ());
82
g_object_class_override_property (gobject_class, PROP_CAN_FOCUS,
88
goo_canvas_group_view_init (GooCanvasGroupView *group_view)
90
group_view->item_views = g_ptr_array_sized_new (8);
92
group_view->flags = GOO_CANVAS_ITEM_VIEW_NEED_UPDATE
93
| GOO_CANVAS_ITEM_VIEW_NEED_ENTIRE_SUBTREE_UPDATE;
98
goo_canvas_group_view_title_changed (GooCanvasItem *group,
100
GooCanvasGroupView *group_view)
102
AtkObject *accessible;
105
accessible = atk_gobject_accessible_for_object (G_OBJECT (group_view));
106
g_object_get (group, "title", &title, NULL);
107
atk_object_set_name (accessible, title);
113
goo_canvas_group_view_description_changed (GooCanvasItem *group,
115
GooCanvasGroupView *group_view)
117
AtkObject *accessible;
120
accessible = atk_gobject_accessible_for_object (G_OBJECT (group_view));
121
g_object_get (group, "description", &description, NULL);
122
atk_object_set_description (accessible, description);
123
g_free (description);
128
* goo_canvas_group_view_set_group:
129
* @group_view: a #GooCanvasGroupView.
130
* @group: a #GooCanvasItem.
132
* This function is only intended to be used by subclasses during construction
135
* It sets the underlying group item, creates any necessary child views, and
136
* sets up signal handlers to update child views as the underlying items
140
goo_canvas_group_view_set_group (GooCanvasGroupView *group_view,
141
GooCanvasItem *group)
143
AtkObject *accessible;
144
gchar *title, *description;
146
if (group_view->group)
148
g_signal_handlers_disconnect_matched (group_view->group,
150
0, 0, NULL, NULL, group_view);
152
g_object_unref (group_view->group);
155
group_view->group = g_object_ref (group);
159
"description", &description,
162
accessible = atk_gobject_accessible_for_object (G_OBJECT (group_view));
164
atk_object_set_name (accessible, title);
166
atk_object_set_description (accessible, description);
168
g_free (description);
170
g_signal_connect (group, "notify::title",
171
G_CALLBACK (goo_canvas_group_view_title_changed),
173
g_signal_connect (group, "notify::description",
174
G_CALLBACK (goo_canvas_group_view_description_changed),
177
add_child_views_recursively (group_view);
178
connect_group_signals (group_view);
180
g_signal_connect (group, "changed", G_CALLBACK (on_group_changed),
186
* goo_canvas_group_view_new:
187
* @canvas_view: the canvas view.
188
* @parent_view: the parent view.
189
* @group: the group item.
191
* Creates a new #GooCanvasGroupView for the given #GooCanvasItem.
193
* This is not normally used by application code, as the views are created
194
* automatically by #GooCanvasView.
196
* Returns: a new #GooCanvasGroupView.
199
goo_canvas_group_view_new (GooCanvasView *canvas_view,
200
GooCanvasItemView *parent_view,
201
GooCanvasItem *group)
203
GooCanvasGroupView *group_view;
205
group_view = g_object_new (GOO_TYPE_CANVAS_GROUP_VIEW, NULL);
207
group_view->canvas_view = canvas_view;
208
group_view->parent_view = parent_view;
210
goo_canvas_group_view_set_group (group_view, group);
212
return GOO_CANVAS_ITEM_VIEW (group_view);
217
goo_canvas_group_view_finalize (GObject *object)
219
GooCanvasGroupView *group_view = (GooCanvasGroupView*) object;
222
/* Unref all the items in the group. */
223
for (i = 0; i < group_view->item_views->len; i++)
225
GooCanvasItemView *item_view = group_view->item_views->pdata[i];
226
goo_canvas_item_view_set_parent_view (item_view, NULL);
227
g_object_unref (item_view);
230
g_ptr_array_free (group_view->item_views, TRUE);
232
/* Remove the view from the GooCanvasView hash table. */
233
goo_canvas_view_unregister_item_view (group_view->canvas_view,
236
/* Unref the group. */
237
g_object_unref (group_view->group);
238
group_view->group = NULL;
240
G_OBJECT_CLASS (goo_canvas_group_view_parent_class)->finalize (object);
245
goo_canvas_group_view_get_property (GObject *object,
250
GooCanvasGroupView *group_view = (GooCanvasGroupView*) object;
255
g_value_set_boolean (value,
256
group_view->flags & GOO_CANVAS_ITEM_VIEW_CAN_FOCUS);
259
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
266
goo_canvas_group_view_set_property (GObject *object,
271
GooCanvasGroupView *group_view = (GooCanvasGroupView*) object;
276
if (g_value_get_boolean (value))
277
group_view->flags |= GOO_CANVAS_ITEM_VIEW_CAN_FOCUS;
279
group_view->flags &= ~GOO_CANVAS_ITEM_VIEW_CAN_FOCUS;
282
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
289
on_child_item_added (GooCanvasItem *group,
291
GooCanvasGroupView *group_view)
294
GooCanvasItemView *view;
296
/* Get a view for the item. */
297
item = goo_canvas_item_get_child (group, position);
298
view = goo_canvas_view_create_item_view (group_view->canvas_view, item,
299
(GooCanvasItemView*) group_view);
302
goo_canvas_util_ptr_array_insert (group_view->item_views, view, position);
304
g_ptr_array_add (group_view->item_views, view);
306
goo_canvas_item_view_request_update ((GooCanvasItemView*) group_view);
311
on_child_item_moved (GooCanvasItem *group,
314
GooCanvasGroupView *group_view)
316
GooCanvasItemView *view;
317
GooCanvasBounds bounds;
319
/* Request a redraw of the item's bounds. */
320
view = group_view->item_views->pdata[old_position];
321
goo_canvas_item_view_get_bounds (view, &bounds);
322
goo_canvas_view_request_redraw (group_view->canvas_view, &bounds);
324
goo_canvas_util_ptr_array_move (group_view->item_views, old_position,
327
goo_canvas_item_view_request_update ((GooCanvasItemView*) group_view);
332
on_child_item_removed (GooCanvasItem *group,
334
GooCanvasGroupView *group_view)
336
GooCanvasItemView *view;
337
GooCanvasBounds bounds;
339
view = group_view->item_views->pdata[item_num];
341
/* Request a redraw of the item's bounds. */
342
goo_canvas_item_view_get_bounds (view, &bounds);
343
goo_canvas_view_request_redraw (group_view->canvas_view, &bounds);
345
/* Reset the item's parent to NULL, in case it is kept around. */
346
goo_canvas_item_view_set_parent_view (view, NULL);
347
g_object_unref (view);
349
g_ptr_array_remove_index (group_view->item_views, item_num);
351
goo_canvas_item_view_request_update ((GooCanvasItemView*) group_view);
356
add_child_views_recursively (GooCanvasGroupView *group_view)
360
n_children = goo_canvas_item_get_n_children (group_view->group);
362
for (i = 0; i < n_children; i++)
364
on_child_item_added (group_view->group, i, group_view);
370
connect_group_signals (GooCanvasGroupView *group_view)
372
GooCanvasItem *group = group_view->group;
374
g_signal_connect (group, "child-added", G_CALLBACK (on_child_item_added),
376
g_signal_connect (group, "child-moved", G_CALLBACK (on_child_item_moved),
378
g_signal_connect (group, "child-removed", G_CALLBACK (on_child_item_removed),
383
static GooCanvasView*
384
goo_canvas_group_view_get_canvas_view (GooCanvasItemView *view)
386
GooCanvasGroupView *group_view = (GooCanvasGroupView*) view;
387
return group_view->canvas_view;
392
goo_canvas_group_view_get_n_children (GooCanvasItemView *view)
394
GooCanvasGroupView *group_view = (GooCanvasGroupView*) view;
395
return group_view->item_views->len;
399
static GooCanvasItemView*
400
goo_canvas_group_view_get_child (GooCanvasItemView *view,
403
GooCanvasGroupView *group_view = (GooCanvasGroupView*) view;
404
return group_view->item_views->pdata[child_num];
409
goo_canvas_group_view_request_update (GooCanvasItemView *view)
411
GooCanvasGroupView *group_view = (GooCanvasGroupView*) view;
413
if (!(group_view->flags & GOO_CANVAS_ITEM_VIEW_NEED_UPDATE))
415
group_view->flags |= GOO_CANVAS_ITEM_VIEW_NEED_UPDATE;
417
if (group_view->parent_view)
418
goo_canvas_item_view_request_update (group_view->parent_view);
420
goo_canvas_view_request_update (group_view->canvas_view);
426
goo_canvas_group_view_update (GooCanvasItemView *view,
427
gboolean entire_tree,
429
GooCanvasBounds *bounds)
431
GooCanvasGroupView *group_view = (GooCanvasGroupView*) view;
432
GooCanvasBounds child_bounds;
433
cairo_matrix_t transform;
436
if (entire_tree || (group_view->flags & GOO_CANVAS_ITEM_VIEW_NEED_UPDATE))
438
if (group_view->flags & GOO_CANVAS_ITEM_VIEW_NEED_ENTIRE_SUBTREE_UPDATE)
441
group_view->flags &= ~GOO_CANVAS_ITEM_VIEW_NEED_UPDATE;
442
group_view->flags &= ~GOO_CANVAS_ITEM_VIEW_NEED_ENTIRE_SUBTREE_UPDATE;
444
group_view->bounds.x1 = group_view->bounds.y1 = 0.0;
445
group_view->bounds.x2 = group_view->bounds.y2 = 0.0;
449
if (goo_canvas_item_view_get_combined_transform (view, &transform))
450
cairo_transform (cr, &transform);
452
for (i = 0; i < group_view->item_views->len; i++)
454
GooCanvasItemView *child_view = group_view->item_views->pdata[i];
456
goo_canvas_item_view_update (child_view, entire_tree, cr,
461
group_view->bounds.x1 = child_bounds.x1;
462
group_view->bounds.y1 = child_bounds.y1;
463
group_view->bounds.x2 = child_bounds.x2;
464
group_view->bounds.y2 = child_bounds.y2;
468
group_view->bounds.x1 = MIN (group_view->bounds.x1,
470
group_view->bounds.y1 = MIN (group_view->bounds.y1,
472
group_view->bounds.x2 = MAX (group_view->bounds.x2,
474
group_view->bounds.y2 = MAX (group_view->bounds.y2,
481
*bounds = group_view->bounds;
485
static GooCanvasItemView*
486
goo_canvas_group_view_get_parent_view (GooCanvasItemView *view)
488
GooCanvasGroupView *group_view = (GooCanvasGroupView*) view;
489
return group_view->parent_view;
494
goo_canvas_group_view_set_parent_view (GooCanvasItemView *view,
495
GooCanvasItemView *parent_view)
497
GooCanvasGroupView *group_view = (GooCanvasGroupView*) view;
498
group_view->parent_view = parent_view;
502
static GooCanvasItem*
503
goo_canvas_group_view_get_item (GooCanvasItemView *view)
505
GooCanvasGroupView *group_view = (GooCanvasGroupView*) view;
506
return (GooCanvasItem*) group_view->group;
511
goo_canvas_group_view_get_bounds (GooCanvasItemView *view,
512
GooCanvasBounds *bounds)
514
GooCanvasGroupView *group_view = (GooCanvasGroupView*) view;
516
if (group_view->flags & GOO_CANVAS_ITEM_VIEW_NEED_UPDATE)
517
goo_canvas_item_view_ensure_updated (view);
519
*bounds = group_view->bounds;
523
static GooCanvasItemView*
524
goo_canvas_group_view_get_item_view_at (GooCanvasItemView *view,
528
gboolean is_pointer_event,
529
gboolean parent_visible)
531
GooCanvasGroupView *group_view = (GooCanvasGroupView*) view;
532
GooCanvasBounds child_bounds;
533
GooCanvasItemView *found_item = NULL;
534
GooCanvasItemVisibility visibility;
535
gboolean visible = parent_visible;
536
cairo_matrix_t transform;
539
if (group_view->flags & GOO_CANVAS_ITEM_VIEW_NEED_UPDATE)
540
goo_canvas_item_view_ensure_updated (view);
542
g_object_get (group_view->group, "visibility", &visibility, NULL);
544
if (visibility == GOO_CANVAS_ITEM_INVISIBLE)
548
else if (visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD)
550
gdouble visibility_threshold;
551
g_object_get (group_view->group,
552
"visibility-threshold", &visibility_threshold,
554
if (group_view->canvas_view->scale < visibility_threshold)
558
/* Check if the group should receive events. */
559
if (is_pointer_event)
561
GooCanvasPointerEvents pointer_events;
562
g_object_get (group_view->group,
563
"pointer-events", &pointer_events,
565
if (pointer_events == GOO_CANVAS_EVENTS_NONE
566
|| ((pointer_events & GOO_CANVAS_EVENTS_VISIBLE_MASK) && !visible))
570
/* Step down from the top item to the bottom in the stack/layer, and return
571
the first item found that contains the given point. */
574
if (goo_canvas_item_view_get_combined_transform (view, &transform))
575
cairo_transform (cr, &transform);
577
for (i = group_view->item_views->len - 1; i >= 0; i--)
579
GooCanvasItemView *child_view = group_view->item_views->pdata[i];
580
goo_canvas_item_view_get_bounds (child_view, &child_bounds);
582
/* Skip the item if the bounds don't contain the point. */
583
if (child_bounds.x1 > x || child_bounds.x2 < x
584
|| child_bounds.y1 > y || child_bounds.y2 < y)
587
found_item = goo_canvas_item_view_get_item_view_at (child_view, x, y, cr,
600
goo_canvas_group_view_is_visible (GooCanvasItemView *view)
602
GooCanvasGroupView *group_view = (GooCanvasGroupView*) view;
603
GooCanvasItemVisibility visibility;
605
g_object_get (group_view->group, "visibility", &visibility, NULL);
607
if (visibility == GOO_CANVAS_ITEM_INVISIBLE)
610
if (visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD)
612
gdouble visibility_threshold;
613
g_object_get (group_view->group,
614
"visibility-threshold", &visibility_threshold,
616
if (group_view->canvas_view->scale < visibility_threshold)
620
if (group_view->parent_view)
621
return goo_canvas_item_view_is_visible (group_view->parent_view);
628
goo_canvas_group_view_paint (GooCanvasItemView *view,
630
GooCanvasBounds *bounds,
633
GooCanvasGroupView *group_view = (GooCanvasGroupView*) view;
634
GooCanvasBounds child_bounds;
635
GooCanvasItemVisibility visibility;
636
cairo_matrix_t transform;
639
/* Check if the item should be visible. */
640
g_object_get (group_view->group, "visibility", &visibility, NULL);
642
if (visibility == GOO_CANVAS_ITEM_INVISIBLE)
645
if (visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD)
647
gdouble visibility_threshold;
648
g_object_get (group_view->group,
649
"visibility-threshold", &visibility_threshold,
651
if (group_view->canvas_view->scale < visibility_threshold)
655
/* Paint all the items in the group. */
658
if (goo_canvas_item_view_get_combined_transform (view, &transform))
659
cairo_transform (cr, &transform);
661
for (i = 0; i < group_view->item_views->len; i++)
663
GooCanvasItemView *child_view = group_view->item_views->pdata[i];
665
goo_canvas_item_view_get_bounds (child_view, &child_bounds);
667
/* Skip the item if the bounds don't intersect the expose rectangle. */
668
if (child_bounds.x1 > bounds->x2 || child_bounds.x2 < bounds->x1
669
|| child_bounds.y1 > bounds->y2 || child_bounds.y2 < bounds->y1)
672
goo_canvas_item_view_paint (child_view, cr, bounds, scale);
679
canvas_item_view_interface_init (GooCanvasItemViewIface *iface)
681
iface->get_canvas_view = goo_canvas_group_view_get_canvas_view;
682
iface->get_n_children = goo_canvas_group_view_get_n_children;
683
iface->get_child = goo_canvas_group_view_get_child;
684
iface->request_update = goo_canvas_group_view_request_update;
686
iface->get_parent_view = goo_canvas_group_view_get_parent_view;
687
iface->set_parent_view = goo_canvas_group_view_set_parent_view;
688
iface->get_item = goo_canvas_group_view_get_item;
689
iface->get_bounds = goo_canvas_group_view_get_bounds;
690
iface->get_item_view_at = goo_canvas_group_view_get_item_view_at;
691
iface->is_visible = goo_canvas_group_view_is_visible;
692
iface->update = goo_canvas_group_view_update;
693
iface->paint = goo_canvas_group_view_paint;
698
on_group_changed (GooCanvasItem *group,
699
gboolean recompute_bounds,
700
GooCanvasGroupView *view)
702
view->flags |= GOO_CANVAS_ITEM_VIEW_NEED_ENTIRE_SUBTREE_UPDATE;
703
goo_canvas_item_view_request_update ((GooCanvasItemView*) view);