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.
23 * @short_description: A stroked entity
25 * The #AdgStroke object is a stroked representation of an #AdgTrail model.
33 * All fields are private and should not be used directly.
34 * Use its public methods instead.
40 #include "adg-internal.h"
41 #include "adg-style.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
)
65 static void _adg_dispose (GObject
*object
);
66 static void _adg_get_property (GObject
*object
,
70 static void _adg_set_property (GObject
*object
,
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
,
79 static void _adg_unset_trail (AdgStroke
*stroke
);
83 adg_stroke_class_init(AdgStrokeClass
*klass
)
85 GObjectClass
*gobject_class
;
86 AdgEntityClass
*entity_class
;
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",
103 P_("The dress to use for stroking this entity"),
104 ADG_DRESS_LINE_STROKE
,
106 g_object_class_install_property(gobject_class
, PROP_LINE_DRESS
, param
);
108 param
= g_param_spec_object("trail",
110 P_("The trail to be stroked"),
112 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
);
113 g_object_class_install_property(gobject_class
, PROP_TRAIL
, param
);
117 adg_stroke_init(AdgStroke
*stroke
)
119 AdgStrokePrivate
*data
= adg_stroke_get_instance_private(stroke
);
120 data
->line_dress
= ADG_DRESS_LINE_STROKE
;
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
);
136 _adg_get_property(GObject
*object
, guint prop_id
,
137 GValue
*value
, GParamSpec
*pspec
)
139 AdgStrokePrivate
*data
= adg_stroke_get_instance_private((AdgStroke
*) object
);
142 case PROP_LINE_DRESS
:
143 g_value_set_enum(value
, data
->line_dress
);
146 g_value_set_object(value
, data
->trail
);
149 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
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
);
162 case PROP_LINE_DRESS
:
163 data
->line_dress
= g_value_get_enum(value
);
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
);
187 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
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
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
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.
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.
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.
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.
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
);
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
);
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
);
314 _adg_arrange(AdgEntity
*entity
)
316 AdgStrokePrivate
*data
;
317 const CpmlExtents
*trail_extents
;
320 /* Check for cached result */
321 if (adg_entity_get_extents(entity
)->is_defined
)
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
)
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
);
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
));
347 cairo_transform(cr
, adg_entity_get_local_matrix(entity
));
348 cairo_append_path(cr
, cairo_path
);
351 adg_entity_apply_dress(entity
, data
->line_dress
, cr
);
357 _adg_unset_trail(AdgStroke
*stroke
)
359 g_object_set(stroke
, "trail", NULL
, NULL
);