[AdgTable] Fatten up APIs
[adg.git] / adg / adg-projection.c
blob6a648337db9b4efa1f4e14f94f44279fc147353d
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-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.
27 **/
29 /**
30 * AdgProjection:
32 * All fields are private and should not be used directly.
33 * Use its public methods instead.
34 **/
37 #include "adg-projection.h"
38 #include "adg-projection-private.h"
39 #include "adg-line-style.h"
40 #include "adg-dress-builtins.h"
41 #include "adg-intl.h"
43 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_projection_parent_class)
46 enum {
47 PROP_0,
48 PROP_SYMBOL_DRESS,
49 PROP_AXIS_DRESS,
50 PROP_SCHEME
54 static void get_property (GObject *object,
55 guint param_id,
56 GValue *value,
57 GParamSpec *pspec);
58 static void set_property (GObject *object,
59 guint param_id,
60 const GValue *value,
61 GParamSpec *pspec);
62 static void arrange (AdgEntity *entity);
63 static void render (AdgEntity *entity,
64 cairo_t *cr);
65 static void arrange_class (AdgProjectionClass *projection_class,
66 AdgProjectionScheme scheme);
67 static gboolean set_scheme (AdgProjection *projection,
68 AdgProjectionScheme scheme);
71 G_DEFINE_TYPE(AdgProjection, adg_projection, ADG_TYPE_ENTITY);
74 static void
75 adg_projection_class_init(AdgProjectionClass *klass)
77 GObjectClass *gobject_class;
78 AdgEntityClass *entity_class;
79 GParamSpec *param;
80 AdgProjectionClassPrivate *data_class;
82 gobject_class = (GObjectClass *) klass;
83 entity_class = (AdgEntityClass *) klass;
85 g_type_class_add_private(klass, sizeof(AdgProjectionPrivate));
87 gobject_class->get_property = get_property;
88 gobject_class->set_property = set_property;
90 entity_class->arrange = arrange;
91 entity_class->render = render;
93 param = adg_param_spec_dress("symbol-dress",
94 P_("Symbol Dress"),
95 P_("The line dress to use for rendering the views of the projection"),
96 ADG_DRESS_LINE,
97 G_PARAM_READWRITE);
98 g_object_class_install_property(gobject_class, PROP_SYMBOL_DRESS, param);
100 param = adg_param_spec_dress("axis-dress",
101 P_("Axis Dress"),
102 P_("The line dress to use for rendering the axis of the projection scheme"),
103 ADG_DRESS_LINE,
104 G_PARAM_READWRITE);
105 g_object_class_install_property(gobject_class, PROP_AXIS_DRESS, param);
107 param = g_param_spec_enum("scheme",
108 P_("Projection Scheme"),
109 P_("The projection scheme to be represented"),
110 ADG_TYPE_PROJECTION_SCHEME,
111 ADG_PROJECTION_UNDEFINED,
112 G_PARAM_READWRITE);
113 g_object_class_install_property(gobject_class, PROP_SCHEME, param);
115 /* Initialize the private class data: the allocated struct is
116 * never freed as this type is registered statically, hence
117 * never destroyed. A better approach would be to use the old
118 * type initialization (no G_TYPE_DEFINE and friends) that
119 * allows to specify a custom class finalization method */
120 data_class = g_new(AdgProjectionClassPrivate, 1);
122 data_class->scheme = ADG_PROJECTION_UNDEFINED;
123 data_class->symbol = NULL;
124 data_class->axis = NULL;
125 data_class->extents.is_defined = FALSE;
127 klass->data_class = data_class;
130 static void
131 adg_projection_init(AdgProjection *projection)
133 AdgProjectionPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(projection, ADG_TYPE_PROJECTION,
134 AdgProjectionPrivate);
136 data->symbol_dress = ADG_DRESS_LINE;
137 data->axis_dress = ADG_DRESS_LINE;
138 data->scheme = ADG_PROJECTION_UNDEFINED;
140 projection->data = data;
143 static void
144 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
146 AdgProjectionPrivate *data = ((AdgProjection *) object)->data;
148 switch (prop_id) {
149 case PROP_SYMBOL_DRESS:
150 g_value_set_int(value, data->symbol_dress);
151 break;
152 case PROP_AXIS_DRESS:
153 g_value_set_int(value, data->axis_dress);
154 break;
155 case PROP_SCHEME:
156 g_value_set_enum(value, data->scheme);
157 break;
158 default:
159 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
160 break;
164 static void
165 set_property(GObject *object, guint prop_id,
166 const GValue *value, GParamSpec *pspec)
168 AdgProjection *projection;
169 AdgProjectionPrivate *data;
171 projection = (AdgProjection *) object;
172 data = projection->data;
174 switch (prop_id) {
175 case PROP_SYMBOL_DRESS:
176 adg_dress_set(&data->symbol_dress, g_value_get_int(value));
177 break;
178 case PROP_AXIS_DRESS:
179 adg_dress_set(&data->axis_dress, g_value_get_int(value));
180 break;
181 case PROP_SCHEME:
182 set_scheme(projection, g_value_get_enum(value));
183 break;
184 default:
185 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
186 break;
192 * adg_projection_new:
193 * @scheme: the scheme represented by this projection
195 * Creates a new projection entity. The #AdgEntity:local-method
196 * property is set by default to #ADG_MIX_DISABLED, that is the
197 * projection is not subject to any local transformations.
199 * Returns: the newly created projection entity
201 AdgProjection *
202 adg_projection_new(AdgProjectionScheme scheme)
204 return g_object_new(ADG_TYPE_PROJECTION,
205 "local-method", ADG_MIX_DISABLED,
206 "scheme", scheme, NULL);
210 * adg_projection_get_symbol_dress:
211 * @projection: an #AdgProjection
213 * Gets the line dress to be used in stroking the symbol of @projection.
215 * Returns: the requested line dress
217 AdgDress
218 adg_projection_get_symbol_dress(AdgProjection *projection)
220 AdgProjectionPrivate *data;
222 g_return_val_if_fail(ADG_IS_PROJECTION(projection), ADG_DRESS_UNDEFINED);
224 data = projection->data;
226 return data->symbol_dress;
230 * adg_projection_set_symbol_dress:
231 * @projection: an #AdgProjection
232 * @dress: the new #AdgDress to use
234 * Sets a new line dress for rendering the symbol of @projection. The
235 * new dress must be a line dress: the check is done by calling
236 * adg_dress_are_related() with @dress and the old dress as
237 * arguments. Check out its documentation for further details.
239 * The default dress is a transparent line dress: the rendering
240 * callback will stroke the symbol using the default color with
241 * a predefined thickness.
243 void
244 adg_projection_set_symbol_dress(AdgProjection *projection, AdgDress dress)
246 AdgProjectionPrivate *data;
248 g_return_if_fail(ADG_IS_PROJECTION(projection));
250 data = projection->data;
252 if (adg_dress_set(&data->symbol_dress, dress))
253 g_object_notify((GObject *) projection, "symbol-dress");
257 * adg_projection_get_axis_dress:
258 * @projection: an #AdgProjection
260 * Gets the line dress to be used in stroking the axis of @projection.
262 * Returns: the requested line dress
264 AdgDress
265 adg_projection_get_axis_dress(AdgProjection *projection)
267 AdgProjectionPrivate *data;
269 g_return_val_if_fail(ADG_IS_PROJECTION(projection), ADG_DRESS_UNDEFINED);
271 data = projection->data;
273 return data->axis_dress;
277 * adg_projection_set_axis_dress:
278 * @projection: an #AdgProjection
279 * @dress: the new #AdgDress to use
281 * Sets a new line dress for rendering the axis of @projection.
282 * The new dress must be a line dress: the check is done by
283 * calling adg_dress_are_related() with @dress and the old
284 * dress as arguments. Check out its documentation for
285 * further details.
287 * The default dress is a transparent line dress: the rendering
288 * callback will stroke the axis using the default line style.
290 void
291 adg_projection_set_axis_dress(AdgProjection *projection, AdgDress dress)
293 AdgProjectionPrivate *data;
295 g_return_if_fail(ADG_IS_PROJECTION(projection));
297 data = projection->data;
299 if (adg_dress_set(&data->axis_dress, dress))
300 g_object_notify((GObject *) projection, "axis-dress");
304 * adg_projection_get_scheme:
305 * @projection: an #AdgProjection
307 * Gets the scheme represented by @projection.
309 * Returns: the scheme of @projection
311 AdgProjectionScheme
312 adg_projection_get_scheme(AdgProjection *projection)
314 AdgProjectionPrivate *data;
316 g_return_val_if_fail(ADG_IS_PROJECTION(projection),
317 ADG_PROJECTION_UNDEFINED);
319 data = projection->data;
321 return data->scheme;
325 * adg_projection_set_scheme:
326 * @projection: an #AdgProjection
327 * @scheme: the new projection scheme
329 * Sets a new scheme on @projection. If @scheme is different
330 * from the old one, @projection is invalidated.
332 void
333 adg_projection_set_scheme(AdgProjection *projection,
334 AdgProjectionScheme scheme)
336 g_return_if_fail(ADG_IS_PROJECTION(projection));
338 if (set_scheme(projection, scheme))
339 g_object_notify((GObject *) projection, "scheme");
343 static void
344 arrange(AdgEntity *entity)
346 AdgProjectionPrivate *data;
347 AdgProjectionClass *projection_class;
348 AdgProjectionClassPrivate *data_class;
349 CpmlExtents *extents;
350 const AdgMatrix *local;
352 data = ((AdgProjection *) entity)->data;
353 projection_class = ADG_PROJECTION_GET_CLASS(entity);
354 data_class = projection_class->data_class;
355 extents = (CpmlExtents *) adg_entity_extents(entity);
356 local = adg_entity_local_matrix(entity);
358 arrange_class(projection_class, data->scheme);
359 cpml_extents_copy(extents, &data_class->extents);
361 /* Apply the local matrix to the extents of this projection instance */
362 cpml_pair_transform(&extents->org, local);
363 cpml_vector_transform(&extents->size, local);
366 static void
367 arrange_class(AdgProjectionClass *projection_class, AdgProjectionScheme scheme)
369 AdgProjectionClassPrivate *data_class;
370 AdgPath *symbol, *axis;
372 data_class = projection_class->data_class;
374 if (data_class->scheme == scheme)
375 return;
377 if (data_class->symbol != NULL)
378 g_object_unref(data_class->symbol);
380 if (data_class->axis != NULL)
381 g_object_unref(data_class->axis);
383 data_class->scheme = scheme;
385 switch(scheme) {
386 case ADG_PROJECTION_UNDEFINED:
387 symbol = NULL;
388 axis = NULL;
389 break;
390 case ADG_PROJECTION_FIRST_ANGLE:
391 symbol = adg_path_new();
392 adg_path_move_to_explicit(symbol, 5, 20);
393 adg_path_line_to_explicit(symbol, 25, 25);
394 adg_path_line_to_explicit(symbol, 25, 5);
395 adg_path_line_to_explicit(symbol, 5, 10);
396 adg_path_close(symbol);
397 adg_path_move_to_explicit(symbol, 50, 15);
398 adg_path_arc_to_explicit(symbol, 30, 15, 50, 15);
399 adg_path_move_to_explicit(symbol, 45, 15);
400 adg_path_arc_to_explicit(symbol, 35, 15, 45, 15);
402 axis = adg_path_new();
403 adg_path_move_to_explicit(axis, 1, 15);
404 adg_path_line_to_explicit(axis, 54, 15);
405 adg_path_move_to_explicit(axis, 40, 1);
406 adg_path_line_to_explicit(axis, 40, 29);
407 break;
408 case ADG_PROJECTION_THIRD_ANGLE:
409 symbol = adg_path_new();
410 adg_path_move_to_explicit(symbol, 30, 20);
411 adg_path_line_to_explicit(symbol, 50, 25);
412 adg_path_line_to_explicit(symbol, 50, 5);
413 adg_path_line_to_explicit(symbol, 30, 10);
414 adg_path_close(symbol);
415 adg_path_move_to_explicit(symbol, 25, 15);
416 adg_path_arc_to_explicit(symbol, 5, 15, 25, 15);
417 adg_path_move_to_explicit(symbol, 20, 15);
418 adg_path_arc_to_explicit(symbol, 10, 15, 20, 15);
420 axis = adg_path_new();
421 adg_path_move_to_explicit(axis, 1, 15);
422 adg_path_line_to_explicit(axis, 54, 15);
423 adg_path_move_to_explicit(axis, 15, 1);
424 adg_path_line_to_explicit(axis, 15, 29);
425 break;
426 default:
427 g_assert_not_reached();
428 break;
431 data_class->symbol = symbol;
432 data_class->axis = axis;
433 data_class->extents.is_defined = FALSE;
435 if (symbol != NULL)
436 cpml_extents_add(&data_class->extents,
437 adg_trail_extents((AdgTrail *) symbol));
439 if (axis != NULL)
440 cpml_extents_add(&data_class->extents,
441 adg_trail_extents((AdgTrail *) axis));
444 static void
445 render(AdgEntity *entity, cairo_t *cr)
447 AdgProjectionClassPrivate *data_class;
448 AdgProjectionPrivate *data;
449 const cairo_path_t *cairo_path;
451 data_class = ADG_PROJECTION_GET_CLASS(entity)->data_class;
452 data = ((AdgProjection *) entity)->data;
454 if (data_class->symbol != NULL) {
455 cairo_path = adg_trail_get_cairo_path((AdgTrail *) data_class->symbol);
457 cairo_save(cr);
458 cairo_set_matrix(cr, adg_entity_ctm(entity));
459 cairo_append_path(cr, cairo_path);
460 cairo_restore(cr);
462 cairo_set_line_width(cr, 2);
463 adg_entity_apply_dress(entity, data->symbol_dress, cr);
465 cairo_stroke(cr);
468 if (data_class->axis != NULL) {
469 const gdouble dashes[] = { 5, 2, 1, 2 };
471 cairo_path = adg_trail_get_cairo_path((AdgTrail *) data_class->axis);
473 cairo_save(cr);
474 cairo_set_matrix(cr, adg_entity_ctm(entity));
475 cairo_append_path(cr, cairo_path);
476 cairo_restore(cr);
478 cairo_set_line_width(cr, 1);
479 cairo_set_dash(cr, dashes, G_N_ELEMENTS(dashes), -1.5);
480 adg_entity_apply_dress(entity, data->axis_dress, cr);
482 cairo_stroke(cr);
486 static gboolean
487 set_scheme(AdgProjection *projection, AdgProjectionScheme scheme)
489 AdgProjectionPrivate *data = projection->data;
491 if (data->scheme == scheme)
492 return FALSE;
494 data->scheme = scheme;
496 adg_entity_invalidate((AdgEntity *) projection);
497 return TRUE;