Reworked whole documentation and improved organization
[adg.git] / adg / adg-arrow-style.c
blob545d753e217ae43956a28a447532a9938f1ecc82
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);
270 static void
271 arrow_renderer (AdgArrowStyle *arrow_style,
272 cairo_t *cr,
273 CpmlPath *segment)
275 draw_triangle (cr, arrow_style, segment);
276 cairo_fill (cr);
279 static void
280 triangle_renderer (AdgArrowStyle *arrow_style,
281 cairo_t *cr,
282 CpmlPath *segment)
284 draw_triangle (cr, arrow_style, segment);
285 cairo_stroke (cr);
288 static void
289 dot_renderer (AdgArrowStyle *arrow_style,
290 cairo_t *cr,
291 CpmlPath *segment)
293 draw_circle (cr, arrow_style, segment);
294 cairo_fill (cr);
297 static void
298 circle_renderer (AdgArrowStyle *arrow_style,
299 cairo_t *cr,
300 CpmlPath *segment)
302 draw_circle (cr, arrow_style, segment);
303 cairo_stroke (cr);
306 static void
307 block_renderer (AdgArrowStyle *arrow_style,
308 cairo_t *cr,
309 CpmlPath *segment)
311 ADG_STUB ();
314 static void
315 square_renderer (AdgArrowStyle *arrow_style,
316 cairo_t *cr,
317 CpmlPath *segment)
319 ADG_STUB ();
322 static void
323 tick_renderer (AdgArrowStyle *arrow_style,
324 cairo_t *cr,
325 CpmlPath *segment)
327 ADG_STUB ();
330 static void
331 draw_triangle (cairo_t *cr,
332 AdgArrowStyle *arrow_style,
333 CpmlPath *segment)
335 double length, height_2;
336 double tmp;
337 CpmlPair tail, tail1, tail2;
338 CpmlPair vector;
340 length = arrow_style->priv->size;
341 height_2 = tan (arrow_style->priv->angle / 2.0) * length;
342 cairo_device_to_user_distance (cr, &length, &height_2);
344 switch (segment->cairo_path.data[0].header.type)
346 case CAIRO_PATH_LINE_TO:
347 cpml_primitive_get_pair (segment, &vector, CPML_FIRST);
348 vector.x -= segment->org.x;
349 vector.y -= segment->org.y;
350 cpml_vector_from_pair (&vector, &vector);
352 tail.x = vector.x*length + segment->org.x;
353 tail.y = vector.y*length + segment->org.y;
355 tmp = vector.x;
356 vector.x = -vector.y*height_2;
357 vector.y = tmp*height_2;
359 tail1.x = tail.x+vector.x;
360 tail1.y = tail.y+vector.y;
362 tail2.x = tail.x-vector.x;
363 tail2.y = tail.y-vector.y;
365 cairo_move_to (cr, segment->org.x, segment->org.y);
366 cairo_line_to (cr, tail1.x, tail1.y);
367 cairo_line_to (cr, tail2.x, tail2.y);
368 cairo_close_path (cr);
370 break;
371 case CAIRO_PATH_CURVE_TO:
372 ADG_STUB ();
373 break;
374 default:
375 g_assert_not_reached ();
379 static void
380 draw_circle (cairo_t *cr,
381 AdgArrowStyle *arrow_style,
382 CpmlPath *segment)
384 double radius = arrow_style->priv->size / 2.;
385 double dummy = 0.;
387 cairo_device_to_user_distance (cr, &radius, &dummy);
388 cairo_new_path (cr);
389 cairo_arc (cr, segment->org.x, segment->org.y, radius, 0., M_PI);