[docs] Updated TODO.xml
[adg.git] / adg / adg-arrow-style.c
blob9bec0aa548df430f8be896ac1b9d9a4817c6eb4b
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-arrow-style
23 * @short_description: Arrow rendering related stuff
25 * Contains parameters on how to draw arrows, providing a way to register a
26 * custom rendering callback.
29 /**
30 * AdgArrowStyle:
32 * All fields are private and should not be used directly.
33 * Use its public methods instead.
34 **/
37 /**
38 * ADG_SLOT_ARROW_STYLE:
40 * Gets the slot id for this style class.
42 * Return value: the requested slot id
43 **/
46 #include "adg-arrow-style.h"
47 #include "adg-arrow-style-private.h"
48 #include "adg-context.h"
49 #include "adg-intl.h"
50 #include "adg-util.h"
51 #include <math.h>
54 enum {
55 PROP_0,
56 PROP_SIZE,
57 PROP_ANGLE,
58 PROP_MARGIN,
59 PROP_RENDERER
63 static void get_property (GObject *object,
64 guint prop_id,
65 GValue *value,
66 GParamSpec *pspec);
67 static void set_property (GObject *object,
68 guint prop_id,
69 const GValue *value,
70 GParamSpec *pspec);
71 static GPtrArray * get_pool (void);
72 static void arrow_renderer (AdgArrowStyle *arrow_style,
73 cairo_t *cr,
74 CpmlSegment *segment);
75 static void triangle_renderer (AdgArrowStyle *arrow_style,
76 cairo_t *cr,
77 CpmlSegment *segment);
78 static void dot_renderer (AdgArrowStyle *arrow_style,
79 cairo_t *cr,
80 CpmlSegment *segment);
81 static void circle_renderer (AdgArrowStyle *arrow_style,
82 cairo_t *cr,
83 CpmlSegment *segment);
84 static void block_renderer (AdgArrowStyle *arrow_style,
85 cairo_t *cr,
86 CpmlSegment *segment);
87 static void square_renderer (AdgArrowStyle *arrow_style,
88 cairo_t *cr,
89 CpmlSegment *segment);
90 static void tick_renderer (AdgArrowStyle *arrow_style,
91 cairo_t *cr,
92 CpmlSegment *segment);
93 static void draw_triangle (cairo_t *cr,
94 AdgArrowStyle *arrow_style,
95 CpmlSegment *segment);
96 static void draw_circle (cairo_t *cr,
97 AdgArrowStyle *arrow_style,
98 CpmlSegment *segment);
101 G_DEFINE_TYPE(AdgArrowStyle, adg_arrow_style, ADG_TYPE_STYLE)
104 static void
105 adg_arrow_style_class_init(AdgArrowStyleClass *klass)
107 GObjectClass *gobject_class;
108 AdgStyleClass *style_class;
109 GParamSpec *param;
111 gobject_class = (GObjectClass *) klass;
112 style_class = (AdgStyleClass *) klass;
114 g_type_class_add_private(klass, sizeof(AdgArrowStylePrivate));
116 gobject_class->get_property = get_property;
117 gobject_class->set_property = set_property;
119 style_class->get_pool = get_pool;
121 param = g_param_spec_double("size",
122 P_("Arrow Size"),
124 ("The size of the arrow, a renderer dependent parameter"),
125 -G_MAXDOUBLE, G_MAXDOUBLE, 14.,
126 G_PARAM_READWRITE);
127 g_object_class_install_property(gobject_class, PROP_SIZE, param);
129 param = g_param_spec_double("angle",
130 P_("Arrow Angle"),
132 ("The angle of the arrow, a renderer dependent parameter"),
133 -G_MAXDOUBLE, G_MAXDOUBLE, G_PI / 6.,
134 G_PARAM_READWRITE);
135 g_object_class_install_property(gobject_class, PROP_ANGLE, param);
137 param = g_param_spec_double("margin",
138 P_("Arrow Margin"),
140 ("The margin of the arrow, a renderer dependent parameter"),
141 -G_MAXDOUBLE, G_MAXDOUBLE, 14.,
142 G_PARAM_READWRITE);
143 g_object_class_install_property(gobject_class, PROP_MARGIN, param);
145 param = g_param_spec_pointer("renderer",
146 P_("Renderer Callback"),
148 ("The callback to call to renderer this arrow type"),
149 G_PARAM_READWRITE);
150 g_object_class_install_property(gobject_class, PROP_RENDERER, param);
153 static void
154 adg_arrow_style_init(AdgArrowStyle *arrow_style)
156 AdgArrowStylePrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(arrow_style,
157 ADG_TYPE_ARROW_STYLE,
158 AdgArrowStylePrivate);
160 data->size = 14.;
161 data->angle = G_PI / 6.;
162 data->margin = 14.;
163 data->renderer = NULL;
165 arrow_style->data = data;
168 static void
169 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
171 AdgArrowStylePrivate *data = ((AdgArrowStyle *) object)->data;
173 switch (prop_id) {
174 case PROP_SIZE:
175 g_value_set_double(value, data->size);
176 break;
177 case PROP_ANGLE:
178 g_value_set_double(value, data->angle);
179 break;
180 case PROP_MARGIN:
181 g_value_set_double(value, data->margin);
182 break;
183 case PROP_RENDERER:
184 g_value_set_pointer(value, data->renderer);
185 break;
186 default:
187 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
188 break;
192 static void
193 set_property(GObject *object,
194 guint prop_id, const GValue *value, GParamSpec *pspec)
196 AdgArrowStylePrivate *data = ((AdgArrowStyle *) object)->data;
198 switch (prop_id) {
199 case PROP_SIZE:
200 data->size = g_value_get_double(value);
201 break;
202 case PROP_ANGLE:
203 data->angle = g_value_get_double(value);
204 break;
205 case PROP_MARGIN:
206 data->margin = g_value_get_double(value);
207 break;
208 case PROP_RENDERER:
209 data->renderer = g_value_get_pointer(value);
210 break;
211 default:
212 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
213 break;
218 AdgStyleSlot
219 _adg_arrow_style_get_slot(void)
221 static AdgStyleSlot slot = -1;
223 if (G_UNLIKELY(slot < 0))
224 slot = adg_context_get_slot(ADG_TYPE_ARROW_STYLE);
226 return slot;
230 * adg_arrow_style_new:
232 * Constructs a new arrow style initialized with default params.
234 * Return value: a new arrow style
236 AdgStyle *
237 adg_arrow_style_new(void)
239 return g_object_new(ADG_TYPE_ARROW_STYLE, NULL);
243 * adg_arrow_style_render:
244 * @arrow_style: an #AdgArrowStyle instance
245 * @cr: the cairo context to use
246 * @segment: the #CpmlSegment where the arrow must be rendered
248 * Renders an arrow on @cr at the beginning of @segment in the way
249 * specified by @arrow_style.
251 void
252 adg_arrow_style_render(AdgArrowStyle *arrow_style,
253 cairo_t *cr, CpmlSegment *segment)
255 AdgStyleClass *style_class;
256 AdgArrowStylePrivate *data;
258 g_return_if_fail(arrow_style != NULL);
259 g_return_if_fail(cr != NULL);
260 g_return_if_fail(segment != NULL);
262 data = arrow_style->data;
264 /* NULL renderer */
265 if (data->renderer == NULL)
266 return;
268 style_class = (AdgStyleClass *) adg_arrow_style_parent_class;
270 if (style_class->apply != NULL)
271 style_class->apply((AdgStyle *) arrow_style, cr);
273 data->renderer(arrow_style, cr, segment);
277 * adg_arrow_style_get_size:
278 * @arrow_style: an #AdgArrowStyle object
280 * Gets the size (in global space) of the arrow (renderer dependent value).
282 * Return value: the size value
284 gdouble
285 adg_arrow_style_get_size(AdgArrowStyle *arrow_style)
287 AdgArrowStylePrivate *data;
289 g_return_val_if_fail(ADG_IS_ARROW_STYLE(arrow_style), 0.);
291 data = arrow_style->data;
293 return data->size;
297 * adg_arrow_style_set_size:
298 * @arrow_style: an #AdgArrowStyle object
299 * @size: the new size
301 * Sets a new size.
303 void
304 adg_arrow_style_set_size(AdgArrowStyle *arrow_style, gdouble size)
306 AdgArrowStylePrivate *data;
308 g_return_if_fail(ADG_IS_ARROW_STYLE(arrow_style));
310 data = arrow_style->data;
311 data->size = size;
313 g_object_notify((GObject *) arrow_style, "size");
317 * adg_arrow_style_get_angle:
318 * @arrow_style: an #AdgArrowStyle object
320 * Gets the angle (in degree) of the arrow (renderer dependent value).
322 * Return value: the angle value
324 gdouble
325 adg_arrow_style_get_angle(AdgArrowStyle *arrow_style)
327 AdgArrowStylePrivate *data;
329 g_return_val_if_fail(ADG_IS_ARROW_STYLE(arrow_style), 0.);
331 data = arrow_style->data;
333 return data->angle;
337 * adg_arrow_style_set_angle:
338 * @arrow_style: an #AdgArrowStyle object
339 * @angle: the new angle
341 * Sets a new angle.
343 void
344 adg_arrow_style_set_angle(AdgArrowStyle *arrow_style, gdouble angle)
346 AdgArrowStylePrivate *data;
348 g_return_if_fail(ADG_IS_ARROW_STYLE(arrow_style));
350 data = arrow_style->data;
351 data->angle = angle;
353 g_object_notify((GObject *) arrow_style, "angle");
357 * adg_arrow_style_get_margin:
358 * @arrow_style: an #AdgArrowStyle object
360 * Gets the margin (in global space) of this arrow (renderer dependent value).
361 * The margin is also used to trim the baseline of this amount.
363 * Return value: the margin value
365 gdouble
366 adg_arrow_style_get_margin(AdgArrowStyle *arrow_style)
368 AdgArrowStylePrivate *data;
370 g_return_val_if_fail(ADG_IS_ARROW_STYLE(arrow_style), 0.);
372 data = arrow_style->data;
374 return data->margin;
378 * adg_arrow_style_set_margin:
379 * @arrow_style: an #AdgArrowStyle object
380 * @margin: the new margin
382 * Sets a new margin.
384 void
385 adg_arrow_style_set_margin(AdgArrowStyle *arrow_style, gdouble margin)
387 AdgArrowStylePrivate *data;
389 g_return_if_fail(ADG_IS_ARROW_STYLE(arrow_style));
391 data = arrow_style->data;
392 data->margin = margin;
394 g_object_notify((GObject *) arrow_style, "margin");
398 * adg_arrow_style_get_renderer:
399 * @arrow_style: an #AdgArrowStyle object
401 * Gets the renderer of @arrow_style.
403 * Return value: the renderer value
405 AdgArrowRenderer
406 adg_arrow_style_get_renderer(AdgArrowStyle *arrow_style)
408 AdgArrowStylePrivate *data;
410 g_return_val_if_fail(ADG_IS_ARROW_STYLE(arrow_style), NULL);
412 data = arrow_style->data;
414 return data->renderer;
418 * adg_arrow_style_set_renderer:
419 * @arrow_style: an #AdgArrowStyle object
420 * @renderer: the new renderer
422 * Sets a new renderer.
424 void
425 adg_arrow_style_set_renderer(AdgArrowStyle *arrow_style,
426 AdgArrowRenderer renderer)
428 AdgArrowStylePrivate *data;
430 g_return_if_fail(ADG_IS_ARROW_STYLE(arrow_style));
432 data = arrow_style->data;
433 data->renderer = renderer;
435 g_object_notify((GObject *) arrow_style, "renderer");
439 static GPtrArray *
440 get_pool(void)
442 static GPtrArray *pool = NULL;
444 if (G_UNLIKELY(pool == NULL)) {
445 pool = g_ptr_array_sized_new(ADG_ARROW_STYLE_LAST);
447 pool->pdata[ADG_ARROW_STYLE_ARROW] =
448 g_object_new(ADG_TYPE_ARROW_STYLE, "renderer", arrow_renderer,
449 NULL);
450 pool->pdata[ADG_ARROW_STYLE_TRIANGLE] =
451 g_object_new(ADG_TYPE_ARROW_STYLE, "renderer",
452 triangle_renderer, NULL);
453 pool->pdata[ADG_ARROW_STYLE_DOT] =
454 g_object_new(ADG_TYPE_ARROW_STYLE, "size", 5., "angle", 0.,
455 "margin", 2.5, "renderer", dot_renderer, NULL);
456 pool->pdata[ADG_ARROW_STYLE_CIRCLE] =
457 g_object_new(ADG_TYPE_ARROW_STYLE, "size", 10., "angle", 0.,
458 "margin", 5., "renderer", circle_renderer, NULL);
459 pool->pdata[ADG_ARROW_STYLE_BLOCK] =
460 g_object_new(ADG_TYPE_ARROW_STYLE, "size", 10., "angle", 0.,
461 "margin", 5., "renderer", block_renderer, NULL);
462 pool->pdata[ADG_ARROW_STYLE_SQUARE] =
463 g_object_new(ADG_TYPE_ARROW_STYLE, "size", 10., "angle", 0.,
464 "margin", -0.1, "renderer", square_renderer,
465 NULL);
466 pool->pdata[ADG_ARROW_STYLE_TICK] =
467 g_object_new(ADG_TYPE_ARROW_STYLE, "size", 20., "angle",
468 G_PI / 3., "margin", 0., "renderer",
469 tick_renderer, NULL);
471 pool->len = ADG_ARROW_STYLE_LAST;
474 return pool;
477 static void
478 arrow_renderer(AdgArrowStyle *arrow_style, cairo_t *cr, CpmlSegment *segment)
480 draw_triangle(cr, arrow_style, segment);
481 cairo_fill(cr);
484 static void
485 triangle_renderer(AdgArrowStyle *arrow_style, cairo_t *cr, CpmlSegment *segment)
487 draw_triangle(cr, arrow_style, segment);
488 cairo_stroke(cr);
491 static void
492 dot_renderer(AdgArrowStyle *arrow_style, cairo_t *cr, CpmlSegment *segment)
494 draw_circle(cr, arrow_style, segment);
495 cairo_fill(cr);
498 static void
499 circle_renderer(AdgArrowStyle *arrow_style, cairo_t *cr, CpmlSegment *segment)
501 draw_circle(cr, arrow_style, segment);
502 cairo_stroke(cr);
505 static void
506 block_renderer(AdgArrowStyle *arrow_style, cairo_t *cr, CpmlSegment *segment)
508 ADG_STUB();
511 static void
512 square_renderer(AdgArrowStyle *arrow_style, cairo_t *cr, CpmlSegment *segment)
514 ADG_STUB();
517 static void
518 tick_renderer(AdgArrowStyle *arrow_style, cairo_t *cr, CpmlSegment *segment)
520 ADG_STUB();
523 static void
524 draw_triangle(cairo_t *cr, AdgArrowStyle *arrow_style, CpmlSegment *segment)
526 AdgArrowStylePrivate *data;
527 double length, height_2;
528 double org_x, org_y;
529 double tmp;
530 CpmlPair tail, tail1, tail2;
531 CpmlPair vector;
533 data = arrow_style->data;
534 length = data->size;
535 height_2 = tan(data->angle / 2.0) * length;
536 cairo_device_to_user_distance(cr, &length, &height_2);
537 org_x = segment->data[1].point.x;
538 org_y = segment->data[1].point.y;
540 switch (segment->data[2].header.type) {
541 case CAIRO_PATH_LINE_TO:
542 vector.x = segment->data[3].point.x - org_x;
543 vector.y = segment->data[3].point.y - org_y;
544 cpml_vector_set_length(&vector, 1.);
546 tail.x = vector.x * length + org_x;
547 tail.y = vector.y * length + org_y;
549 tmp = vector.x;
550 vector.x = -vector.y * height_2;
551 vector.y = tmp * height_2;
553 tail1.x = tail.x + vector.x;
554 tail1.y = tail.y + vector.y;
556 tail2.x = tail.x - vector.x;
557 tail2.y = tail.y - vector.y;
559 cairo_move_to(cr, org_x, org_y);
560 cairo_line_to(cr, tail1.x, tail1.y);
561 cairo_line_to(cr, tail2.x, tail2.y);
562 cairo_close_path(cr);
564 break;
565 case CAIRO_PATH_CURVE_TO:
566 ADG_STUB();
567 break;
568 default:
569 g_assert_not_reached();
573 static void
574 draw_circle(cairo_t *cr, AdgArrowStyle *arrow_style, CpmlSegment *segment)
576 AdgArrowStylePrivate *data;
577 double radius;
578 double dummy;
580 data = arrow_style->data;
581 radius = data->size / 2.;
582 dummy = 0;
584 cairo_device_to_user_distance(cr, &radius, &dummy);
585 cairo_new_path(cr);
586 cairo_arc(cr,
587 segment->data[1].point.x, segment->data[1].point.y,
588 radius, 0., M_PI);