Updated docs for slots related changes
[adg.git] / adg / adg-arrow-style.c
blobde427b0188852bfad46c28c7aec28a684e3ee10e
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2008, 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 Library 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 * Library 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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 /**
22 * SECTION:arrow-style
23 * @title: AdgArrowStyle
24 * @short_description: Arrow rendering related stuff
26 * Contains parameters on how to draw arrows, providing a way to register a
27 * custom rendering callback.
30 #include "adg-arrow-style.h"
31 #include "adg-arrow-style-private.h"
32 #include "adg-intl.h"
33 #include "adg-util.h"
35 #include <math.h>
37 #define PARENT_CLASS ((AdgStyleClass *) adg_arrow_style_parent_class)
40 enum
42 PROP_0,
43 PROP_SIZE,
44 PROP_ANGLE,
45 PROP_MARGIN,
46 PROP_RENDERER
50 static void get_property (GObject *object,
51 guint prop_id,
52 GValue *value,
53 GParamSpec *pspec);
54 static void set_property (GObject *object,
55 guint prop_id,
56 const GValue *value,
57 GParamSpec *pspec);
59 static GPtrArray * get_pool (void);
60 static void arrow_renderer (AdgArrowStyle *arrow_style,
61 cairo_t *cr,
62 CpmlPath *segment);
63 static void triangle_renderer (AdgArrowStyle *arrow_style,
64 cairo_t *cr,
65 CpmlPath *segment);
66 static void dot_renderer (AdgArrowStyle *arrow_style,
67 cairo_t *cr,
68 CpmlPath *segment);
69 static void circle_renderer (AdgArrowStyle *arrow_style,
70 cairo_t *cr,
71 CpmlPath *segment);
72 static void block_renderer (AdgArrowStyle *arrow_style,
73 cairo_t *cr,
74 CpmlPath *segment);
75 static void square_renderer (AdgArrowStyle *arrow_style,
76 cairo_t *cr,
77 CpmlPath *segment);
78 static void tick_renderer (AdgArrowStyle *arrow_style,
79 cairo_t *cr,
80 CpmlPath *segment);
81 static void draw_triangle (cairo_t *cr,
82 AdgArrowStyle *arrow_style,
83 CpmlPath *segment);
84 static void draw_circle (cairo_t *cr,
85 AdgArrowStyle *arrow_style,
86 CpmlPath *segment);
89 G_DEFINE_TYPE (AdgArrowStyle, adg_arrow_style, ADG_TYPE_STYLE)
92 static void
93 adg_arrow_style_class_init (AdgArrowStyleClass *klass)
95 GObjectClass *gobject_class;
96 AdgStyleClass *style_class;
97 GParamSpec *param;
99 gobject_class = (GObjectClass *) klass;
100 style_class = (AdgStyleClass *) klass;
102 g_type_class_add_private (klass, sizeof (AdgArrowStylePrivate));
104 gobject_class->get_property = get_property;
105 gobject_class->set_property = set_property;
107 style_class->get_pool = get_pool;
109 param = g_param_spec_double ("size",
110 P_("Arrow Size"),
111 P_("The size of the arrow, a renderer dependent parameter"),
112 -G_MAXDOUBLE, G_MAXDOUBLE, 14.,
113 G_PARAM_READWRITE);
114 g_object_class_install_property (gobject_class, PROP_SIZE, param);
116 param = g_param_spec_double ("angle",
117 P_("Arrow Angle"),
118 P_("The angle of the arrow, a renderer dependent parameter"),
119 -G_MAXDOUBLE, G_MAXDOUBLE, G_PI / 6.,
120 G_PARAM_READWRITE);
121 g_object_class_install_property (gobject_class, PROP_ANGLE, param);
123 param = g_param_spec_double ("margin",
124 P_("Arrow Margin"),
125 P_("The margin of the arrow, a renderer dependent parameter"),
126 -G_MAXDOUBLE, G_MAXDOUBLE, 14.,
127 G_PARAM_READWRITE);
128 g_object_class_install_property (gobject_class, PROP_MARGIN, param);
130 param = g_param_spec_pointer ("renderer",
131 P_("Renderer Callback"),
132 P_("The callback to call to renderer this arrow type"),
133 G_PARAM_READWRITE);
134 g_object_class_install_property (gobject_class, PROP_RENDERER, param);
137 static void
138 adg_arrow_style_init (AdgArrowStyle *arrow_style)
140 AdgArrowStylePrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (arrow_style,
141 ADG_TYPE_ARROW_STYLE,
142 AdgArrowStylePrivate);
144 priv->size = 14.;
145 priv->angle = G_PI / 6.;
146 priv->margin = 14.;
147 priv->renderer = NULL;
149 arrow_style->priv = priv;
152 static void
153 get_property (GObject *object,
154 guint prop_id,
155 GValue *value,
156 GParamSpec *pspec)
158 AdgArrowStyle *arrow_style = (AdgArrowStyle *) object;
160 switch (prop_id)
162 case PROP_SIZE:
163 g_value_set_double (value, arrow_style->priv->size);
164 break;
165 case PROP_ANGLE:
166 g_value_set_double (value, arrow_style->priv->angle);
167 break;
168 case PROP_MARGIN:
169 g_value_set_double (value, arrow_style->priv->margin);
170 break;
171 case PROP_RENDERER:
172 g_value_set_pointer (value, arrow_style->priv->renderer);
173 break;
174 default:
175 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
176 break;
180 static void
181 set_property (GObject *object,
182 guint prop_id,
183 const GValue *value,
184 GParamSpec *pspec)
186 AdgArrowStyle *arrow_style = (AdgArrowStyle *) object;
188 switch (prop_id)
190 case PROP_SIZE:
191 arrow_style->priv->size = g_value_get_double (value);
192 break;
193 case PROP_ANGLE:
194 arrow_style->priv->angle = g_value_get_double (value);
195 break;
196 case PROP_MARGIN:
197 arrow_style->priv->margin = g_value_get_double (value);
198 break;
199 case PROP_RENDERER:
200 arrow_style->priv->renderer = g_value_get_pointer (value);
201 break;
202 default:
203 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
204 break;
210 * adg_arrow_style_get_slot:
212 * Gets the slot id for this style class.
214 * Return value: the slot
216 AdgStyleSlot
217 adg_arrow_style_get_slot (void)
219 static AdgStyleSlot slot = -1;
221 if G_UNLIKELY (slot < 0)
222 slot = adg_context_get_slot (ADG_TYPE_ARROW_STYLE);
224 return slot;
228 * adg_arrow_style_new:
230 * Constructs a new arrow style initialized with default params.
232 * Return value: a new arrow style
234 AdgStyle *
235 adg_arrow_style_new (void)
237 return g_object_new (ADG_TYPE_ARROW_STYLE, NULL);
241 * adg_arrow_style_render:
242 * @arrow_style: an #AdgArrowStyle instance
243 * @cr: the cairo context to use
244 * @segment: the #CpmlPath where the arrow must be rendered
246 * Renders an arrow on @cr at the beginning of @segment in the way
247 * specified by @arrow_style.
249 void
250 adg_arrow_style_render (AdgArrowStyle *arrow_style,
251 cairo_t *cr,
252 CpmlPath *segment)
254 g_return_if_fail (arrow_style != NULL);
255 g_return_if_fail (cr != NULL);
256 g_return_if_fail (segment != NULL);
258 /* NULL renderer */
259 if (arrow_style->priv->renderer == NULL)
260 return;
262 PARENT_CLASS->apply ((AdgStyle *) arrow_style, cr);
263 arrow_style->priv->renderer (arrow_style, cr, segment);
267 * adg_arrow_style_get_size:
268 * @arrow_style: an #AdgArrowStyle object
270 * Gets the size (in paper units) of the arrow (renderer dependent value).
272 * Return value: the size value
274 gdouble
275 adg_arrow_style_get_size (AdgArrowStyle *arrow_style)
277 g_return_val_if_fail (ADG_IS_ARROW_STYLE (arrow_style), 0.);
279 return arrow_style->priv->size;
283 * adg_arrow_style_set_size:
284 * @arrow_style: an #AdgArrowStyle object
285 * @size: the new size
287 * Sets a new size.
289 void
290 adg_arrow_style_set_size (AdgArrowStyle *arrow_style,
291 gdouble size)
293 g_return_if_fail (ADG_IS_ARROW_STYLE (arrow_style));
295 arrow_style->priv->size = size;
296 g_object_notify ((GObject *) arrow_style, "size");
300 * adg_arrow_style_get_angle:
301 * @arrow_style: an #AdgArrowStyle object
303 * Gets the angle (in degree) of the arrow (renderer dependent value).
305 * Return value: the angle value
307 gdouble
308 adg_arrow_style_get_angle (AdgArrowStyle *arrow_style)
310 g_return_val_if_fail (ADG_IS_ARROW_STYLE (arrow_style), 0.);
312 return arrow_style->priv->angle;
316 * adg_arrow_style_set_angle:
317 * @arrow_style: an #AdgArrowStyle object
318 * @angle: the new angle
320 * Sets a new angle.
322 void
323 adg_arrow_style_set_angle (AdgArrowStyle *arrow_style,
324 gdouble angle)
326 g_return_if_fail (ADG_IS_ARROW_STYLE (arrow_style));
328 arrow_style->priv->angle = angle;
329 g_object_notify ((GObject *) arrow_style, "angle");
333 * adg_arrow_style_get_margin:
334 * @arrow_style: an #AdgArrowStyle object
336 * Gets the margin (in paper units) of this arrow (renderer dependent value).
337 * The margin is also used to trim the baseline of this amount.
339 * Return value: the margin value
341 gdouble
342 adg_arrow_style_get_margin (AdgArrowStyle *arrow_style)
344 g_return_val_if_fail (ADG_IS_ARROW_STYLE (arrow_style), 0.);
346 return arrow_style->priv->margin;
350 * adg_arrow_style_set_margin:
351 * @arrow_style: an #AdgArrowStyle object
352 * @margin: the new margin
354 * Sets a new margin.
356 void
357 adg_arrow_style_set_margin (AdgArrowStyle *arrow_style,
358 gdouble margin)
360 g_return_if_fail (ADG_IS_ARROW_STYLE (arrow_style));
362 arrow_style->priv->margin = margin;
363 g_object_notify ((GObject *) arrow_style, "margin");
367 * adg_arrow_style_get_renderer:
368 * @arrow_style: an #AdgArrowStyle object
370 * Gets the renderer of @arrow_style.
372 * Return value: the renderer value
374 const AdgArrowRenderer
375 adg_arrow_style_get_renderer (AdgArrowStyle *arrow_style)
377 g_return_val_if_fail (ADG_IS_ARROW_STYLE (arrow_style), NULL);
379 return arrow_style->priv->renderer;
383 * adg_arrow_style_set_renderer:
384 * @arrow_style: an #AdgArrowStyle object
385 * @renderer: the new renderer
387 * Sets a new renderer.
389 void
390 adg_arrow_style_set_renderer (AdgArrowStyle *arrow_style,
391 AdgArrowRenderer renderer)
393 g_return_if_fail (ADG_IS_ARROW_STYLE (arrow_style));
395 arrow_style->priv->renderer = renderer;
396 g_object_notify ((GObject *) arrow_style, "renderer");
400 static GPtrArray *
401 get_pool (void)
403 static GPtrArray *pool = NULL;
405 if G_UNLIKELY (pool == NULL)
407 pool = g_ptr_array_sized_new (ADG_ARROW_STYLE_LAST);
409 pool->pdata[ADG_ARROW_STYLE_ARROW] = g_object_new (ADG_TYPE_ARROW_STYLE,
410 "renderer", arrow_renderer,
411 NULL);
412 pool->pdata[ADG_ARROW_STYLE_TRIANGLE] = g_object_new (ADG_TYPE_ARROW_STYLE,
413 "renderer", triangle_renderer,
414 NULL);
415 pool->pdata[ADG_ARROW_STYLE_DOT] = g_object_new (ADG_TYPE_ARROW_STYLE,
416 "size", 5.,
417 "angle", 0.,
418 "margin", 2.5,
419 "renderer", dot_renderer,
420 NULL);
421 pool->pdata[ADG_ARROW_STYLE_CIRCLE] = g_object_new (ADG_TYPE_ARROW_STYLE,
422 "size", 10.,
423 "angle", 0.,
424 "margin", 5.,
425 "renderer", circle_renderer,
426 NULL);
427 pool->pdata[ADG_ARROW_STYLE_BLOCK] = g_object_new (ADG_TYPE_ARROW_STYLE,
428 "size", 10.,
429 "angle", 0.,
430 "margin", 5.,
431 "renderer", block_renderer,
432 NULL);
433 pool->pdata[ADG_ARROW_STYLE_SQUARE] = g_object_new (ADG_TYPE_ARROW_STYLE,
434 "size", 10.,
435 "angle", 0.,
436 "margin", -0.1,
437 "renderer", square_renderer,
438 NULL);
439 pool->pdata[ADG_ARROW_STYLE_TICK] = g_object_new (ADG_TYPE_ARROW_STYLE,
440 "size", 20.,
441 "angle", G_PI / 3.,
442 "margin", 0.,
443 "renderer", tick_renderer,
444 NULL);
446 pool->len = ADG_ARROW_STYLE_LAST;
449 return pool;
452 static void
453 arrow_renderer (AdgArrowStyle *arrow_style,
454 cairo_t *cr,
455 CpmlPath *segment)
457 draw_triangle (cr, arrow_style, segment);
458 cairo_fill (cr);
461 static void
462 triangle_renderer (AdgArrowStyle *arrow_style,
463 cairo_t *cr,
464 CpmlPath *segment)
466 draw_triangle (cr, arrow_style, segment);
467 cairo_stroke (cr);
470 static void
471 dot_renderer (AdgArrowStyle *arrow_style,
472 cairo_t *cr,
473 CpmlPath *segment)
475 draw_circle (cr, arrow_style, segment);
476 cairo_fill (cr);
479 static void
480 circle_renderer (AdgArrowStyle *arrow_style,
481 cairo_t *cr,
482 CpmlPath *segment)
484 draw_circle (cr, arrow_style, segment);
485 cairo_stroke (cr);
488 static void
489 block_renderer (AdgArrowStyle *arrow_style,
490 cairo_t *cr,
491 CpmlPath *segment)
493 ADG_STUB ();
496 static void
497 square_renderer (AdgArrowStyle *arrow_style,
498 cairo_t *cr,
499 CpmlPath *segment)
501 ADG_STUB ();
504 static void
505 tick_renderer (AdgArrowStyle *arrow_style,
506 cairo_t *cr,
507 CpmlPath *segment)
509 ADG_STUB ();
512 static void
513 draw_triangle (cairo_t *cr,
514 AdgArrowStyle *arrow_style,
515 CpmlPath *segment)
517 double length, height_2;
518 double tmp;
519 CpmlPair tail, tail1, tail2;
520 CpmlPair vector;
522 length = arrow_style->priv->size;
523 height_2 = tan (arrow_style->priv->angle / 2.0) * length;
524 cairo_device_to_user_distance (cr, &length, &height_2);
526 switch (segment->cairo_path.data[0].header.type)
528 case CAIRO_PATH_LINE_TO:
529 cpml_primitive_get_pair (segment, &vector, CPML_FIRST);
530 vector.x -= segment->org.x;
531 vector.y -= segment->org.y;
532 cpml_vector_from_pair (&vector, &vector);
534 tail.x = vector.x*length + segment->org.x;
535 tail.y = vector.y*length + segment->org.y;
537 tmp = vector.x;
538 vector.x = -vector.y*height_2;
539 vector.y = tmp*height_2;
541 tail1.x = tail.x+vector.x;
542 tail1.y = tail.y+vector.y;
544 tail2.x = tail.x-vector.x;
545 tail2.y = tail.y-vector.y;
547 cairo_move_to (cr, segment->org.x, segment->org.y);
548 cairo_line_to (cr, tail1.x, tail1.y);
549 cairo_line_to (cr, tail2.x, tail2.y);
550 cairo_close_path (cr);
552 break;
553 case CAIRO_PATH_CURVE_TO:
554 ADG_STUB ();
555 break;
556 default:
557 g_assert_not_reached ();
561 static void
562 draw_circle (cairo_t *cr,
563 AdgArrowStyle *arrow_style,
564 CpmlPath *segment)
566 double radius = arrow_style->priv->size / 2.;
567 double dummy = 0.;
569 cairo_device_to_user_distance (cr, &radius, &dummy);
570 cairo_new_path (cr);
571 cairo_arc (cr, segment->org.x, segment->org.y, radius, 0., M_PI);