[AdgADim] Added "angle1" and "angle2" properties
[adg.git] / adg / adg-entity.c
blob382eec4b0f4478c404558898ee61011c4b936d22
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 a base interface for all renderable objects
26 * (all the objects that can be printed or viewed).
27 **/
29 /**
30 * AdgEntity:
32 * All fields are private and should not be used directly.
33 * Use its public methods instead.
34 **/
37 #include "adg-entity.h"
38 #include "adg-entity-private.h"
39 #include "adg-canvas.h"
40 #include "adg-context.h"
41 #include "adg-util.h"
42 #include "adg-intl.h"
45 enum {
46 PROP_0,
47 PROP_PARENT,
48 PROP_CONTEXT,
49 PROP_GLOBAL_MAP,
50 PROP_LOCAL_MAP
53 enum {
54 PARENT_SET,
55 MODEL_MATRIX_CHANGED,
56 PAPER_MATRIX_CHANGED,
57 INVALIDATE,
58 RENDER,
59 LAST_SIGNAL
63 static void get_property (GObject *object,
64 guint prop_id,
65 GValue *value,
66 GParamSpec *pspec);
67 static void set_property (GObject *object,
68 guint prop_id,
69 const GValue *value,
70 GParamSpec *pspec);
71 static void dispose (GObject *object);
72 static AdgContainer * get_parent (AdgEntity *entity);
73 static void set_parent (AdgEntity *entity,
74 AdgContainer *parent);
75 static void parent_set (AdgEntity *entity,
76 AdgContainer *old_parent);
77 static AdgContext * get_context (AdgEntity *entity);
78 static void set_context (AdgEntity *entity,
79 AdgContext *context);
80 static void set_global_map (AdgEntity *entity,
81 const AdgMatrix *map);
82 static void set_local_map (AdgEntity *entity,
83 const AdgMatrix *map);
84 static void model_matrix_changed (AdgEntity *entity,
85 AdgMatrix *parent_matrix);
86 static void paper_matrix_changed (AdgEntity *entity,
87 AdgMatrix *parent_matrix);
88 static void render (AdgEntity *entity,
89 cairo_t *cr);
90 static const AdgMatrix *get_model_matrix (AdgEntity *entity);
91 static const AdgMatrix *get_paper_matrix (AdgEntity *entity);
93 static guint signals[LAST_SIGNAL] = { 0 };
96 G_DEFINE_ABSTRACT_TYPE(AdgEntity, adg_entity, G_TYPE_INITIALLY_UNOWNED);
99 static void
100 adg_entity_class_init(AdgEntityClass *klass)
102 GObjectClass *gobject_class;
103 GParamSpec *param;
105 gobject_class = (GObjectClass *) klass;
107 g_type_class_add_private(klass, sizeof(AdgEntityPrivate));
109 gobject_class->get_property = get_property;
110 gobject_class->set_property = set_property;
111 gobject_class->dispose = dispose;
113 klass->get_parent = get_parent;
114 klass->set_parent = set_parent;
115 klass->parent_set = parent_set;
116 klass->get_context = get_context;
117 klass->model_matrix_changed = model_matrix_changed;
118 klass->paper_matrix_changed = paper_matrix_changed;
119 klass->invalidate = NULL;
120 klass->render = render;
121 klass->get_model_matrix = get_model_matrix;
122 klass->get_paper_matrix = get_paper_matrix;
124 param = g_param_spec_object("parent",
125 P_("Parent Container"),
126 P_("The parent AdgContainer of this entity or NULL if this is a top-level entity"),
127 ADG_TYPE_CONTAINER, G_PARAM_READWRITE);
128 g_object_class_install_property(gobject_class, PROP_PARENT, param);
130 param = g_param_spec_object("context",
131 P_("Context"),
132 P_("The context associated to this entity or NULL to inherit the parent context"),
133 ADG_TYPE_CONTEXT, G_PARAM_READWRITE);
134 g_object_class_install_property(gobject_class, PROP_CONTEXT, param);
136 param = g_param_spec_boxed("global-map",
137 P_("Global Map"),
138 P_("The transformation to be combined with the parent ones to get the global matrix"),
139 ADG_TYPE_MATRIX, G_PARAM_READWRITE);
140 g_object_class_install_property(gobject_class, PROP_GLOBAL_MAP, param);
142 param = g_param_spec_boxed("local-map",
143 P_("Local Map"),
144 P_("The transformation to be combined with the parent ones to get the local matrix"),
145 ADG_TYPE_MATRIX, G_PARAM_READWRITE);
146 g_object_class_install_property(gobject_class, PROP_LOCAL_MAP, param);
149 * AdgEntity::parent-set:
150 * @entity: an #AdgEntity
151 * @parent: the #AdgContainer parent of @entity
153 * Emitted after the parent container has changed.
155 signals[PARENT_SET] =
156 g_signal_new("parent-set",
157 G_OBJECT_CLASS_TYPE(gobject_class),
158 G_SIGNAL_RUN_FIRST,
159 G_STRUCT_OFFSET(AdgEntityClass, parent_set),
160 NULL, NULL,
161 g_cclosure_marshal_VOID__OBJECT,
162 G_TYPE_NONE, 1, ADG_TYPE_CONTAINER);
165 * AdgEntity::model-matrix-changed:
166 * @entity: an #AdgEntity
167 * @parent_matrix: the parent model matrix
169 * Emitted after the current model matrix has changed.
171 signals[MODEL_MATRIX_CHANGED] =
172 g_signal_new("model-matrix-changed",
173 G_OBJECT_CLASS_TYPE(gobject_class),
174 G_SIGNAL_RUN_FIRST,
175 G_STRUCT_OFFSET(AdgEntityClass, model_matrix_changed),
176 NULL, NULL,
177 g_cclosure_marshal_VOID__BOXED,
178 G_TYPE_NONE, 1,
179 ADG_TYPE_MATRIX | G_SIGNAL_TYPE_STATIC_SCOPE);
182 * AdgEntity::paper-matrix-changed:
183 * @entity: an #AdgEntity
184 * @parent_matrix: the parent paper matrix
186 * Emitted after the current paper matrix has changed.
188 signals[PAPER_MATRIX_CHANGED] =
189 g_signal_new("paper-matrix-changed",
190 G_OBJECT_CLASS_TYPE(gobject_class),
191 G_SIGNAL_RUN_FIRST,
192 G_STRUCT_OFFSET(AdgEntityClass, paper_matrix_changed),
193 NULL, NULL,
194 g_cclosure_marshal_VOID__BOXED,
195 G_TYPE_NONE, 1,
196 ADG_TYPE_MATRIX | G_SIGNAL_TYPE_STATIC_SCOPE);
199 * AdgEntity::invalidate:
200 * @entity: an #AdgEntity
202 * Clears the cached data of @entity.
204 signals[INVALIDATE] =
205 g_signal_new("invalidate",
206 G_OBJECT_CLASS_TYPE(gobject_class),
207 G_SIGNAL_RUN_FIRST,
208 G_STRUCT_OFFSET(AdgEntityClass, invalidate),
209 NULL, NULL,
210 g_cclosure_marshal_VOID__BOOLEAN,
211 G_TYPE_NONE, 0);
214 * AdgEntity::render:
215 * @entity: an #AdgEntity
216 * @cr: a #cairo_t drawing context
218 * Causes the rendering of @entity on @cr.
220 signals[RENDER] =
221 g_signal_new("render",
222 G_OBJECT_CLASS_TYPE(gobject_class),
223 G_SIGNAL_RUN_FIRST,
224 G_STRUCT_OFFSET(AdgEntityClass, render),
225 NULL, NULL,
226 g_cclosure_marshal_VOID__POINTER,
227 G_TYPE_NONE, 1, G_TYPE_POINTER);
230 static void
231 adg_entity_init(AdgEntity *entity)
233 AdgEntityPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(entity,
234 ADG_TYPE_ENTITY,
235 AdgEntityPrivate);
236 data->parent = NULL;
237 data->flags = 0;
238 data->context = NULL;
239 cairo_matrix_init_identity(&data->local_map);
240 cairo_matrix_init_identity(&data->global_map);
242 entity->data = data;
245 static void
246 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
248 AdgEntity *entity;
249 AdgEntityPrivate *data;
251 entity = (AdgEntity *) object;
252 data = entity->data;
254 switch (prop_id) {
255 case PROP_PARENT:
256 g_value_set_object(value, get_parent(entity));
257 break;
258 case PROP_CONTEXT:
259 g_value_set_object(value, get_context(entity));
260 break;
261 case PROP_GLOBAL_MAP:
262 g_value_set_boxed(value, &data->global_map);
263 break;
264 case PROP_LOCAL_MAP:
265 g_value_set_boxed(value, &data->local_map);
266 break;
267 default:
268 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
269 break;
273 static void
274 set_property(GObject *object,
275 guint prop_id, const GValue *value, GParamSpec *pspec)
277 AdgEntity *entity = (AdgEntity *) object;
279 switch (prop_id) {
280 case PROP_PARENT:
281 set_parent(entity, g_value_get_object(value));
282 break;
283 case PROP_CONTEXT:
284 set_context(entity, g_value_get_object(value));
285 break;
286 case PROP_GLOBAL_MAP:
287 set_global_map(entity, g_value_get_boxed(value));
288 break;
289 case PROP_LOCAL_MAP:
290 set_local_map(entity, g_value_get_boxed(value));
291 break;
292 default:
293 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
294 break;
298 static void
299 dispose(GObject *object)
301 AdgEntity *entity;
302 AdgEntityPrivate *data;
303 GObjectClass *object_class;
305 entity = (AdgEntity *) object;
306 data = entity->data;
307 object_class = (GObjectClass *) adg_entity_parent_class;
309 if (data->parent)
310 adg_container_remove(data->parent, entity);
312 if (object_class->dispose != NULL)
313 object_class->dispose(object);
318 * adg_entity_get_parent:
319 * @entity: an #AdgEntity
321 * Gets the container parent of @entity.
323 * This function is only useful in entity implementations.
325 * Return value: the container object or %NULL if @entity is not contained
327 AdgContainer *
328 adg_entity_get_parent(AdgEntity *entity)
330 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
332 return ADG_ENTITY_GET_CLASS(entity)->get_parent(entity);
336 * adg_entity_set_parent:
337 * @entity: an #AdgEntity
338 * @parent: an #AdgContainer
340 * Sets a new container of @entity.
342 * This function is only useful in entity implementations.
344 void
345 adg_entity_set_parent(AdgEntity *entity, AdgContainer *parent)
347 g_return_if_fail(ADG_IS_ENTITY(entity));
349 ADG_ENTITY_GET_CLASS(entity)->set_parent(entity, parent);
350 g_object_notify((GObject *) entity, "parent");
354 * adg_entity_unparent:
355 * @entity: an #AdgEntity
357 * Removes the current parent of @entity, properly handling
358 * the references between them.
360 * If @entity has no parent, this function simply returns.
362 void
363 adg_entity_unparent(AdgEntity *entity)
365 AdgContainer *old_parent;
367 g_return_if_fail(ADG_IS_ENTITY(entity));
369 old_parent = ADG_ENTITY_GET_CLASS(entity)->get_parent(entity);
371 if (old_parent == NULL)
372 return;
374 ADG_ENTITY_GET_CLASS(entity)->set_parent(entity, NULL);
375 g_signal_emit(entity, signals[PARENT_SET], 0, old_parent);
377 g_object_unref(entity);
381 * adg_entity_reparent:
382 * @entity: an #AdgEntity
383 * @parent: the new container
385 * Moves @entity from the old parent to @parent, handling reference
386 * count issues to avoid destroying the object.
388 void
389 adg_entity_reparent(AdgEntity *entity, AdgContainer *parent)
391 AdgContainer *old_parent;
393 g_return_if_fail(ADG_IS_CONTAINER(parent));
395 old_parent = adg_entity_get_parent(entity);
397 /* Reparenting on the same container: do nothing */
398 if (old_parent == parent)
399 return;
401 g_return_if_fail(ADG_IS_CONTAINER(old_parent));
403 g_object_ref(entity);
404 adg_container_remove(old_parent, entity);
405 adg_container_add(parent, entity);
406 g_object_unref(entity);
410 * adg_entity_get_context:
411 * @entity: an #AdgEntity instance
413 * Gets the context associated to @entity.
414 * If no context was explicitely set, get the parent context.
416 * Return value: the requested context or %NULL on errors
418 AdgContext *
419 adg_entity_get_context(AdgEntity *entity)
421 AdgEntityPrivate *data;
423 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
425 data = entity->data;
427 if (data->context)
428 return data->context;
430 if (data->parent)
431 return adg_entity_get_context((AdgEntity *) data->parent);
433 return NULL;
437 * adg_entity_set_context:
438 * @entity: an #AdgEntity instance
439 * @context: the new context
441 * Sets a new context. The old context (if any) will be unreferenced
442 * while a new reference will be added to @context.
444 void
445 adg_entity_set_context(AdgEntity *entity, AdgContext *context)
447 g_return_if_fail(ADG_IS_ENTITY(entity));
448 g_return_if_fail(ADG_IS_CONTEXT(context));
450 set_context(entity, context);
451 g_object_notify((GObject *) entity, "context");
455 * adg_entity_get_canvas:
456 * @entity: an #AdgEntity
458 * Walks on the @entity hierarchy and gets the first parent of @entity that is
459 * of #AdgCanvas derived type.
461 * Return value: the requested object or %NULL if there is no #AdgCanvas in
462 * the parent hierarchy.
464 AdgCanvas *
465 adg_entity_get_canvas(AdgEntity *entity)
467 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
469 while (entity) {
470 if (ADG_IS_CANVAS(entity))
471 return (AdgCanvas *) entity;
473 entity = (AdgEntity *) adg_entity_get_parent(entity);
476 return NULL;
480 * adg_entity_get_global_map:
481 * @entity: an #AdgEntity object
482 * @map: where to store the global map
484 * Gets the transformation to be used to compute the global matrix
485 * of @entity and store it in @map.
487 void
488 adg_entity_get_global_map(AdgEntity *entity, AdgMatrix *map)
490 AdgEntityPrivate *data;
492 g_return_if_fail(ADG_IS_ENTITY(entity));
493 g_return_if_fail(map != NULL);
495 data = entity->data;
496 adg_matrix_copy(map, &data->global_map);
500 * adg_entity_set_global_map:
501 * @entity: an #AdgEntity object
502 * @map: the new map
504 * Sets the new global transformation of @entity to @map:
505 * the old map is discarded. If @map is %NULL an identity
506 * matrix is implied.
508 void
509 adg_entity_set_global_map(AdgEntity *entity, const AdgMatrix *map)
511 g_return_if_fail(ADG_IS_ENTITY(entity));
513 set_global_map(entity, map);
514 g_object_notify((GObject *) entity, "global-map");
518 * adg_entity_get_local_map:
519 * @entity: an #AdgEntity object
520 * @map: where to store the local map
522 * Gets the transformation to be used to compute the local matrix
523 * of @entity and store it in @map.
525 void
526 adg_entity_get_local_map(AdgEntity *entity, AdgMatrix *map)
528 AdgEntityPrivate *data;
530 g_return_if_fail(ADG_IS_ENTITY(entity));
531 g_return_if_fail(map != NULL);
533 data = entity->data;
534 adg_matrix_copy(map, &data->local_map);
538 * adg_entity_set_local_map:
539 * @entity: an #AdgEntity object
540 * @map: the new map
542 * Sets the new global transformation of @entity to @map:
543 * the old map is discarded. If @map is %NULL an identity
544 * matrix is implied.
546 void
547 adg_entity_set_local_map(AdgEntity *entity, const AdgMatrix *map)
549 g_return_if_fail(ADG_IS_ENTITY(entity));
551 set_local_map(entity, map);
552 g_object_notify((GObject *) entity, "local-map");
556 * adg_entity_get_global_matrix:
557 * @entity: an #AdgEntity object
558 * @matrix: where to store the global matrix
560 * Computes the global matrix by combining all the global maps of the
561 * @entity hierarchy and stores the result in @matrix.
563 void
564 adg_entity_get_global_matrix(AdgEntity *entity, AdgMatrix *matrix)
566 AdgEntityPrivate *data;
568 g_return_if_fail(ADG_IS_ENTITY(entity));
569 g_return_if_fail(matrix != NULL);
571 data = entity->data;
573 if (data->parent == NULL) {
574 adg_matrix_copy(matrix, &data->global_map);
575 } else {
576 adg_entity_get_global_matrix((AdgEntity *) data->parent, matrix);
577 cairo_matrix_multiply(matrix, &data->global_map, matrix);
582 * adg_entity_get_local_matrix:
583 * @entity: an #AdgEntity object
584 * @matrix: where to store the local matrix
586 * Computes the local matrix by combining all the local maps of the
587 * @entity hierarchy and stores the result in @matrix.
589 void
590 adg_entity_get_local_matrix(AdgEntity *entity, AdgMatrix *matrix)
592 AdgEntityPrivate *data;
594 g_return_if_fail(ADG_IS_ENTITY(entity));
595 g_return_if_fail(matrix != NULL);
597 data = entity->data;
599 if (data->parent == NULL) {
600 adg_matrix_copy(matrix, &data->local_map);
601 } else {
602 adg_entity_get_local_matrix((AdgEntity *) data->parent, matrix);
603 cairo_matrix_multiply(matrix, &data->local_map, matrix);
608 * adg_entity_get_model_matrix:
609 * @entity: an #AdgEntity object
611 * Gets the model matrix to be used in rendering this @entity.
613 * Return value: the requested matrix
615 const AdgMatrix *
616 adg_entity_get_model_matrix(AdgEntity *entity)
618 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
619 return ADG_ENTITY_GET_CLASS(entity)->get_model_matrix(entity);
623 * adg_entity_get_paper_matrix:
624 * @entity: an #AdgEntity object
626 * Gets the paper matrix to be used in rendering this @entity.
628 * Return value: the requested matrix
630 const AdgMatrix *
631 adg_entity_get_paper_matrix(AdgEntity *entity)
633 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
634 return ADG_ENTITY_GET_CLASS(entity)->get_paper_matrix(entity);
638 * adg_entity_build_paper2model:
639 * @entity: an #AdgEntity
640 * @matrix: the destination matrix
642 * Builds a matrix to translate from paper to model space and
643 * put the result in @matrix.
645 * Return value: %TRUE on success, %FALSE on errors
647 gboolean
648 adg_entity_build_paper2model(AdgEntity *entity, AdgMatrix *matrix)
650 cairo_status_t status;
652 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
653 g_return_val_if_fail(matrix != NULL, FALSE);
655 adg_matrix_copy(matrix, adg_entity_get_model_matrix(entity));
656 status = cairo_matrix_invert(matrix);
657 if (status != CAIRO_STATUS_SUCCESS) {
658 g_error("Unable to invert model matrix (cairo message: %s)",
659 cairo_status_to_string(status));
660 return FALSE;
663 cairo_matrix_multiply(matrix, matrix, adg_entity_get_paper_matrix(entity));
664 return TRUE;
668 * adg_entity_build_model2paper:
669 * @entity: an #AdgEntity
670 * @matrix: the destination matrix
672 * Builds a matrix to translate from model to paper space and
673 * put the result in @matrix.
675 * Return value: %TRUE on success, %FALSE on errors
677 gboolean
678 adg_entity_build_model2paper(AdgEntity *entity, AdgMatrix *matrix)
680 cairo_status_t status;
682 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
683 g_return_val_if_fail(matrix != NULL, FALSE);
685 adg_matrix_copy(matrix, adg_entity_get_paper_matrix(entity));
686 status = cairo_matrix_invert(matrix);
687 if (status != CAIRO_STATUS_SUCCESS) {
688 g_error("Unable to invert paper matrix (cairo message: %s)",
689 cairo_status_to_string(status));
690 return FALSE;
693 cairo_matrix_multiply(matrix, matrix, adg_entity_get_model_matrix(entity));
694 return TRUE;
698 * adg_entity_model_matrix_changed:
699 * @entity: an #AdgEntity
700 * @parent_matrix: the parent #AdgMatrix
702 * Emits the "model-matrix-changed" signal on @entity.
704 * This function is only useful in entity implementations.
706 void
707 adg_entity_model_matrix_changed(AdgEntity *entity,
708 const AdgMatrix *parent_matrix)
710 g_return_if_fail(ADG_IS_ENTITY(entity));
712 g_signal_emit(entity, signals[MODEL_MATRIX_CHANGED], 0, parent_matrix);
716 * adg_entity_paper_matrix_changed:
717 * @entity: an #AdgEntity
718 * @parent_matrix: the parent #AdgMatrix
720 * Emits the "paper-matrix-changed" signal on @entity.
722 * This function is only useful in entity implementations.
724 void
725 adg_entity_paper_matrix_changed(AdgEntity *entity,
726 const AdgMatrix *parent_matrix)
728 g_return_if_fail(ADG_IS_ENTITY(entity));
730 g_signal_emit(entity, signals[PAPER_MATRIX_CHANGED], 0, parent_matrix);
734 * adg_entity_get_style:
735 * @entity: an #AdgEntity
736 * @style_slot: the slot of the style to get
738 * Gets a style from this entity. If the entity has no context associated
739 * or the style in undefined within this context, gets the style from its
740 * parent container.
742 * Return value: the requested style or %NULL on errors
744 AdgStyle *
745 adg_entity_get_style(AdgEntity *entity, AdgStyleSlot style_slot)
747 AdgEntityPrivate *data;
749 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
751 data = entity->data;
753 if (data->context) {
754 AdgStyle *style = adg_context_get_style(data->context, style_slot);
755 if (style)
756 return style;
759 if (data->parent)
760 return adg_entity_get_style((AdgEntity *) data->parent, style_slot);
762 return NULL;
766 * adg_entity_apply:
767 * @entity: an #AdgEntity
768 * @style_slot: the slot of the style to apply
769 * @cr: a #cairo_t drawing context
771 * Applies the specified style to the @cr cairo context.
773 void
774 adg_entity_apply(AdgEntity *entity, AdgStyleSlot style_slot, cairo_t *cr)
776 AdgStyle *style = adg_entity_get_style(entity, style_slot);
778 if (style)
779 adg_style_apply(style, cr);
783 * adg_entity_model_matrix_applied:
784 * @entity: an #AdgEntity
786 * Return value: %TRUE if the model matrix didn't change from the last render
788 gboolean
789 adg_entity_model_matrix_applied(AdgEntity *entity)
791 AdgEntityPrivate *data;
793 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
795 data = entity->data;
797 return ADG_ISSET(data->flags, MODEL_MATRIX_APPLIED);
801 * adg_entity_paper_matrix_applied:
802 * @entity: an #AdgEntity
804 * Return value: %TRUE if the paper matrix didn't change from the last render
806 gboolean
807 adg_entity_paper_matrix_applied(AdgEntity *entity)
809 AdgEntityPrivate *data;
811 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
813 data = entity->data;
815 return ADG_ISSET(data->flags, PAPER_MATRIX_APPLIED);
819 * adg_entity_model_applied:
820 * @entity: an #AdgEntity
822 * Return value: %TRUE if the model didn't change from the last render
824 gboolean
825 adg_entity_model_applied(AdgEntity *entity)
827 AdgEntityPrivate *data;
829 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
831 data = entity->data;
833 return ADG_ISSET(data->flags, MODEL_APPLIED);
837 * adg_entity_invalidate:
838 * @entity: an #AdgEntity
840 * Emits the "invalidate" signal on @entity and all its children, if any,
841 * so subsequent rendering will need a global recomputation.
843 void
844 adg_entity_invalidate(AdgEntity *entity)
846 g_return_if_fail(ADG_IS_ENTITY(entity));
848 g_signal_emit(entity, signals[INVALIDATE], 0, NULL);
852 * adg_entity_render:
853 * @entity: an #AdgEntity
854 * @cr: a #cairo_t drawing context
856 * Emits the "render" signal on @entity and all its children, if any,
857 * causing the rendering operation the @cr cairo context.
859 void
860 adg_entity_render(AdgEntity *entity, cairo_t *cr)
862 g_return_if_fail(ADG_IS_ENTITY(entity));
864 g_signal_emit(entity, signals[RENDER], 0, cr);
868 static AdgContainer *
869 get_parent(AdgEntity *entity)
871 AdgEntityPrivate *data = entity->data;
873 return data->parent;
876 static void
877 set_parent(AdgEntity *entity, AdgContainer *parent)
879 AdgEntityPrivate *data = entity->data;
881 data->parent = parent;
884 static void
885 parent_set(AdgEntity *entity, AdgContainer *old_parent)
887 if (ADG_IS_CONTAINER(old_parent)) {
888 const AdgMatrix *old_model;
889 const AdgMatrix *old_paper;
891 old_model = adg_entity_get_model_matrix((AdgEntity *) old_parent);
892 old_paper = adg_entity_get_paper_matrix((AdgEntity *) old_parent);
894 adg_entity_model_matrix_changed(entity, old_model);
895 adg_entity_paper_matrix_changed(entity, old_paper);
899 static AdgContext *
900 get_context(AdgEntity *entity)
902 AdgEntityPrivate *data = entity->data;
903 AdgEntity *parent;
905 if (data->context)
906 return data->context;
908 parent = (AdgEntity *) data->parent;
910 return parent ? ADG_ENTITY_GET_CLASS(parent)->get_context(parent) : NULL;
913 static void
914 set_context(AdgEntity *entity, AdgContext *context)
916 AdgEntityPrivate *data = entity->data;
918 if (data->context)
919 g_object_unref((GObject *) data->context);
921 g_object_ref((GObject *) context);
922 data->context = context;
925 static void
926 set_global_map(AdgEntity *entity, const AdgMatrix *map)
928 AdgEntityPrivate *data = entity->data;
930 if (map == NULL)
931 cairo_matrix_init_identity(&data->global_map);
932 else
933 adg_matrix_copy(&data->global_map, map);
936 static void
937 set_local_map(AdgEntity *entity, const AdgMatrix *map)
939 AdgEntityPrivate *data = entity->data;
941 if (map == NULL)
942 cairo_matrix_init_identity(&data->local_map);
943 else
944 adg_matrix_copy(&data->local_map, map);
947 static void
948 model_matrix_changed(AdgEntity *entity, AdgMatrix *parent_matrix)
950 AdgEntityPrivate *data = entity->data;
952 ADG_UNSET(data->flags, MODEL_MATRIX_APPLIED);
955 static void
956 paper_matrix_changed(AdgEntity *entity, AdgMatrix *parent_matrix)
958 AdgEntityPrivate *data = entity->data;
960 ADG_UNSET(data->flags, PAPER_MATRIX_APPLIED);
963 static void
964 render(AdgEntity *entity, cairo_t *cr)
966 AdgEntityPrivate *data = entity->data;
968 ADG_SET(data->flags,
969 MODEL_MATRIX_APPLIED | PAPER_MATRIX_APPLIED | MODEL_APPLIED);
972 static const AdgMatrix *
973 get_model_matrix(AdgEntity *entity)
975 AdgEntityPrivate *data = entity->data;
977 return adg_entity_get_model_matrix((AdgEntity *) data->parent);
980 static const AdgMatrix *
981 get_paper_matrix(AdgEntity *entity)
983 AdgEntityPrivate *data = entity->data;
985 return adg_entity_get_paper_matrix((AdgEntity *) data->parent);