doc: update copyright line for 2021
[adg.git] / src / adg / adg-stroke.c
blobb074aa41d86a1bcaa6aab33fc177f74dce9c803c
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2021 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_WITH_PRIVATE(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 gobject_class->dispose = _adg_dispose;
93 gobject_class->get_property = _adg_get_property;
94 gobject_class->set_property = _adg_set_property;
96 entity_class->global_changed = _adg_global_changed;
97 entity_class->local_changed = _adg_local_changed;
98 entity_class->arrange = _adg_arrange;
99 entity_class->render = _adg_render;
101 param = adg_param_spec_dress("line-dress",
102 P_("Line Dress"),
103 P_("The dress to use for stroking this entity"),
104 ADG_DRESS_LINE_STROKE,
105 G_PARAM_READWRITE);
106 g_object_class_install_property(gobject_class, PROP_LINE_DRESS, param);
108 param = g_param_spec_object("trail",
109 P_("Trail"),
110 P_("The trail to be stroked"),
111 ADG_TYPE_TRAIL,
112 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
113 g_object_class_install_property(gobject_class, PROP_TRAIL, param);
116 static void
117 adg_stroke_init(AdgStroke *stroke)
119 AdgStrokePrivate *data = adg_stroke_get_instance_private(stroke);
120 data->line_dress = ADG_DRESS_LINE_STROKE;
121 data->trail = NULL;
124 static void
125 _adg_dispose(GObject *object)
127 AdgStroke *stroke = (AdgStroke *) object;
129 adg_stroke_set_trail(stroke, NULL);
131 if (_ADG_OLD_OBJECT_CLASS->dispose)
132 _ADG_OLD_OBJECT_CLASS->dispose(object);
135 static void
136 _adg_get_property(GObject *object, guint prop_id,
137 GValue *value, GParamSpec *pspec)
139 AdgStrokePrivate *data = adg_stroke_get_instance_private((AdgStroke *) object);
141 switch (prop_id) {
142 case PROP_LINE_DRESS:
143 g_value_set_enum(value, data->line_dress);
144 break;
145 case PROP_TRAIL:
146 g_value_set_object(value, data->trail);
147 break;
148 default:
149 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
150 break;
154 static void
155 _adg_set_property(GObject *object, guint prop_id,
156 const GValue *value, GParamSpec *pspec)
158 AdgStrokePrivate *data = adg_stroke_get_instance_private((AdgStroke *) object);
159 AdgTrail *old_trail;
161 switch (prop_id) {
162 case PROP_LINE_DRESS:
163 data->line_dress = g_value_get_enum(value);
164 break;
165 case PROP_TRAIL:
166 old_trail = data->trail;
167 data->trail = g_value_get_object(value);
169 if (data->trail != old_trail) {
170 if (data->trail != NULL) {
171 g_object_ref(data->trail);
172 g_object_weak_ref((GObject *) data->trail,
173 (GWeakNotify) _adg_unset_trail, object);
174 adg_model_add_dependency((AdgModel *) data->trail,
175 (AdgEntity *) object);
177 if (old_trail != NULL) {
178 g_object_unref(data->trail);
179 g_object_weak_unref((GObject *) old_trail,
180 (GWeakNotify) _adg_unset_trail, object);
181 adg_model_remove_dependency((AdgModel *) old_trail,
182 (AdgEntity *) object);
185 break;
186 default:
187 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
188 break;
194 * adg_stroke_new:
195 * @trail: the #AdgTrail to stroke
197 * Creates a new stroke entity based on the @trail model.
198 * @trail can be <constant>NULL</constant>, in which case
199 * an empty stroke is created.
201 * Returns: the newly created stroke entity
203 * Since: 1.0
205 AdgStroke *
206 adg_stroke_new(AdgTrail *trail)
208 return g_object_new(ADG_TYPE_STROKE, "trail", trail, NULL);
212 * adg_stroke_set_line_dress:
213 * @stroke: an #AdgStroke
214 * @dress: the new #AdgDress to use
216 * Sets a new line dress for rendering @stroke. The new dress
217 * must be related to the original dress for this property:
218 * you cannot set a dress used for line styles to a dress
219 * managing fonts.
221 * The check is done by calling adg_dress_are_related() with
222 * @dress and the previous dress as arguments. Check out its
223 * documentation for details on what is a related dress.
225 * Since: 1.0
227 void
228 adg_stroke_set_line_dress(AdgStroke *stroke, AdgDress dress)
230 g_return_if_fail(ADG_IS_STROKE(stroke));
231 g_object_set(stroke, "line-dress", dress, NULL);
235 * adg_stroke_get_line_dress:
236 * @stroke: an #AdgStroke
238 * Gets the line dress to be used in rendering @stroke.
240 * Returns: (transfer none): the current line dress.
242 * Since: 1.0
244 AdgDress
245 adg_stroke_get_line_dress(AdgStroke *stroke)
247 AdgStrokePrivate *data;
249 g_return_val_if_fail(ADG_IS_STROKE(stroke), ADG_DRESS_UNDEFINED);
251 data = adg_stroke_get_instance_private(stroke);
252 return data->line_dress;
256 * adg_stroke_set_trail:
257 * @stroke: an #AdgStroke
258 * @trail: (allow-none) (transfer none): the new #AdgTrail to bind
260 * Sets @trail as the new trail to be stroked by @stroke.
262 * Since: 1.0
264 void
265 adg_stroke_set_trail(AdgStroke *stroke, AdgTrail *trail)
267 g_return_if_fail(ADG_IS_STROKE(stroke));
268 g_object_set(stroke, "trail", trail, NULL);
272 * adg_stroke_get_trail:
273 * @stroke: an #AdgStroke
275 * Gets the #AdgTrail bound to this @stroke entity.
276 * The returned trail is owned by @stroke and should not
277 * be freed or modified.
279 * Returns: (transfer none): the requested #AdgTrail or <constant>NULL</constant> on errors.
281 * Since: 1.0
283 AdgTrail *
284 adg_stroke_get_trail(AdgStroke *stroke)
286 AdgStrokePrivate *data;
288 g_return_val_if_fail(ADG_IS_STROKE(stroke), NULL);
290 data = adg_stroke_get_instance_private(stroke);
291 return data->trail;
295 static void
296 _adg_global_changed(AdgEntity *entity)
298 if (_ADG_OLD_ENTITY_CLASS->global_changed)
299 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
301 adg_entity_invalidate(entity);
304 static void
305 _adg_local_changed(AdgEntity *entity)
307 if (_ADG_OLD_ENTITY_CLASS->local_changed)
308 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
310 adg_entity_invalidate(entity);
313 static void
314 _adg_arrange(AdgEntity *entity)
316 AdgStrokePrivate *data;
317 const CpmlExtents *trail_extents;
318 CpmlExtents extents;
320 /* Check for cached result */
321 if (adg_entity_get_extents(entity)->is_defined)
322 return;
324 data = adg_stroke_get_instance_private((AdgStroke *) entity);
325 trail_extents = adg_trail_get_extents(data->trail);
327 /* Ensure a trail is bound to this entity */
328 if (trail_extents == NULL)
329 return;
331 cpml_extents_copy(&extents, trail_extents);
332 cpml_extents_transform(&extents, adg_entity_get_local_matrix(entity));
333 cpml_extents_transform(&extents, adg_entity_get_global_matrix(entity));
334 adg_entity_set_extents(entity, &extents);
337 static void
338 _adg_render(AdgEntity *entity, cairo_t *cr)
340 AdgStrokePrivate *data = adg_stroke_get_instance_private((AdgStroke *) entity);
341 const cairo_path_t *cairo_path = adg_trail_get_cairo_path(data->trail);
343 if (cairo_path != NULL) {
344 cairo_transform(cr, adg_entity_get_global_matrix(entity));
346 cairo_save(cr);
347 cairo_transform(cr, adg_entity_get_local_matrix(entity));
348 cairo_append_path(cr, cairo_path);
349 cairo_restore(cr);
351 adg_entity_apply_dress(entity, data->line_dress, cr);
352 cairo_stroke(cr);
356 static void
357 _adg_unset_trail(AdgStroke *stroke)
359 g_object_set(stroke, "trail", NULL, NULL);