Included 2009 in the copyright
[adg.git] / adg / adg-entity.c
blob148914caad4f3281d93ecc93e583eeb867dd2535
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.
20 /**
21 * SECTION:entity
22 * @title: AdgEntity
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).
29 #include "adg-entity.h"
30 #include "adg-entity-private.h"
31 #include "adg-canvas.h"
32 #include "adg-context.h"
33 #include "adg-util.h"
34 #include "adg-intl.h"
36 #define PARENT_CLASS ((GInitiallyUnownedClass *) adg_entity_parent_class)
39 enum {
40 PROP_0,
41 PROP_PARENT,
42 PROP_CONTEXT
45 enum {
46 PARENT_SET,
47 MODEL_MATRIX_CHANGED,
48 PAPER_MATRIX_CHANGED,
49 INVALIDATE,
50 RENDER,
51 LAST_SIGNAL
55 static void get_property (GObject *object,
56 guint prop_id,
57 GValue *value,
58 GParamSpec *pspec);
59 static void set_property (GObject *object,
60 guint prop_id,
61 const GValue *value,
62 GParamSpec *pspec);
63 static void dispose (GObject *object);
64 static AdgContainer * get_parent (AdgEntity *entity);
65 static void set_parent (AdgEntity *entity,
66 AdgContainer *parent);
67 static void parent_set (AdgEntity *entity,
68 AdgContainer *old_parent);
69 static AdgContext * get_context (AdgEntity *entity);
70 static void set_context (AdgEntity *entity,
71 AdgContext *context);
72 static void model_matrix_changed (AdgEntity *entity,
73 AdgMatrix *parent_matrix);
74 static void paper_matrix_changed (AdgEntity *entity,
75 AdgMatrix *parent_matrix);
76 static void render (AdgEntity *entity,
77 cairo_t *cr);
78 static const AdgMatrix *get_model_matrix (AdgEntity *entity);
79 static const AdgMatrix *get_paper_matrix (AdgEntity *entity);
81 static guint signals[LAST_SIGNAL] = { 0 };
84 G_DEFINE_ABSTRACT_TYPE(AdgEntity, adg_entity, G_TYPE_INITIALLY_UNOWNED)
87 static void
88 adg_entity_class_init(AdgEntityClass *klass)
90 GObjectClass *gobject_class;
91 GParamSpec *param;
93 gobject_class = (GObjectClass *) klass;
95 g_type_class_add_private(klass, sizeof(AdgEntityPrivate));
97 gobject_class->get_property = get_property;
98 gobject_class->set_property = set_property;
99 gobject_class->dispose = dispose;
101 klass->get_parent = get_parent;
102 klass->set_parent = set_parent;
103 klass->parent_set = parent_set;
104 klass->get_context = get_context;
105 klass->model_matrix_changed = model_matrix_changed;
106 klass->paper_matrix_changed = NULL;
107 klass->invalidate = NULL;
108 klass->render = render;
109 klass->get_model_matrix = get_model_matrix;
110 klass->get_paper_matrix = get_paper_matrix;
112 param = g_param_spec_object("parent",
113 P_("Parent Container"),
114 P_("The parent AdgContainer of this entity or NULL if this is a top-level entity"),
115 ADG_TYPE_CONTAINER, G_PARAM_READWRITE);
116 g_object_class_install_property(gobject_class, PROP_PARENT, param);
118 param = g_param_spec_object("context",
119 P_("Context"),
120 P_("The context associated to this entity or NULL to inherit the parent context"),
121 ADG_TYPE_CONTEXT, G_PARAM_READWRITE);
122 g_object_class_install_property(gobject_class, PROP_CONTEXT, param);
125 * AdgEntity::parent-set:
126 * @entity: an #AdgEntity
127 * @parent: the #AdgContainer parent of @entity
129 * Emitted after the parent container has changed.
131 signals[PARENT_SET] =
132 g_signal_new("parent-set",
133 G_OBJECT_CLASS_TYPE(gobject_class),
134 G_SIGNAL_RUN_FIRST,
135 G_STRUCT_OFFSET(AdgEntityClass, parent_set),
136 NULL, NULL,
137 g_cclosure_marshal_VOID__OBJECT,
138 G_TYPE_NONE, 1, ADG_TYPE_CONTAINER);
141 * AdgEntity::model-matrix-changed:
142 * @entity: an #AdgEntity
143 * @parent_matrix: the parent model matrix
145 * Emitted after the current model matrix has changed.
147 signals[MODEL_MATRIX_CHANGED] =
148 g_signal_new("model-matrix-changed",
149 G_OBJECT_CLASS_TYPE(gobject_class),
150 G_SIGNAL_RUN_FIRST,
151 G_STRUCT_OFFSET(AdgEntityClass, model_matrix_changed),
152 NULL, NULL,
153 g_cclosure_marshal_VOID__BOXED,
154 G_TYPE_NONE, 1,
155 ADG_TYPE_MATRIX | G_SIGNAL_TYPE_STATIC_SCOPE);
158 * AdgEntity::paper-matrix-changed:
159 * @entity: an #AdgEntity
160 * @parent_matrix: the parent paper matrix
162 * Emitted after the current paper matrix has changed.
164 signals[PAPER_MATRIX_CHANGED] =
165 g_signal_new("paper-matrix-changed",
166 G_OBJECT_CLASS_TYPE(gobject_class),
167 G_SIGNAL_RUN_FIRST,
168 G_STRUCT_OFFSET(AdgEntityClass, paper_matrix_changed),
169 NULL, NULL,
170 g_cclosure_marshal_VOID__BOXED,
171 G_TYPE_NONE, 1,
172 ADG_TYPE_MATRIX | G_SIGNAL_TYPE_STATIC_SCOPE);
175 * AdgEntity::invalidate:
176 * @entity: an #AdgEntity
178 * Clears the cached data of @entity.
180 signals[INVALIDATE] =
181 g_signal_new("invalidate",
182 G_OBJECT_CLASS_TYPE(gobject_class),
183 G_SIGNAL_RUN_FIRST,
184 G_STRUCT_OFFSET(AdgEntityClass, invalidate),
185 NULL, NULL,
186 g_cclosure_marshal_VOID__BOOLEAN,
187 G_TYPE_NONE, 0);
190 * AdgEntity::render:
191 * @entity: an #AdgEntity
192 * @cr: a #cairo_t drawing context
194 * Causes the rendering of @entity on @cr.
196 signals[RENDER] =
197 g_signal_new("render",
198 G_OBJECT_CLASS_TYPE(gobject_class),
199 G_SIGNAL_RUN_FIRST,
200 G_STRUCT_OFFSET(AdgEntityClass, render),
201 NULL, NULL,
202 g_cclosure_marshal_VOID__POINTER,
203 G_TYPE_NONE, 1, G_TYPE_POINTER);
206 static void
207 adg_entity_init(AdgEntity *entity)
209 AdgEntityPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE(entity,
210 ADG_TYPE_ENTITY,
211 AdgEntityPrivate);
212 priv->parent = NULL;
213 priv->flags = 0;
214 priv->context = NULL;
216 entity->priv = priv;
219 static void
220 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
222 AdgEntity *entity = (AdgEntity *) object;
224 switch (prop_id) {
225 case PROP_PARENT:
226 g_value_set_object(value, get_parent(entity));
227 break;
228 case PROP_CONTEXT:
229 g_value_set_object(value, get_context(entity));
230 break;
231 default:
232 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
233 break;
237 static void
238 set_property(GObject *object,
239 guint prop_id, const GValue *value, GParamSpec *pspec)
241 AdgEntity *entity = (AdgEntity *) object;
243 switch (prop_id) {
244 case PROP_PARENT:
245 set_parent(entity, (AdgContainer *) g_value_get_object(value));
246 break;
247 case PROP_CONTEXT:
248 set_context(entity, g_value_get_object(value));
249 break;
250 default:
251 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
252 break;
256 static void
257 dispose(GObject *object)
259 AdgEntity *entity;
261 entity = (AdgEntity *) object;
263 if (entity->priv->parent)
264 adg_container_remove(entity->priv->parent, entity);
266 PARENT_CLASS->dispose(object);
271 * adg_entity_get_parent:
272 * @entity: an #AdgEntity
274 * Gets the container parent of @entity.
276 * This function is only useful in entity implementations.
278 * Return value: the container object or %NULL if @entity is not contained
280 AdgContainer *
281 adg_entity_get_parent(AdgEntity *entity)
283 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
285 return ADG_ENTITY_GET_CLASS(entity)->get_parent(entity);
289 * adg_entity_set_parent:
290 * @entity: an #AdgEntity
291 * @parent: an #AdgContainer
293 * Sets a new container of @entity.
295 * This function is only useful in entity implementations.
297 void
298 adg_entity_set_parent(AdgEntity *entity, AdgContainer *parent)
300 g_return_if_fail(ADG_IS_ENTITY(entity));
302 ADG_ENTITY_GET_CLASS(entity)->set_parent(entity, parent);
303 g_object_notify((GObject *) entity, "parent");
307 * adg_entity_unparent:
308 * @entity: an #AdgEntity
310 * Removes the current parent of @entity, properly handling
311 * the references between them.
313 * If @entity has no parent, this function simply returns.
315 void
316 adg_entity_unparent(AdgEntity *entity)
318 AdgContainer *old_parent;
320 g_return_if_fail(ADG_IS_ENTITY(entity));
322 old_parent = ADG_ENTITY_GET_CLASS(entity)->get_parent(entity);
324 if (old_parent == NULL)
325 return;
327 ADG_ENTITY_GET_CLASS(entity)->set_parent(entity, NULL);
328 g_signal_emit(entity, signals[PARENT_SET], 0, old_parent);
330 g_object_unref(entity);
334 * adg_entity_reparent:
335 * @entity: an #AdgEntity
336 * @parent: the new container
338 * Moves @entity from the old parent to @parent, handling reference
339 * count issues to avoid destroying the object.
341 void
342 adg_entity_reparent(AdgEntity *entity, AdgContainer *parent)
344 AdgContainer *old_parent;
346 g_return_if_fail(ADG_IS_CONTAINER(parent));
348 old_parent = adg_entity_get_parent(entity);
350 /* Reparenting on the same container: do nothing */
351 if (old_parent == parent)
352 return;
354 g_return_if_fail(ADG_IS_CONTAINER(old_parent));
356 g_object_ref(entity);
357 adg_container_remove(old_parent, entity);
358 adg_container_add(parent, entity);
359 g_object_unref(entity);
363 * adg_entity_get_context:
364 * @entity: an #AdgEntity instance
366 * Gets the context associated to @entity.
367 * If no context was explicitely set, get the parent context.
369 * Return value: the requested context or %NULL on errors
371 AdgContext *
372 adg_entity_get_context(AdgEntity *entity)
374 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
376 if (entity->priv->context)
377 return entity->priv->context;
379 if (entity->priv->parent)
380 return adg_entity_get_context((AdgEntity *) entity->priv->parent);
382 return NULL;
386 * adg_entity_set_context:
387 * @entity: an #AdgEntity instance
388 * @context: the new context
390 * Sets a new context. The old context (if any) will be unreferenced
391 * while a new reference will be added to @context.
393 void
394 adg_entity_set_context(AdgEntity *entity, AdgContext *context)
396 g_return_if_fail(ADG_IS_ENTITY(entity));
397 g_return_if_fail(ADG_IS_CONTEXT(context));
399 set_context(entity, context);
400 g_object_notify((GObject *) entity, "context");
404 * adg_entity_get_canvas:
405 * @entity: an #AdgEntity
407 * Walks on the @entity hierarchy and gets the first parent of @entity that is
408 * of #AdgCanvas derived type.
410 * Return value: the requested object or %NULL if there is no #AdgCanvas in
411 * the parent hierarchy.
413 AdgCanvas *
414 adg_entity_get_canvas(AdgEntity *entity)
416 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
418 while (entity) {
419 if (ADG_IS_CANVAS(entity))
420 return (AdgCanvas *) entity;
422 entity = (AdgEntity *) adg_entity_get_parent(entity);
425 return NULL;
429 * adg_entity_get_model_matrix:
430 * @entity: an #AdgEntity object
432 * Gets the model matrix to be used in rendering this @entity.
434 * Return value: the requested matrix
436 const AdgMatrix *
437 adg_entity_get_model_matrix(AdgEntity *entity)
439 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
440 return ADG_ENTITY_GET_CLASS(entity)->get_model_matrix(entity);
444 * adg_entity_get_paper_matrix:
445 * @entity: an #AdgEntity object
447 * Gets the paper matrix to be used in rendering this @entity.
449 * Return value: the requested matrix
451 const AdgMatrix *
452 adg_entity_get_paper_matrix(AdgEntity *entity)
454 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
455 return ADG_ENTITY_GET_CLASS(entity)->get_paper_matrix(entity);
459 * adg_entity_scale_to_model:
460 * @entity: an #AdgEntity object
461 * @cr: a #cairo_t drawing context
463 * Sets the model matrix as current matrix on @cr. The translation
464 * and rotation component of the previous matrix are kept: only the
465 * scale is changed.
467 void
468 adg_entity_scale_to_model(AdgEntity *entity, cairo_t *cr)
470 const AdgMatrix *model_matrix;
471 cairo_matrix_t matrix;
473 g_return_if_fail(ADG_IS_ENTITY(entity));
475 model_matrix = ADG_ENTITY_GET_CLASS(entity)->get_model_matrix(entity);
476 cairo_get_matrix(cr, &matrix);
478 matrix.xx = model_matrix->xx;
479 matrix.yy = model_matrix->yy;
480 cairo_set_matrix(cr, &matrix);
484 * adg_entity_scale_to_paper:
485 * @entity: an #AdgEntity object
486 * @cr: a #cairo_t drawing context
488 * Sets the paper matrix as current matrix on @cr. The translation
489 * and rotation component of the previous matrix are kept: only the
490 * scale is changed.
492 void
493 adg_entity_scale_to_paper(AdgEntity *entity, cairo_t *cr)
495 const AdgMatrix *paper_matrix;
496 cairo_matrix_t matrix;
498 g_return_if_fail(ADG_IS_ENTITY(entity));
500 paper_matrix = ADG_ENTITY_GET_CLASS(entity)->get_paper_matrix(entity);
501 cairo_get_matrix(cr, &matrix);
503 matrix.xx = paper_matrix->xx;
504 matrix.yy = paper_matrix->yy;
505 cairo_set_matrix(cr, &matrix);
509 * adg_entity_build_paper2model:
510 * @entity: an #AdgEntity
511 * @matrix: the destination matrix
513 * Builds a matrix to translate from paper to model space and
514 * put the result in @matrix.
516 * Return value: %TRUE on success, %FALSE on errors
518 gboolean
519 adg_entity_build_paper2model(AdgEntity *entity, AdgMatrix *matrix)
521 cairo_status_t status;
523 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
524 g_return_val_if_fail(matrix != NULL, FALSE);
526 adg_matrix_copy(matrix, adg_entity_get_model_matrix(entity));
527 status = cairo_matrix_invert(matrix);
528 if (status != CAIRO_STATUS_SUCCESS) {
529 g_error("Unable to invert model matrix (cairo message: %s)",
530 cairo_status_to_string(status));
531 return FALSE;
534 cairo_matrix_multiply(matrix, matrix, adg_entity_get_paper_matrix(entity));
535 return TRUE;
539 * adg_entity_build_model2paper:
540 * @entity: an #AdgEntity
541 * @matrix: the destination matrix
543 * Builds a matrix to translate from model to paper space and
544 * put the result in @matrix.
546 * Return value: %TRUE on success, %FALSE on errors
548 gboolean
549 adg_entity_build_model2paper(AdgEntity *entity, AdgMatrix *matrix)
551 cairo_status_t status;
553 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
554 g_return_val_if_fail(matrix != NULL, FALSE);
556 adg_matrix_copy(matrix, adg_entity_get_paper_matrix(entity));
557 status = cairo_matrix_invert(matrix);
558 if (status != CAIRO_STATUS_SUCCESS) {
559 g_error("Unable to invert paper matrix (cairo message: %s)",
560 cairo_status_to_string(status));
561 return FALSE;
564 cairo_matrix_multiply(matrix, matrix, adg_entity_get_model_matrix(entity));
565 return TRUE;
569 * adg_entity_model_matrix_changed:
570 * @entity: an #AdgEntity
571 * @parent_matrix: the parent #AdgMatrix
573 * Emits the "model-matrix-changed" signal on @entity.
575 * This function is only useful in entity implementations.
577 void
578 adg_entity_model_matrix_changed(AdgEntity *entity,
579 const AdgMatrix *parent_matrix)
581 g_return_if_fail(ADG_IS_ENTITY(entity));
583 g_signal_emit(entity, signals[MODEL_MATRIX_CHANGED], 0, parent_matrix);
587 * adg_entity_paper_matrix_changed:
588 * @entity: an #AdgEntity
589 * @parent_matrix: the parent #AdgMatrix
591 * Emits the "paper-matrix-changed" signal on @entity.
593 * This function is only useful in entity implementations.
595 void
596 adg_entity_paper_matrix_changed(AdgEntity *entity,
597 const AdgMatrix *parent_matrix)
599 g_return_if_fail(ADG_IS_ENTITY(entity));
601 g_signal_emit(entity, signals[PAPER_MATRIX_CHANGED], 0, parent_matrix);
605 * adg_entity_get_style:
606 * @entity: an #AdgEntity
607 * @style_slot: the slot of the style to get
609 * Gets a style from this entity. If the entity has no context associated
610 * or the style in undefined within this context, gets the style from its
611 * parent container.
613 * Return value: the requested style
615 AdgStyle *
616 adg_entity_get_style(AdgEntity *entity, AdgStyleSlot style_slot)
618 g_return_if_fail(ADG_IS_ENTITY(entity));
620 if (entity->priv->context) {
621 AdgStyle *style = adg_context_get_style(entity->priv->context,
622 style_slot);
623 if (style)
624 return style;
627 if (entity->priv->parent)
628 return adg_entity_get_style((AdgEntity *) entity->priv->parent,
629 style_slot);
631 return NULL;
635 * adg_entity_apply:
636 * @entity: an #AdgEntity
637 * @style_slot: the slot of the style to apply
638 * @cr: a #cairo_t drawing context
640 * Applies the specified style to the @cr cairo context.
642 void
643 adg_entity_apply(AdgEntity *entity, AdgStyleSlot style_slot, cairo_t *cr)
645 AdgStyle *style = adg_entity_get_style(entity, style_slot);
647 if (style)
648 adg_style_apply(style, cr);
652 * adg_entity_point_to_pair:
653 * @entity: an #AdgEntity
654 * @point: the source #AdgPoint
655 * @pair: the destination #AdgPair
656 * @cr: a #cairo_t drawing context
658 * Converts @point to @pair using the model and paper matrix of @entity,
659 * as if the current matrix is an identity matrix.
661 void
662 adg_entity_point_to_pair(AdgEntity *entity, const AdgPoint *point,
663 AdgPair *pair, cairo_t *cr)
665 AdgMatrix inverted_ctm;
666 const AdgMatrix *model_matrix;
667 const AdgMatrix *paper_matrix;
668 AdgPair model_pair, paper_pair;
670 g_return_if_fail(ADG_IS_ENTITY(entity));
671 g_return_if_fail(point != NULL);
672 g_return_if_fail(pair != NULL);
674 cairo_get_matrix(cr, &inverted_ctm);
675 cairo_matrix_invert(&inverted_ctm);
676 model_matrix = ADG_ENTITY_GET_CLASS(entity)->get_model_matrix(entity);
677 paper_matrix = ADG_ENTITY_GET_CLASS(entity)->get_paper_matrix(entity);
679 adg_pair_copy(&model_pair, &point->model);
680 cpml_pair_transform(&model_pair, model_matrix);
682 adg_pair_copy(&paper_pair, &point->paper);
683 cpml_pair_transform(&paper_pair, paper_matrix);
685 pair->x = model_pair.x + paper_pair.x;
686 pair->y = model_pair.y + paper_pair.y;
688 cpml_pair_transform(pair, &inverted_ctm);
692 * adg_entity_point_to_model_pair:
693 * @entity: an #AdgEntity
694 * @point: the source #AdgPoint
695 * @pair: the destination #AdgPair
697 * Converts @point to @pair in model space.
699 void
700 adg_entity_point_to_model_pair(AdgEntity *entity,
701 const AdgPoint *point, AdgPair *pair)
703 const AdgMatrix *paper_matrix;
705 g_return_if_fail(ADG_IS_ENTITY(entity));
706 g_return_if_fail(point != NULL);
707 g_return_if_fail(pair != NULL);
709 paper_matrix = ADG_ENTITY_GET_CLASS(entity)->get_paper_matrix(entity);
710 adg_pair_copy(pair, &point->paper);
711 cpml_pair_transform(pair, paper_matrix);
713 pair->x += point->model.x;
714 pair->y += point->model.y;
718 * adg_entity_point_to_paper_pair:
719 * @entity: an #AdgEntity
720 * @point: the source #AdgPoint
721 * @pair: the destination #AdgPair
723 * Converts @point to @pair in paper space.
725 void
726 adg_entity_point_to_paper_pair(AdgEntity *entity,
727 const AdgPoint *point, AdgPair *pair)
729 const AdgMatrix *model_matrix;
731 g_return_if_fail(ADG_IS_ENTITY(entity));
732 g_return_if_fail(point != NULL);
733 g_return_if_fail(pair != NULL);
735 model_matrix = ADG_ENTITY_GET_CLASS(entity)->get_model_matrix(entity);
736 adg_pair_copy(pair, &point->model);
737 cpml_pair_transform(pair, model_matrix);
739 pair->x += point->paper.x;
740 pair->y += point->paper.y;
741 g_print("Pair (%lf, %lf)\n", pair->x, pair->y);
745 * adg_entity_model_matrix_applied:
746 * @entity: an #AdgEntity
748 * Return value: %TRUE if the model matrix didn't change from the last render
750 gboolean
751 adg_entity_model_matrix_applied(AdgEntity *entity)
753 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
754 return ADG_ISSET(entity->priv->flags, MODEL_MATRIX_APPLIED);
758 * adg_entity_paper_matrix_applied:
759 * @entity: an #AdgEntity
761 * Return value: %TRUE if the paper matrix didn't change from the last render
763 gboolean
764 adg_entity_paper_matrix_applied(AdgEntity *entity)
766 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
767 return ADG_ISSET(entity->priv->flags, PAPER_MATRIX_APPLIED);
771 * adg_entity_model_applied:
772 * @entity: an #AdgEntity
774 * Return value: %TRUE if the model didn't change from the last render
776 gboolean
777 adg_entity_model_applied(AdgEntity *entity)
779 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
780 return ADG_ISSET(entity->priv->flags, MODEL_APPLIED);
784 * adg_entity_invalidate:
785 * @entity: an #AdgEntity
787 * Emits the "invalidate" signal on @entity and all its children, if any,
788 * so subsequent rendering will need a global recomputation.
790 void
791 adg_entity_invalidate(AdgEntity *entity)
793 g_return_if_fail(ADG_IS_ENTITY(entity));
795 g_signal_emit(entity, signals[INVALIDATE], 0, NULL);
799 * adg_entity_render:
800 * @entity: an #AdgEntity
801 * @cr: a #cairo_t drawing context
803 * Emits the "render" signal on @entity and all its children, if any,
804 * causing the rendering operation the @cr cairo context.
806 void
807 adg_entity_render(AdgEntity *entity, cairo_t *cr)
809 g_return_if_fail(ADG_IS_ENTITY(entity));
811 g_signal_emit(entity, signals[RENDER], 0, cr);
815 static AdgContainer *
816 get_parent(AdgEntity *entity)
818 return entity->priv->parent;
821 static void
822 set_parent(AdgEntity *entity, AdgContainer *parent)
824 entity->priv->parent = parent;
827 static void
828 parent_set(AdgEntity *entity, AdgContainer *old_parent)
830 if (ADG_IS_CONTAINER(old_parent)) {
831 const AdgMatrix *old_model;
832 const AdgMatrix *old_paper;
834 old_model = adg_entity_get_model_matrix((AdgEntity *) old_parent);
835 old_paper = adg_entity_get_paper_matrix((AdgEntity *) old_parent);
837 adg_entity_model_matrix_changed(entity, old_model);
838 adg_entity_paper_matrix_changed(entity, old_paper);
842 static AdgContext *
843 get_context(AdgEntity *entity)
845 AdgEntity *parent;
847 if (entity->priv->context)
848 return entity->priv->context;
850 parent = (AdgEntity *) entity->priv->parent;
852 return parent ? ADG_ENTITY_GET_CLASS(parent)->get_context(parent) : NULL;
855 static void
856 set_context(AdgEntity *entity, AdgContext *context)
858 if (entity->priv->context)
859 g_object_unref((GObject *) entity->priv->context);
861 g_object_ref((GObject *) context);
862 entity->priv->context = context;
865 static void
866 model_matrix_changed(AdgEntity *entity, AdgMatrix *parent_matrix)
868 ADG_UNSET(entity->priv->flags, MODEL_MATRIX_APPLIED);
871 static void
872 paper_matrix_changed(AdgEntity *entity, AdgMatrix *parent_matrix)
874 ADG_UNSET(entity->priv->flags, PAPER_MATRIX_APPLIED);
877 static void
878 render(AdgEntity *entity, cairo_t *cr)
880 ADG_SET(entity->priv->flags,
881 MODEL_MATRIX_APPLIED | PAPER_MATRIX_APPLIED | MODEL_APPLIED);
884 static const AdgMatrix *
885 get_model_matrix(AdgEntity *entity)
887 return adg_entity_get_model_matrix((AdgEntity *) entity->priv->parent);
890 static const AdgMatrix *
891 get_paper_matrix(AdgEntity *entity)
893 return adg_entity_get_paper_matrix((AdgEntity *) entity->priv->parent);