adg: inherit AdgDress from GEnum
[adg.git] / src / adg / adg-projection.c
blob7a488de1b9dd34e3e9d59bd5b01c14f75a7eec38
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011,2012,2013 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-projection
23 * @short_description: The standard symbol for specifying the projection scheme
25 * The #AdgProjection is an entity representing the standard symbol
26 * of the projection scheme.
28 * Since: 1.0
29 **/
31 /**
32 * AdgProjection:
34 * All fields are private and should not be used directly.
35 * Use its public methods instead.
37 * Since: 1.0
38 **/
41 #include "adg-internal.h"
42 #include "adg-dress.h"
43 #include "adg-model.h"
44 #include "adg-trail.h"
45 #include "adg-path.h"
47 #include "adg-projection.h"
48 #include "adg-projection-private.h"
51 G_DEFINE_TYPE(AdgProjection, adg_projection, ADG_TYPE_ENTITY)
53 enum {
54 PROP_0,
55 PROP_SYMBOL_DRESS,
56 PROP_AXIS_DRESS,
57 PROP_SCHEME
61 static void _adg_get_property (GObject *object,
62 guint param_id,
63 GValue *value,
64 GParamSpec *pspec);
65 static void _adg_set_property (GObject *object,
66 guint param_id,
67 const GValue *value,
68 GParamSpec *pspec);
69 static void _adg_arrange (AdgEntity *entity);
70 static void _adg_render (AdgEntity *entity,
71 cairo_t *cr);
72 static void _adg_arrange_class (AdgProjectionClass *projection_class,
73 AdgProjectionScheme scheme);
76 static void
77 adg_projection_class_init(AdgProjectionClass *klass)
79 GObjectClass *gobject_class;
80 AdgEntityClass *entity_class;
81 GParamSpec *param;
82 AdgProjectionClassPrivate *data_class;
84 gobject_class = (GObjectClass *) klass;
85 entity_class = (AdgEntityClass *) klass;
87 g_type_class_add_private(klass, sizeof(AdgProjectionPrivate));
89 gobject_class->get_property = _adg_get_property;
90 gobject_class->set_property = _adg_set_property;
92 entity_class->arrange = _adg_arrange;
93 entity_class->render = _adg_render;
95 param = adg_param_spec_dress("symbol-dress",
96 P_("Symbol Dress"),
97 P_("The line dress to use for rendering the views of the projection"),
98 ADG_DRESS_LINE,
99 G_PARAM_READWRITE);
100 g_object_class_install_property(gobject_class, PROP_SYMBOL_DRESS, param);
102 param = adg_param_spec_dress("axis-dress",
103 P_("Axis Dress"),
104 P_("The line dress to use for rendering the axis of the projection scheme"),
105 ADG_DRESS_LINE,
106 G_PARAM_READWRITE);
107 g_object_class_install_property(gobject_class, PROP_AXIS_DRESS, param);
109 param = g_param_spec_enum("scheme",
110 P_("Projection Scheme"),
111 P_("The projection scheme to be represented"),
112 ADG_TYPE_PROJECTION_SCHEME,
113 ADG_PROJECTION_SCHEME_UNDEFINED,
114 G_PARAM_READWRITE);
115 g_object_class_install_property(gobject_class, PROP_SCHEME, param);
117 /* Initialize the private class data: the allocated struct is
118 * never freed as this type is registered statically, hence
119 * never destroyed. A better approach would be to use the old
120 * type initialization (no G_TYPE_DEFINE and friends) that
121 * allows to specify a custom class finalization method */
122 data_class = g_new(AdgProjectionClassPrivate, 1);
124 data_class->scheme = ADG_PROJECTION_SCHEME_UNDEFINED;
125 data_class->symbol = NULL;
126 data_class->axis = NULL;
127 data_class->extents.is_defined = FALSE;
129 klass->data_class = data_class;
132 static void
133 adg_projection_init(AdgProjection *projection)
135 AdgProjectionPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(projection, ADG_TYPE_PROJECTION,
136 AdgProjectionPrivate);
138 data->symbol_dress = ADG_DRESS_LINE;
139 data->axis_dress = ADG_DRESS_LINE;
140 data->scheme = ADG_PROJECTION_SCHEME_UNDEFINED;
142 projection->data = data;
145 static void
146 _adg_get_property(GObject *object, guint prop_id,
147 GValue *value, GParamSpec *pspec)
149 AdgProjectionPrivate *data = ((AdgProjection *) object)->data;
151 switch (prop_id) {
152 case PROP_SYMBOL_DRESS:
153 g_value_set_enum(value, data->symbol_dress);
154 break;
155 case PROP_AXIS_DRESS:
156 g_value_set_enum(value, data->axis_dress);
157 break;
158 case PROP_SCHEME:
159 g_value_set_enum(value, data->scheme);
160 break;
161 default:
162 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
163 break;
167 static void
168 _adg_set_property(GObject *object, guint prop_id,
169 const GValue *value, GParamSpec *pspec)
171 AdgProjection *projection;
172 AdgProjectionPrivate *data;
174 projection = (AdgProjection *) object;
175 data = projection->data;
177 switch (prop_id) {
178 case PROP_SYMBOL_DRESS:
179 data->symbol_dress = g_value_get_enum(value);
180 break;
181 case PROP_AXIS_DRESS:
182 data->axis_dress = g_value_get_enum(value);
183 break;
184 case PROP_SCHEME:
185 data->scheme = g_value_get_enum(value);
186 adg_entity_invalidate((AdgEntity *) object);
187 break;
188 default:
189 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
190 break;
196 * adg_projection_new:
197 * @scheme: the scheme represented by this projection
199 * Creates a new projection entity representing the selected @scheme.
200 * If @scheme is invalid, a projection symbol without a scheme is
201 * returned, that is #AdgProjection:scheme is set to
202 * #ADG_PROJECTION_SCHEME_UNDEFINED, and a warning is raised.
204 * Returns: (transfer full): the newly created projection entity.
206 * Since: 1.0
208 AdgProjection *
209 adg_projection_new(AdgProjectionScheme scheme)
211 return g_object_new(ADG_TYPE_PROJECTION, "scheme", scheme, NULL);
215 * adg_projection_set_symbol_dress:
216 * @projection: an #AdgProjection
217 * @dress: the new #AdgDress to use
219 * Sets a new line dress for rendering the symbol of @projection. The
220 * new dress must be a line dress: the check is done by calling
221 * adg_dress_are_related() with @dress and the old dress as
222 * arguments. Check out its documentation for further details.
224 * The default dress is a transparent line dress: the rendering
225 * callback will stroke the symbol using the default color with
226 * a predefined thickness.
228 * Since: 1.0
230 void
231 adg_projection_set_symbol_dress(AdgProjection *projection, AdgDress dress)
233 g_return_if_fail(ADG_IS_PROJECTION(projection));
234 g_object_set(projection, "symbol-dress", dress, NULL);
238 * adg_projection_get_symbol_dress:
239 * @projection: an #AdgProjection
241 * Gets the line dress to be used in stroking the symbol of @projection.
243 * Returns: (transfer none): the requested line dress.
245 * Since: 1.0
247 AdgDress
248 adg_projection_get_symbol_dress(AdgProjection *projection)
250 AdgProjectionPrivate *data;
252 g_return_val_if_fail(ADG_IS_PROJECTION(projection), ADG_DRESS_UNDEFINED);
254 data = projection->data;
256 return data->symbol_dress;
260 * adg_projection_set_axis_dress:
261 * @projection: an #AdgProjection
262 * @dress: the new #AdgDress to use
264 * Sets a new line dress for rendering the axis of @projection.
265 * The new dress must be a line dress: the check is done by
266 * calling adg_dress_are_related() with @dress and the old
267 * dress as arguments. Check out its documentation for
268 * further details.
270 * The default dress is a transparent line dress: the rendering
271 * callback will stroke the axis using the default line style.
273 * Since: 1.0
275 void
276 adg_projection_set_axis_dress(AdgProjection *projection, AdgDress dress)
278 g_return_if_fail(ADG_IS_PROJECTION(projection));
279 g_object_set(projection, "axis-dress", dress, NULL);
283 * adg_projection_get_axis_dress:
284 * @projection: an #AdgProjection
286 * Gets the line dress to be used in stroking the axis of @projection.
288 * Returns: (transfer none): the requested line dress.
290 * Since: 1.0
292 AdgDress
293 adg_projection_get_axis_dress(AdgProjection *projection)
295 AdgProjectionPrivate *data;
297 g_return_val_if_fail(ADG_IS_PROJECTION(projection), ADG_DRESS_UNDEFINED);
299 data = projection->data;
301 return data->axis_dress;
305 * adg_projection_set_scheme:
306 * @projection: an #AdgProjection
307 * @scheme: the new projection scheme
309 * Sets a new scheme on @projection. If @scheme is different
310 * from the old one, @projection is invalidated.
312 * Since: 1.0
314 void
315 adg_projection_set_scheme(AdgProjection *projection,
316 AdgProjectionScheme scheme)
318 g_return_if_fail(ADG_IS_PROJECTION(projection));
319 g_object_set(projection, "scheme", scheme, NULL);
323 * adg_projection_get_scheme:
324 * @projection: an #AdgProjection
326 * Gets the scheme represented by @projection.
328 * Returns: (transfer none): the scheme of @projection
330 * Since: 1.0
332 AdgProjectionScheme
333 adg_projection_get_scheme(AdgProjection *projection)
335 AdgProjectionPrivate *data;
337 g_return_val_if_fail(ADG_IS_PROJECTION(projection),
338 ADG_PROJECTION_SCHEME_UNDEFINED);
340 data = projection->data;
342 return data->scheme;
346 static void
347 _adg_arrange(AdgEntity *entity)
349 AdgProjectionPrivate *data;
350 AdgProjectionClass *projection_class;
351 AdgProjectionClassPrivate *data_class;
352 CpmlExtents extents;
354 data = ((AdgProjection *) entity)->data;
355 projection_class = ADG_PROJECTION_GET_CLASS(entity);
356 data_class = projection_class->data_class;
358 _adg_arrange_class(projection_class, data->scheme);
359 cpml_extents_copy(&extents, &data_class->extents);
361 cpml_extents_transform(&extents, adg_entity_get_local_matrix(entity));
362 cpml_extents_transform(&extents, adg_entity_get_global_matrix(entity));
363 adg_entity_set_extents(entity, &extents);
366 static void
367 _adg_arrange_class(AdgProjectionClass *projection_class,
368 AdgProjectionScheme scheme)
370 AdgProjectionClassPrivate *data_class;
371 AdgPath *symbol, *axis;
373 data_class = projection_class->data_class;
375 if (data_class->scheme == scheme)
376 return;
378 if (data_class->symbol != NULL)
379 g_object_unref(data_class->symbol);
381 if (data_class->axis != NULL)
382 g_object_unref(data_class->axis);
384 data_class->scheme = scheme;
386 switch(scheme) {
387 case ADG_PROJECTION_SCHEME_UNDEFINED:
388 symbol = NULL;
389 axis = NULL;
390 break;
391 case ADG_PROJECTION_SCHEME_FIRST_ANGLE:
392 symbol = adg_path_new();
393 adg_path_move_to_explicit(symbol, 4, 19);
394 adg_path_line_to_explicit(symbol, 24, 24);
395 adg_path_line_to_explicit(symbol, 24, 4);
396 adg_path_line_to_explicit(symbol, 4, 9);
397 adg_path_close(symbol);
398 adg_path_move_to_explicit(symbol, 49, 14);
399 adg_path_arc_to_explicit(symbol, 29, 14, 49, 14);
400 adg_path_move_to_explicit(symbol, 44, 14);
401 adg_path_arc_to_explicit(symbol, 34, 14, 44, 14);
403 axis = adg_path_new();
404 adg_path_move_to_explicit(axis, 0, 14);
405 adg_path_line_to_explicit(axis, 53, 14);
406 adg_path_move_to_explicit(axis, 39, 0);
407 adg_path_line_to_explicit(axis, 39, 28);
408 break;
409 case ADG_PROJECTION_SCHEME_THIRD_ANGLE:
410 symbol = adg_path_new();
411 adg_path_move_to_explicit(symbol, 29, 19);
412 adg_path_line_to_explicit(symbol, 49, 24);
413 adg_path_line_to_explicit(symbol, 49, 4);
414 adg_path_line_to_explicit(symbol, 29, 9);
415 adg_path_close(symbol);
416 adg_path_move_to_explicit(symbol, 24, 14);
417 adg_path_arc_to_explicit(symbol, 4, 14, 24, 14);
418 adg_path_move_to_explicit(symbol, 19, 14);
419 adg_path_arc_to_explicit(symbol, 9, 14, 19, 14);
421 axis = adg_path_new();
422 adg_path_move_to_explicit(axis, 0, 14);
423 adg_path_line_to_explicit(axis, 53, 14);
424 adg_path_move_to_explicit(axis, 14, 0);
425 adg_path_line_to_explicit(axis, 14, 28);
426 break;
427 default:
428 g_return_if_reached();
429 break;
432 data_class->symbol = symbol;
433 data_class->axis = axis;
434 data_class->extents.is_defined = FALSE;
436 if (axis != NULL)
437 cpml_extents_add(&data_class->extents,
438 adg_trail_get_extents((AdgTrail *) axis));
440 if (symbol != NULL)
441 cpml_extents_add(&data_class->extents,
442 adg_trail_get_extents((AdgTrail *) symbol));
445 static void
446 _adg_render(AdgEntity *entity, cairo_t *cr)
448 AdgProjectionClassPrivate *data_class;
449 AdgProjectionPrivate *data;
450 const cairo_path_t *cairo_path;
452 data_class = ADG_PROJECTION_GET_CLASS(entity)->data_class;
453 data = ((AdgProjection *) entity)->data;
455 cairo_transform(cr, adg_entity_get_global_matrix(entity));
457 if (data_class->symbol != NULL) {
458 cairo_path = adg_trail_get_cairo_path((AdgTrail *) data_class->symbol);
460 cairo_save(cr);
461 cairo_transform(cr, adg_entity_get_local_matrix(entity));
462 cairo_append_path(cr, cairo_path);
463 cairo_restore(cr);
465 cairo_set_line_width(cr, 2);
466 adg_entity_apply_dress(entity, data->symbol_dress, cr);
468 cairo_stroke(cr);
471 if (data_class->axis != NULL) {
472 const gdouble dashes[] = { 5, 2, 1, 2 };
474 cairo_path = adg_trail_get_cairo_path((AdgTrail *) data_class->axis);
476 cairo_save(cr);
477 cairo_transform(cr, adg_entity_get_local_matrix(entity));
478 cairo_append_path(cr, cairo_path);
479 cairo_restore(cr);
481 cairo_set_line_width(cr, 1);
482 cairo_set_dash(cr, dashes, G_N_ELEMENTS(dashes), -1.5);
483 adg_entity_apply_dress(entity, data->axis_dress, cr);
485 cairo_stroke(cr);