adg: cosmetic refactoring on adg-canvas.c
[adg.git] / src / adg / adg-stroke.c
blob9413e80bfcdddabbf9ae18f6a7e2a176460041b7
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-style.h"
42 #include "adg-dash.h"
43 #include "adg-line-style.h"
44 #include "adg-model.h"
45 #include "adg-trail.h"
46 #include "adg-dress.h"
47 #include "adg-param-dress.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_enum(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_enum(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 != NULL) {
178 g_object_ref(data->trail);
179 g_object_weak_ref((GObject *) data->trail,
180 (GWeakNotify) _adg_unset_trail, object);
181 adg_model_add_dependency((AdgModel *) data->trail,
182 (AdgEntity *) object);
184 if (old_trail != NULL) {
185 g_object_unref(data->trail);
186 g_object_weak_unref((GObject *) old_trail,
187 (GWeakNotify) _adg_unset_trail, object);
188 adg_model_remove_dependency((AdgModel *) old_trail,
189 (AdgEntity *) object);
192 break;
193 default:
194 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
195 break;
201 * adg_stroke_new:
202 * @trail: the #AdgTrail to stroke
204 * Creates a new stroke entity based on the @trail model.
205 * @trail can be %NULL, in which case an empty stroke is created.
207 * Returns: the newly created stroke entity
209 * Since: 1.0
211 AdgStroke *
212 adg_stroke_new(AdgTrail *trail)
214 return g_object_new(ADG_TYPE_STROKE, "trail", trail, NULL);
218 * adg_stroke_set_line_dress:
219 * @stroke: an #AdgStroke
220 * @dress: the new #AdgDress to use
222 * Sets a new line dress for rendering @stroke. The new dress
223 * must be related to the original dress for this property:
224 * you cannot set a dress used for line styles to a dress
225 * managing fonts.
227 * The check is done by calling adg_dress_are_related() with
228 * @dress and the previous dress as arguments. Check out its
229 * documentation for details on what is a related dress.
231 * Since: 1.0
233 void
234 adg_stroke_set_line_dress(AdgStroke *stroke, AdgDress dress)
236 g_return_if_fail(ADG_IS_STROKE(stroke));
237 g_object_set(stroke, "line-dress", dress, NULL);
241 * adg_stroke_get_line_dress:
242 * @stroke: an #AdgStroke
244 * Gets the line dress to be used in rendering @stroke.
246 * Returns: (transfer none): the current line dress.
248 * Since: 1.0
250 AdgDress
251 adg_stroke_get_line_dress(AdgStroke *stroke)
253 AdgStrokePrivate *data;
255 g_return_val_if_fail(ADG_IS_STROKE(stroke), ADG_DRESS_UNDEFINED);
257 data = stroke->data;
259 return data->line_dress;
263 * adg_stroke_set_trail:
264 * @stroke: an #AdgStroke
265 * @trail: (allow-none) (transfer none): the new #AdgTrail to bind
267 * Sets @trail as the new trail to be stroked by @stroke.
269 * Since: 1.0
271 void
272 adg_stroke_set_trail(AdgStroke *stroke, AdgTrail *trail)
274 g_return_if_fail(ADG_IS_STROKE(stroke));
275 g_object_set(stroke, "trail", trail, NULL);
279 * adg_stroke_get_trail:
280 * @stroke: an #AdgStroke
282 * Gets the #AdgTrail bound to this @stroke entity.
283 * The returned trail is owned by @stroke and should not
284 * be freed or modified.
286 * Returns: (transfer none): the requested #AdgTrail or %NULL on errors.
288 * Since: 1.0
290 AdgTrail *
291 adg_stroke_get_trail(AdgStroke *stroke)
293 AdgStrokePrivate *data;
295 g_return_val_if_fail(ADG_IS_STROKE(stroke), NULL);
297 data = stroke->data;
299 return data->trail;
303 static void
304 _adg_global_changed(AdgEntity *entity)
306 if (_ADG_OLD_ENTITY_CLASS->global_changed)
307 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
309 adg_entity_invalidate(entity);
312 static void
313 _adg_local_changed(AdgEntity *entity)
315 if (_ADG_OLD_ENTITY_CLASS->local_changed)
316 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
318 adg_entity_invalidate(entity);
321 static void
322 _adg_arrange(AdgEntity *entity)
324 AdgStroke *stroke;
325 AdgStrokePrivate *data;
326 CpmlExtents extents;
328 /* Check for cached result */
329 if (adg_entity_get_extents(entity)->is_defined)
330 return;
332 stroke = (AdgStroke *) entity;
333 data = stroke->data;
335 cpml_extents_copy(&extents, adg_trail_get_extents(data->trail));
336 cpml_extents_transform(&extents, adg_entity_get_local_matrix(entity));
337 cpml_extents_transform(&extents, adg_entity_get_global_matrix(entity));
339 adg_entity_set_extents(entity, &extents);
342 static void
343 _adg_render(AdgEntity *entity, cairo_t *cr)
345 AdgStroke *stroke;
346 AdgStrokePrivate *data;
347 const cairo_path_t *cairo_path;
349 stroke = (AdgStroke *) entity;
350 data = stroke->data;
351 cairo_path = adg_trail_get_cairo_path(data->trail);
353 if (cairo_path != NULL) {
354 cairo_transform(cr, adg_entity_get_global_matrix(entity));
356 cairo_save(cr);
357 cairo_transform(cr, adg_entity_get_local_matrix(entity));
358 cairo_append_path(cr, cairo_path);
359 cairo_restore(cr);
361 adg_entity_apply_dress(entity, data->line_dress, cr);
362 cairo_stroke(cr);
366 static void
367 _adg_unset_trail(AdgStroke *stroke)
369 g_object_set(stroke, "trail", NULL, NULL);