Implemented patterns in AdgStyle
[adg.git] / adg / adg-arrow-style.c
blob31f8c39b0ce7746c5ede26dcf7b66f86ea892cfc
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);
58 static void arrow_renderer (AdgArrowStyle *arrow_style,
59 cairo_t *cr,
60 CpmlPath *segment);
61 static void triangle_renderer (AdgArrowStyle *arrow_style,
62 cairo_t *cr,
63 CpmlPath *segment);
64 static void dot_renderer (AdgArrowStyle *arrow_style,
65 cairo_t *cr,
66 CpmlPath *segment);
67 static void circle_renderer (AdgArrowStyle *arrow_style,
68 cairo_t *cr,
69 CpmlPath *segment);
70 static void block_renderer (AdgArrowStyle *arrow_style,
71 cairo_t *cr,
72 CpmlPath *segment);
73 static void square_renderer (AdgArrowStyle *arrow_style,
74 cairo_t *cr,
75 CpmlPath *segment);
76 static void tick_renderer (AdgArrowStyle *arrow_style,
77 cairo_t *cr,
78 CpmlPath *segment);
79 static void draw_triangle (cairo_t *cr,
80 AdgArrowStyle *arrow_style,
81 CpmlPath *segment);
82 static void draw_circle (cairo_t *cr,
83 AdgArrowStyle *arrow_style,
84 CpmlPath *segment);
87 G_DEFINE_TYPE (AdgArrowStyle, adg_arrow_style, ADG_TYPE_STYLE)
90 static void
91 adg_arrow_style_class_init (AdgArrowStyleClass *klass)
93 GObjectClass *gobject_class;
94 GParamSpec *param;
96 gobject_class = (GObjectClass *) klass;
98 g_type_class_add_private (klass, sizeof (AdgArrowStylePrivate));
100 gobject_class->get_property = get_property;
101 gobject_class->set_property = set_property;
103 param = g_param_spec_double ("size",
104 P_("Arrow Size"),
105 P_("The size of the arrow, a renderer dependent parameter"),
106 -G_MAXDOUBLE, G_MAXDOUBLE, 14.,
107 G_PARAM_READWRITE);
108 g_object_class_install_property (gobject_class, PROP_SIZE, param);
110 param = g_param_spec_double ("angle",
111 P_("Arrow Angle"),
112 P_("The angle of the arrow, a renderer dependent parameter"),
113 -G_MAXDOUBLE, G_MAXDOUBLE, G_PI / 6.,
114 G_PARAM_READWRITE);
115 g_object_class_install_property (gobject_class, PROP_ANGLE, param);
117 param = g_param_spec_double ("margin",
118 P_("Arrow Margin"),
119 P_("The margin of the arrow, a renderer dependent parameter"),
120 -G_MAXDOUBLE, G_MAXDOUBLE, 14.,
121 G_PARAM_READWRITE);
122 g_object_class_install_property (gobject_class, PROP_MARGIN, param);
124 param = g_param_spec_pointer ("renderer",
125 P_("Renderer Callback"),
126 P_("The callback to call to renderer this arrow type"),
127 G_PARAM_READWRITE);
128 g_object_class_install_property (gobject_class, PROP_RENDERER, param);
131 static void
132 adg_arrow_style_init (AdgArrowStyle *arrow_style)
134 AdgArrowStylePrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (arrow_style,
135 ADG_TYPE_ARROW_STYLE,
136 AdgArrowStylePrivate);
138 priv->size = 14.;
139 priv->angle = G_PI / 6.;
140 priv->margin = 14.;
141 priv->renderer = NULL;
143 arrow_style->priv = priv;
146 static void
147 get_property (GObject *object,
148 guint prop_id,
149 GValue *value,
150 GParamSpec *pspec)
152 AdgArrowStyle *arrow_style = (AdgArrowStyle *) object;
154 switch (prop_id)
156 case PROP_SIZE:
157 g_value_set_double (value, arrow_style->priv->size);
158 break;
159 case PROP_ANGLE:
160 g_value_set_double (value, arrow_style->priv->angle);
161 break;
162 case PROP_MARGIN:
163 g_value_set_double (value, arrow_style->priv->margin);
164 break;
165 case PROP_RENDERER:
166 g_value_set_pointer (value, arrow_style->priv->renderer);
167 break;
168 default:
169 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
170 break;
174 static void
175 set_property (GObject *object,
176 guint prop_id,
177 const GValue *value,
178 GParamSpec *pspec)
180 AdgArrowStyle *arrow_style = (AdgArrowStyle *) object;
182 switch (prop_id)
184 case PROP_SIZE:
185 arrow_style->priv->size = g_value_get_double (value);
186 break;
187 case PROP_ANGLE:
188 arrow_style->priv->angle = g_value_get_double (value);
189 break;
190 case PROP_MARGIN:
191 arrow_style->priv->margin = g_value_get_double (value);
192 break;
193 case PROP_RENDERER:
194 arrow_style->priv->renderer = g_value_get_pointer (value);
195 break;
196 default:
197 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
198 break;
203 AdgStyle *
204 adg_arrow_style_from_id (AdgArrowStyleId id)
206 static AdgStyle **builtins = NULL;
208 if G_UNLIKELY (builtins == NULL)
210 builtins = g_new (AdgStyle *, ADG_ARROW_STYLE_LAST);
212 builtins[ADG_ARROW_STYLE_ARROW] = g_object_new (ADG_TYPE_ARROW_STYLE,
213 "renderer", arrow_renderer,
214 NULL);
215 builtins[ADG_ARROW_STYLE_TRIANGLE] = g_object_new (ADG_TYPE_ARROW_STYLE,
216 "renderer", triangle_renderer,
217 NULL);
218 builtins[ADG_ARROW_STYLE_DOT] = g_object_new (ADG_TYPE_ARROW_STYLE,
219 "size", 5.,
220 "angle", 0.,
221 "margin", 2.5,
222 "renderer", dot_renderer,
223 NULL);
224 builtins[ADG_ARROW_STYLE_CIRCLE] = g_object_new (ADG_TYPE_ARROW_STYLE,
225 "size", 10.,
226 "angle", 0.,
227 "margin", 5.,
228 "renderer", circle_renderer,
229 NULL);
230 builtins[ADG_ARROW_STYLE_BLOCK] = g_object_new (ADG_TYPE_ARROW_STYLE,
231 "size", 10.,
232 "angle", 0.,
233 "margin", 5.,
234 "renderer", block_renderer,
235 NULL);
236 builtins[ADG_ARROW_STYLE_SQUARE] = g_object_new (ADG_TYPE_ARROW_STYLE,
237 "size", 10.,
238 "angle", 0.,
239 "margin", -0.1,
240 "renderer", square_renderer,
241 NULL);
242 builtins[ADG_ARROW_STYLE_TICK] = g_object_new (ADG_TYPE_ARROW_STYLE,
243 "size", 20.,
244 "angle", G_PI / 3.,
245 "margin", 0.,
246 "renderer", tick_renderer,
247 NULL);
250 g_return_val_if_fail (id < ADG_ARROW_STYLE_LAST, NULL);
251 return builtins[id];
254 void
255 adg_arrow_style_render (AdgArrowStyle *arrow_style,
256 cairo_t *cr,
257 CpmlPath *segment)
259 g_return_if_fail (arrow_style != NULL);
260 g_return_if_fail (cr != NULL);
261 g_return_if_fail (segment != NULL);
263 /* NULL renderer */
264 if (arrow_style->priv->renderer == NULL)
265 return;
267 arrow_style->priv->renderer (arrow_style, cr, segment);
271 * adg_arrow_style_get_size:
272 * @arrow_style: an #AdgArrowStyle object
274 * Gets the size (in paper units) of the arrow (renderer dependent value).
276 * Return value: the size value
278 gdouble
279 adg_arrow_style_get_size (AdgArrowStyle *arrow_style)
281 g_return_val_if_fail (ADG_IS_ARROW_STYLE (arrow_style), 0.);
283 return arrow_style->priv->size;
287 * adg_arrow_style_set_size:
288 * @arrow_style: an #AdgArrowStyle object
289 * @size: the new size
291 * Sets a new size.
293 void
294 adg_arrow_style_set_size (AdgArrowStyle *arrow_style,
295 gdouble size)
297 g_return_if_fail (ADG_IS_ARROW_STYLE (arrow_style));
299 arrow_style->priv->size = size;
300 g_object_notify ((GObject *) arrow_style, "size");
304 * adg_arrow_style_get_angle:
305 * @arrow_style: an #AdgArrowStyle object
307 * Gets the angle (in degree) of the arrow (renderer dependent value).
309 * Return value: the angle value
311 gdouble
312 adg_arrow_style_get_angle (AdgArrowStyle *arrow_style)
314 g_return_val_if_fail (ADG_IS_ARROW_STYLE (arrow_style), 0.);
316 return arrow_style->priv->angle;
320 * adg_arrow_style_set_angle:
321 * @arrow_style: an #AdgArrowStyle object
322 * @angle: the new angle
324 * Sets a new angle.
326 void
327 adg_arrow_style_set_angle (AdgArrowStyle *arrow_style,
328 gdouble angle)
330 g_return_if_fail (ADG_IS_ARROW_STYLE (arrow_style));
332 arrow_style->priv->angle = angle;
333 g_object_notify ((GObject *) arrow_style, "angle");
337 * adg_arrow_style_get_margin:
338 * @arrow_style: an #AdgArrowStyle object
340 * Gets the margin (in paper units) of this arrow (renderer dependent value).
341 * The margin is also used to trim the baseline of this amount.
343 * Return value: the margin value
345 gdouble
346 adg_arrow_style_get_margin (AdgArrowStyle *arrow_style)
348 g_return_val_if_fail (ADG_IS_ARROW_STYLE (arrow_style), 0.);
350 return arrow_style->priv->margin;
354 * adg_arrow_style_set_margin:
355 * @arrow_style: an #AdgArrowStyle object
356 * @margin: the new margin
358 * Sets a new margin.
360 void
361 adg_arrow_style_set_margin (AdgArrowStyle *arrow_style,
362 gdouble margin)
364 g_return_if_fail (ADG_IS_ARROW_STYLE (arrow_style));
366 arrow_style->priv->margin = margin;
367 g_object_notify ((GObject *) arrow_style, "margin");
371 * adg_arrow_style_get_renderer:
372 * @arrow_style: an #AdgArrowStyle object
374 * Gets the renderer of @arrow_style.
376 * Return value: the renderer value
378 const AdgArrowRenderer
379 adg_arrow_style_get_renderer (AdgArrowStyle *arrow_style)
381 g_return_val_if_fail (ADG_IS_ARROW_STYLE (arrow_style), NULL);
383 return arrow_style->priv->renderer;
387 * adg_arrow_style_set_renderer:
388 * @arrow_style: an #AdgArrowStyle object
389 * @renderer: the new renderer
391 * Sets a new renderer.
393 void
394 adg_arrow_style_set_renderer (AdgArrowStyle *arrow_style,
395 AdgArrowRenderer renderer)
397 g_return_if_fail (ADG_IS_ARROW_STYLE (arrow_style));
399 arrow_style->priv->renderer = renderer;
400 g_object_notify ((GObject *) arrow_style, "renderer");
404 static void
405 arrow_renderer (AdgArrowStyle *arrow_style,
406 cairo_t *cr,
407 CpmlPath *segment)
409 draw_triangle (cr, arrow_style, segment);
410 cairo_fill (cr);
413 static void
414 triangle_renderer (AdgArrowStyle *arrow_style,
415 cairo_t *cr,
416 CpmlPath *segment)
418 draw_triangle (cr, arrow_style, segment);
419 cairo_stroke (cr);
422 static void
423 dot_renderer (AdgArrowStyle *arrow_style,
424 cairo_t *cr,
425 CpmlPath *segment)
427 draw_circle (cr, arrow_style, segment);
428 cairo_fill (cr);
431 static void
432 circle_renderer (AdgArrowStyle *arrow_style,
433 cairo_t *cr,
434 CpmlPath *segment)
436 draw_circle (cr, arrow_style, segment);
437 cairo_stroke (cr);
440 static void
441 block_renderer (AdgArrowStyle *arrow_style,
442 cairo_t *cr,
443 CpmlPath *segment)
445 ADG_STUB ();
448 static void
449 square_renderer (AdgArrowStyle *arrow_style,
450 cairo_t *cr,
451 CpmlPath *segment)
453 ADG_STUB ();
456 static void
457 tick_renderer (AdgArrowStyle *arrow_style,
458 cairo_t *cr,
459 CpmlPath *segment)
461 ADG_STUB ();
464 static void
465 draw_triangle (cairo_t *cr,
466 AdgArrowStyle *arrow_style,
467 CpmlPath *segment)
469 double length, height_2;
470 double tmp;
471 CpmlPair tail, tail1, tail2;
472 CpmlPair vector;
474 length = arrow_style->priv->size;
475 height_2 = tan (arrow_style->priv->angle / 2.0) * length;
476 cairo_device_to_user_distance (cr, &length, &height_2);
478 switch (segment->cairo_path.data[0].header.type)
480 case CAIRO_PATH_LINE_TO:
481 cpml_primitive_get_pair (segment, &vector, CPML_FIRST);
482 vector.x -= segment->org.x;
483 vector.y -= segment->org.y;
484 cpml_vector_from_pair (&vector, &vector);
486 tail.x = vector.x*length + segment->org.x;
487 tail.y = vector.y*length + segment->org.y;
489 tmp = vector.x;
490 vector.x = -vector.y*height_2;
491 vector.y = tmp*height_2;
493 tail1.x = tail.x+vector.x;
494 tail1.y = tail.y+vector.y;
496 tail2.x = tail.x-vector.x;
497 tail2.y = tail.y-vector.y;
499 cairo_move_to (cr, segment->org.x, segment->org.y);
500 cairo_line_to (cr, tail1.x, tail1.y);
501 cairo_line_to (cr, tail2.x, tail2.y);
502 cairo_close_path (cr);
504 break;
505 case CAIRO_PATH_CURVE_TO:
506 ADG_STUB ();
507 break;
508 default:
509 g_assert_not_reached ();
513 static void
514 draw_circle (cairo_t *cr,
515 AdgArrowStyle *arrow_style,
516 CpmlPath *segment)
518 double radius = arrow_style->priv->size / 2.;
519 double dummy = 0.;
521 cairo_device_to_user_distance (cr, &radius, &dummy);
522 cairo_new_path (cr);
523 cairo_arc (cr, segment->org.x, segment->org.y, radius, 0., M_PI);