[docs] NEWS.xml updated
[adg.git] / adg / adg-entity.c
blobf2179f971d5ace4a5cf39aea2d8ede71709c488b
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"
37 enum {
38 PROP_0,
39 PROP_PARENT,
40 PROP_CONTEXT
43 enum {
44 PARENT_SET,
45 MODEL_MATRIX_CHANGED,
46 PAPER_MATRIX_CHANGED,
47 INVALIDATE,
48 RENDER,
49 LAST_SIGNAL
53 static void get_property (GObject *object,
54 guint prop_id,
55 GValue *value,
56 GParamSpec *pspec);
57 static void set_property (GObject *object,
58 guint prop_id,
59 const GValue *value,
60 GParamSpec *pspec);
61 static void dispose (GObject *object);
62 static AdgContainer * get_parent (AdgEntity *entity);
63 static void set_parent (AdgEntity *entity,
64 AdgContainer *parent);
65 static void parent_set (AdgEntity *entity,
66 AdgContainer *old_parent);
67 static AdgContext * get_context (AdgEntity *entity);
68 static void set_context (AdgEntity *entity,
69 AdgContext *context);
70 static void model_matrix_changed (AdgEntity *entity,
71 AdgMatrix *parent_matrix);
72 static void paper_matrix_changed (AdgEntity *entity,
73 AdgMatrix *parent_matrix);
74 static void render (AdgEntity *entity,
75 cairo_t *cr);
76 static const AdgMatrix *get_model_matrix (AdgEntity *entity);
77 static const AdgMatrix *get_paper_matrix (AdgEntity *entity);
79 static guint signals[LAST_SIGNAL] = { 0 };
82 G_DEFINE_ABSTRACT_TYPE(AdgEntity, adg_entity, G_TYPE_INITIALLY_UNOWNED)
85 static void
86 adg_entity_class_init(AdgEntityClass *klass)
88 GObjectClass *gobject_class;
89 GParamSpec *param;
91 gobject_class = (GObjectClass *) klass;
93 g_type_class_add_private(klass, sizeof(AdgEntityPrivate));
95 gobject_class->get_property = get_property;
96 gobject_class->set_property = set_property;
97 gobject_class->dispose = dispose;
99 klass->get_parent = get_parent;
100 klass->set_parent = set_parent;
101 klass->parent_set = parent_set;
102 klass->get_context = get_context;
103 klass->model_matrix_changed = model_matrix_changed;
104 klass->paper_matrix_changed = paper_matrix_changed;
105 klass->invalidate = NULL;
106 klass->render = render;
107 klass->get_model_matrix = get_model_matrix;
108 klass->get_paper_matrix = get_paper_matrix;
110 param = g_param_spec_object("parent",
111 P_("Parent Container"),
112 P_("The parent AdgContainer of this entity or NULL if this is a top-level entity"),
113 ADG_TYPE_CONTAINER, G_PARAM_READWRITE);
114 g_object_class_install_property(gobject_class, PROP_PARENT, param);
116 param = g_param_spec_object("context",
117 P_("Context"),
118 P_("The context associated to this entity or NULL to inherit the parent context"),
119 ADG_TYPE_CONTEXT, G_PARAM_READWRITE);
120 g_object_class_install_property(gobject_class, PROP_CONTEXT, param);
123 * AdgEntity::parent-set:
124 * @entity: an #AdgEntity
125 * @parent: the #AdgContainer parent of @entity
127 * Emitted after the parent container has changed.
129 signals[PARENT_SET] =
130 g_signal_new("parent-set",
131 G_OBJECT_CLASS_TYPE(gobject_class),
132 G_SIGNAL_RUN_FIRST,
133 G_STRUCT_OFFSET(AdgEntityClass, parent_set),
134 NULL, NULL,
135 g_cclosure_marshal_VOID__OBJECT,
136 G_TYPE_NONE, 1, ADG_TYPE_CONTAINER);
139 * AdgEntity::model-matrix-changed:
140 * @entity: an #AdgEntity
141 * @parent_matrix: the parent model matrix
143 * Emitted after the current model matrix has changed.
145 signals[MODEL_MATRIX_CHANGED] =
146 g_signal_new("model-matrix-changed",
147 G_OBJECT_CLASS_TYPE(gobject_class),
148 G_SIGNAL_RUN_FIRST,
149 G_STRUCT_OFFSET(AdgEntityClass, model_matrix_changed),
150 NULL, NULL,
151 g_cclosure_marshal_VOID__BOXED,
152 G_TYPE_NONE, 1,
153 ADG_TYPE_MATRIX | G_SIGNAL_TYPE_STATIC_SCOPE);
156 * AdgEntity::paper-matrix-changed:
157 * @entity: an #AdgEntity
158 * @parent_matrix: the parent paper matrix
160 * Emitted after the current paper matrix has changed.
162 signals[PAPER_MATRIX_CHANGED] =
163 g_signal_new("paper-matrix-changed",
164 G_OBJECT_CLASS_TYPE(gobject_class),
165 G_SIGNAL_RUN_FIRST,
166 G_STRUCT_OFFSET(AdgEntityClass, paper_matrix_changed),
167 NULL, NULL,
168 g_cclosure_marshal_VOID__BOXED,
169 G_TYPE_NONE, 1,
170 ADG_TYPE_MATRIX | G_SIGNAL_TYPE_STATIC_SCOPE);
173 * AdgEntity::invalidate:
174 * @entity: an #AdgEntity
176 * Clears the cached data of @entity.
178 signals[INVALIDATE] =
179 g_signal_new("invalidate",
180 G_OBJECT_CLASS_TYPE(gobject_class),
181 G_SIGNAL_RUN_FIRST,
182 G_STRUCT_OFFSET(AdgEntityClass, invalidate),
183 NULL, NULL,
184 g_cclosure_marshal_VOID__BOOLEAN,
185 G_TYPE_NONE, 0);
188 * AdgEntity::render:
189 * @entity: an #AdgEntity
190 * @cr: a #cairo_t drawing context
192 * Causes the rendering of @entity on @cr.
194 signals[RENDER] =
195 g_signal_new("render",
196 G_OBJECT_CLASS_TYPE(gobject_class),
197 G_SIGNAL_RUN_FIRST,
198 G_STRUCT_OFFSET(AdgEntityClass, render),
199 NULL, NULL,
200 g_cclosure_marshal_VOID__POINTER,
201 G_TYPE_NONE, 1, G_TYPE_POINTER);
204 static void
205 adg_entity_init(AdgEntity *entity)
207 AdgEntityPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE(entity,
208 ADG_TYPE_ENTITY,
209 AdgEntityPrivate);
210 priv->parent = NULL;
211 priv->flags = 0;
212 priv->context = NULL;
214 entity->priv = priv;
217 static void
218 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
220 AdgEntity *entity = (AdgEntity *) object;
222 switch (prop_id) {
223 case PROP_PARENT:
224 g_value_set_object(value, get_parent(entity));
225 break;
226 case PROP_CONTEXT:
227 g_value_set_object(value, get_context(entity));
228 break;
229 default:
230 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
231 break;
235 static void
236 set_property(GObject *object,
237 guint prop_id, const GValue *value, GParamSpec *pspec)
239 AdgEntity *entity = (AdgEntity *) object;
241 switch (prop_id) {
242 case PROP_PARENT:
243 set_parent(entity, (AdgContainer *) g_value_get_object(value));
244 break;
245 case PROP_CONTEXT:
246 set_context(entity, g_value_get_object(value));
247 break;
248 default:
249 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
250 break;
254 static void
255 dispose(GObject *object)
257 AdgEntity *entity;
258 GObjectClass *object_class;
260 entity = (AdgEntity *) object;
261 object_class = (GObjectClass *) adg_entity_parent_class;
263 if (entity->priv->parent)
264 adg_container_remove(entity->priv->parent, entity);
266 if (object_class->dispose != NULL)
267 object_class->dispose(object);
272 * adg_entity_get_parent:
273 * @entity: an #AdgEntity
275 * Gets the container parent of @entity.
277 * This function is only useful in entity implementations.
279 * Return value: the container object or %NULL if @entity is not contained
281 AdgContainer *
282 adg_entity_get_parent(AdgEntity *entity)
284 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
286 return ADG_ENTITY_GET_CLASS(entity)->get_parent(entity);
290 * adg_entity_set_parent:
291 * @entity: an #AdgEntity
292 * @parent: an #AdgContainer
294 * Sets a new container of @entity.
296 * This function is only useful in entity implementations.
298 void
299 adg_entity_set_parent(AdgEntity *entity, AdgContainer *parent)
301 g_return_if_fail(ADG_IS_ENTITY(entity));
303 ADG_ENTITY_GET_CLASS(entity)->set_parent(entity, parent);
304 g_object_notify((GObject *) entity, "parent");
308 * adg_entity_unparent:
309 * @entity: an #AdgEntity
311 * Removes the current parent of @entity, properly handling
312 * the references between them.
314 * If @entity has no parent, this function simply returns.
316 void
317 adg_entity_unparent(AdgEntity *entity)
319 AdgContainer *old_parent;
321 g_return_if_fail(ADG_IS_ENTITY(entity));
323 old_parent = ADG_ENTITY_GET_CLASS(entity)->get_parent(entity);
325 if (old_parent == NULL)
326 return;
328 ADG_ENTITY_GET_CLASS(entity)->set_parent(entity, NULL);
329 g_signal_emit(entity, signals[PARENT_SET], 0, old_parent);
331 g_object_unref(entity);
335 * adg_entity_reparent:
336 * @entity: an #AdgEntity
337 * @parent: the new container
339 * Moves @entity from the old parent to @parent, handling reference
340 * count issues to avoid destroying the object.
342 void
343 adg_entity_reparent(AdgEntity *entity, AdgContainer *parent)
345 AdgContainer *old_parent;
347 g_return_if_fail(ADG_IS_CONTAINER(parent));
349 old_parent = adg_entity_get_parent(entity);
351 /* Reparenting on the same container: do nothing */
352 if (old_parent == parent)
353 return;
355 g_return_if_fail(ADG_IS_CONTAINER(old_parent));
357 g_object_ref(entity);
358 adg_container_remove(old_parent, entity);
359 adg_container_add(parent, entity);
360 g_object_unref(entity);
364 * adg_entity_get_context:
365 * @entity: an #AdgEntity instance
367 * Gets the context associated to @entity.
368 * If no context was explicitely set, get the parent context.
370 * Return value: the requested context or %NULL on errors
372 AdgContext *
373 adg_entity_get_context(AdgEntity *entity)
375 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
377 if (entity->priv->context)
378 return entity->priv->context;
380 if (entity->priv->parent)
381 return adg_entity_get_context((AdgEntity *) entity->priv->parent);
383 return NULL;
387 * adg_entity_set_context:
388 * @entity: an #AdgEntity instance
389 * @context: the new context
391 * Sets a new context. The old context (if any) will be unreferenced
392 * while a new reference will be added to @context.
394 void
395 adg_entity_set_context(AdgEntity *entity, AdgContext *context)
397 g_return_if_fail(ADG_IS_ENTITY(entity));
398 g_return_if_fail(ADG_IS_CONTEXT(context));
400 set_context(entity, context);
401 g_object_notify((GObject *) entity, "context");
405 * adg_entity_get_canvas:
406 * @entity: an #AdgEntity
408 * Walks on the @entity hierarchy and gets the first parent of @entity that is
409 * of #AdgCanvas derived type.
411 * Return value: the requested object or %NULL if there is no #AdgCanvas in
412 * the parent hierarchy.
414 AdgCanvas *
415 adg_entity_get_canvas(AdgEntity *entity)
417 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
419 while (entity) {
420 if (ADG_IS_CANVAS(entity))
421 return (AdgCanvas *) entity;
423 entity = (AdgEntity *) adg_entity_get_parent(entity);
426 return NULL;
430 * adg_entity_get_model_matrix:
431 * @entity: an #AdgEntity object
433 * Gets the model matrix to be used in rendering this @entity.
435 * Return value: the requested matrix
437 const AdgMatrix *
438 adg_entity_get_model_matrix(AdgEntity *entity)
440 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
441 return ADG_ENTITY_GET_CLASS(entity)->get_model_matrix(entity);
445 * adg_entity_get_paper_matrix:
446 * @entity: an #AdgEntity object
448 * Gets the paper matrix to be used in rendering this @entity.
450 * Return value: the requested matrix
452 const AdgMatrix *
453 adg_entity_get_paper_matrix(AdgEntity *entity)
455 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
456 return ADG_ENTITY_GET_CLASS(entity)->get_paper_matrix(entity);
460 * adg_entity_scale_to_model:
461 * @entity: an #AdgEntity object
462 * @cr: a #cairo_t drawing context
464 * Sets the model matrix as current matrix on @cr. The translation
465 * and rotation component of the previous matrix are kept: only the
466 * scale is changed.
468 void
469 adg_entity_scale_to_model(AdgEntity *entity, cairo_t *cr)
471 const AdgMatrix *model_matrix;
472 cairo_matrix_t matrix;
474 g_return_if_fail(ADG_IS_ENTITY(entity));
476 model_matrix = ADG_ENTITY_GET_CLASS(entity)->get_model_matrix(entity);
477 cairo_get_matrix(cr, &matrix);
479 matrix.xx = model_matrix->xx;
480 matrix.yy = model_matrix->yy;
481 cairo_set_matrix(cr, &matrix);
485 * adg_entity_scale_to_paper:
486 * @entity: an #AdgEntity object
487 * @cr: a #cairo_t drawing context
489 * Sets the paper matrix as current matrix on @cr. The translation
490 * and rotation component of the previous matrix are kept: only the
491 * scale is changed.
493 void
494 adg_entity_scale_to_paper(AdgEntity *entity, cairo_t *cr)
496 const AdgMatrix *paper_matrix;
497 cairo_matrix_t matrix;
499 g_return_if_fail(ADG_IS_ENTITY(entity));
501 paper_matrix = ADG_ENTITY_GET_CLASS(entity)->get_paper_matrix(entity);
502 cairo_get_matrix(cr, &matrix);
504 matrix.xx = paper_matrix->xx;
505 matrix.yy = paper_matrix->yy;
506 cairo_set_matrix(cr, &matrix);
510 * adg_entity_build_paper2model:
511 * @entity: an #AdgEntity
512 * @matrix: the destination matrix
514 * Builds a matrix to translate from paper to model space and
515 * put the result in @matrix.
517 * Return value: %TRUE on success, %FALSE on errors
519 gboolean
520 adg_entity_build_paper2model(AdgEntity *entity, AdgMatrix *matrix)
522 cairo_status_t status;
524 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
525 g_return_val_if_fail(matrix != NULL, FALSE);
527 adg_matrix_copy(matrix, adg_entity_get_model_matrix(entity));
528 status = cairo_matrix_invert(matrix);
529 if (status != CAIRO_STATUS_SUCCESS) {
530 g_error("Unable to invert model matrix (cairo message: %s)",
531 cairo_status_to_string(status));
532 return FALSE;
535 cairo_matrix_multiply(matrix, matrix, adg_entity_get_paper_matrix(entity));
536 return TRUE;
540 * adg_entity_build_model2paper:
541 * @entity: an #AdgEntity
542 * @matrix: the destination matrix
544 * Builds a matrix to translate from model to paper space and
545 * put the result in @matrix.
547 * Return value: %TRUE on success, %FALSE on errors
549 gboolean
550 adg_entity_build_model2paper(AdgEntity *entity, AdgMatrix *matrix)
552 cairo_status_t status;
554 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
555 g_return_val_if_fail(matrix != NULL, FALSE);
557 adg_matrix_copy(matrix, adg_entity_get_paper_matrix(entity));
558 status = cairo_matrix_invert(matrix);
559 if (status != CAIRO_STATUS_SUCCESS) {
560 g_error("Unable to invert paper matrix (cairo message: %s)",
561 cairo_status_to_string(status));
562 return FALSE;
565 cairo_matrix_multiply(matrix, matrix, adg_entity_get_model_matrix(entity));
566 return TRUE;
570 * adg_entity_model_matrix_changed:
571 * @entity: an #AdgEntity
572 * @parent_matrix: the parent #AdgMatrix
574 * Emits the "model-matrix-changed" signal on @entity.
576 * This function is only useful in entity implementations.
578 void
579 adg_entity_model_matrix_changed(AdgEntity *entity,
580 const AdgMatrix *parent_matrix)
582 g_return_if_fail(ADG_IS_ENTITY(entity));
584 g_signal_emit(entity, signals[MODEL_MATRIX_CHANGED], 0, parent_matrix);
588 * adg_entity_paper_matrix_changed:
589 * @entity: an #AdgEntity
590 * @parent_matrix: the parent #AdgMatrix
592 * Emits the "paper-matrix-changed" signal on @entity.
594 * This function is only useful in entity implementations.
596 void
597 adg_entity_paper_matrix_changed(AdgEntity *entity,
598 const AdgMatrix *parent_matrix)
600 g_return_if_fail(ADG_IS_ENTITY(entity));
602 g_signal_emit(entity, signals[PAPER_MATRIX_CHANGED], 0, parent_matrix);
606 * adg_entity_get_style:
607 * @entity: an #AdgEntity
608 * @style_slot: the slot of the style to get
610 * Gets a style from this entity. If the entity has no context associated
611 * or the style in undefined within this context, gets the style from its
612 * parent container.
614 * Return value: the requested style or %NULL on errors
616 AdgStyle *
617 adg_entity_get_style(AdgEntity *entity, AdgStyleSlot style_slot)
619 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
621 if (entity->priv->context) {
622 AdgStyle *style = adg_context_get_style(entity->priv->context,
623 style_slot);
624 if (style)
625 return style;
628 if (entity->priv->parent)
629 return adg_entity_get_style((AdgEntity *) entity->priv->parent,
630 style_slot);
632 return NULL;
636 * adg_entity_apply:
637 * @entity: an #AdgEntity
638 * @style_slot: the slot of the style to apply
639 * @cr: a #cairo_t drawing context
641 * Applies the specified style to the @cr cairo context.
643 void
644 adg_entity_apply(AdgEntity *entity, AdgStyleSlot style_slot, cairo_t *cr)
646 AdgStyle *style = adg_entity_get_style(entity, style_slot);
648 if (style)
649 adg_style_apply(style, cr);
653 * adg_entity_point_to_pair:
654 * @entity: an #AdgEntity
655 * @point: the source #AdgPoint
656 * @pair: the destination #AdgPair
657 * @cr: a #cairo_t drawing context
659 * Converts @point to @pair using the model and paper matrix of @entity,
660 * as if the current matrix is an identity matrix.
662 void
663 adg_entity_point_to_pair(AdgEntity *entity, const AdgPoint *point,
664 AdgPair *pair, cairo_t *cr)
666 AdgMatrix inverted_ctm;
667 const AdgMatrix *model_matrix;
668 const AdgMatrix *paper_matrix;
669 AdgPair model_pair, paper_pair;
671 g_return_if_fail(ADG_IS_ENTITY(entity));
672 g_return_if_fail(point != NULL);
673 g_return_if_fail(pair != NULL);
675 cairo_get_matrix(cr, &inverted_ctm);
676 cairo_matrix_invert(&inverted_ctm);
677 model_matrix = ADG_ENTITY_GET_CLASS(entity)->get_model_matrix(entity);
678 paper_matrix = ADG_ENTITY_GET_CLASS(entity)->get_paper_matrix(entity);
680 cpml_pair_copy(&model_pair, &point->model);
681 cpml_pair_transform(&model_pair, model_matrix);
683 cpml_pair_copy(&paper_pair, &point->paper);
684 cpml_pair_transform(&paper_pair, paper_matrix);
686 pair->x = model_pair.x + paper_pair.x;
687 pair->y = model_pair.y + paper_pair.y;
689 cpml_pair_transform(pair, &inverted_ctm);
693 * adg_entity_point_to_model_pair:
694 * @entity: an #AdgEntity
695 * @point: the source #AdgPoint
696 * @pair: the destination #AdgPair
698 * Converts @point to @pair in model space.
700 void
701 adg_entity_point_to_model_pair(AdgEntity *entity,
702 const AdgPoint *point, AdgPair *pair)
704 const AdgMatrix *paper_matrix;
706 g_return_if_fail(ADG_IS_ENTITY(entity));
707 g_return_if_fail(point != NULL);
708 g_return_if_fail(pair != NULL);
710 paper_matrix = ADG_ENTITY_GET_CLASS(entity)->get_paper_matrix(entity);
711 cpml_pair_copy(pair, &point->paper);
712 cpml_pair_transform(pair, paper_matrix);
714 pair->x += point->model.x;
715 pair->y += point->model.y;
719 * adg_entity_point_to_paper_pair:
720 * @entity: an #AdgEntity
721 * @point: the source #AdgPoint
722 * @pair: the destination #AdgPair
724 * Converts @point to @pair in paper space.
726 void
727 adg_entity_point_to_paper_pair(AdgEntity *entity,
728 const AdgPoint *point, AdgPair *pair)
730 const AdgMatrix *model_matrix;
732 g_return_if_fail(ADG_IS_ENTITY(entity));
733 g_return_if_fail(point != NULL);
734 g_return_if_fail(pair != NULL);
736 model_matrix = ADG_ENTITY_GET_CLASS(entity)->get_model_matrix(entity);
737 cpml_pair_copy(pair, &point->model);
738 cpml_pair_transform(pair, model_matrix);
740 pair->x += point->paper.x;
741 pair->y += point->paper.y;
742 g_print("Pair (%lf, %lf)\n", pair->x, pair->y);
746 * adg_entity_model_matrix_applied:
747 * @entity: an #AdgEntity
749 * Return value: %TRUE if the model matrix didn't change from the last render
751 gboolean
752 adg_entity_model_matrix_applied(AdgEntity *entity)
754 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
755 return ADG_ISSET(entity->priv->flags, MODEL_MATRIX_APPLIED);
759 * adg_entity_paper_matrix_applied:
760 * @entity: an #AdgEntity
762 * Return value: %TRUE if the paper matrix didn't change from the last render
764 gboolean
765 adg_entity_paper_matrix_applied(AdgEntity *entity)
767 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
768 return ADG_ISSET(entity->priv->flags, PAPER_MATRIX_APPLIED);
772 * adg_entity_model_applied:
773 * @entity: an #AdgEntity
775 * Return value: %TRUE if the model didn't change from the last render
777 gboolean
778 adg_entity_model_applied(AdgEntity *entity)
780 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
781 return ADG_ISSET(entity->priv->flags, MODEL_APPLIED);
785 * adg_entity_invalidate:
786 * @entity: an #AdgEntity
788 * Emits the "invalidate" signal on @entity and all its children, if any,
789 * so subsequent rendering will need a global recomputation.
791 void
792 adg_entity_invalidate(AdgEntity *entity)
794 g_return_if_fail(ADG_IS_ENTITY(entity));
796 g_signal_emit(entity, signals[INVALIDATE], 0, NULL);
800 * adg_entity_render:
801 * @entity: an #AdgEntity
802 * @cr: a #cairo_t drawing context
804 * Emits the "render" signal on @entity and all its children, if any,
805 * causing the rendering operation the @cr cairo context.
807 void
808 adg_entity_render(AdgEntity *entity, cairo_t *cr)
810 g_return_if_fail(ADG_IS_ENTITY(entity));
812 g_signal_emit(entity, signals[RENDER], 0, cr);
816 static AdgContainer *
817 get_parent(AdgEntity *entity)
819 return entity->priv->parent;
822 static void
823 set_parent(AdgEntity *entity, AdgContainer *parent)
825 entity->priv->parent = parent;
828 static void
829 parent_set(AdgEntity *entity, AdgContainer *old_parent)
831 if (ADG_IS_CONTAINER(old_parent)) {
832 const AdgMatrix *old_model;
833 const AdgMatrix *old_paper;
835 old_model = adg_entity_get_model_matrix((AdgEntity *) old_parent);
836 old_paper = adg_entity_get_paper_matrix((AdgEntity *) old_parent);
838 adg_entity_model_matrix_changed(entity, old_model);
839 adg_entity_paper_matrix_changed(entity, old_paper);
843 static AdgContext *
844 get_context(AdgEntity *entity)
846 AdgEntity *parent;
848 if (entity->priv->context)
849 return entity->priv->context;
851 parent = (AdgEntity *) entity->priv->parent;
853 return parent ? ADG_ENTITY_GET_CLASS(parent)->get_context(parent) : NULL;
856 static void
857 set_context(AdgEntity *entity, AdgContext *context)
859 if (entity->priv->context)
860 g_object_unref((GObject *) entity->priv->context);
862 g_object_ref((GObject *) context);
863 entity->priv->context = context;
866 static void
867 model_matrix_changed(AdgEntity *entity, AdgMatrix *parent_matrix)
869 ADG_UNSET(entity->priv->flags, MODEL_MATRIX_APPLIED);
872 static void
873 paper_matrix_changed(AdgEntity *entity, AdgMatrix *parent_matrix)
875 ADG_UNSET(entity->priv->flags, PAPER_MATRIX_APPLIED);
878 static void
879 render(AdgEntity *entity, cairo_t *cr)
881 ADG_SET(entity->priv->flags,
882 MODEL_MATRIX_APPLIED | PAPER_MATRIX_APPLIED | MODEL_APPLIED);
885 static const AdgMatrix *
886 get_model_matrix(AdgEntity *entity)
888 return adg_entity_get_model_matrix((AdgEntity *) entity->priv->parent);
891 static const AdgMatrix *
892 get_paper_matrix(AdgEntity *entity)
894 return adg_entity_get_paper_matrix((AdgEntity *) entity->priv->parent);