[AdgDress] Rearranged builtin dresses
[adg.git] / src / adg / adg-stroke.c
blob1818f2440280462ff5a95fbc5cbbb22d5a897a3c
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010 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-internal.h"
37 #include "adg-stroke.h"
38 #include "adg-stroke-private.h"
39 #include "adg-dress-builtins.h"
40 #include "adg-line-style.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 global_changed (AdgEntity *entity);
62 static void local_changed (AdgEntity *entity);
63 static void arrange (AdgEntity *entity);
64 static void render (AdgEntity *entity,
65 cairo_t *cr);
66 static gboolean set_trail (AdgStroke *stroke,
67 AdgTrail *trail);
68 static void unset_trail (AdgStroke *stroke);
71 G_DEFINE_TYPE(AdgStroke, adg_stroke, ADG_TYPE_ENTITY);
74 static void
75 adg_stroke_class_init(AdgStrokeClass *klass)
77 GObjectClass *gobject_class;
78 AdgEntityClass *entity_class;
79 GParamSpec *param;
81 gobject_class = (GObjectClass *) klass;
82 entity_class = (AdgEntityClass *) klass;
84 g_type_class_add_private(klass, sizeof(AdgStrokePrivate));
86 gobject_class->dispose = dispose;
87 gobject_class->get_property = get_property;
88 gobject_class->set_property = set_property;
90 entity_class->global_changed = global_changed;
91 entity_class->local_changed = local_changed;
92 entity_class->arrange = arrange;
93 entity_class->render = render;
95 param = adg_param_spec_dress("line-dress",
96 P_("Line Dress"),
97 P_("The dress to use for stroking this entity"),
98 ADG_DRESS_LINE_STROKE,
99 G_PARAM_READWRITE);
100 g_object_class_install_property(gobject_class, PROP_LINE_DRESS, param);
102 param = g_param_spec_object("trail",
103 P_("Trail"),
104 P_("The trail to be stroked"),
105 ADG_TYPE_TRAIL,
106 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
107 g_object_class_install_property(gobject_class, PROP_TRAIL, param);
110 static void
111 adg_stroke_init(AdgStroke *stroke)
113 AdgStrokePrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(stroke,
114 ADG_TYPE_STROKE,
115 AdgStrokePrivate);
117 data->line_dress = ADG_DRESS_LINE_STROKE;
118 data->trail = NULL;
120 stroke->data = data;
123 static void
124 dispose(GObject *object)
126 AdgStroke *stroke = (AdgStroke *) object;
128 adg_stroke_set_trail(stroke, NULL);
130 if (PARENT_OBJECT_CLASS->dispose)
131 PARENT_OBJECT_CLASS->dispose(object);
134 static void
135 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
137 AdgStrokePrivate *data = ((AdgStroke *) object)->data;
139 switch (prop_id) {
140 case PROP_LINE_DRESS:
141 g_value_set_int(value, data->line_dress);
142 break;
143 case PROP_TRAIL:
144 g_value_set_object(value, data->trail);
145 break;
146 default:
147 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
148 break;
152 static void
153 set_property(GObject *object, guint prop_id,
154 const GValue *value, GParamSpec *pspec)
156 AdgStroke *stroke;
157 AdgStrokePrivate *data;
159 stroke = (AdgStroke *) object;
160 data = stroke->data;
162 switch (prop_id) {
163 case PROP_LINE_DRESS:
164 adg_dress_set(&data->line_dress, g_value_get_int(value));
165 break;
166 case PROP_TRAIL:
167 set_trail(stroke, (AdgTrail *) g_value_get_object(value));
168 break;
169 default:
170 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
171 break;
177 * adg_stroke_new:
178 * @trail: the #AdgTrail to stroke
180 * Creates a new stroke entity based on the @trail model.
181 * @trail can be %NULL, in which case an empty stroke is created.
183 * Returns: the newly created stroke entity
185 AdgStroke *
186 adg_stroke_new(AdgTrail *trail)
188 return g_object_new(ADG_TYPE_STROKE, "trail", trail, NULL);
192 * adg_stroke_set_line_dress:
193 * @stroke: an #AdgStroke
194 * @dress: the new #AdgDress to use
196 * Sets a new line dress for rendering @stroke. The new dress
197 * must be related to the original dress for this property:
198 * you cannot set a dress used for line styles to a dress
199 * managing fonts.
201 * The check is done by calling adg_dress_are_related() with
202 * @dress and the previous dress as arguments. Check out its
203 * documentation for details on what is a related dress.
205 void
206 adg_stroke_set_line_dress(AdgStroke *stroke, AdgDress dress)
208 AdgStrokePrivate *data;
210 g_return_if_fail(ADG_IS_STROKE(stroke));
212 data = stroke->data;
214 if (adg_dress_set(&data->line_dress, dress))
215 g_object_notify((GObject *) stroke, "line-dress");
219 * adg_stroke_get_line_dress:
220 * @stroke: an #AdgStroke
222 * Gets the line dress to be used in rendering @stroke.
224 * Returns: the current line dress
226 AdgDress
227 adg_stroke_get_line_dress(AdgStroke *stroke)
229 AdgStrokePrivate *data;
231 g_return_val_if_fail(ADG_IS_STROKE(stroke), ADG_DRESS_UNDEFINED);
233 data = stroke->data;
235 return data->line_dress;
239 * adg_stroke_set_trail:
240 * @stroke: an #AdgStroke
241 * @trail: the new #AdgTrail to bind
243 * Sets @trail as the new trail to be stroked by @stroke.
245 void
246 adg_stroke_set_trail(AdgStroke *stroke, AdgTrail *trail)
248 g_return_if_fail(ADG_IS_STROKE(stroke));
250 if (set_trail(stroke, trail))
251 g_object_notify((GObject *) stroke, "trail");
255 * adg_stroke_get_trail:
256 * @stroke: an #AdgStroke
258 * Gets the #AdgTrail bound to this @stroke entity.
260 * Returns: the requested #AdgTrail or %NULL on errors
262 AdgTrail *
263 adg_stroke_get_trail(AdgStroke *stroke)
265 AdgStrokePrivate *data;
267 g_return_val_if_fail(ADG_IS_STROKE(stroke), NULL);
269 data = stroke->data;
271 return data->trail;
275 static void
276 global_changed(AdgEntity *entity)
278 if (PARENT_ENTITY_CLASS->global_changed)
279 PARENT_ENTITY_CLASS->global_changed(entity);
281 adg_entity_invalidate(entity);
284 static void
285 local_changed(AdgEntity *entity)
287 if (PARENT_ENTITY_CLASS->local_changed)
288 PARENT_ENTITY_CLASS->local_changed(entity);
290 adg_entity_invalidate(entity);
293 static void
294 arrange(AdgEntity *entity)
296 AdgStroke *stroke;
297 AdgStrokePrivate *data;
298 CpmlExtents extents;
300 /* Check for cached result */
301 if (adg_entity_get_extents(entity)->is_defined)
302 return;
304 stroke = (AdgStroke *) entity;
305 data = stroke->data;
307 cpml_extents_copy(&extents, adg_trail_get_extents(data->trail));
308 cpml_extents_transform(&extents, adg_entity_get_local_matrix(entity));
309 cpml_extents_transform(&extents, adg_entity_get_global_matrix(entity));
311 adg_entity_set_extents(entity, &extents);
314 static void
315 render(AdgEntity *entity, cairo_t *cr)
317 AdgStroke *stroke;
318 AdgStrokePrivate *data;
319 const cairo_path_t *cairo_path;
321 stroke = (AdgStroke *) entity;
322 data = stroke->data;
323 cairo_path = adg_trail_get_cairo_path(data->trail);
325 if (cairo_path != NULL) {
326 cairo_save(cr);
327 cairo_transform(cr, adg_entity_get_local_matrix(entity));
328 cairo_append_path(cr, cairo_path);
329 cairo_restore(cr);
331 adg_entity_apply_dress(entity, data->line_dress, cr);
332 cairo_stroke(cr);
336 static gboolean
337 set_trail(AdgStroke *stroke, AdgTrail *trail)
339 AdgEntity *entity;
340 AdgStrokePrivate *data;
342 g_return_val_if_fail(trail == NULL || ADG_IS_TRAIL(trail), FALSE);
344 entity = (AdgEntity *) stroke;
345 data = stroke->data;
347 if (trail == data->trail)
348 return FALSE;
350 if (data->trail != NULL) {
351 g_object_weak_unref((GObject *) data->trail,
352 (GWeakNotify) unset_trail, stroke);
353 adg_model_remove_dependency((AdgModel *) data->trail, entity);
356 data->trail = trail;
358 if (data->trail != NULL) {
359 g_object_weak_ref((GObject *) data->trail,
360 (GWeakNotify) unset_trail, stroke);
361 adg_model_add_dependency((AdgModel *) data->trail, entity);
364 return TRUE;
367 static void
368 unset_trail(AdgStroke *stroke)
370 AdgStrokePrivate *data = stroke->data;
372 if (data->trail != NULL)
373 set_trail(stroke, NULL);