[docs] Autogenerate adg-sections.txt
[adg.git] / adg / adg-entity.c
blob6197823402f65adcc40170ea39a5d82d1f0f1a0b
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: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
52 enum {
53 PARENT_SET,
54 MODEL_MATRIX_CHANGED,
55 PAPER_MATRIX_CHANGED,
56 INVALIDATE,
57 RENDER,
58 LAST_SIGNAL
62 static void get_property (GObject *object,
63 guint prop_id,
64 GValue *value,
65 GParamSpec *pspec);
66 static void set_property (GObject *object,
67 guint prop_id,
68 const GValue *value,
69 GParamSpec *pspec);
70 static void dispose (GObject *object);
71 static AdgContainer * get_parent (AdgEntity *entity);
72 static void set_parent (AdgEntity *entity,
73 AdgContainer *parent);
74 static void parent_set (AdgEntity *entity,
75 AdgContainer *old_parent);
76 static AdgContext * get_context (AdgEntity *entity);
77 static void set_context (AdgEntity *entity,
78 AdgContext *context);
79 static void model_matrix_changed (AdgEntity *entity,
80 AdgMatrix *parent_matrix);
81 static void paper_matrix_changed (AdgEntity *entity,
82 AdgMatrix *parent_matrix);
83 static void render (AdgEntity *entity,
84 cairo_t *cr);
85 static const AdgMatrix *get_model_matrix (AdgEntity *entity);
86 static const AdgMatrix *get_paper_matrix (AdgEntity *entity);
88 static guint signals[LAST_SIGNAL] = { 0 };
91 G_DEFINE_ABSTRACT_TYPE(AdgEntity, adg_entity, G_TYPE_INITIALLY_UNOWNED);
94 static void
95 adg_entity_class_init(AdgEntityClass *klass)
97 GObjectClass *gobject_class;
98 GParamSpec *param;
100 gobject_class = (GObjectClass *) klass;
102 g_type_class_add_private(klass, sizeof(AdgEntityPrivate));
104 gobject_class->get_property = get_property;
105 gobject_class->set_property = set_property;
106 gobject_class->dispose = dispose;
108 klass->get_parent = get_parent;
109 klass->set_parent = set_parent;
110 klass->parent_set = parent_set;
111 klass->get_context = get_context;
112 klass->model_matrix_changed = model_matrix_changed;
113 klass->paper_matrix_changed = paper_matrix_changed;
114 klass->invalidate = NULL;
115 klass->render = render;
116 klass->get_model_matrix = get_model_matrix;
117 klass->get_paper_matrix = get_paper_matrix;
119 param = g_param_spec_object("parent",
120 P_("Parent Container"),
121 P_("The parent AdgContainer of this entity or NULL if this is a top-level entity"),
122 ADG_TYPE_CONTAINER, G_PARAM_READWRITE);
123 g_object_class_install_property(gobject_class, PROP_PARENT, param);
125 param = g_param_spec_object("context",
126 P_("Context"),
127 P_("The context associated to this entity or NULL to inherit the parent context"),
128 ADG_TYPE_CONTEXT, G_PARAM_READWRITE);
129 g_object_class_install_property(gobject_class, PROP_CONTEXT, param);
132 * AdgEntity::parent-set:
133 * @entity: an #AdgEntity
134 * @parent: the #AdgContainer parent of @entity
136 * Emitted after the parent container has changed.
138 signals[PARENT_SET] =
139 g_signal_new("parent-set",
140 G_OBJECT_CLASS_TYPE(gobject_class),
141 G_SIGNAL_RUN_FIRST,
142 G_STRUCT_OFFSET(AdgEntityClass, parent_set),
143 NULL, NULL,
144 g_cclosure_marshal_VOID__OBJECT,
145 G_TYPE_NONE, 1, ADG_TYPE_CONTAINER);
148 * AdgEntity::model-matrix-changed:
149 * @entity: an #AdgEntity
150 * @parent_matrix: the parent model matrix
152 * Emitted after the current model matrix has changed.
154 signals[MODEL_MATRIX_CHANGED] =
155 g_signal_new("model-matrix-changed",
156 G_OBJECT_CLASS_TYPE(gobject_class),
157 G_SIGNAL_RUN_FIRST,
158 G_STRUCT_OFFSET(AdgEntityClass, model_matrix_changed),
159 NULL, NULL,
160 g_cclosure_marshal_VOID__BOXED,
161 G_TYPE_NONE, 1,
162 ADG_TYPE_MATRIX | G_SIGNAL_TYPE_STATIC_SCOPE);
165 * AdgEntity::paper-matrix-changed:
166 * @entity: an #AdgEntity
167 * @parent_matrix: the parent paper matrix
169 * Emitted after the current paper matrix has changed.
171 signals[PAPER_MATRIX_CHANGED] =
172 g_signal_new("paper-matrix-changed",
173 G_OBJECT_CLASS_TYPE(gobject_class),
174 G_SIGNAL_RUN_FIRST,
175 G_STRUCT_OFFSET(AdgEntityClass, paper_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::invalidate:
183 * @entity: an #AdgEntity
185 * Clears the cached data of @entity.
187 signals[INVALIDATE] =
188 g_signal_new("invalidate",
189 G_OBJECT_CLASS_TYPE(gobject_class),
190 G_SIGNAL_RUN_FIRST,
191 G_STRUCT_OFFSET(AdgEntityClass, invalidate),
192 NULL, NULL,
193 g_cclosure_marshal_VOID__BOOLEAN,
194 G_TYPE_NONE, 0);
197 * AdgEntity::render:
198 * @entity: an #AdgEntity
199 * @cr: a #cairo_t drawing context
201 * Causes the rendering of @entity on @cr.
203 signals[RENDER] =
204 g_signal_new("render",
205 G_OBJECT_CLASS_TYPE(gobject_class),
206 G_SIGNAL_RUN_FIRST,
207 G_STRUCT_OFFSET(AdgEntityClass, render),
208 NULL, NULL,
209 g_cclosure_marshal_VOID__POINTER,
210 G_TYPE_NONE, 1, G_TYPE_POINTER);
213 static void
214 adg_entity_init(AdgEntity *entity)
216 AdgEntityPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(entity,
217 ADG_TYPE_ENTITY,
218 AdgEntityPrivate);
219 data->parent = NULL;
220 data->flags = 0;
221 data->context = NULL;
223 entity->data = data;
226 static void
227 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
229 AdgEntity *entity = (AdgEntity *) object;
231 switch (prop_id) {
232 case PROP_PARENT:
233 g_value_set_object(value, get_parent(entity));
234 break;
235 case PROP_CONTEXT:
236 g_value_set_object(value, get_context(entity));
237 break;
238 default:
239 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
240 break;
244 static void
245 set_property(GObject *object,
246 guint prop_id, const GValue *value, GParamSpec *pspec)
248 AdgEntity *entity = (AdgEntity *) object;
250 switch (prop_id) {
251 case PROP_PARENT:
252 set_parent(entity, (AdgContainer *) g_value_get_object(value));
253 break;
254 case PROP_CONTEXT:
255 set_context(entity, g_value_get_object(value));
256 break;
257 default:
258 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
259 break;
263 static void
264 dispose(GObject *object)
266 AdgEntity *entity;
267 AdgEntityPrivate *data;
268 GObjectClass *object_class;
270 entity = (AdgEntity *) object;
271 data = entity->data;
272 object_class = (GObjectClass *) adg_entity_parent_class;
274 if (data->parent)
275 adg_container_remove(data->parent, entity);
277 if (object_class->dispose != NULL)
278 object_class->dispose(object);
283 * adg_entity_get_parent:
284 * @entity: an #AdgEntity
286 * Gets the container parent of @entity.
288 * This function is only useful in entity implementations.
290 * Return value: the container object or %NULL if @entity is not contained
292 AdgContainer *
293 adg_entity_get_parent(AdgEntity *entity)
295 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
297 return ADG_ENTITY_GET_CLASS(entity)->get_parent(entity);
301 * adg_entity_set_parent:
302 * @entity: an #AdgEntity
303 * @parent: an #AdgContainer
305 * Sets a new container of @entity.
307 * This function is only useful in entity implementations.
309 void
310 adg_entity_set_parent(AdgEntity *entity, AdgContainer *parent)
312 g_return_if_fail(ADG_IS_ENTITY(entity));
314 ADG_ENTITY_GET_CLASS(entity)->set_parent(entity, parent);
315 g_object_notify((GObject *) entity, "parent");
319 * adg_entity_unparent:
320 * @entity: an #AdgEntity
322 * Removes the current parent of @entity, properly handling
323 * the references between them.
325 * If @entity has no parent, this function simply returns.
327 void
328 adg_entity_unparent(AdgEntity *entity)
330 AdgContainer *old_parent;
332 g_return_if_fail(ADG_IS_ENTITY(entity));
334 old_parent = ADG_ENTITY_GET_CLASS(entity)->get_parent(entity);
336 if (old_parent == NULL)
337 return;
339 ADG_ENTITY_GET_CLASS(entity)->set_parent(entity, NULL);
340 g_signal_emit(entity, signals[PARENT_SET], 0, old_parent);
342 g_object_unref(entity);
346 * adg_entity_reparent:
347 * @entity: an #AdgEntity
348 * @parent: the new container
350 * Moves @entity from the old parent to @parent, handling reference
351 * count issues to avoid destroying the object.
353 void
354 adg_entity_reparent(AdgEntity *entity, AdgContainer *parent)
356 AdgContainer *old_parent;
358 g_return_if_fail(ADG_IS_CONTAINER(parent));
360 old_parent = adg_entity_get_parent(entity);
362 /* Reparenting on the same container: do nothing */
363 if (old_parent == parent)
364 return;
366 g_return_if_fail(ADG_IS_CONTAINER(old_parent));
368 g_object_ref(entity);
369 adg_container_remove(old_parent, entity);
370 adg_container_add(parent, entity);
371 g_object_unref(entity);
375 * adg_entity_get_context:
376 * @entity: an #AdgEntity instance
378 * Gets the context associated to @entity.
379 * If no context was explicitely set, get the parent context.
381 * Return value: the requested context or %NULL on errors
383 AdgContext *
384 adg_entity_get_context(AdgEntity *entity)
386 AdgEntityPrivate *data;
388 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
390 data = entity->data;
392 if (data->context)
393 return data->context;
395 if (data->parent)
396 return adg_entity_get_context((AdgEntity *) data->parent);
398 return NULL;
402 * adg_entity_set_context:
403 * @entity: an #AdgEntity instance
404 * @context: the new context
406 * Sets a new context. The old context (if any) will be unreferenced
407 * while a new reference will be added to @context.
409 void
410 adg_entity_set_context(AdgEntity *entity, AdgContext *context)
412 g_return_if_fail(ADG_IS_ENTITY(entity));
413 g_return_if_fail(ADG_IS_CONTEXT(context));
415 set_context(entity, context);
416 g_object_notify((GObject *) entity, "context");
420 * adg_entity_get_canvas:
421 * @entity: an #AdgEntity
423 * Walks on the @entity hierarchy and gets the first parent of @entity that is
424 * of #AdgCanvas derived type.
426 * Return value: the requested object or %NULL if there is no #AdgCanvas in
427 * the parent hierarchy.
429 AdgCanvas *
430 adg_entity_get_canvas(AdgEntity *entity)
432 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
434 while (entity) {
435 if (ADG_IS_CANVAS(entity))
436 return (AdgCanvas *) entity;
438 entity = (AdgEntity *) adg_entity_get_parent(entity);
441 return NULL;
445 * adg_entity_get_model_matrix:
446 * @entity: an #AdgEntity object
448 * Gets the model matrix to be used in rendering this @entity.
450 * Return value: the requested matrix
452 const AdgMatrix *
453 adg_entity_get_model_matrix(AdgEntity *entity)
455 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
456 return ADG_ENTITY_GET_CLASS(entity)->get_model_matrix(entity);
460 * adg_entity_get_paper_matrix:
461 * @entity: an #AdgEntity object
463 * Gets the paper matrix to be used in rendering this @entity.
465 * Return value: the requested matrix
467 const AdgMatrix *
468 adg_entity_get_paper_matrix(AdgEntity *entity)
470 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
471 return ADG_ENTITY_GET_CLASS(entity)->get_paper_matrix(entity);
475 * adg_entity_scale_to_model:
476 * @entity: an #AdgEntity object
477 * @cr: a #cairo_t drawing context
479 * Sets the model matrix as current matrix on @cr. The translation
480 * and rotation component of the previous matrix are kept: only the
481 * scale is changed.
483 void
484 adg_entity_scale_to_model(AdgEntity *entity, cairo_t *cr)
486 const AdgMatrix *model_matrix;
487 cairo_matrix_t matrix;
489 g_return_if_fail(ADG_IS_ENTITY(entity));
491 model_matrix = ADG_ENTITY_GET_CLASS(entity)->get_model_matrix(entity);
492 cairo_get_matrix(cr, &matrix);
494 matrix.xx = model_matrix->xx;
495 matrix.yy = model_matrix->yy;
496 cairo_set_matrix(cr, &matrix);
500 * adg_entity_scale_to_paper:
501 * @entity: an #AdgEntity object
502 * @cr: a #cairo_t drawing context
504 * Sets the paper matrix as current matrix on @cr. The translation
505 * and rotation component of the previous matrix are kept: only the
506 * scale is changed.
508 void
509 adg_entity_scale_to_paper(AdgEntity *entity, cairo_t *cr)
511 const AdgMatrix *paper_matrix;
512 cairo_matrix_t matrix;
514 g_return_if_fail(ADG_IS_ENTITY(entity));
516 paper_matrix = ADG_ENTITY_GET_CLASS(entity)->get_paper_matrix(entity);
517 cairo_get_matrix(cr, &matrix);
519 matrix.xx = paper_matrix->xx;
520 matrix.yy = paper_matrix->yy;
521 cairo_set_matrix(cr, &matrix);
525 * adg_entity_build_paper2model:
526 * @entity: an #AdgEntity
527 * @matrix: the destination matrix
529 * Builds a matrix to translate from paper to model space and
530 * put the result in @matrix.
532 * Return value: %TRUE on success, %FALSE on errors
534 gboolean
535 adg_entity_build_paper2model(AdgEntity *entity, AdgMatrix *matrix)
537 cairo_status_t status;
539 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
540 g_return_val_if_fail(matrix != NULL, FALSE);
542 adg_matrix_copy(matrix, adg_entity_get_model_matrix(entity));
543 status = cairo_matrix_invert(matrix);
544 if (status != CAIRO_STATUS_SUCCESS) {
545 g_error("Unable to invert model matrix (cairo message: %s)",
546 cairo_status_to_string(status));
547 return FALSE;
550 cairo_matrix_multiply(matrix, matrix, adg_entity_get_paper_matrix(entity));
551 return TRUE;
555 * adg_entity_build_model2paper:
556 * @entity: an #AdgEntity
557 * @matrix: the destination matrix
559 * Builds a matrix to translate from model to paper space and
560 * put the result in @matrix.
562 * Return value: %TRUE on success, %FALSE on errors
564 gboolean
565 adg_entity_build_model2paper(AdgEntity *entity, AdgMatrix *matrix)
567 cairo_status_t status;
569 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
570 g_return_val_if_fail(matrix != NULL, FALSE);
572 adg_matrix_copy(matrix, adg_entity_get_paper_matrix(entity));
573 status = cairo_matrix_invert(matrix);
574 if (status != CAIRO_STATUS_SUCCESS) {
575 g_error("Unable to invert paper matrix (cairo message: %s)",
576 cairo_status_to_string(status));
577 return FALSE;
580 cairo_matrix_multiply(matrix, matrix, adg_entity_get_model_matrix(entity));
581 return TRUE;
585 * adg_entity_model_matrix_changed:
586 * @entity: an #AdgEntity
587 * @parent_matrix: the parent #AdgMatrix
589 * Emits the "model-matrix-changed" signal on @entity.
591 * This function is only useful in entity implementations.
593 void
594 adg_entity_model_matrix_changed(AdgEntity *entity,
595 const AdgMatrix *parent_matrix)
597 g_return_if_fail(ADG_IS_ENTITY(entity));
599 g_signal_emit(entity, signals[MODEL_MATRIX_CHANGED], 0, parent_matrix);
603 * adg_entity_paper_matrix_changed:
604 * @entity: an #AdgEntity
605 * @parent_matrix: the parent #AdgMatrix
607 * Emits the "paper-matrix-changed" signal on @entity.
609 * This function is only useful in entity implementations.
611 void
612 adg_entity_paper_matrix_changed(AdgEntity *entity,
613 const AdgMatrix *parent_matrix)
615 g_return_if_fail(ADG_IS_ENTITY(entity));
617 g_signal_emit(entity, signals[PAPER_MATRIX_CHANGED], 0, parent_matrix);
621 * adg_entity_get_style:
622 * @entity: an #AdgEntity
623 * @style_slot: the slot of the style to get
625 * Gets a style from this entity. If the entity has no context associated
626 * or the style in undefined within this context, gets the style from its
627 * parent container.
629 * Return value: the requested style or %NULL on errors
631 AdgStyle *
632 adg_entity_get_style(AdgEntity *entity, AdgStyleSlot style_slot)
634 AdgEntityPrivate *data;
636 g_return_val_if_fail(ADG_IS_ENTITY(entity), NULL);
638 data = entity->data;
640 if (data->context) {
641 AdgStyle *style = adg_context_get_style(data->context, style_slot);
642 if (style)
643 return style;
646 if (data->parent)
647 return adg_entity_get_style((AdgEntity *) data->parent, style_slot);
649 return NULL;
653 * adg_entity_apply:
654 * @entity: an #AdgEntity
655 * @style_slot: the slot of the style to apply
656 * @cr: a #cairo_t drawing context
658 * Applies the specified style to the @cr cairo context.
660 void
661 adg_entity_apply(AdgEntity *entity, AdgStyleSlot style_slot, cairo_t *cr)
663 AdgStyle *style = adg_entity_get_style(entity, style_slot);
665 if (style)
666 adg_style_apply(style, cr);
670 * adg_entity_point_to_pair:
671 * @entity: an #AdgEntity
672 * @point: the source #AdgPoint
673 * @pair: the destination #AdgPair
674 * @cr: a #cairo_t drawing context
676 * Converts @point to @pair using the model and paper matrix of @entity,
677 * as if the current matrix is an identity matrix.
679 void
680 adg_entity_point_to_pair(AdgEntity *entity, const AdgPoint *point,
681 AdgPair *pair, cairo_t *cr)
683 AdgMatrix inverted_ctm;
684 const AdgMatrix *model_matrix;
685 const AdgMatrix *paper_matrix;
686 AdgPair model_pair, paper_pair;
688 g_return_if_fail(ADG_IS_ENTITY(entity));
689 g_return_if_fail(point != NULL);
690 g_return_if_fail(pair != NULL);
692 cairo_get_matrix(cr, &inverted_ctm);
693 cairo_matrix_invert(&inverted_ctm);
694 model_matrix = ADG_ENTITY_GET_CLASS(entity)->get_model_matrix(entity);
695 paper_matrix = ADG_ENTITY_GET_CLASS(entity)->get_paper_matrix(entity);
697 cpml_pair_copy(&model_pair, &point->model);
698 cpml_pair_transform(&model_pair, model_matrix);
700 cpml_pair_copy(&paper_pair, &point->paper);
701 cpml_pair_transform(&paper_pair, paper_matrix);
703 pair->x = model_pair.x + paper_pair.x;
704 pair->y = model_pair.y + paper_pair.y;
706 cpml_pair_transform(pair, &inverted_ctm);
710 * adg_entity_point_to_model_pair:
711 * @entity: an #AdgEntity
712 * @point: the source #AdgPoint
713 * @pair: the destination #AdgPair
715 * Converts @point to @pair in model space.
717 void
718 adg_entity_point_to_model_pair(AdgEntity *entity,
719 const AdgPoint *point, AdgPair *pair)
721 const AdgMatrix *paper_matrix;
723 g_return_if_fail(ADG_IS_ENTITY(entity));
724 g_return_if_fail(point != NULL);
725 g_return_if_fail(pair != NULL);
727 paper_matrix = ADG_ENTITY_GET_CLASS(entity)->get_paper_matrix(entity);
728 cpml_pair_copy(pair, &point->paper);
729 cpml_pair_transform(pair, paper_matrix);
731 pair->x += point->model.x;
732 pair->y += point->model.y;
736 * adg_entity_point_to_paper_pair:
737 * @entity: an #AdgEntity
738 * @point: the source #AdgPoint
739 * @pair: the destination #AdgPair
741 * Converts @point to @pair in paper space.
743 void
744 adg_entity_point_to_paper_pair(AdgEntity *entity,
745 const AdgPoint *point, AdgPair *pair)
747 const AdgMatrix *model_matrix;
749 g_return_if_fail(ADG_IS_ENTITY(entity));
750 g_return_if_fail(point != NULL);
751 g_return_if_fail(pair != NULL);
753 model_matrix = ADG_ENTITY_GET_CLASS(entity)->get_model_matrix(entity);
754 cpml_pair_copy(pair, &point->model);
755 cpml_pair_transform(pair, model_matrix);
757 pair->x += point->paper.x;
758 pair->y += point->paper.y;
759 g_print("Pair (%lf, %lf)\n", pair->x, pair->y);
763 * adg_entity_model_matrix_applied:
764 * @entity: an #AdgEntity
766 * Return value: %TRUE if the model matrix didn't change from the last render
768 gboolean
769 adg_entity_model_matrix_applied(AdgEntity *entity)
771 AdgEntityPrivate *data;
773 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
775 data = entity->data;
777 return ADG_ISSET(data->flags, MODEL_MATRIX_APPLIED);
781 * adg_entity_paper_matrix_applied:
782 * @entity: an #AdgEntity
784 * Return value: %TRUE if the paper matrix didn't change from the last render
786 gboolean
787 adg_entity_paper_matrix_applied(AdgEntity *entity)
789 AdgEntityPrivate *data;
791 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
793 data = entity->data;
795 return ADG_ISSET(data->flags, PAPER_MATRIX_APPLIED);
799 * adg_entity_model_applied:
800 * @entity: an #AdgEntity
802 * Return value: %TRUE if the model didn't change from the last render
804 gboolean
805 adg_entity_model_applied(AdgEntity *entity)
807 AdgEntityPrivate *data;
809 g_return_val_if_fail(ADG_IS_ENTITY(entity), FALSE);
811 data = entity->data;
813 return ADG_ISSET(data->flags, MODEL_APPLIED);
817 * adg_entity_invalidate:
818 * @entity: an #AdgEntity
820 * Emits the "invalidate" signal on @entity and all its children, if any,
821 * so subsequent rendering will need a global recomputation.
823 void
824 adg_entity_invalidate(AdgEntity *entity)
826 g_return_if_fail(ADG_IS_ENTITY(entity));
828 g_signal_emit(entity, signals[INVALIDATE], 0, NULL);
832 * adg_entity_render:
833 * @entity: an #AdgEntity
834 * @cr: a #cairo_t drawing context
836 * Emits the "render" signal on @entity and all its children, if any,
837 * causing the rendering operation the @cr cairo context.
839 void
840 adg_entity_render(AdgEntity *entity, cairo_t *cr)
842 g_return_if_fail(ADG_IS_ENTITY(entity));
844 g_signal_emit(entity, signals[RENDER], 0, cr);
848 static AdgContainer *
849 get_parent(AdgEntity *entity)
851 AdgEntityPrivate *data = entity->data;
853 return data->parent;
856 static void
857 set_parent(AdgEntity *entity, AdgContainer *parent)
859 AdgEntityPrivate *data = entity->data;
861 data->parent = parent;
864 static void
865 parent_set(AdgEntity *entity, AdgContainer *old_parent)
867 if (ADG_IS_CONTAINER(old_parent)) {
868 const AdgMatrix *old_model;
869 const AdgMatrix *old_paper;
871 old_model = adg_entity_get_model_matrix((AdgEntity *) old_parent);
872 old_paper = adg_entity_get_paper_matrix((AdgEntity *) old_parent);
874 adg_entity_model_matrix_changed(entity, old_model);
875 adg_entity_paper_matrix_changed(entity, old_paper);
879 static AdgContext *
880 get_context(AdgEntity *entity)
882 AdgEntityPrivate *data = entity->data;
883 AdgEntity *parent;
885 if (data->context)
886 return data->context;
888 parent = (AdgEntity *) data->parent;
890 return parent ? ADG_ENTITY_GET_CLASS(parent)->get_context(parent) : NULL;
893 static void
894 set_context(AdgEntity *entity, AdgContext *context)
896 AdgEntityPrivate *data = entity->data;
898 if (data->context)
899 g_object_unref((GObject *) data->context);
901 g_object_ref((GObject *) context);
902 data->context = context;
905 static void
906 model_matrix_changed(AdgEntity *entity, AdgMatrix *parent_matrix)
908 AdgEntityPrivate *data = entity->data;
910 ADG_UNSET(data->flags, MODEL_MATRIX_APPLIED);
913 static void
914 paper_matrix_changed(AdgEntity *entity, AdgMatrix *parent_matrix)
916 AdgEntityPrivate *data = entity->data;
918 ADG_UNSET(data->flags, PAPER_MATRIX_APPLIED);
921 static void
922 render(AdgEntity *entity, cairo_t *cr)
924 AdgEntityPrivate *data = entity->data;
926 ADG_SET(data->flags,
927 MODEL_MATRIX_APPLIED | PAPER_MATRIX_APPLIED | MODEL_APPLIED);
930 static const AdgMatrix *
931 get_model_matrix(AdgEntity *entity)
933 AdgEntityPrivate *data = entity->data;
935 return adg_entity_get_model_matrix((AdgEntity *) data->parent);
938 static const AdgMatrix *
939 get_paper_matrix(AdgEntity *entity)
941 AdgEntityPrivate *data = entity->data;
943 return adg_entity_get_paper_matrix((AdgEntity *) data->parent);