[build] Ignoring libtool m4 files
[adg.git] / adg / adg-arrow-style.c
blobc96276d4fbb652c69a4e8f175e5650483c40b072
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.
20 /**
21 * SECTION:arrow-style
22 * @title: AdgArrowStyle
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 #include "adg-arrow-style.h"
30 #include "adg-arrow-style-private.h"
31 #include "adg-context.h"
32 #include "adg-intl.h"
33 #include "adg-util.h"
34 #include <math.h>
37 enum {
38 PROP_0,
39 PROP_SIZE,
40 PROP_ANGLE,
41 PROP_MARGIN,
42 PROP_RENDERER
46 static void get_property (GObject *object,
47 guint prop_id,
48 GValue *value,
49 GParamSpec *pspec);
50 static void set_property (GObject *object,
51 guint prop_id,
52 const GValue *value,
53 GParamSpec *pspec);
54 static GPtrArray * get_pool (void);
55 static void arrow_renderer (AdgArrowStyle *arrow_style,
56 cairo_t *cr,
57 CpmlSegment *segment);
58 static void triangle_renderer (AdgArrowStyle *arrow_style,
59 cairo_t *cr,
60 CpmlSegment *segment);
61 static void dot_renderer (AdgArrowStyle *arrow_style,
62 cairo_t *cr,
63 CpmlSegment *segment);
64 static void circle_renderer (AdgArrowStyle *arrow_style,
65 cairo_t *cr,
66 CpmlSegment *segment);
67 static void block_renderer (AdgArrowStyle *arrow_style,
68 cairo_t *cr,
69 CpmlSegment *segment);
70 static void square_renderer (AdgArrowStyle *arrow_style,
71 cairo_t *cr,
72 CpmlSegment *segment);
73 static void tick_renderer (AdgArrowStyle *arrow_style,
74 cairo_t *cr,
75 CpmlSegment *segment);
76 static void draw_triangle (cairo_t *cr,
77 AdgArrowStyle *arrow_style,
78 CpmlSegment *segment);
79 static void draw_circle (cairo_t *cr,
80 AdgArrowStyle *arrow_style,
81 CpmlSegment *segment);
84 G_DEFINE_TYPE(AdgArrowStyle, adg_arrow_style, ADG_TYPE_STYLE)
87 static void
88 adg_arrow_style_class_init(AdgArrowStyleClass *klass)
90 GObjectClass *gobject_class;
91 AdgStyleClass *style_class;
92 GParamSpec *param;
94 gobject_class = (GObjectClass *) klass;
95 style_class = (AdgStyleClass *) klass;
97 g_type_class_add_private(klass, sizeof(AdgArrowStylePrivate));
99 gobject_class->get_property = get_property;
100 gobject_class->set_property = set_property;
102 style_class->get_pool = get_pool;
104 param = g_param_spec_double("size",
105 P_("Arrow Size"),
107 ("The size of the arrow, a renderer dependent parameter"),
108 -G_MAXDOUBLE, G_MAXDOUBLE, 14.,
109 G_PARAM_READWRITE);
110 g_object_class_install_property(gobject_class, PROP_SIZE, param);
112 param = g_param_spec_double("angle",
113 P_("Arrow Angle"),
115 ("The angle of the arrow, a renderer dependent parameter"),
116 -G_MAXDOUBLE, G_MAXDOUBLE, G_PI / 6.,
117 G_PARAM_READWRITE);
118 g_object_class_install_property(gobject_class, PROP_ANGLE, param);
120 param = g_param_spec_double("margin",
121 P_("Arrow Margin"),
123 ("The margin of the arrow, a renderer dependent parameter"),
124 -G_MAXDOUBLE, G_MAXDOUBLE, 14.,
125 G_PARAM_READWRITE);
126 g_object_class_install_property(gobject_class, PROP_MARGIN, param);
128 param = g_param_spec_pointer("renderer",
129 P_("Renderer Callback"),
131 ("The callback to call to renderer this arrow type"),
132 G_PARAM_READWRITE);
133 g_object_class_install_property(gobject_class, PROP_RENDERER, param);
136 static void
137 adg_arrow_style_init(AdgArrowStyle *arrow_style)
139 AdgArrowStylePrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE(arrow_style,
140 ADG_TYPE_ARROW_STYLE,
141 AdgArrowStylePrivate);
143 priv->size = 14.;
144 priv->angle = G_PI / 6.;
145 priv->margin = 14.;
146 priv->renderer = NULL;
148 arrow_style->priv = priv;
151 static void
152 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
154 AdgArrowStyle *arrow_style = (AdgArrowStyle *) object;
156 switch (prop_id) {
157 case PROP_SIZE:
158 g_value_set_double(value, arrow_style->priv->size);
159 break;
160 case PROP_ANGLE:
161 g_value_set_double(value, arrow_style->priv->angle);
162 break;
163 case PROP_MARGIN:
164 g_value_set_double(value, arrow_style->priv->margin);
165 break;
166 case PROP_RENDERER:
167 g_value_set_pointer(value, arrow_style->priv->renderer);
168 break;
169 default:
170 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
171 break;
175 static void
176 set_property(GObject *object,
177 guint prop_id, const GValue *value, GParamSpec *pspec)
179 AdgArrowStyle *arrow_style = (AdgArrowStyle *) object;
181 switch (prop_id) {
182 case PROP_SIZE:
183 arrow_style->priv->size = g_value_get_double(value);
184 break;
185 case PROP_ANGLE:
186 arrow_style->priv->angle = g_value_get_double(value);
187 break;
188 case PROP_MARGIN:
189 arrow_style->priv->margin = g_value_get_double(value);
190 break;
191 case PROP_RENDERER:
192 arrow_style->priv->renderer = g_value_get_pointer(value);
193 break;
194 default:
195 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
196 break;
202 * adg_arrow_style_get_slot:
204 * Gets the slot id for this style class.
206 * Return value: the slot
208 AdgStyleSlot
209 adg_arrow_style_get_slot(void)
211 static AdgStyleSlot slot = -1;
213 if (G_UNLIKELY(slot < 0))
214 slot = adg_context_get_slot(ADG_TYPE_ARROW_STYLE);
216 return slot;
220 * adg_arrow_style_new:
222 * Constructs a new arrow style initialized with default params.
224 * Return value: a new arrow style
226 AdgStyle *
227 adg_arrow_style_new(void)
229 return g_object_new(ADG_TYPE_ARROW_STYLE, NULL);
233 * adg_arrow_style_render:
234 * @arrow_style: an #AdgArrowStyle instance
235 * @cr: the cairo context to use
236 * @segment: the #CpmlSegment where the arrow must be rendered
238 * Renders an arrow on @cr at the beginning of @segment in the way
239 * specified by @arrow_style.
241 void
242 adg_arrow_style_render(AdgArrowStyle *arrow_style,
243 cairo_t *cr, CpmlSegment *segment)
245 AdgStyleClass *style_class;
247 g_return_if_fail(arrow_style != NULL);
248 g_return_if_fail(cr != NULL);
249 g_return_if_fail(segment != NULL);
251 /* NULL renderer */
252 if (arrow_style->priv->renderer == NULL)
253 return;
255 style_class = (AdgStyleClass *) adg_arrow_style_parent_class;
257 if (style_class->apply != NULL)
258 style_class->apply((AdgStyle *) arrow_style, cr);
260 arrow_style->priv->renderer(arrow_style, cr, segment);
264 * adg_arrow_style_get_size:
265 * @arrow_style: an #AdgArrowStyle object
267 * Gets the size (in paper units) of the arrow (renderer dependent value).
269 * Return value: the size value
271 gdouble
272 adg_arrow_style_get_size(AdgArrowStyle *arrow_style)
274 g_return_val_if_fail(ADG_IS_ARROW_STYLE(arrow_style), 0.);
276 return arrow_style->priv->size;
280 * adg_arrow_style_set_size:
281 * @arrow_style: an #AdgArrowStyle object
282 * @size: the new size
284 * Sets a new size.
286 void
287 adg_arrow_style_set_size(AdgArrowStyle *arrow_style, gdouble size)
289 g_return_if_fail(ADG_IS_ARROW_STYLE(arrow_style));
291 arrow_style->priv->size = size;
292 g_object_notify((GObject *) arrow_style, "size");
296 * adg_arrow_style_get_angle:
297 * @arrow_style: an #AdgArrowStyle object
299 * Gets the angle (in degree) of the arrow (renderer dependent value).
301 * Return value: the angle value
303 gdouble
304 adg_arrow_style_get_angle(AdgArrowStyle *arrow_style)
306 g_return_val_if_fail(ADG_IS_ARROW_STYLE(arrow_style), 0.);
308 return arrow_style->priv->angle;
312 * adg_arrow_style_set_angle:
313 * @arrow_style: an #AdgArrowStyle object
314 * @angle: the new angle
316 * Sets a new angle.
318 void
319 adg_arrow_style_set_angle(AdgArrowStyle *arrow_style, gdouble angle)
321 g_return_if_fail(ADG_IS_ARROW_STYLE(arrow_style));
323 arrow_style->priv->angle = angle;
324 g_object_notify((GObject *) arrow_style, "angle");
328 * adg_arrow_style_get_margin:
329 * @arrow_style: an #AdgArrowStyle object
331 * Gets the margin (in paper units) of this arrow (renderer dependent value).
332 * The margin is also used to trim the baseline of this amount.
334 * Return value: the margin value
336 gdouble
337 adg_arrow_style_get_margin(AdgArrowStyle *arrow_style)
339 g_return_val_if_fail(ADG_IS_ARROW_STYLE(arrow_style), 0.);
341 return arrow_style->priv->margin;
345 * adg_arrow_style_set_margin:
346 * @arrow_style: an #AdgArrowStyle object
347 * @margin: the new margin
349 * Sets a new margin.
351 void
352 adg_arrow_style_set_margin(AdgArrowStyle *arrow_style, gdouble margin)
354 g_return_if_fail(ADG_IS_ARROW_STYLE(arrow_style));
356 arrow_style->priv->margin = margin;
357 g_object_notify((GObject *) arrow_style, "margin");
361 * adg_arrow_style_get_renderer:
362 * @arrow_style: an #AdgArrowStyle object
364 * Gets the renderer of @arrow_style.
366 * Return value: the renderer value
368 AdgArrowRenderer
369 adg_arrow_style_get_renderer(AdgArrowStyle *arrow_style)
371 g_return_val_if_fail(ADG_IS_ARROW_STYLE(arrow_style), NULL);
373 return arrow_style->priv->renderer;
377 * adg_arrow_style_set_renderer:
378 * @arrow_style: an #AdgArrowStyle object
379 * @renderer: the new renderer
381 * Sets a new renderer.
383 void
384 adg_arrow_style_set_renderer(AdgArrowStyle *arrow_style,
385 AdgArrowRenderer renderer)
387 g_return_if_fail(ADG_IS_ARROW_STYLE(arrow_style));
389 arrow_style->priv->renderer = renderer;
390 g_object_notify((GObject *) arrow_style, "renderer");
394 static GPtrArray *
395 get_pool(void)
397 static GPtrArray *pool = NULL;
399 if (G_UNLIKELY(pool == NULL)) {
400 pool = g_ptr_array_sized_new(ADG_ARROW_STYLE_LAST);
402 pool->pdata[ADG_ARROW_STYLE_ARROW] =
403 g_object_new(ADG_TYPE_ARROW_STYLE, "renderer", arrow_renderer,
404 NULL);
405 pool->pdata[ADG_ARROW_STYLE_TRIANGLE] =
406 g_object_new(ADG_TYPE_ARROW_STYLE, "renderer",
407 triangle_renderer, NULL);
408 pool->pdata[ADG_ARROW_STYLE_DOT] =
409 g_object_new(ADG_TYPE_ARROW_STYLE, "size", 5., "angle", 0.,
410 "margin", 2.5, "renderer", dot_renderer, NULL);
411 pool->pdata[ADG_ARROW_STYLE_CIRCLE] =
412 g_object_new(ADG_TYPE_ARROW_STYLE, "size", 10., "angle", 0.,
413 "margin", 5., "renderer", circle_renderer, NULL);
414 pool->pdata[ADG_ARROW_STYLE_BLOCK] =
415 g_object_new(ADG_TYPE_ARROW_STYLE, "size", 10., "angle", 0.,
416 "margin", 5., "renderer", block_renderer, NULL);
417 pool->pdata[ADG_ARROW_STYLE_SQUARE] =
418 g_object_new(ADG_TYPE_ARROW_STYLE, "size", 10., "angle", 0.,
419 "margin", -0.1, "renderer", square_renderer,
420 NULL);
421 pool->pdata[ADG_ARROW_STYLE_TICK] =
422 g_object_new(ADG_TYPE_ARROW_STYLE, "size", 20., "angle",
423 G_PI / 3., "margin", 0., "renderer",
424 tick_renderer, NULL);
426 pool->len = ADG_ARROW_STYLE_LAST;
429 return pool;
432 static void
433 arrow_renderer(AdgArrowStyle *arrow_style, cairo_t *cr, CpmlSegment *segment)
435 draw_triangle(cr, arrow_style, segment);
436 cairo_fill(cr);
439 static void
440 triangle_renderer(AdgArrowStyle *arrow_style, cairo_t *cr, CpmlSegment *segment)
442 draw_triangle(cr, arrow_style, segment);
443 cairo_stroke(cr);
446 static void
447 dot_renderer(AdgArrowStyle *arrow_style, cairo_t *cr, CpmlSegment *segment)
449 draw_circle(cr, arrow_style, segment);
450 cairo_fill(cr);
453 static void
454 circle_renderer(AdgArrowStyle *arrow_style, cairo_t *cr, CpmlSegment *segment)
456 draw_circle(cr, arrow_style, segment);
457 cairo_stroke(cr);
460 static void
461 block_renderer(AdgArrowStyle *arrow_style, cairo_t *cr, CpmlSegment *segment)
463 ADG_STUB();
466 static void
467 square_renderer(AdgArrowStyle *arrow_style, cairo_t *cr, CpmlSegment *segment)
469 ADG_STUB();
472 static void
473 tick_renderer(AdgArrowStyle *arrow_style, cairo_t *cr, CpmlSegment *segment)
475 ADG_STUB();
478 static void
479 draw_triangle(cairo_t *cr, AdgArrowStyle *arrow_style, CpmlSegment *segment)
481 double length, height_2;
482 double org_x, org_y;
483 double tmp;
484 CpmlPair tail, tail1, tail2;
485 CpmlPair vector;
487 length = arrow_style->priv->size;
488 height_2 = tan(arrow_style->priv->angle / 2.0) * length;
489 cairo_device_to_user_distance(cr, &length, &height_2);
490 org_x = segment->data[1].point.x;
491 org_y = segment->data[1].point.y;
493 switch (segment->data[2].header.type) {
494 case CAIRO_PATH_LINE_TO:
495 vector.x = segment->data[3].point.x - org_x;
496 vector.y = segment->data[3].point.y - org_y;
497 cpml_vector_set_length(&vector, 1.);
499 tail.x = vector.x * length + org_x;
500 tail.y = vector.y * length + org_y;
502 tmp = vector.x;
503 vector.x = -vector.y * height_2;
504 vector.y = tmp * height_2;
506 tail1.x = tail.x + vector.x;
507 tail1.y = tail.y + vector.y;
509 tail2.x = tail.x - vector.x;
510 tail2.y = tail.y - vector.y;
512 cairo_move_to(cr, org_x, org_y);
513 cairo_line_to(cr, tail1.x, tail1.y);
514 cairo_line_to(cr, tail2.x, tail2.y);
515 cairo_close_path(cr);
517 break;
518 case CAIRO_PATH_CURVE_TO:
519 ADG_STUB();
520 break;
521 default:
522 g_assert_not_reached();
526 static void
527 draw_circle(cairo_t *cr, AdgArrowStyle *arrow_style, CpmlSegment *segment)
529 double radius = arrow_style->priv->size / 2.;
530 double dummy = 0.;
532 cairo_device_to_user_distance(cr, &radius, &dummy);
533 cairo_new_path(cr);
534 cairo_arc(cr,
535 segment->data[1].point.x, segment->data[1].point.y,
536 radius, 0., M_PI);