[AdgPoint] Removed from ADG
[adg.git] / adg / adg-entity.c
blob2b240a01619686408db83d679dbdcdc37ac9f92a
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 * @title: AdgEntity
24 * @short_description: The base class for renderable objects
26 * This abstract class provides a base interface for all renderable objects
27 * (all the objects that can be printed or viewed).
28 **/
30 /**
31 * AdgEntity:
33 * All fields are private and should not be used directly.
34 * Use its public methods instead.
35 **/
38 #include "adg-entity.h"
39 #include "adg-entity-private.h"
40 #include "adg-canvas.h"
41 #include "adg-context.h"
42 #include "adg-util.h"
43 #include "adg-intl.h"
46 enum {
47 PROP_0,
48 PROP_PARENT,
49 PROP_CONTEXT,
50 PROP_GLOBAL_MAP,
51 PROP_LOCAL_MAP
54 enum {
55 PARENT_SET,
56 MODEL_MATRIX_CHANGED,
57 PAPER_MATRIX_CHANGED,
58 INVALIDATE,
59 RENDER,
60 LAST_SIGNAL
64 static void get_property (GObject *object,
65 guint prop_id,
66 GValue *value,
67 GParamSpec *pspec);
68 static void set_property (GObject *object,
69 guint prop_id,
70 const GValue *value,
71 GParamSpec *pspec);
72 static void dispose (GObject *object);
73 static AdgContainer * get_parent (AdgEntity *entity);
74 static void set_parent (AdgEntity *entity,
75 AdgContainer *parent);
76 static void parent_set (AdgEntity *entity,
77 AdgContainer *old_parent);
78 static AdgContext * get_context (AdgEntity *entity);
79 static void set_context (AdgEntity *entity,
80 AdgContext *context);
81 static void set_global_map (AdgEntity *entity,
82 const AdgMatrix *map);
83 static void set_local_map (AdgEntity *entity,
84 const AdgMatrix *map);
85 static void model_matrix_changed (AdgEntity *entity,
86 AdgMatrix *parent_matrix);
87 static void paper_matrix_changed (AdgEntity *entity,
88 AdgMatrix *parent_matrix);
89 static void render (AdgEntity *entity,
90 cairo_t *cr);
91 static const AdgMatrix *get_model_matrix (AdgEntity *entity);
92 static const AdgMatrix *get_paper_matrix (AdgEntity *entity);
94 static guint signals[LAST_SIGNAL] = { 0 };
97 G_DEFINE_ABSTRACT_TYPE(AdgEntity, adg_entity, G_TYPE_INITIALLY_UNOWNED);
100 static void
101 adg_entity_class_init(AdgEntityClass *klass)
103 GObjectClass *gobject_class;
104 GParamSpec *param;
106 gobject_class = (GObjectClass *) klass;
108 g_type_class_add_private(klass, sizeof(AdgEntityPrivate));
110 gobject_class->get_property = get_property;
111 gobject_class->set_property = set_property;
112 gobject_class->dispose = dispose;
114 klass->get_parent = get_parent;
115 klass->set_parent = set_parent;
116 klass->parent_set = parent_set;
117 klass->get_context = get_context;
118 klass->model_matrix_changed = model_matrix_changed;
119 klass->paper_matrix_changed = paper_matrix_changed;
120 klass->invalidate = NULL;
121 klass->render = render;
122 klass->get_model_matrix = get_model_matrix;
123 klass->get_paper_matrix = get_paper_matrix;
125 param = g_param_spec_object("parent",
126 P_("Parent Container"),
127 P_("The parent AdgContainer of this entity or NULL if this is a top-level entity"),
128 ADG_TYPE_CONTAINER, G_PARAM_READWRITE);
129 g_object_class_install_property(gobject_class, PROP_PARENT, param);
131 param = g_param_spec_object("context",
132 P_("Context"),
133 P_("The context associated to this entity or NULL to inherit the parent context"),
134 ADG_TYPE_CONTEXT, G_PARAM_READWRITE);
135 g_object_class_install_property(gobject_class, PROP_CONTEXT, param);
137 param = g_param_spec_boxed("global-map",
138 P_("Global Map"),
139 P_("The transformation to be combined with the parent ones to get the global matrix"),
140 ADG_TYPE_MATRIX, G_PARAM_READWRITE);
141 g_object_class_install_property(gobject_class, PROP_GLOBAL_MAP, param);
143 param = g_param_spec_boxed("local-map",
144 P_("Local Map"),
145 P_("The transformation to be combined with the parent ones to get the local matrix"),
146 ADG_TYPE_MATRIX, G_PARAM_READWRITE);
147 g_object_class_install_property(gobject_class, PROP_LOCAL_MAP, param);
150 * AdgEntity::parent-set:
151 * @entity: an #AdgEntity
152 * @parent: the #AdgContainer parent of @entity
154 * Emitted after the parent container has changed.
156 signals[PARENT_SET] =
157 g_signal_new("parent-set",
158 G_OBJECT_CLASS_TYPE(gobject_class),
159 G_SIGNAL_RUN_FIRST,
160 G_STRUCT_OFFSET(AdgEntityClass, parent_set),
161 NULL, NULL,
162 g_cclosure_marshal_VOID__OBJECT,
163 G_TYPE_NONE, 1, ADG_TYPE_CONTAINER);
166 * AdgEntity::model-matrix-changed:
167 * @entity: an #AdgEntity
168 * @parent_matrix: the parent model matrix
170 * Emitted after the current model matrix has changed.
172 signals[MODEL_MATRIX_CHANGED] =
173 g_signal_new("model-matrix-changed",
174 G_OBJECT_CLASS_TYPE(gobject_class),
175 G_SIGNAL_RUN_FIRST,
176 G_STRUCT_OFFSET(AdgEntityClass, model_matrix_changed),
177 NULL, NULL,
178 g_cclosure_marshal_VOID__BOXED,
179 G_TYPE_NONE, 1,
180 ADG_TYPE_MATRIX | G_SIGNAL_TYPE_STATIC_SCOPE);
183 * AdgEntity::paper-matrix-changed:
184 * @entity: an #AdgEntity
185 * @parent_matrix: the parent paper matrix
187 * Emitted after the current paper matrix has changed.
189 signals[PAPER_MATRIX_CHANGED] =
190 g_signal_new("paper-matrix-changed",
191 G_OBJECT_CLASS_TYPE(gobject_class),
192 G_SIGNAL_RUN_FIRST,
193 G_STRUCT_OFFSET(AdgEntityClass, paper_matrix_changed),
194 NULL, NULL,
195 g_cclosure_marshal_VOID__BOXED,
196 G_TYPE_NONE, 1,
197 ADG_TYPE_MATRIX | G_SIGNAL_TYPE_STATIC_SCOPE);
200 * AdgEntity::invalidate:
201 * @entity: an #AdgEntity
203 * Clears the cached data of @entity.
205 signals[INVALIDATE] =
206 g_signal_new("invalidate",
207 G_OBJECT_CLASS_TYPE(gobject_class),
208 G_SIGNAL_RUN_FIRST,
209 G_STRUCT_OFFSET(AdgEntityClass, invalidate),
210 NULL, NULL,
211 g_cclosure_marshal_VOID__BOOLEAN,
212 G_TYPE_NONE, 0);
215 * AdgEntity::render:
216 * @entity: an #AdgEntity
217 * @cr: a #cairo_t drawing context
219 * Causes the rendering of @entity on @cr.
221 signals[RENDER] =
222 g_signal_new("render",
223 G_OBJECT_CLASS_TYPE(gobject_class),
224 G_SIGNAL_RUN_FIRST,
225 G_STRUCT_OFFSET(AdgEntityClass, render),
226 NULL, NULL,
227 g_cclosure_marshal_VOID__POINTER,
228 G_TYPE_NONE, 1, G_TYPE_POINTER);
231 static void
232 adg_entity_init(AdgEntity *entity)
234 AdgEntityPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(entity,
235 ADG_TYPE_ENTITY,
236 AdgEntityPrivate);
237 data->parent = NULL;
238 data->flags = 0;
239 data->context = NULL;
240 cairo_matrix_init_identity(&data->local_map);
241 cairo_matrix_init_identity(&data->global_map);
243 entity->data = data;
246 static void
247 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
249 AdgEntity *entity;
250 AdgEntityPrivate *data;
252 entity = (AdgEntity *) object;
253 data = entity->data;
255 switch (prop_id) {
256 case PROP_PARENT:
257 g_value_set_object(value, get_parent(entity));
258 break;
259 case PROP_CONTEXT:
260 g_value_set_object(value, get_context(entity));
261 break;
262 case PROP_GLOBAL_MAP:
263 g_value_set_boxed(value, &data->global_map);
264 break;
265 case PROP_LOCAL_MAP:
266 g_value_set_boxed(value, &data->local_map);
267 break;
268 default:
269 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
270 break;
274 static void
275 set_property(GObject *object,
276 guint prop_id, const GValue *value, GParamSpec *pspec)
278 AdgEntity *entity = (AdgEntity *) object;
280 switch (prop_id) {
281 case PROP_PARENT:
282 set_parent(entity, g_value_get_object(value));
283 break;
284 case PROP_CONTEXT:
285 set_context(entity, g_value_get_object(value));
286 break;
287 case PROP_GLOBAL_MAP:
288 set_global_map(entity, g_value_get_boxed(value));
289 break;
290 case PROP_LOCAL_MAP:
291 set_local_map(entity, g_value_get_boxed(value));
292 break;
293 default:
294 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
295 break;
299 static void
300 dispose(GObject *object)
302 AdgEntity *entity;
303 AdgEntityPrivate *data;
304 GObjectClass *object_class;
306 entity = (AdgEntity *) object;
307 data = entity->data;
308 object_class = (GObjectClass *) adg_entity_parent_class;
310 if (data->parent)
311 adg_container_remove(data->parent, entity);
313 if (object_class->dispose != NULL)
314 object_class->dispose(object);
319 * adg_entity_get_parent:
320 * @entity: an #AdgEntity
322 * Gets the container parent of @entity.
324 * This function is only useful in entity implementations.
326 * Return value: the container object or %NULL if @entity is not contained
328 AdgContainer *
329 adg_entity_get_parent(AdgEntity *entity)
331 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
333 return ADG_ENTITY_GET_CLASS(entity)->get_parent(entity);
337 * adg_entity_set_parent:
338 * @entity: an #AdgEntity
339 * @parent: an #AdgContainer
341 * Sets a new container of @entity.
343 * This function is only useful in entity implementations.
345 void
346 adg_entity_set_parent(AdgEntity *entity, AdgContainer *parent)
348 g_return_if_fail(ADG_IS_ENTITY(entity));
350 ADG_ENTITY_GET_CLASS(entity)->set_parent(entity, parent);
351 g_object_notify((GObject *) entity, "parent");
355 * adg_entity_unparent:
356 * @entity: an #AdgEntity
358 * Removes the current parent of @entity, properly handling
359 * the references between them.
361 * If @entity has no parent, this function simply returns.
363 void
364 adg_entity_unparent(AdgEntity *entity)
366 AdgContainer *old_parent;
368 g_return_if_fail(ADG_IS_ENTITY(entity));
370 old_parent = ADG_ENTITY_GET_CLASS(entity)->get_parent(entity);
372 if (old_parent == NULL)
373 return;
375 ADG_ENTITY_GET_CLASS(entity)->set_parent(entity, NULL);
376 g_signal_emit(entity, signals[PARENT_SET], 0, old_parent);
378 g_object_unref(entity);
382 * adg_entity_reparent:
383 * @entity: an #AdgEntity
384 * @parent: the new container
386 * Moves @entity from the old parent to @parent, handling reference
387 * count issues to avoid destroying the object.
389 void
390 adg_entity_reparent(AdgEntity *entity, AdgContainer *parent)
392 AdgContainer *old_parent;
394 g_return_if_fail(ADG_IS_CONTAINER(parent));
396 old_parent = adg_entity_get_parent(entity);
398 /* Reparenting on the same container: do nothing */
399 if (old_parent == parent)
400 return;
402 g_return_if_fail(ADG_IS_CONTAINER(old_parent));
404 g_object_ref(entity);
405 adg_container_remove(old_parent, entity);
406 adg_container_add(parent, entity);
407 g_object_unref(entity);
411 * adg_entity_get_context:
412 * @entity: an #AdgEntity instance
414 * Gets the context associated to @entity.
415 * If no context was explicitely set, get the parent context.
417 * Return value: the requested context or %NULL on errors
419 AdgContext *
420 adg_entity_get_context(AdgEntity *entity)
422 AdgEntityPrivate *data;
424 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
426 data = entity->data;
428 if (data->context)
429 return data->context;
431 if (data->parent)
432 return adg_entity_get_context((AdgEntity *) data->parent);
434 return NULL;
438 * adg_entity_set_context:
439 * @entity: an #AdgEntity instance
440 * @context: the new context
442 * Sets a new context. The old context (if any) will be unreferenced
443 * while a new reference will be added to @context.
445 void
446 adg_entity_set_context(AdgEntity *entity, AdgContext *context)
448 g_return_if_fail(ADG_IS_ENTITY(entity));
449 g_return_if_fail(ADG_IS_CONTEXT(context));
451 set_context(entity, context);
452 g_object_notify((GObject *) entity, "context");
456 * adg_entity_get_canvas:
457 * @entity: an #AdgEntity
459 * Walks on the @entity hierarchy and gets the first parent of @entity that is
460 * of #AdgCanvas derived type.
462 * Return value: the requested object or %NULL if there is no #AdgCanvas in
463 * the parent hierarchy.
465 AdgCanvas *
466 adg_entity_get_canvas(AdgEntity *entity)
468 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
470 while (entity) {
471 if (ADG_IS_CANVAS(entity))
472 return (AdgCanvas *) entity;
474 entity = (AdgEntity *) adg_entity_get_parent(entity);
477 return NULL;
481 * adg_entity_get_global_map:
482 * @entity: an #AdgEntity object
483 * @map: where to store the global map
485 * Gets the transformation to be used to compute the global matrix
486 * of @entity and store it in @map.
488 void
489 adg_entity_get_global_map(AdgEntity *entity, AdgMatrix *map)
491 AdgEntityPrivate *data;
493 g_return_if_fail(ADG_IS_ENTITY(entity));
494 g_return_if_fail(map != NULL);
496 data = entity->data;
497 adg_matrix_copy(map, &data->global_map);
501 * adg_entity_set_global_map:
502 * @entity: an #AdgEntity object
503 * @map: the new map
505 * Sets the new global transformation of @entity to @map:
506 * the old map is discarded. If @map is %NULL an identity
507 * matrix is implied.
509 void
510 adg_entity_set_global_map(AdgEntity *entity, const AdgMatrix *map)
512 g_return_if_fail(ADG_IS_ENTITY(entity));
514 set_global_map(entity, map);
515 g_object_notify((GObject *) entity, "global-map");
519 * adg_entity_get_local_map:
520 * @entity: an #AdgEntity object
521 * @map: where to store the local map
523 * Gets the transformation to be used to compute the local matrix
524 * of @entity and store it in @map.
526 void
527 adg_entity_get_local_map(AdgEntity *entity, AdgMatrix *map)
529 AdgEntityPrivate *data;
531 g_return_if_fail(ADG_IS_ENTITY(entity));
532 g_return_if_fail(map != NULL);
534 data = entity->data;
535 adg_matrix_copy(map, &data->local_map);
539 * adg_entity_set_local_map:
540 * @entity: an #AdgEntity object
541 * @map: the new map
543 * Sets the new global transformation of @entity to @map:
544 * the old map is discarded. If @map is %NULL an identity
545 * matrix is implied.
547 void
548 adg_entity_set_local_map(AdgEntity *entity, const AdgMatrix *map)
550 g_return_if_fail(ADG_IS_ENTITY(entity));
552 set_local_map(entity, map);
553 g_object_notify((GObject *) entity, "local-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_matrix:
584 * @entity: an #AdgEntity object
585 * @matrix: where to store the local matrix
587 * Computes the local matrix by combining all the local maps of the
588 * @entity hierarchy and stores the result in @matrix.
590 void
591 adg_entity_get_local_matrix(AdgEntity *entity, AdgMatrix *matrix)
593 AdgEntityPrivate *data;
595 g_return_if_fail(ADG_IS_ENTITY(entity));
596 g_return_if_fail(matrix != NULL);
598 data = entity->data;
600 if (data->parent == NULL) {
601 adg_matrix_copy(matrix, &data->local_map);
602 } else {
603 adg_entity_get_local_matrix((AdgEntity *) data->parent, matrix);
604 cairo_matrix_multiply(matrix, &data->local_map, matrix);
609 * adg_entity_get_model_matrix:
610 * @entity: an #AdgEntity object
612 * Gets the model matrix to be used in rendering this @entity.
614 * Return value: the requested matrix
616 const AdgMatrix *
617 adg_entity_get_model_matrix(AdgEntity *entity)
619 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
620 return ADG_ENTITY_GET_CLASS(entity)->get_model_matrix(entity);
624 * adg_entity_get_paper_matrix:
625 * @entity: an #AdgEntity object
627 * Gets the paper matrix to be used in rendering this @entity.
629 * Return value: the requested matrix
631 const AdgMatrix *
632 adg_entity_get_paper_matrix(AdgEntity *entity)
634 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
635 return ADG_ENTITY_GET_CLASS(entity)->get_paper_matrix(entity);
639 * adg_entity_build_paper2model:
640 * @entity: an #AdgEntity
641 * @matrix: the destination matrix
643 * Builds a matrix to translate from paper to model space and
644 * put the result in @matrix.
646 * Return value: %TRUE on success, %FALSE on errors
648 gboolean
649 adg_entity_build_paper2model(AdgEntity *entity, AdgMatrix *matrix)
651 cairo_status_t status;
653 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
654 g_return_val_if_fail(matrix != NULL, FALSE);
656 adg_matrix_copy(matrix, adg_entity_get_model_matrix(entity));
657 status = cairo_matrix_invert(matrix);
658 if (status != CAIRO_STATUS_SUCCESS) {
659 g_error("Unable to invert model matrix (cairo message: %s)",
660 cairo_status_to_string(status));
661 return FALSE;
664 cairo_matrix_multiply(matrix, matrix, adg_entity_get_paper_matrix(entity));
665 return TRUE;
669 * adg_entity_build_model2paper:
670 * @entity: an #AdgEntity
671 * @matrix: the destination matrix
673 * Builds a matrix to translate from model to paper space and
674 * put the result in @matrix.
676 * Return value: %TRUE on success, %FALSE on errors
678 gboolean
679 adg_entity_build_model2paper(AdgEntity *entity, AdgMatrix *matrix)
681 cairo_status_t status;
683 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
684 g_return_val_if_fail(matrix != NULL, FALSE);
686 adg_matrix_copy(matrix, adg_entity_get_paper_matrix(entity));
687 status = cairo_matrix_invert(matrix);
688 if (status != CAIRO_STATUS_SUCCESS) {
689 g_error("Unable to invert paper matrix (cairo message: %s)",
690 cairo_status_to_string(status));
691 return FALSE;
694 cairo_matrix_multiply(matrix, matrix, adg_entity_get_model_matrix(entity));
695 return TRUE;
699 * adg_entity_model_matrix_changed:
700 * @entity: an #AdgEntity
701 * @parent_matrix: the parent #AdgMatrix
703 * Emits the "model-matrix-changed" signal on @entity.
705 * This function is only useful in entity implementations.
707 void
708 adg_entity_model_matrix_changed(AdgEntity *entity,
709 const AdgMatrix *parent_matrix)
711 g_return_if_fail(ADG_IS_ENTITY(entity));
713 g_signal_emit(entity, signals[MODEL_MATRIX_CHANGED], 0, parent_matrix);
717 * adg_entity_paper_matrix_changed:
718 * @entity: an #AdgEntity
719 * @parent_matrix: the parent #AdgMatrix
721 * Emits the "paper-matrix-changed" signal on @entity.
723 * This function is only useful in entity implementations.
725 void
726 adg_entity_paper_matrix_changed(AdgEntity *entity,
727 const AdgMatrix *parent_matrix)
729 g_return_if_fail(ADG_IS_ENTITY(entity));
731 g_signal_emit(entity, signals[PAPER_MATRIX_CHANGED], 0, parent_matrix);
735 * adg_entity_get_style:
736 * @entity: an #AdgEntity
737 * @style_slot: the slot of the style to get
739 * Gets a style from this entity. If the entity has no context associated
740 * or the style in undefined within this context, gets the style from its
741 * parent container.
743 * Return value: the requested style or %NULL on errors
745 AdgStyle *
746 adg_entity_get_style(AdgEntity *entity, AdgStyleSlot style_slot)
748 AdgEntityPrivate *data;
750 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
752 data = entity->data;
754 if (data->context) {
755 AdgStyle *style = adg_context_get_style(data->context, style_slot);
756 if (style)
757 return style;
760 if (data->parent)
761 return adg_entity_get_style((AdgEntity *) data->parent, style_slot);
763 return NULL;
767 * adg_entity_apply:
768 * @entity: an #AdgEntity
769 * @style_slot: the slot of the style to apply
770 * @cr: a #cairo_t drawing context
772 * Applies the specified style to the @cr cairo context.
774 void
775 adg_entity_apply(AdgEntity *entity, AdgStyleSlot style_slot, cairo_t *cr)
777 AdgStyle *style = adg_entity_get_style(entity, style_slot);
779 if (style)
780 adg_style_apply(style, cr);
784 * adg_entity_model_matrix_applied:
785 * @entity: an #AdgEntity
787 * Return value: %TRUE if the model matrix didn't change from the last render
789 gboolean
790 adg_entity_model_matrix_applied(AdgEntity *entity)
792 AdgEntityPrivate *data;
794 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
796 data = entity->data;
798 return ADG_ISSET(data->flags, MODEL_MATRIX_APPLIED);
802 * adg_entity_paper_matrix_applied:
803 * @entity: an #AdgEntity
805 * Return value: %TRUE if the paper matrix didn't change from the last render
807 gboolean
808 adg_entity_paper_matrix_applied(AdgEntity *entity)
810 AdgEntityPrivate *data;
812 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
814 data = entity->data;
816 return ADG_ISSET(data->flags, PAPER_MATRIX_APPLIED);
820 * adg_entity_model_applied:
821 * @entity: an #AdgEntity
823 * Return value: %TRUE if the model didn't change from the last render
825 gboolean
826 adg_entity_model_applied(AdgEntity *entity)
828 AdgEntityPrivate *data;
830 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
832 data = entity->data;
834 return ADG_ISSET(data->flags, MODEL_APPLIED);
838 * adg_entity_invalidate:
839 * @entity: an #AdgEntity
841 * Emits the "invalidate" signal on @entity and all its children, if any,
842 * so subsequent rendering will need a global recomputation.
844 void
845 adg_entity_invalidate(AdgEntity *entity)
847 g_return_if_fail(ADG_IS_ENTITY(entity));
849 g_signal_emit(entity, signals[INVALIDATE], 0, NULL);
853 * adg_entity_render:
854 * @entity: an #AdgEntity
855 * @cr: a #cairo_t drawing context
857 * Emits the "render" signal on @entity and all its children, if any,
858 * causing the rendering operation the @cr cairo context.
860 void
861 adg_entity_render(AdgEntity *entity, cairo_t *cr)
863 g_return_if_fail(ADG_IS_ENTITY(entity));
865 g_signal_emit(entity, signals[RENDER], 0, cr);
869 static AdgContainer *
870 get_parent(AdgEntity *entity)
872 AdgEntityPrivate *data = entity->data;
874 return data->parent;
877 static void
878 set_parent(AdgEntity *entity, AdgContainer *parent)
880 AdgEntityPrivate *data = entity->data;
882 data->parent = parent;
885 static void
886 parent_set(AdgEntity *entity, AdgContainer *old_parent)
888 if (ADG_IS_CONTAINER(old_parent)) {
889 const AdgMatrix *old_model;
890 const AdgMatrix *old_paper;
892 old_model = adg_entity_get_model_matrix((AdgEntity *) old_parent);
893 old_paper = adg_entity_get_paper_matrix((AdgEntity *) old_parent);
895 adg_entity_model_matrix_changed(entity, old_model);
896 adg_entity_paper_matrix_changed(entity, old_paper);
900 static AdgContext *
901 get_context(AdgEntity *entity)
903 AdgEntityPrivate *data = entity->data;
904 AdgEntity *parent;
906 if (data->context)
907 return data->context;
909 parent = (AdgEntity *) data->parent;
911 return parent ? ADG_ENTITY_GET_CLASS(parent)->get_context(parent) : NULL;
914 static void
915 set_context(AdgEntity *entity, AdgContext *context)
917 AdgEntityPrivate *data = entity->data;
919 if (data->context)
920 g_object_unref((GObject *) data->context);
922 g_object_ref((GObject *) context);
923 data->context = context;
926 static void
927 set_global_map(AdgEntity *entity, const AdgMatrix *map)
929 AdgEntityPrivate *data = entity->data;
931 if (map == NULL)
932 cairo_matrix_init_identity(&data->global_map);
933 else
934 adg_matrix_copy(&data->global_map, map);
937 static void
938 set_local_map(AdgEntity *entity, const AdgMatrix *map)
940 AdgEntityPrivate *data = entity->data;
942 if (map == NULL)
943 cairo_matrix_init_identity(&data->local_map);
944 else
945 adg_matrix_copy(&data->local_map, map);
948 static void
949 model_matrix_changed(AdgEntity *entity, AdgMatrix *parent_matrix)
951 AdgEntityPrivate *data = entity->data;
953 ADG_UNSET(data->flags, MODEL_MATRIX_APPLIED);
956 static void
957 paper_matrix_changed(AdgEntity *entity, AdgMatrix *parent_matrix)
959 AdgEntityPrivate *data = entity->data;
961 ADG_UNSET(data->flags, PAPER_MATRIX_APPLIED);
964 static void
965 render(AdgEntity *entity, cairo_t *cr)
967 AdgEntityPrivate *data = entity->data;
969 ADG_SET(data->flags,
970 MODEL_MATRIX_APPLIED | PAPER_MATRIX_APPLIED | MODEL_APPLIED);
973 static const AdgMatrix *
974 get_model_matrix(AdgEntity *entity)
976 AdgEntityPrivate *data = entity->data;
978 return adg_entity_get_model_matrix((AdgEntity *) data->parent);
981 static const AdgMatrix *
982 get_paper_matrix(AdgEntity *entity)
984 AdgEntityPrivate *data = entity->data;
986 return adg_entity_get_paper_matrix((AdgEntity *) data->parent);