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.
23 * @short_description: A stroked entity
25 * The #AdgStroke object is a stroked representation of an #AdgTrail model.
31 * All fields are private and should not be used directly.
32 * Use its public methods instead.
36 #include "adg-stroke.h"
37 #include "adg-stroke-private.h"
38 #include "adg-dress-builtins.h"
39 #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)
52 static void dispose (GObject
*object
);
53 static void get_property (GObject
*object
,
57 static void set_property (GObject
*object
,
61 static void local_changed (AdgEntity
*entity
);
62 static void arrange (AdgEntity
*entity
);
63 static void render (AdgEntity
*entity
,
65 static gboolean
set_trail (AdgStroke
*stroke
,
67 static void unset_trail (AdgStroke
*stroke
);
70 G_DEFINE_TYPE(AdgStroke
, adg_stroke
, ADG_TYPE_ENTITY
);
74 adg_stroke_class_init(AdgStrokeClass
*klass
)
76 GObjectClass
*gobject_class
;
77 AdgEntityClass
*entity_class
;
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",
95 P_("The dress to use for stroking this entity"),
96 ADG_DRESS_LINE_MEDIUM
,
98 g_object_class_install_property(gobject_class
, PROP_LINE_DRESS
, param
);
100 param
= g_param_spec_object("trail",
102 P_("The trail to be stroked"),
104 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
);
105 g_object_class_install_property(gobject_class
, PROP_TRAIL
, param
);
109 adg_stroke_init(AdgStroke
*stroke
)
111 AdgStrokePrivate
*data
= G_TYPE_INSTANCE_GET_PRIVATE(stroke
,
115 data
->line_dress
= ADG_DRESS_LINE_MEDIUM
;
122 dispose(GObject
*object
)
124 AdgStroke
*stroke
= (AdgStroke
*) object
;
126 adg_stroke_set_trail(stroke
, NULL
);
128 if (PARENT_OBJECT_CLASS
->dispose
)
129 PARENT_OBJECT_CLASS
->dispose(object
);
133 get_property(GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
135 AdgStrokePrivate
*data
= ((AdgStroke
*) object
)->data
;
138 case PROP_LINE_DRESS
:
139 g_value_set_int(value
, data
->line_dress
);
142 g_value_set_object(value
, &data
->trail
);
145 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
151 set_property(GObject
*object
, guint prop_id
,
152 const GValue
*value
, GParamSpec
*pspec
)
155 AdgStrokePrivate
*data
;
157 stroke
= (AdgStroke
*) object
;
161 case PROP_LINE_DRESS
:
162 adg_dress_set(&data
->line_dress
, g_value_get_int(value
));
165 set_trail(stroke
, (AdgTrail
*) g_value_get_object(value
));
168 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
176 * @trail: the #AdgTrail to stroke
178 * Creates a new stroke entity.
180 * Returns: the newly created stroke entity
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
199 adg_stroke_get_line_dress(AdgStroke
*stroke
)
201 AdgStrokePrivate
*data
;
203 g_return_val_if_fail(ADG_IS_STROKE(stroke
), ADG_DRESS_UNDEFINED
);
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
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.
225 adg_stroke_set_line_dress(AdgStroke
*stroke
, AdgDress dress
)
227 AdgStrokePrivate
*data
;
229 g_return_if_fail(ADG_IS_STROKE(stroke
));
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
246 adg_stroke_get_trail(AdgStroke
*stroke
)
248 AdgStrokePrivate
*data
;
250 g_return_val_if_fail(ADG_IS_STROKE(stroke
), NULL
);
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.
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");
275 local_changed(AdgEntity
*entity
)
278 const AdgMatrix
*new;
280 adg_matrix_copy(&old
, adg_entity_get_local_matrix(entity
));
282 if (PARENT_ENTITY_CLASS
->local_changed
)
283 PARENT_ENTITY_CLASS
->local_changed(entity
);
285 new = adg_entity_get_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
) {
293 cpml_extents_copy(&extents
, adg_entity_get_extents(entity
));
295 extents
.org
.x
+= new->x0
- old
.x0
;
296 extents
.org
.y
+= new->y0
- old
.y0
;
298 adg_entity_set_extents(entity
, &extents
);
301 adg_entity_invalidate(entity
);
305 arrange(AdgEntity
*entity
)
308 AdgStrokePrivate
*data
;
311 /* Check for cached result */
312 if (adg_entity_get_extents(entity
)->is_defined
)
315 stroke
= (AdgStroke
*) entity
;
318 cpml_extents_copy(&extents
, adg_trail_get_extents(data
->trail
));
319 cpml_extents_transform(&extents
, adg_entity_get_local_matrix(entity
));
321 adg_entity_set_extents(entity
, &extents
);
325 render(AdgEntity
*entity
, cairo_t
*cr
)
328 AdgStrokePrivate
*data
;
329 const cairo_path_t
*cairo_path
;
331 stroke
= (AdgStroke
*) entity
;
333 cairo_path
= adg_trail_get_cairo_path(data
->trail
);
335 if (cairo_path
!= NULL
) {
337 cairo_transform(cr
, adg_entity_get_local_matrix(entity
));
338 cairo_append_path(cr
, cairo_path
);
341 adg_entity_apply_dress(entity
, data
->line_dress
, cr
);
347 set_trail(AdgStroke
*stroke
, AdgTrail
*trail
)
350 AdgStrokePrivate
*data
;
352 entity
= (AdgEntity
*) stroke
;
355 if (trail
== data
->trail
)
358 if (data
->trail
!= NULL
) {
359 g_object_weak_unref((GObject
*) data
->trail
,
360 (GWeakNotify
) unset_trail
, stroke
);
361 adg_model_remove_dependency((AdgModel
*) data
->trail
, entity
);
366 if (data
->trail
!= NULL
) {
367 g_object_weak_ref((GObject
*) data
->trail
,
368 (GWeakNotify
) unset_trail
, stroke
);
369 adg_model_add_dependency((AdgModel
*) data
->trail
, entity
);
376 unset_trail(AdgStroke
*stroke
)
378 AdgStrokePrivate
*data
= stroke
->data
;
380 if (data
->trail
!= NULL
)
381 set_trail(stroke
, NULL
);