doc: update copyright line for 2019
[adg.git] / src / adg / adg-stroke.c
blob039d80178288e113fad7ec13a9c73366da6be8d9
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2019 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 <constant>NULL</constant>, in which case
206 * an empty stroke is created.
208 * Returns: the newly created stroke entity
210 * Since: 1.0
212 AdgStroke *
213 adg_stroke_new(AdgTrail *trail)
215 return g_object_new(ADG_TYPE_STROKE, "trail", trail, NULL);
219 * adg_stroke_set_line_dress:
220 * @stroke: an #AdgStroke
221 * @dress: the new #AdgDress to use
223 * Sets a new line dress for rendering @stroke. The new dress
224 * must be related to the original dress for this property:
225 * you cannot set a dress used for line styles to a dress
226 * managing fonts.
228 * The check is done by calling adg_dress_are_related() with
229 * @dress and the previous dress as arguments. Check out its
230 * documentation for details on what is a related dress.
232 * Since: 1.0
234 void
235 adg_stroke_set_line_dress(AdgStroke *stroke, AdgDress dress)
237 g_return_if_fail(ADG_IS_STROKE(stroke));
238 g_object_set(stroke, "line-dress", dress, NULL);
242 * adg_stroke_get_line_dress:
243 * @stroke: an #AdgStroke
245 * Gets the line dress to be used in rendering @stroke.
247 * Returns: (transfer none): the current line dress.
249 * Since: 1.0
251 AdgDress
252 adg_stroke_get_line_dress(AdgStroke *stroke)
254 AdgStrokePrivate *data;
256 g_return_val_if_fail(ADG_IS_STROKE(stroke), ADG_DRESS_UNDEFINED);
258 data = stroke->data;
260 return data->line_dress;
264 * adg_stroke_set_trail:
265 * @stroke: an #AdgStroke
266 * @trail: (allow-none) (transfer none): the new #AdgTrail to bind
268 * Sets @trail as the new trail to be stroked by @stroke.
270 * Since: 1.0
272 void
273 adg_stroke_set_trail(AdgStroke *stroke, AdgTrail *trail)
275 g_return_if_fail(ADG_IS_STROKE(stroke));
276 g_object_set(stroke, "trail", trail, NULL);
280 * adg_stroke_get_trail:
281 * @stroke: an #AdgStroke
283 * Gets the #AdgTrail bound to this @stroke entity.
284 * The returned trail is owned by @stroke and should not
285 * be freed or modified.
287 * Returns: (transfer none): the requested #AdgTrail or <constant>NULL</constant> on errors.
289 * Since: 1.0
291 AdgTrail *
292 adg_stroke_get_trail(AdgStroke *stroke)
294 AdgStrokePrivate *data;
296 g_return_val_if_fail(ADG_IS_STROKE(stroke), NULL);
298 data = stroke->data;
300 return data->trail;
304 static void
305 _adg_global_changed(AdgEntity *entity)
307 if (_ADG_OLD_ENTITY_CLASS->global_changed)
308 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
310 adg_entity_invalidate(entity);
313 static void
314 _adg_local_changed(AdgEntity *entity)
316 if (_ADG_OLD_ENTITY_CLASS->local_changed)
317 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
319 adg_entity_invalidate(entity);
322 static void
323 _adg_arrange(AdgEntity *entity)
325 AdgStroke *stroke;
326 AdgStrokePrivate *data;
327 const CpmlExtents *trail_extents;
328 CpmlExtents extents;
330 /* Check for cached result */
331 if (adg_entity_get_extents(entity)->is_defined)
332 return;
334 stroke = (AdgStroke *) entity;
335 data = stroke->data;
336 trail_extents = adg_trail_get_extents(data->trail);
338 /* Ensure a trail is bound to this entity */
339 if (trail_extents == NULL)
340 return;
342 cpml_extents_copy(&extents, trail_extents);
343 cpml_extents_transform(&extents, adg_entity_get_local_matrix(entity));
344 cpml_extents_transform(&extents, adg_entity_get_global_matrix(entity));
345 adg_entity_set_extents(entity, &extents);
348 static void
349 _adg_render(AdgEntity *entity, cairo_t *cr)
351 AdgStroke *stroke;
352 AdgStrokePrivate *data;
353 const cairo_path_t *cairo_path;
355 stroke = (AdgStroke *) entity;
356 data = stroke->data;
357 cairo_path = adg_trail_get_cairo_path(data->trail);
359 if (cairo_path != NULL) {
360 cairo_transform(cr, adg_entity_get_global_matrix(entity));
362 cairo_save(cr);
363 cairo_transform(cr, adg_entity_get_local_matrix(entity));
364 cairo_append_path(cr, cairo_path);
365 cairo_restore(cr);
367 adg_entity_apply_dress(entity, data->line_dress, cr);
368 cairo_stroke(cr);
372 static void
373 _adg_unset_trail(AdgStroke *stroke)
375 g_object_set(stroke, "trail", NULL, NULL);