[AdgContainer] Adding child with g_slist_prepend()
[adg.git] / adg / adg-entity.c
blob6c367352632ee460cf265a626455218f5e9c640f
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009 Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 /**
22 * SECTION:adg-entity
23 * @short_description: The base class for renderable objects
25 * This abstract class provides the base for all renderable objects.
27 * To provide a proper #AdgEntity derived type, you must at least
28 * implement the render() virtual method. Also, if you are using
29 * some sort of caching, you must implement invalidate() to clear
30 * this cache.
31 **/
33 /**
34 * AdgEntity:
36 * All fields are private and should not be used directly.
37 * Use its public methods instead.
38 **/
40 /**
41 * AdgEntityClass:
42 * @parent_set: called after the parent has changed
43 * @context_set: called after the context has changed
44 * @invalidate: invalidating callback, used to clear the cache
45 * @render: rendering callback, it must be implemented
47 * Any entity (if not abstract) must implement at least the @render method.
48 **/
51 #include "adg-entity.h"
52 #include "adg-entity-private.h"
53 #include "adg-canvas.h"
54 #include "adg-font-style.h"
55 #include "adg-dim-style.h"
56 #include "adg-intl.h"
58 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_entity_parent_class)
61 enum {
62 PROP_0,
63 PROP_PARENT,
64 PROP_CONTEXT,
65 PROP_GLOBAL_MAP,
66 PROP_LOCAL_MAP
69 enum {
70 PARENT_SET,
71 CONTEXT_SET,
72 INVALIDATE,
73 RENDER,
74 LAST_SIGNAL
78 static void dispose (GObject *object);
79 static void get_property (GObject *object,
80 guint prop_id,
81 GValue *value,
82 GParamSpec *pspec);
83 static void set_property (GObject *object,
84 guint prop_id,
85 const GValue *value,
86 GParamSpec *pspec);
87 static gboolean set_parent (AdgEntity *entity,
88 AdgEntity *parent);
89 static gboolean set_context (AdgEntity *entity,
90 AdgContext *context);
91 static void set_global_map (AdgEntity *entity,
92 const AdgMatrix *map);
93 static void set_local_map (AdgEntity *entity,
94 const AdgMatrix *map);
95 static void real_invalidate (AdgEntity *entity,
96 gpointer user_data);
97 static void real_render (AdgEntity *entity,
98 cairo_t *cr,
99 gpointer user_data);
101 static guint signals[LAST_SIGNAL] = { 0 };
104 G_DEFINE_ABSTRACT_TYPE(AdgEntity, adg_entity, G_TYPE_INITIALLY_UNOWNED);
107 static void
108 adg_entity_class_init(AdgEntityClass *klass)
110 GObjectClass *gobject_class;
111 GParamSpec *param;
112 GClosure *closure;
113 GType param_types[1];
115 gobject_class = (GObjectClass *) klass;
117 g_type_class_add_private(klass, sizeof(AdgEntityPrivate));
119 gobject_class->get_property = get_property;
120 gobject_class->set_property = set_property;
121 gobject_class->dispose = dispose;
123 klass->parent_set = NULL;
124 klass->context_set = NULL;
125 klass->invalidate = NULL;
126 klass->render = NULL;
128 param = g_param_spec_object("parent",
129 P_("Parent Entity"),
130 P_("The parent entity of this entity or NULL if this is a top-level entity"),
131 ADG_TYPE_ENTITY, G_PARAM_READWRITE);
132 g_object_class_install_property(gobject_class, PROP_PARENT, param);
134 param = g_param_spec_object("context",
135 P_("Context"),
136 P_("The context associated to this entity or NULL to inherit the parent context"),
137 ADG_TYPE_CONTEXT, G_PARAM_READWRITE);
138 g_object_class_install_property(gobject_class, PROP_CONTEXT, param);
140 param = g_param_spec_boxed("global-map",
141 P_("Global Map"),
142 P_("The transformation to be combined with the parent ones to get the global matrix"),
143 ADG_TYPE_MATRIX, G_PARAM_READWRITE);
144 g_object_class_install_property(gobject_class, PROP_GLOBAL_MAP, param);
146 param = g_param_spec_boxed("local-map",
147 P_("Local Map"),
148 P_("The transformation to be combined with the parent ones to get the local matrix"),
149 ADG_TYPE_MATRIX, G_PARAM_READWRITE);
150 g_object_class_install_property(gobject_class, PROP_LOCAL_MAP, param);
153 * AdgEntity::parent-set:
154 * @entity: an #AdgEntity
155 * @old_parent: the old parent
157 * Emitted after the parent entity has changed. The new parent
158 * can be inspected using adg_entity_get_parent().
160 * It is allowed for both old and new parent to be %NULL.
162 signals[PARENT_SET] = g_signal_new("parent-set",
163 G_OBJECT_CLASS_TYPE(gobject_class),
164 G_SIGNAL_RUN_FIRST,
165 G_STRUCT_OFFSET(AdgEntityClass, parent_set),
166 NULL, NULL,
167 g_cclosure_marshal_VOID__OBJECT,
168 G_TYPE_NONE, 1, ADG_TYPE_ENTITY);
171 * AdgEntity::context-set:
172 * @entity: an #AdgEntity
173 * @old_context: the old context
175 * Emitted after the context has changed.
176 * Emitted after the context has changed. The new context can be
177 * inspected using adg_entity_get_context().
179 * It is allowed for both old and new context to be %NULL.
181 signals[CONTEXT_SET] = g_signal_new("context-set",
182 G_OBJECT_CLASS_TYPE(gobject_class),
183 G_SIGNAL_RUN_FIRST,
184 G_STRUCT_OFFSET(AdgEntityClass, context_set),
185 NULL, NULL,
186 g_cclosure_marshal_VOID__OBJECT,
187 G_TYPE_NONE, 1, ADG_TYPE_CONTEXT);
190 * AdgEntity::invalidate:
191 * @entity: an #AdgEntity
193 * The inverse of the rendering. Usually, invalidation causes the
194 * cache of @entity to be cleared. After a succesful invalidation
195 * the rendered flag is reset: you can access its state using
196 * adg_entity_get_rendered().
198 closure = g_cclosure_new(G_CALLBACK(real_invalidate),
199 (gpointer)0xdeadbeaf, NULL);
200 signals[INVALIDATE] = g_signal_newv("invalidate", ADG_TYPE_ENTITY,
201 G_SIGNAL_RUN_LAST, closure, NULL, NULL,
202 g_cclosure_marshal_VOID__VOID,
203 G_TYPE_NONE, 0, param_types);
206 * AdgEntity::render:
207 * @entity: an #AdgEntity
208 * @cr: a #cairo_t drawing context
210 * Causes the rendering of @entity on @cr. After a succesful rendering
211 * the rendered flag is set: you can access its state using
212 * adg_entity_get_rendered().
214 closure = g_cclosure_new(G_CALLBACK(real_render),
215 (gpointer)0xdeadbeaf, NULL);
216 param_types[0] = G_TYPE_POINTER;
217 signals[RENDER] = g_signal_newv("render", ADG_TYPE_ENTITY,
218 G_SIGNAL_RUN_LAST, closure, NULL, NULL,
219 g_cclosure_marshal_VOID__POINTER,
220 G_TYPE_NONE, 1, param_types);
223 static void
224 adg_entity_init(AdgEntity *entity)
226 AdgEntityPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(entity,
227 ADG_TYPE_ENTITY,
228 AdgEntityPrivate);
229 data->parent = NULL;
230 data->flags = 0;
231 data->context = NULL;
232 cairo_matrix_init_identity(&data->local_map);
233 cairo_matrix_init_identity(&data->global_map);
235 entity->data = data;
238 static void
239 dispose(GObject *object)
241 AdgEntity *entity;
242 AdgEntity *parent;
244 entity = (AdgEntity *) object;
245 parent = adg_entity_get_parent(entity);
247 /* These calls will emit a "notify" signal both for parent and
248 * context if they are not NULL. Consequentially, the references
249 * to the old parent and context are dropped. */
250 adg_entity_set_parent(entity, NULL);
251 adg_entity_set_context(entity, NULL);
253 if (PARENT_OBJECT_CLASS->dispose != NULL)
254 PARENT_OBJECT_CLASS->dispose(object);
258 static void
259 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
261 AdgEntity *entity;
262 AdgEntityPrivate *data;
264 entity = (AdgEntity *) object;
265 data = entity->data;
267 switch (prop_id) {
268 case PROP_PARENT:
269 g_value_set_object(value, data->parent);
270 break;
271 case PROP_CONTEXT:
272 g_value_set_object(value, adg_entity_get_context(entity));
273 break;
274 case PROP_GLOBAL_MAP:
275 g_value_set_boxed(value, &data->global_map);
276 break;
277 case PROP_LOCAL_MAP:
278 g_value_set_boxed(value, &data->local_map);
279 break;
280 default:
281 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
282 break;
286 static void
287 set_property(GObject *object,
288 guint prop_id, const GValue *value, GParamSpec *pspec)
290 AdgEntity *entity = (AdgEntity *) object;
292 switch (prop_id) {
293 case PROP_PARENT:
294 set_parent(entity, g_value_get_object(value));
295 break;
296 case PROP_CONTEXT:
297 set_context(entity, g_value_get_object(value));
298 break;
299 case PROP_GLOBAL_MAP:
300 set_global_map(entity, g_value_get_boxed(value));
301 break;
302 case PROP_LOCAL_MAP:
303 set_local_map(entity, g_value_get_boxed(value));
304 break;
305 default:
306 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
307 break;
313 * adg_entity_get_parent:
314 * @entity: an #AdgEntity
316 * Gets the parent of @entity.
318 * Returns: the parent entity or %NULL on errors or if @entity is a toplevel
320 AdgEntity *
321 adg_entity_get_parent(AdgEntity *entity)
323 AdgEntityPrivate *data;
325 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
327 data = entity->data;
329 return data->parent;
333 * adg_entity_set_parent:
334 * @entity: an #AdgEntity
335 * @parent: the parent entity
337 * Sets a new parent on @entity.
339 * This function is only useful in entity implementations.
341 void
342 adg_entity_set_parent(AdgEntity *entity, AdgEntity *parent)
344 g_return_if_fail(ADG_IS_ENTITY(entity));
346 if (set_parent(entity, parent))
347 g_object_notify((GObject *) entity, "parent");
351 * adg_entity_context:
352 * @entity: an #AdgEntity instance
354 * Gets the context to be used for @entity. If no context was
355 * explicitely set, it returns the parent context.
357 * Returns: the requested context or %NULL on errors or if @entity
358 * does not have any parent with a context defined
360 AdgContext *
361 adg_entity_context(AdgEntity *entity)
363 AdgContext *context;
365 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
367 context = adg_entity_get_context(entity);
369 if (context == NULL) {
370 AdgEntity *parent = adg_entity_get_parent(entity);
372 if (parent != NULL)
373 context = adg_entity_get_context(parent);
376 return context;
380 * adg_entity_get_context:
381 * @entity: an #AdgEntity instance
383 * Gets the context associated to @entity. This is an accessor method:
384 * if you need to get the context for rendering, use adg_entity_context()
385 * instead.
387 * Returns: the context binded to @entity
389 AdgContext *
390 adg_entity_get_context(AdgEntity *entity)
392 AdgEntityPrivate *data;
394 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
396 data = entity->data;
398 return data->context;
402 * adg_entity_set_context:
403 * @entity: an #AdgEntity instance
404 * @context: the new context
406 * Sets a new context. The old context (if any) will be unreferenced
407 * while a new reference will be added to @context.
409 void
410 adg_entity_set_context(AdgEntity *entity, AdgContext *context)
412 g_return_if_fail(ADG_IS_ENTITY(entity));
413 g_return_if_fail(ADG_IS_CONTEXT(context));
415 if (set_context(entity, context))
416 g_object_notify((GObject *) entity, "context");
420 * adg_entity_get_canvas:
421 * @entity: an #AdgEntity
423 * Walks on the @entity hierarchy and gets the first parent of @entity that is
424 * of #AdgCanvas derived type.
426 * Returns: the requested canvas or %NULL on errors or if there is
427 * no #AdgCanvas in the @entity hierarchy
429 AdgCanvas *
430 adg_entity_get_canvas(AdgEntity *entity)
432 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
434 while (entity) {
435 if (ADG_IS_CANVAS(entity))
436 return (AdgCanvas *) entity;
438 entity = (AdgEntity *) adg_entity_get_parent(entity);
441 return NULL;
445 * adg_entity_get_rendered:
446 * @entity: an #AdgEntity object
448 * This function is only useful in entity implementations.
449 * Gets the rendered flag of @entity.
451 * Returns: the current rendered state
453 gboolean
454 adg_entity_get_rendered(AdgEntity *entity)
456 AdgEntityPrivate *data;
458 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
460 data = entity->data;
462 return ADG_ISSET(data->flags, RENDERED);
466 * adg_entity_set_rendered:
467 * @entity: an #AdgEntity object
468 * @rendered: new state for the rendered flag
470 * This function is only useful in entity implementations.
471 * Sets the rendered flag of @entity to @rendered.
473 void
474 adg_entity_set_rendered(AdgEntity *entity, gboolean rendered)
476 AdgEntityPrivate *data;
478 g_return_if_fail(ADG_IS_ENTITY(entity));
480 data = entity->data;
482 if (rendered)
483 ADG_SET(data->flags, RENDERED);
484 else
485 ADG_UNSET(data->flags, RENDERED);
489 * adg_entity_get_global_map:
490 * @entity: an #AdgEntity object
491 * @map: where to store the global map
493 * Gets the transformation to be used to compute the global matrix
494 * of @entity and store it in @map.
496 void
497 adg_entity_get_global_map(AdgEntity *entity, AdgMatrix *map)
499 AdgEntityPrivate *data;
501 g_return_if_fail(ADG_IS_ENTITY(entity));
502 g_return_if_fail(map != NULL);
504 data = entity->data;
505 adg_matrix_copy(map, &data->global_map);
509 * adg_entity_set_global_map:
510 * @entity: an #AdgEntity object
511 * @map: the new map
513 * Sets the new global transformation of @entity to @map:
514 * the old map is discarded. If @map is %NULL an identity
515 * matrix is implied.
517 void
518 adg_entity_set_global_map(AdgEntity *entity, const AdgMatrix *map)
520 g_return_if_fail(ADG_IS_ENTITY(entity));
522 set_global_map(entity, map);
523 g_object_notify((GObject *) entity, "global-map");
527 * adg_entity_transform_global_map:
528 * @entity: an #AdgEntity object
529 * @transformation: the transformation to apply
531 * Applies a transformation to the global map of @entity. This is
532 * equivalent to the following code:
534 * |[
535 * AdgMatrix tmp_map;
536 * adg_entity_get_global_map(entity, &tmp_map);
537 * cairo_matrix_multiply(&tmp_map, transformation, &tmp_map);
538 * adg_entity_set_global_map(entity, &tmp_map);
539 * ]|
541 void
542 adg_entity_transform_global_map(AdgEntity *entity,
543 const AdgMatrix *transformation)
545 AdgEntityPrivate *data;
547 g_return_if_fail(ADG_IS_ENTITY(entity));
548 g_return_if_fail(transformation != NULL);
550 data = entity->data;
552 cairo_matrix_multiply(&data->global_map, transformation, &data->global_map);
553 g_object_notify((GObject *) entity, "global-map");
557 * adg_entity_get_global_matrix:
558 * @entity: an #AdgEntity object
559 * @matrix: where to store the global matrix
561 * Computes the global matrix by combining all the global maps of the
562 * @entity hierarchy and stores the result in @matrix.
564 void
565 adg_entity_get_global_matrix(AdgEntity *entity, AdgMatrix *matrix)
567 AdgEntityPrivate *data;
569 g_return_if_fail(ADG_IS_ENTITY(entity));
570 g_return_if_fail(matrix != NULL);
572 data = entity->data;
574 if (data->parent == NULL) {
575 adg_matrix_copy(matrix, &data->global_map);
576 } else {
577 adg_entity_get_global_matrix((AdgEntity *) data->parent, matrix);
578 cairo_matrix_multiply(matrix, &data->global_map, matrix);
583 * adg_entity_get_local_map:
584 * @entity: an #AdgEntity object
585 * @map: where to store the local map
587 * Gets the transformation to be used to compute the local matrix
588 * of @entity and store it in @map.
590 void
591 adg_entity_get_local_map(AdgEntity *entity, AdgMatrix *map)
593 AdgEntityPrivate *data;
595 g_return_if_fail(ADG_IS_ENTITY(entity));
596 g_return_if_fail(map != NULL);
598 data = entity->data;
599 adg_matrix_copy(map, &data->local_map);
603 * adg_entity_set_local_map:
604 * @entity: an #AdgEntity object
605 * @map: the new map
607 * Sets the new global transformation of @entity to @map:
608 * the old map is discarded. If @map is %NULL an identity
609 * matrix is implied.
611 void
612 adg_entity_set_local_map(AdgEntity *entity, const AdgMatrix *map)
614 g_return_if_fail(ADG_IS_ENTITY(entity));
616 set_local_map(entity, map);
617 g_object_notify((GObject *) entity, "local-map");
621 * adg_entity_transform_local_map:
622 * @entity: an #AdgEntity object
623 * @transformation: the transformation to apply
625 * Applies a transformation to the local map of @entity. This is
626 * equivalent to the following code:
628 * |[
629 * AdgMatrix tmp_map;
630 * adg_entity_get_local_map(entity, &tmp_map);
631 * cairo_matrix_multiply(&tmp_map, transformation, &tmp_map);
632 * adg_entity_set_local_map(entity, &tmp_map);
633 * ]|
635 void
636 adg_entity_transform_local_map(AdgEntity *entity,
637 const AdgMatrix *transformation)
639 AdgEntityPrivate *data;
641 g_return_if_fail(ADG_IS_ENTITY(entity));
642 g_return_if_fail(transformation != NULL);
644 data = entity->data;
646 cairo_matrix_multiply(&data->local_map, transformation, &data->local_map);
647 g_object_notify((GObject *) entity, "local-map");
651 * adg_entity_get_local_matrix:
652 * @entity: an #AdgEntity object
653 * @matrix: where to store the local matrix
655 * Computes the local matrix by combining all the local maps of the
656 * @entity hierarchy and stores the result in @matrix.
658 void
659 adg_entity_get_local_matrix(AdgEntity *entity, AdgMatrix *matrix)
661 AdgEntityPrivate *data;
663 g_return_if_fail(ADG_IS_ENTITY(entity));
664 g_return_if_fail(matrix != NULL);
666 data = entity->data;
668 if (data->parent == NULL) {
669 adg_matrix_copy(matrix, &data->local_map);
670 } else {
671 adg_entity_get_local_matrix((AdgEntity *) data->parent, matrix);
672 cairo_matrix_multiply(matrix, &data->local_map, matrix);
677 * adg_entity_get_style:
678 * @entity: an #AdgEntity
679 * @style_slot: the slot of the style to get
681 * Gets a style from this entity. If the entity has no context associated
682 * or the style is undefined within this context, gets the style from its
683 * parent entity.
685 * Returns: the requested style or %NULL on errors or if there is no
686 * context with this style defined in the @entity hierarchy
688 AdgStyle *
689 adg_entity_get_style(AdgEntity *entity, AdgStyleSlot style_slot)
691 AdgEntityPrivate *data;
693 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
695 data = entity->data;
697 if (data->context) {
698 AdgStyle *style = adg_context_get_style(data->context, style_slot);
699 if (style)
700 return style;
703 if (data->parent)
704 return adg_entity_get_style((AdgEntity *) data->parent, style_slot);
706 return NULL;
710 * adg_entity_apply:
711 * @entity: an #AdgEntity
712 * @style_slot: the slot of the style to apply
713 * @cr: a #cairo_t drawing context
715 * Applies the specified style to the @cr cairo context.
717 void
718 adg_entity_apply(AdgEntity *entity, AdgStyleSlot style_slot, cairo_t *cr)
720 AdgStyle *style = adg_entity_get_style(entity, style_slot);
722 if (style)
723 adg_style_apply(style, cr);
727 * adg_entity_apply_font:
728 * @entity: an #AdgEntity
729 * @font_id: a font id
730 * @cr: a #cairo_t drawing context
732 * Applies the specified font to the @cr cairo context. It is similar
733 * to adg_entity_apply() but instead of looking for a font slot, it
734 * searches for a specific font style by inspecting composite styles too.
736 * A typical example is when the tolerance font should be applied: this
737 * is a font style embedded in the dim style, so it is not enough to
738 * use adg_entity_apply().
740 void
741 adg_entity_apply_font(AdgEntity *entity, AdgFontStyleId font_id, cairo_t *cr)
743 AdgStyle *style;
745 switch (font_id) {
747 case ADG_FONT_STYLE_TEXT:
748 style = adg_entity_get_style(entity, ADG_SLOT_FONT_STYLE);
749 break;
751 case ADG_FONT_STYLE_VALUE:
752 style = adg_entity_get_style(entity, ADG_SLOT_DIM_STYLE);
753 style = adg_dim_style_get_value_style((AdgDimStyle *) style);
754 break;
756 case ADG_FONT_STYLE_TOLERANCE:
757 style = adg_entity_get_style(entity, ADG_SLOT_DIM_STYLE);
758 style = adg_dim_style_get_tolerance_style((AdgDimStyle *) style);
759 break;
761 case ADG_FONT_STYLE_NOTE:
762 style = adg_entity_get_style(entity, ADG_SLOT_DIM_STYLE);
763 style = adg_dim_style_get_note_style((AdgDimStyle *) style);
764 break;
766 default:
767 g_warning ("%s: invalid font id (%d)", G_STRLOC, font_id);
768 return;
771 if (style)
772 adg_style_apply(style, cr);
776 * adg_entity_invalidate:
777 * @entity: an #AdgEntity
779 * Emits the "invalidate" signal on @entity and all its children, if any,
780 * so subsequent rendering will need a global recomputation.
782 void
783 adg_entity_invalidate(AdgEntity *entity)
785 g_return_if_fail(ADG_IS_ENTITY(entity));
787 g_signal_emit(entity, signals[INVALIDATE], 0, NULL);
791 * adg_entity_render:
792 * @entity: an #AdgEntity
793 * @cr: a #cairo_t drawing context
795 * Emits the "render" signal on @entity and all its children, if any,
796 * causing the rendering operation the @cr cairo context.
798 void
799 adg_entity_render(AdgEntity *entity, cairo_t *cr)
801 g_return_if_fail(ADG_IS_ENTITY(entity));
803 g_signal_emit(entity, signals[RENDER], 0, cr);
807 static gboolean
808 set_parent(AdgEntity *entity, AdgEntity *parent)
810 AdgEntityPrivate *data;
811 AdgEntity *old_parent;
813 data = entity->data;
814 old_parent = data->parent;
816 /* Check if parent has changed */
817 if (parent == old_parent)
818 return FALSE;
820 if (parent != NULL)
821 g_object_ref(parent);
823 data->parent = parent;
824 g_signal_emit(entity, signals[PARENT_SET], 0, old_parent);
826 if (old_parent != NULL)
827 g_object_unref(old_parent);
829 return TRUE;
832 static gboolean
833 set_context(AdgEntity *entity, AdgContext *context)
835 AdgEntityPrivate *data;
836 AdgContext *old_context;
838 data = entity->data;
839 old_context = data->context;
841 /* Check if context has changed */
842 if (context == old_context)
843 return FALSE;
845 if (context != NULL)
846 g_object_ref(context);
848 data->context = context;
849 g_signal_emit(entity, signals[CONTEXT_SET], 0, old_context);
851 if (old_context != NULL)
852 g_object_unref(old_context);
854 return TRUE;
857 static void
858 set_global_map(AdgEntity *entity, const AdgMatrix *map)
860 AdgEntityPrivate *data = entity->data;
862 if (map == NULL)
863 cairo_matrix_init_identity(&data->global_map);
864 else
865 adg_matrix_copy(&data->global_map, map);
868 static void
869 set_local_map(AdgEntity *entity, const AdgMatrix *map)
871 AdgEntityPrivate *data = entity->data;
873 if (map == NULL)
874 cairo_matrix_init_identity(&data->local_map);
875 else
876 adg_matrix_copy(&data->local_map, map);
879 static void
880 real_invalidate(AdgEntity *entity, gpointer user_data)
882 AdgEntityClass *entity_class;
883 AdgEntityPrivate *data;
885 g_assert(user_data == (gpointer) 0xdeadbeaf);
887 entity_class = ADG_ENTITY_GET_CLASS(entity);
888 if (entity_class->invalidate == NULL) {
889 /* Assume the entity does not have cache to be cleared */
890 } else if (!entity_class->invalidate(entity)) {
891 return;
894 data = entity->data;
895 ADG_UNSET(data->flags, RENDERED);
898 static void
899 real_render(AdgEntity *entity, cairo_t *cr, gpointer user_data)
901 AdgEntityClass *entity_class;
902 AdgEntityPrivate *data;
904 g_assert(user_data == (gpointer) 0xdeadbeaf);
906 entity_class = ADG_ENTITY_GET_CLASS(entity);
907 if (entity_class->render == NULL) {
908 /* The render method must be defined */
909 g_warning("%s: `render' method not implemented for type `%s'",
910 G_STRLOC, g_type_name(G_OBJECT_TYPE(entity)));
911 return;
914 data = entity->data;
916 cairo_save(cr);
917 cairo_transform(cr, &data->global_map);
919 if (entity_class->render(entity, cr))
920 ADG_SET(data->flags, RENDERED);
922 cairo_restore(cr);