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.
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"
37 #define PARENT_CLASS ((AdgStyleClass *) adg_arrow_style_parent_class)
50 static void get_property (GObject
*object
,
54 static void set_property (GObject
*object
,
58 static void arrow_renderer (AdgArrowStyle
*arrow_style
,
61 static void triangle_renderer (AdgArrowStyle
*arrow_style
,
64 static void dot_renderer (AdgArrowStyle
*arrow_style
,
67 static void circle_renderer (AdgArrowStyle
*arrow_style
,
70 static void block_renderer (AdgArrowStyle
*arrow_style
,
73 static void square_renderer (AdgArrowStyle
*arrow_style
,
76 static void tick_renderer (AdgArrowStyle
*arrow_style
,
79 static void draw_triangle (cairo_t
*cr
,
80 AdgArrowStyle
*arrow_style
,
82 static void draw_circle (cairo_t
*cr
,
83 AdgArrowStyle
*arrow_style
,
87 G_DEFINE_TYPE (AdgArrowStyle
, adg_arrow_style
, ADG_TYPE_STYLE
)
91 adg_arrow_style_class_init (AdgArrowStyleClass
*klass
)
93 GObjectClass
*gobject_class
;
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",
105 P_("The size of the arrow, a renderer dependent parameter"),
106 -G_MAXDOUBLE
, G_MAXDOUBLE
, 14.,
108 g_object_class_install_property (gobject_class
, PROP_SIZE
, param
);
110 param
= g_param_spec_double ("angle",
112 P_("The angle of the arrow, a renderer dependent parameter"),
113 -G_MAXDOUBLE
, G_MAXDOUBLE
, G_PI
/ 6.,
115 g_object_class_install_property (gobject_class
, PROP_ANGLE
, param
);
117 param
= g_param_spec_double ("margin",
119 P_("The margin of the arrow, a renderer dependent parameter"),
120 -G_MAXDOUBLE
, G_MAXDOUBLE
, 14.,
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"),
128 g_object_class_install_property (gobject_class
, PROP_RENDERER
, param
);
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
);
139 priv
->angle
= G_PI
/ 6.;
141 priv
->renderer
= NULL
;
143 arrow_style
->priv
= priv
;
147 get_property (GObject
*object
,
152 AdgArrowStyle
*arrow_style
= (AdgArrowStyle
*) object
;
157 g_value_set_double (value
, arrow_style
->priv
->size
);
160 g_value_set_double (value
, arrow_style
->priv
->angle
);
163 g_value_set_double (value
, arrow_style
->priv
->margin
);
166 g_value_set_pointer (value
, arrow_style
->priv
->renderer
);
169 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
175 set_property (GObject
*object
,
180 AdgArrowStyle
*arrow_style
= (AdgArrowStyle
*) object
;
185 arrow_style
->priv
->size
= g_value_get_double (value
);
188 arrow_style
->priv
->angle
= g_value_get_double (value
);
191 arrow_style
->priv
->margin
= g_value_get_double (value
);
194 arrow_style
->priv
->renderer
= g_value_get_pointer (value
);
197 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
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
,
215 builtins
[ADG_ARROW_STYLE_TRIANGLE
] = g_object_new (ADG_TYPE_ARROW_STYLE
,
216 "renderer", triangle_renderer
,
218 builtins
[ADG_ARROW_STYLE_DOT
] = g_object_new (ADG_TYPE_ARROW_STYLE
,
222 "renderer", dot_renderer
,
224 builtins
[ADG_ARROW_STYLE_CIRCLE
] = g_object_new (ADG_TYPE_ARROW_STYLE
,
228 "renderer", circle_renderer
,
230 builtins
[ADG_ARROW_STYLE_BLOCK
] = g_object_new (ADG_TYPE_ARROW_STYLE
,
234 "renderer", block_renderer
,
236 builtins
[ADG_ARROW_STYLE_SQUARE
] = g_object_new (ADG_TYPE_ARROW_STYLE
,
240 "renderer", square_renderer
,
242 builtins
[ADG_ARROW_STYLE_TICK
] = g_object_new (ADG_TYPE_ARROW_STYLE
,
246 "renderer", tick_renderer
,
250 g_return_val_if_fail (id
< ADG_ARROW_STYLE_LAST
, NULL
);
255 adg_arrow_style_render (AdgArrowStyle
*arrow_style
,
259 g_return_if_fail (arrow_style
!= NULL
);
260 g_return_if_fail (cr
!= NULL
);
261 g_return_if_fail (segment
!= NULL
);
264 if (arrow_style
->priv
->renderer
== NULL
)
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
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
294 adg_arrow_style_set_size (AdgArrowStyle
*arrow_style
,
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
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
327 adg_arrow_style_set_angle (AdgArrowStyle
*arrow_style
,
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
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
361 adg_arrow_style_set_margin (AdgArrowStyle
*arrow_style
,
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.
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");
405 arrow_renderer (AdgArrowStyle
*arrow_style
,
409 draw_triangle (cr
, arrow_style
, segment
);
414 triangle_renderer (AdgArrowStyle
*arrow_style
,
418 draw_triangle (cr
, arrow_style
, segment
);
423 dot_renderer (AdgArrowStyle
*arrow_style
,
427 draw_circle (cr
, arrow_style
, segment
);
432 circle_renderer (AdgArrowStyle
*arrow_style
,
436 draw_circle (cr
, arrow_style
, segment
);
441 block_renderer (AdgArrowStyle
*arrow_style
,
449 square_renderer (AdgArrowStyle
*arrow_style
,
457 tick_renderer (AdgArrowStyle
*arrow_style
,
465 draw_triangle (cairo_t
*cr
,
466 AdgArrowStyle
*arrow_style
,
469 double length
, height_2
;
471 CpmlPair tail
, tail1
, tail2
;
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
;
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
);
505 case CAIRO_PATH_CURVE_TO
:
509 g_assert_not_reached ();
514 draw_circle (cairo_t
*cr
,
515 AdgArrowStyle
*arrow_style
,
518 double radius
= arrow_style
->priv
->size
/ 2.;
521 cairo_device_to_user_distance (cr
, &radius
, &dummy
);
523 cairo_arc (cr
, segment
->org
.x
, segment
->org
.y
, radius
, 0., M_PI
);