Updated "GNU Library General License" to "GNU Lesser General License
[adg.git] / adg / adg-container.c
blob3ceda9a1649a516c106910b68bd5dc61c84e96a2
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2008, 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:container
23 * @title: AdgContainer
24 * @short_description: Base class for entity that can contain other entities
26 * The #AdgContainer is an entity that implements the #GContainerable interface.
27 * Each AdgContainer has its paper matrix (#AdgContainer:paper_matrix) to be
28 * used on paper-dependent references (such as font and arrow sizes, line
29 * thickness etc...) and a model matrix usually applied to the model view. See
30 * http://www.entidi.it/adg/tutorial/view/3 for details on this topic.
32 * This means an AdgContainer can be thought as a group of entities with the
33 * same geometrical identity (same scale, reference point ecc...).
36 #include "adg-container.h"
37 #include "adg-container-private.h"
38 #include "adg-intl.h"
40 #include <gcontainer/gcontainer.h>
42 #define PARENT_CLASS ((AdgEntityClass *) adg_container_parent_class)
45 enum {
46 PROP_0,
47 PROP_CHILD,
48 PROP_MODEL_TRANSFORMATION,
49 PROP_PAPER_TRANSFORMATION
53 static void containerable_init (GContainerableIface *iface);
54 static void get_property (GObject *object,
55 guint prop_id,
56 GValue *value,
57 GParamSpec *pspec);
58 static void set_property (GObject *object,
59 guint prop_id,
60 const GValue *value,
61 GParamSpec *pspec);
62 static const AdgMatrix *get_model_matrix (AdgEntity *entity);
63 static const AdgMatrix *get_paper_matrix (AdgEntity *entity);
64 static void model_matrix_changed (AdgEntity *entity,
65 AdgMatrix *parent_matrix);
66 static void paper_matrix_changed (AdgEntity *entity,
67 AdgMatrix *parent_matrix);
68 static GSList * get_children (GContainerable *containerable);
69 static gboolean add (GContainerable *containerable,
70 GChildable *childable);
71 static gboolean remove (GContainerable *containerable,
72 GChildable *childable);
73 static void invalidate (AdgEntity *entity);
74 static void render (AdgEntity *entity,
75 cairo_t *cr);
78 G_DEFINE_TYPE_EXTENDED(AdgContainer, adg_container,
79 ADG_TYPE_ENTITY, 0,
80 G_IMPLEMENT_INTERFACE(G_TYPE_CONTAINERABLE,
81 containerable_init))
84 static void
85 adg_container_class_init(AdgContainerClass *klass)
87 GObjectClass *gobject_class;
88 AdgEntityClass *entity_class;
89 GParamSpec *param;
91 gobject_class = (GObjectClass *) klass;
92 entity_class = (AdgEntityClass *) klass;
94 g_type_class_add_private(klass, sizeof(AdgContainerPrivate));
96 gobject_class->get_property = get_property;
97 gobject_class->set_property = set_property;
98 gobject_class->dispose = g_containerable_dispose;
100 entity_class->model_matrix_changed = model_matrix_changed;
101 entity_class->paper_matrix_changed = paper_matrix_changed;
102 entity_class->get_model_matrix = get_model_matrix;
103 entity_class->get_paper_matrix = get_paper_matrix;
104 entity_class->invalidate = invalidate;
105 entity_class->render = render;
107 g_object_class_override_property(gobject_class, PROP_CHILD, "child");
109 param = g_param_spec_boxed("model-transformation",
110 P_("The model transformation"),
111 P_("The model transformation to be applied to this container and its children entities"),
112 ADG_TYPE_MATRIX, G_PARAM_READWRITE);
113 g_object_class_install_property(gobject_class,
114 PROP_MODEL_TRANSFORMATION, param);
116 param = g_param_spec_boxed("paper-transformation",
117 P_("The paper transformation"),
118 P_("The paper transformation to be applied to this container and its children entities"),
119 ADG_TYPE_MATRIX, G_PARAM_READWRITE);
120 g_object_class_install_property(gobject_class,
121 PROP_PAPER_TRANSFORMATION, param);
124 static void
125 containerable_init(GContainerableIface *iface)
127 iface->get_children = get_children;
128 iface->add = add;
129 iface->remove = remove;
132 static void
133 adg_container_init(AdgContainer *container)
135 AdgContainerPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE(container,
136 ADG_TYPE_CONTAINER,
137 AdgContainerPrivate);
139 priv->children = NULL;
140 cairo_matrix_init_identity(&priv->model_transformation);
141 cairo_matrix_init_identity(&priv->paper_transformation);
142 cairo_matrix_init_identity(&priv->model_matrix);
143 cairo_matrix_init_identity(&priv->paper_matrix);
145 container->priv = priv;
148 static void
149 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
151 AdgContainer *container = (AdgContainer *) object;
153 switch (prop_id) {
154 case PROP_MODEL_TRANSFORMATION:
155 g_value_set_boxed(value, &container->priv->model_transformation);
156 break;
157 case PROP_PAPER_TRANSFORMATION:
158 g_value_set_boxed(value, &container->priv->paper_transformation);
159 break;
160 default:
161 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
162 break;
166 static void
167 set_property(GObject *object,
168 guint prop_id, const GValue *value, GParamSpec *pspec)
170 AdgContainer *container = (AdgContainer *) object;
172 switch (prop_id) {
173 case PROP_CHILD:
174 g_containerable_add((GContainerable *) container,
175 g_value_get_object(value));
176 break;
177 case PROP_MODEL_TRANSFORMATION:
178 adg_matrix_set(&container->priv->model_transformation,
179 g_value_get_boxed(value));
180 break;
181 case PROP_PAPER_TRANSFORMATION:
182 adg_matrix_set(&container->priv->paper_transformation,
183 g_value_get_boxed(value));
184 break;
185 default:
186 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
191 static GSList *
192 get_children(GContainerable *containerable)
194 AdgContainer *container = (AdgContainer *) containerable;
196 return g_slist_copy(container->priv->children);
199 static gboolean
200 add(GContainerable *containerable, GChildable *childable)
202 AdgContainer *container = (AdgContainer *) containerable;
204 container->priv->children =
205 g_slist_append(container->priv->children, childable);
206 return TRUE;
209 static gboolean
210 remove(GContainerable *containerable, GChildable *childable)
212 AdgContainer *container;
213 GSList *node;
215 container = (AdgContainer *) containerable;
216 node = g_slist_find(container->priv->children, childable);
218 if (!node)
219 return FALSE;
221 container->priv->children =
222 g_slist_delete_link(container->priv->children, node);
223 return TRUE;
227 static void
228 model_matrix_changed(AdgEntity *entity, AdgMatrix *parent_matrix)
230 AdgContainer *container = (AdgContainer *) entity;
232 PARENT_CLASS->model_matrix_changed(entity, parent_matrix);
234 if (parent_matrix)
235 cairo_matrix_multiply(&container->priv->model_matrix,
236 parent_matrix,
237 &container->priv->model_transformation);
238 else
239 adg_matrix_set(&container->priv->model_matrix,
240 &container->priv->model_transformation);
242 g_containerable_propagate_by_name((GContainerable *) entity,
243 "model-matrix-changed",
244 &container->priv->model_matrix);
247 static void
248 paper_matrix_changed(AdgEntity *entity, AdgMatrix *parent_matrix)
250 AdgContainer *container = (AdgContainer *) entity;
252 PARENT_CLASS->paper_matrix_changed(entity, parent_matrix);
254 if (parent_matrix)
255 cairo_matrix_multiply(&container->priv->paper_matrix,
256 parent_matrix,
257 &container->priv->paper_transformation);
258 else
259 adg_matrix_set(&container->priv->paper_matrix,
260 &container->priv->paper_transformation);
262 g_containerable_propagate_by_name((GContainerable *) entity,
263 "paper-matrix-changed",
264 &container->priv->paper_matrix);
267 static const AdgMatrix *
268 get_model_matrix(AdgEntity *entity)
270 return &((AdgContainer *) entity)->priv->model_matrix;
273 static const AdgMatrix *
274 get_paper_matrix(AdgEntity *entity)
276 return &((AdgContainer *) entity)->priv->paper_matrix;
280 static void
281 invalidate(AdgEntity *entity)
283 g_containerable_propagate_by_name((GContainerable *) entity,
284 "invalidate", NULL);
287 static void
288 render(AdgEntity *entity, cairo_t *cr)
290 cairo_set_matrix(cr, adg_entity_get_model_matrix(entity));
291 g_containerable_propagate_by_name((GContainerable *) entity,
292 "render", cr);
293 PARENT_CLASS->render(entity, cr);
297 const AdgMatrix *
298 adg_container_get_model_transformation(AdgContainer *container)
300 g_return_val_if_fail(ADG_IS_CONTAINER(container), NULL);
301 return &container->priv->model_transformation;
304 void
305 adg_container_set_model_transformation(AdgContainer *container,
306 AdgMatrix *transformation)
308 AdgEntity *entity;
309 AdgEntity *parent;
310 const AdgMatrix *parent_matrix;
312 g_return_if_fail(ADG_IS_CONTAINER(container));
313 g_return_if_fail(transformation != NULL);
315 entity = (AdgEntity *) container;
316 parent = (AdgEntity *) g_childable_get_parent((GChildable *) entity);
317 parent_matrix = parent ? adg_entity_get_model_matrix(parent) : NULL;
319 adg_matrix_set(&container->priv->model_transformation, transformation);
320 adg_entity_model_matrix_changed(entity, parent_matrix);
323 const AdgMatrix *
324 adg_container_get_paper_transformation(AdgContainer *container)
326 g_return_val_if_fail(ADG_IS_CONTAINER(container), NULL);
327 return &container->priv->paper_transformation;
330 void
331 adg_container_set_paper_transformation(AdgContainer *container,
332 AdgMatrix *transformation)
334 AdgEntity *entity;
335 AdgEntity *parent;
336 const AdgMatrix *parent_matrix;
338 g_return_if_fail(ADG_IS_CONTAINER(container));
339 g_return_if_fail(transformation != NULL);
341 entity = (AdgEntity *) container;
342 parent = (AdgEntity *) g_childable_get_parent((GChildable *) entity);
343 parent_matrix = parent ? adg_entity_get_paper_matrix(parent) : NULL;
345 adg_matrix_set(&container->priv->paper_transformation, transformation);
346 adg_entity_paper_matrix_changed(entity, parent_matrix);