adg: refactored _adg_read_cairo_path()
[adg.git] / src / adg / adg-stroke.c
blob9ee0be6309f990574a347807184dbc1ace2a1bd8
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011,2012,2013 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.
27 * Since: 1.0
28 **/
30 /**
31 * AdgStroke:
33 * All fields are private and should not be used directly.
34 * Use its public methods instead.
36 * Since: 1.0
37 **/
40 #include "adg-internal.h"
41 #include "adg-dress.h"
42 #include "adg-dress-builtins.h"
43 #include "adg-style.h"
44 #include "adg-dash.h"
45 #include "adg-line-style.h"
46 #include "adg-model.h"
47 #include "adg-trail.h"
49 #include "adg-stroke.h"
50 #include "adg-stroke-private.h"
52 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_stroke_parent_class)
53 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_stroke_parent_class)
56 G_DEFINE_TYPE(AdgStroke, adg_stroke, ADG_TYPE_ENTITY)
58 enum {
59 PROP_0,
60 PROP_LINE_DRESS,
61 PROP_TRAIL
65 static void _adg_dispose (GObject *object);
66 static void _adg_get_property (GObject *object,
67 guint param_id,
68 GValue *value,
69 GParamSpec *pspec);
70 static void _adg_set_property (GObject *object,
71 guint param_id,
72 const GValue *value,
73 GParamSpec *pspec);
74 static void _adg_global_changed (AdgEntity *entity);
75 static void _adg_local_changed (AdgEntity *entity);
76 static void _adg_arrange (AdgEntity *entity);
77 static void _adg_render (AdgEntity *entity,
78 cairo_t *cr);
79 static void _adg_unset_trail (AdgStroke *stroke);
82 static void
83 adg_stroke_class_init(AdgStrokeClass *klass)
85 GObjectClass *gobject_class;
86 AdgEntityClass *entity_class;
87 GParamSpec *param;
89 gobject_class = (GObjectClass *) klass;
90 entity_class = (AdgEntityClass *) klass;
92 g_type_class_add_private(klass, sizeof(AdgStrokePrivate));
94 gobject_class->dispose = _adg_dispose;
95 gobject_class->get_property = _adg_get_property;
96 gobject_class->set_property = _adg_set_property;
98 entity_class->global_changed = _adg_global_changed;
99 entity_class->local_changed = _adg_local_changed;
100 entity_class->arrange = _adg_arrange;
101 entity_class->render = _adg_render;
103 param = adg_param_spec_dress("line-dress",
104 P_("Line Dress"),
105 P_("The dress to use for stroking this entity"),
106 ADG_DRESS_LINE_STROKE,
107 G_PARAM_READWRITE);
108 g_object_class_install_property(gobject_class, PROP_LINE_DRESS, param);
110 param = g_param_spec_object("trail",
111 P_("Trail"),
112 P_("The trail to be stroked"),
113 ADG_TYPE_TRAIL,
114 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
115 g_object_class_install_property(gobject_class, PROP_TRAIL, param);
118 static void
119 adg_stroke_init(AdgStroke *stroke)
121 AdgStrokePrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(stroke,
122 ADG_TYPE_STROKE,
123 AdgStrokePrivate);
125 data->line_dress = ADG_DRESS_LINE_STROKE;
126 data->trail = NULL;
128 stroke->data = data;
131 static void
132 _adg_dispose(GObject *object)
134 AdgStroke *stroke = (AdgStroke *) object;
136 adg_stroke_set_trail(stroke, NULL);
138 if (_ADG_OLD_OBJECT_CLASS->dispose)
139 _ADG_OLD_OBJECT_CLASS->dispose(object);
142 static void
143 _adg_get_property(GObject *object, guint prop_id,
144 GValue *value, GParamSpec *pspec)
146 AdgStrokePrivate *data = ((AdgStroke *) object)->data;
148 switch (prop_id) {
149 case PROP_LINE_DRESS:
150 g_value_set_int(value, data->line_dress);
151 break;
152 case PROP_TRAIL:
153 g_value_set_object(value, data->trail);
154 break;
155 default:
156 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
157 break;
161 static void
162 _adg_set_property(GObject *object, guint prop_id,
163 const GValue *value, GParamSpec *pspec)
165 AdgStrokePrivate *data = ((AdgStroke *) object)->data;
166 AdgTrail *old_trail;
168 switch (prop_id) {
169 case PROP_LINE_DRESS:
170 data->line_dress = g_value_get_int(value);
171 break;
172 case PROP_TRAIL:
173 old_trail = data->trail;
174 data->trail = g_value_get_object(value);
176 if (data->trail != old_trail) {
177 if (data->trail) {
178 g_object_weak_ref((GObject *) data->trail,
179 (GWeakNotify) _adg_unset_trail, object);
180 adg_model_add_dependency((AdgModel *) data->trail,
181 (AdgEntity *) object);
183 if (old_trail) {
184 g_object_weak_unref((GObject *) old_trail,
185 (GWeakNotify) _adg_unset_trail, object);
186 adg_model_remove_dependency((AdgModel *) old_trail,
187 (AdgEntity *) object);
190 break;
191 default:
192 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
193 break;
199 * adg_stroke_new:
200 * @trail: the #AdgTrail to stroke
202 * Creates a new stroke entity based on the @trail model.
203 * @trail can be %NULL, in which case an empty stroke is created.
205 * Returns: the newly created stroke entity
207 * Since: 1.0
209 AdgStroke *
210 adg_stroke_new(AdgTrail *trail)
212 return g_object_new(ADG_TYPE_STROKE, "trail", trail, NULL);
216 * adg_stroke_set_line_dress:
217 * @stroke: an #AdgStroke
218 * @dress: the new #AdgDress to use
220 * Sets a new line dress for rendering @stroke. The new dress
221 * must be related to the original dress for this property:
222 * you cannot set a dress used for line styles to a dress
223 * managing fonts.
225 * The check is done by calling adg_dress_are_related() with
226 * @dress and the previous dress as arguments. Check out its
227 * documentation for details on what is a related dress.
229 * Since: 1.0
231 void
232 adg_stroke_set_line_dress(AdgStroke *stroke, AdgDress dress)
234 g_return_if_fail(ADG_IS_STROKE(stroke));
235 g_object_set(stroke, "line-dress", dress, NULL);
239 * adg_stroke_get_line_dress:
240 * @stroke: an #AdgStroke
242 * Gets the line dress to be used in rendering @stroke.
244 * Returns: (transfer none): the current line dress.
246 * Since: 1.0
248 AdgDress
249 adg_stroke_get_line_dress(AdgStroke *stroke)
251 AdgStrokePrivate *data;
253 g_return_val_if_fail(ADG_IS_STROKE(stroke), ADG_DRESS_UNDEFINED);
255 data = stroke->data;
257 return data->line_dress;
261 * adg_stroke_set_trail:
262 * @stroke: an #AdgStroke
263 * @trail: the new #AdgTrail to bind
265 * Sets @trail as the new trail to be stroked by @stroke.
267 * Since: 1.0
269 void
270 adg_stroke_set_trail(AdgStroke *stroke, AdgTrail *trail)
272 g_return_if_fail(ADG_IS_STROKE(stroke));
273 g_object_set(stroke, "trail", trail, NULL);
277 * adg_stroke_get_trail:
278 * @stroke: an #AdgStroke
280 * Gets the #AdgTrail bound to this @stroke entity.
281 * The returned trail is owned by @stroke and should not
282 * be freed or modified.
284 * Returns: (transfer none): the requested #AdgTrail or %NULL on errors.
286 * Since: 1.0
288 AdgTrail *
289 adg_stroke_get_trail(AdgStroke *stroke)
291 AdgStrokePrivate *data;
293 g_return_val_if_fail(ADG_IS_STROKE(stroke), NULL);
295 data = stroke->data;
297 return data->trail;
301 static void
302 _adg_global_changed(AdgEntity *entity)
304 if (_ADG_OLD_ENTITY_CLASS->global_changed)
305 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
307 adg_entity_invalidate(entity);
310 static void
311 _adg_local_changed(AdgEntity *entity)
313 if (_ADG_OLD_ENTITY_CLASS->local_changed)
314 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
316 adg_entity_invalidate(entity);
319 static void
320 _adg_arrange(AdgEntity *entity)
322 AdgStroke *stroke;
323 AdgStrokePrivate *data;
324 CpmlExtents extents;
326 /* Check for cached result */
327 if (adg_entity_get_extents(entity)->is_defined)
328 return;
330 stroke = (AdgStroke *) entity;
331 data = stroke->data;
333 cpml_extents_copy(&extents, adg_trail_get_extents(data->trail));
334 cpml_extents_transform(&extents, adg_entity_get_local_matrix(entity));
335 cpml_extents_transform(&extents, adg_entity_get_global_matrix(entity));
337 adg_entity_set_extents(entity, &extents);
340 static void
341 _adg_render(AdgEntity *entity, cairo_t *cr)
343 AdgStroke *stroke;
344 AdgStrokePrivate *data;
345 const cairo_path_t *cairo_path;
347 stroke = (AdgStroke *) entity;
348 data = stroke->data;
349 cairo_path = adg_trail_get_cairo_path(data->trail);
351 if (cairo_path != NULL) {
352 cairo_transform(cr, adg_entity_get_global_matrix(entity));
354 cairo_save(cr);
355 cairo_transform(cr, adg_entity_get_local_matrix(entity));
356 cairo_append_path(cr, cairo_path);
357 cairo_restore(cr);
359 adg_entity_apply_dress(entity, data->line_dress, cr);
360 cairo_stroke(cr);
364 static void
365 _adg_unset_trail(AdgStroke *stroke)
367 g_object_set(stroke, "trail", NULL, NULL);