[AdgTransformationMode] Renamed to AdgTransformMode
[adg.git] / adg / adg-stroke.c
blob5be1c67756ae24238106e3b8d2d60e0e2821a9cb
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009 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.
26 **/
28 /**
29 * AdgStroke:
31 * All fields are private and should not be used directly.
32 * Use its public methods instead.
33 **/
36 #include "adg-stroke.h"
37 #include "adg-stroke-private.h"
38 #include "adg-dress-builtins.h"
39 #include "adg-line-style.h"
40 #include "adg-intl.h"
42 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_stroke_parent_class)
43 #define PARENT_ENTITY_CLASS ((AdgEntityClass *) adg_stroke_parent_class)
46 enum {
47 PROP_0,
48 PROP_LINE_DRESS,
49 PROP_TRAIL
52 static void dispose (GObject *object);
53 static void get_property (GObject *object,
54 guint param_id,
55 GValue *value,
56 GParamSpec *pspec);
57 static void set_property (GObject *object,
58 guint param_id,
59 const GValue *value,
60 GParamSpec *pspec);
61 static void local_changed (AdgEntity *entity);
62 static void arrange (AdgEntity *entity);
63 static void render (AdgEntity *entity,
64 cairo_t *cr);
65 static gboolean set_trail (AdgStroke *stroke,
66 AdgTrail *trail);
67 static void unset_trail (AdgStroke *stroke);
70 G_DEFINE_TYPE(AdgStroke, adg_stroke, ADG_TYPE_ENTITY);
73 static void
74 adg_stroke_class_init(AdgStrokeClass *klass)
76 GObjectClass *gobject_class;
77 AdgEntityClass *entity_class;
78 GParamSpec *param;
80 gobject_class = (GObjectClass *) klass;
81 entity_class = (AdgEntityClass *) klass;
83 g_type_class_add_private(klass, sizeof(AdgStrokePrivate));
85 gobject_class->dispose = dispose;
86 gobject_class->get_property = get_property;
87 gobject_class->set_property = set_property;
89 entity_class->local_changed = local_changed;
90 entity_class->arrange = arrange;
91 entity_class->render = render;
93 param = adg_param_spec_dress("line-dress",
94 P_("Line Dress"),
95 P_("The dress to use for stroking this entity"),
96 ADG_DRESS_LINE_MEDIUM,
97 G_PARAM_READWRITE);
98 g_object_class_install_property(gobject_class, PROP_LINE_DRESS, param);
100 param = g_param_spec_object("trail",
101 P_("Trail"),
102 P_("The trail to be stroked"),
103 ADG_TYPE_TRAIL,
104 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
105 g_object_class_install_property(gobject_class, PROP_TRAIL, param);
108 static void
109 adg_stroke_init(AdgStroke *stroke)
111 AdgStrokePrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(stroke,
112 ADG_TYPE_STROKE,
113 AdgStrokePrivate);
115 data->line_dress = ADG_DRESS_LINE_MEDIUM;
116 data->trail = NULL;
118 stroke->data = data;
121 static void
122 dispose(GObject *object)
124 AdgStroke *stroke = (AdgStroke *) object;
126 adg_stroke_set_trail(stroke, NULL);
128 if (PARENT_OBJECT_CLASS->dispose != NULL)
129 PARENT_OBJECT_CLASS->dispose(object);
132 static void
133 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
135 AdgStrokePrivate *data = ((AdgStroke *) object)->data;
137 switch (prop_id) {
138 case PROP_LINE_DRESS:
139 g_value_set_int(value, data->line_dress);
140 break;
141 case PROP_TRAIL:
142 g_value_set_object(value, &data->trail);
143 break;
144 default:
145 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
146 break;
150 static void
151 set_property(GObject *object, guint prop_id,
152 const GValue *value, GParamSpec *pspec)
154 AdgStroke *stroke;
155 AdgStrokePrivate *data;
157 stroke = (AdgStroke *) object;
158 data = stroke->data;
160 switch (prop_id) {
161 case PROP_LINE_DRESS:
162 adg_dress_set(&data->line_dress, g_value_get_int(value));
163 break;
164 case PROP_TRAIL:
165 set_trail(stroke, (AdgTrail *) g_value_get_object(value));
166 break;
167 default:
168 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
169 break;
175 * adg_stroke_new:
176 * @trail: the #AdgTrail to stroke
178 * Creates a new stroke entity.
180 * Returns: the newly created stroke entity
182 AdgStroke *
183 adg_stroke_new(AdgTrail *trail)
185 g_return_val_if_fail(ADG_IS_TRAIL(trail), NULL);
187 return g_object_new(ADG_TYPE_STROKE, "trail", trail, NULL);
191 * adg_stroke_get_line_dress:
192 * @stroke: an #AdgStroke
194 * Gets the line dress to be used in rendering @stroke.
196 * Returns: the current line dress
198 AdgDress
199 adg_stroke_get_line_dress(AdgStroke *stroke)
201 AdgStrokePrivate *data;
203 g_return_val_if_fail(ADG_IS_STROKE(stroke), ADG_DRESS_UNDEFINED);
205 data = stroke->data;
207 return data->line_dress;
211 * adg_stroke_set_line_dress:
212 * @stroke: an #AdgStroke
213 * @dress: the new #AdgDress to use
215 * Sets a new line dress for rendering @stroke. The new dress
216 * must be related to the original dress for this property:
217 * you cannot set a dress used for line styles to a dress
218 * managing fonts.
220 * The check is done by calling adg_dress_are_related() with
221 * @dress and the previous dress as arguments. Check out its
222 * documentation for details on what is a related dress.
224 void
225 adg_stroke_set_line_dress(AdgStroke *stroke, AdgDress dress)
227 AdgStrokePrivate *data;
229 g_return_if_fail(ADG_IS_STROKE(stroke));
231 data = stroke->data;
233 if (adg_dress_set(&data->line_dress, dress))
234 g_object_notify((GObject *) stroke, "line-dress");
238 * adg_stroke_get_trail:
239 * @stroke: an #AdgStroke
241 * Gets the #AdgTrail bound to this @stroke entity.
243 * Returns: the requested #AdgTrail or %NULL on errors
245 AdgTrail *
246 adg_stroke_get_trail(AdgStroke *stroke)
248 AdgStrokePrivate *data;
250 g_return_val_if_fail(ADG_IS_STROKE(stroke), NULL);
252 data = stroke->data;
254 return data->trail;
258 * adg_stroke_set_trail:
259 * @stroke: an #AdgStroke
260 * @trail: the new #AdgTrail to bind
262 * Sets @trail as the new trail to be stroked by @stroke.
264 void
265 adg_stroke_set_trail(AdgStroke *stroke, AdgTrail *trail)
267 g_return_if_fail(ADG_IS_STROKE(stroke));
269 if (set_trail(stroke, trail))
270 g_object_notify((GObject *) stroke, "trail");
274 static void
275 local_changed(AdgEntity *entity)
277 AdgMatrix old;
278 const AdgMatrix *new;
280 adg_matrix_copy(&old, adg_entity_local_matrix(entity));
282 if (PARENT_ENTITY_CLASS->local_changed != NULL)
283 PARENT_ENTITY_CLASS->local_changed(entity);
285 new = adg_entity_local_matrix(entity);
287 /* For simple translation, avoid the entity invalidation:
288 * translate the extents of the same vector instead */
289 if (old.xx != new->xx || old.yy != new->yy ||
290 old.xy != new->xy || old.yx != new->yx) {
291 adg_entity_invalidate(entity);
292 } else {
293 CpmlExtents *extents = (CpmlExtents *) adg_entity_extents(entity);
295 extents->org.x += new->x0 - old.x0;
296 extents->org.y += new->y0 - old.y0;
300 static void
301 arrange(AdgEntity *entity)
303 CpmlExtents *extents = (CpmlExtents *) adg_entity_extents(entity);
305 if (!extents->is_defined) {
306 AdgStroke *stroke;
307 AdgStrokePrivate *data;
308 const AdgMatrix *local;
310 stroke = (AdgStroke *) entity;
311 data = stroke->data;
312 local = adg_entity_local_matrix(entity);
314 cpml_extents_copy(extents, adg_trail_extents(data->trail));
316 /* Apply the local matrix to the extents */
317 cpml_pair_transform(&extents->org, local);
318 cpml_vector_transform(&extents->size, local);
322 static void
323 render(AdgEntity *entity, cairo_t *cr)
325 AdgStroke *stroke;
326 AdgStrokePrivate *data;
327 const cairo_path_t *cairo_path;
329 stroke = (AdgStroke *) entity;
330 data = stroke->data;
331 cairo_path = adg_trail_get_cairo_path(data->trail);
333 if (cairo_path != NULL) {
334 cairo_save(cr);
335 cairo_set_matrix(cr, adg_entity_ctm(entity));
336 cairo_append_path(cr, cairo_path);
337 cairo_restore(cr);
339 adg_entity_apply_dress(entity, data->line_dress, cr);
340 cairo_stroke(cr);
344 static gboolean
345 set_trail(AdgStroke *stroke, AdgTrail *trail)
347 AdgEntity *entity;
348 AdgStrokePrivate *data;
350 entity = (AdgEntity *) stroke;
351 data = stroke->data;
353 if (trail == data->trail)
354 return FALSE;
356 if (data->trail != NULL) {
357 g_object_weak_unref((GObject *) data->trail,
358 (GWeakNotify) unset_trail, stroke);
359 adg_model_remove_dependency((AdgModel *) data->trail, entity);
362 data->trail = trail;
364 if (data->trail != NULL) {
365 g_object_weak_ref((GObject *) data->trail,
366 (GWeakNotify) unset_trail, stroke);
367 adg_model_add_dependency((AdgModel *) data->trail, entity);
370 return TRUE;
373 static void
374 unset_trail(AdgStroke *stroke)
376 AdgStrokePrivate *data = stroke->data;
378 if (data->trail != NULL)
379 set_trail(stroke, NULL);