[ADG] Avoid to forcibly set the CTM on the cr
[adg.git] / src / adg / adg-stroke.c
blobbc5c57734edd20dcb1857ef24300af376da20254
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010 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-stroke
23 * @short_description: A stroked entity
25 * The #AdgStroke object is a stroked representation of an #AdgTrail model.
26 **/
28 /**
29 * AdgStroke:
31 * All fields are private and should not be used directly.
32 * Use its public methods instead.
33 **/
36 #include "adg-internal.h"
37 #include "adg-stroke.h"
38 #include "adg-stroke-private.h"
39 #include "adg-dress-builtins.h"
40 #include "adg-line-style.h"
42 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_stroke_parent_class)
43 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_stroke_parent_class)
46 G_DEFINE_TYPE(AdgStroke, adg_stroke, ADG_TYPE_ENTITY);
48 enum {
49 PROP_0,
50 PROP_LINE_DRESS,
51 PROP_TRAIL
55 static void _adg_dispose (GObject *object);
56 static void _adg_get_property (GObject *object,
57 guint param_id,
58 GValue *value,
59 GParamSpec *pspec);
60 static void _adg_set_property (GObject *object,
61 guint param_id,
62 const GValue *value,
63 GParamSpec *pspec);
64 static void _adg_global_changed (AdgEntity *entity);
65 static void _adg_local_changed (AdgEntity *entity);
66 static void _adg_arrange (AdgEntity *entity);
67 static void _adg_render (AdgEntity *entity,
68 cairo_t *cr);
69 static void _adg_unset_trail (AdgStroke *stroke);
72 static void
73 adg_stroke_class_init(AdgStrokeClass *klass)
75 GObjectClass *gobject_class;
76 AdgEntityClass *entity_class;
77 GParamSpec *param;
79 gobject_class = (GObjectClass *) klass;
80 entity_class = (AdgEntityClass *) klass;
82 g_type_class_add_private(klass, sizeof(AdgStrokePrivate));
84 gobject_class->dispose = _adg_dispose;
85 gobject_class->get_property = _adg_get_property;
86 gobject_class->set_property = _adg_set_property;
88 entity_class->global_changed = _adg_global_changed;
89 entity_class->local_changed = _adg_local_changed;
90 entity_class->arrange = _adg_arrange;
91 entity_class->render = _adg_render;
93 param = adg_param_spec_dress("line-dress",
94 P_("Line Dress"),
95 P_("The dress to use for stroking this entity"),
96 ADG_DRESS_LINE_STROKE,
97 G_PARAM_READWRITE);
98 g_object_class_install_property(gobject_class, PROP_LINE_DRESS, param);
100 param = g_param_spec_object("trail",
101 P_("Trail"),
102 P_("The trail to be stroked"),
103 ADG_TYPE_TRAIL,
104 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
105 g_object_class_install_property(gobject_class, PROP_TRAIL, param);
108 static void
109 adg_stroke_init(AdgStroke *stroke)
111 AdgStrokePrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(stroke,
112 ADG_TYPE_STROKE,
113 AdgStrokePrivate);
115 data->line_dress = ADG_DRESS_LINE_STROKE;
116 data->trail = NULL;
118 stroke->data = data;
121 static void
122 _adg_dispose(GObject *object)
124 AdgStroke *stroke = (AdgStroke *) object;
126 adg_stroke_set_trail(stroke, NULL);
128 if (_ADG_OLD_OBJECT_CLASS->dispose)
129 _ADG_OLD_OBJECT_CLASS->dispose(object);
132 static void
133 _adg_get_property(GObject *object, guint prop_id,
134 GValue *value, GParamSpec *pspec)
136 AdgStrokePrivate *data = ((AdgStroke *) object)->data;
138 switch (prop_id) {
139 case PROP_LINE_DRESS:
140 g_value_set_int(value, data->line_dress);
141 break;
142 case PROP_TRAIL:
143 g_value_set_object(value, data->trail);
144 break;
145 default:
146 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
147 break;
151 static void
152 _adg_set_property(GObject *object, guint prop_id,
153 const GValue *value, GParamSpec *pspec)
155 AdgStrokePrivate *data = ((AdgStroke *) object)->data;
156 AdgTrail *old_trail;
158 switch (prop_id) {
159 case PROP_LINE_DRESS:
160 data->line_dress = g_value_get_int(value);
161 break;
162 case PROP_TRAIL:
163 old_trail = data->trail;
164 data->trail = g_value_get_object(value);
166 if (data->trail != old_trail) {
167 if (data->trail) {
168 g_object_weak_ref((GObject *) data->trail,
169 (GWeakNotify) _adg_unset_trail, object);
170 adg_model_add_dependency((AdgModel *) data->trail,
171 (AdgEntity *) object);
173 if (old_trail) {
174 g_object_weak_unref((GObject *) old_trail,
175 (GWeakNotify) _adg_unset_trail, object);
176 adg_model_remove_dependency((AdgModel *) old_trail,
177 (AdgEntity *) object);
180 break;
181 default:
182 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
183 break;
189 * adg_stroke_new:
190 * @trail: the #AdgTrail to stroke
192 * Creates a new stroke entity based on the @trail model.
193 * @trail can be %NULL, in which case an empty stroke is created.
195 * Returns: the newly created stroke entity
197 AdgStroke *
198 adg_stroke_new(AdgTrail *trail)
200 return g_object_new(ADG_TYPE_STROKE, "trail", trail, NULL);
204 * adg_stroke_set_line_dress:
205 * @stroke: an #AdgStroke
206 * @dress: the new #AdgDress to use
208 * Sets a new line dress for rendering @stroke. The new dress
209 * must be related to the original dress for this property:
210 * you cannot set a dress used for line styles to a dress
211 * managing fonts.
213 * The check is done by calling adg_dress_are_related() with
214 * @dress and the previous dress as arguments. Check out its
215 * documentation for details on what is a related dress.
217 void
218 adg_stroke_set_line_dress(AdgStroke *stroke, AdgDress dress)
220 g_return_if_fail(ADG_IS_STROKE(stroke));
221 g_object_set((GObject *) stroke, "line-dress", dress, NULL);
225 * adg_stroke_get_line_dress:
226 * @stroke: an #AdgStroke
228 * Gets the line dress to be used in rendering @stroke.
230 * Returns: the current line dress
232 AdgDress
233 adg_stroke_get_line_dress(AdgStroke *stroke)
235 AdgStrokePrivate *data;
237 g_return_val_if_fail(ADG_IS_STROKE(stroke), ADG_DRESS_UNDEFINED);
239 data = stroke->data;
241 return data->line_dress;
245 * adg_stroke_set_trail:
246 * @stroke: an #AdgStroke
247 * @trail: the new #AdgTrail to bind
249 * Sets @trail as the new trail to be stroked by @stroke.
251 void
252 adg_stroke_set_trail(AdgStroke *stroke, AdgTrail *trail)
254 g_return_if_fail(ADG_IS_STROKE(stroke));
255 g_object_set(stroke, "trail", trail, NULL);
259 * adg_stroke_get_trail:
260 * @stroke: an #AdgStroke
262 * Gets the #AdgTrail bound to this @stroke entity.
264 * Returns: the requested #AdgTrail or %NULL on errors
266 AdgTrail *
267 adg_stroke_get_trail(AdgStroke *stroke)
269 AdgStrokePrivate *data;
271 g_return_val_if_fail(ADG_IS_STROKE(stroke), NULL);
273 data = stroke->data;
275 return data->trail;
279 static void
280 _adg_global_changed(AdgEntity *entity)
282 if (_ADG_OLD_ENTITY_CLASS->global_changed)
283 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
285 adg_entity_invalidate(entity);
288 static void
289 _adg_local_changed(AdgEntity *entity)
291 if (_ADG_OLD_ENTITY_CLASS->local_changed)
292 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
294 adg_entity_invalidate(entity);
297 static void
298 _adg_arrange(AdgEntity *entity)
300 AdgStroke *stroke;
301 AdgStrokePrivate *data;
302 CpmlExtents extents;
304 /* Check for cached result */
305 if (adg_entity_get_extents(entity)->is_defined)
306 return;
308 stroke = (AdgStroke *) entity;
309 data = stroke->data;
311 cpml_extents_copy(&extents, adg_trail_get_extents(data->trail));
312 cpml_extents_transform(&extents, adg_entity_get_local_matrix(entity));
313 cpml_extents_transform(&extents, adg_entity_get_global_matrix(entity));
315 adg_entity_set_extents(entity, &extents);
318 static void
319 _adg_render(AdgEntity *entity, cairo_t *cr)
321 AdgStroke *stroke;
322 AdgStrokePrivate *data;
323 const cairo_path_t *cairo_path;
325 stroke = (AdgStroke *) entity;
326 data = stroke->data;
327 cairo_path = adg_trail_get_cairo_path(data->trail);
329 if (cairo_path != NULL) {
330 cairo_transform(cr, adg_entity_get_global_matrix(entity));
332 cairo_save(cr);
333 cairo_transform(cr, adg_entity_get_local_matrix(entity));
334 cairo_append_path(cr, cairo_path);
335 cairo_restore(cr);
337 adg_entity_apply_dress(entity, data->line_dress, cr);
338 cairo_stroke(cr);
342 static void
343 _adg_unset_trail(AdgStroke *stroke)
345 g_object_set(stroke, "trail", NULL, NULL);