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
,
59 static GPtrArray
* get_pool (void);
60 static void arrow_renderer (AdgArrowStyle
*arrow_style
,
63 static void triangle_renderer (AdgArrowStyle
*arrow_style
,
66 static void dot_renderer (AdgArrowStyle
*arrow_style
,
69 static void circle_renderer (AdgArrowStyle
*arrow_style
,
72 static void block_renderer (AdgArrowStyle
*arrow_style
,
75 static void square_renderer (AdgArrowStyle
*arrow_style
,
78 static void tick_renderer (AdgArrowStyle
*arrow_style
,
81 static void draw_triangle (cairo_t
*cr
,
82 AdgArrowStyle
*arrow_style
,
84 static void draw_circle (cairo_t
*cr
,
85 AdgArrowStyle
*arrow_style
,
89 G_DEFINE_TYPE (AdgArrowStyle
, adg_arrow_style
, ADG_TYPE_STYLE
)
93 adg_arrow_style_class_init (AdgArrowStyleClass
*klass
)
95 GObjectClass
*gobject_class
;
96 AdgStyleClass
*style_class
;
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",
111 P_("The size of the arrow, a renderer dependent parameter"),
112 -G_MAXDOUBLE
, G_MAXDOUBLE
, 14.,
114 g_object_class_install_property (gobject_class
, PROP_SIZE
, param
);
116 param
= g_param_spec_double ("angle",
118 P_("The angle of the arrow, a renderer dependent parameter"),
119 -G_MAXDOUBLE
, G_MAXDOUBLE
, G_PI
/ 6.,
121 g_object_class_install_property (gobject_class
, PROP_ANGLE
, param
);
123 param
= g_param_spec_double ("margin",
125 P_("The margin of the arrow, a renderer dependent parameter"),
126 -G_MAXDOUBLE
, G_MAXDOUBLE
, 14.,
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"),
134 g_object_class_install_property (gobject_class
, PROP_RENDERER
, param
);
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
);
145 priv
->angle
= G_PI
/ 6.;
147 priv
->renderer
= NULL
;
149 arrow_style
->priv
= priv
;
153 get_property (GObject
*object
,
158 AdgArrowStyle
*arrow_style
= (AdgArrowStyle
*) object
;
163 g_value_set_double (value
, arrow_style
->priv
->size
);
166 g_value_set_double (value
, arrow_style
->priv
->angle
);
169 g_value_set_double (value
, arrow_style
->priv
->margin
);
172 g_value_set_pointer (value
, arrow_style
->priv
->renderer
);
175 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
181 set_property (GObject
*object
,
186 AdgArrowStyle
*arrow_style
= (AdgArrowStyle
*) object
;
191 arrow_style
->priv
->size
= g_value_get_double (value
);
194 arrow_style
->priv
->angle
= g_value_get_double (value
);
197 arrow_style
->priv
->margin
= g_value_get_double (value
);
200 arrow_style
->priv
->renderer
= g_value_get_pointer (value
);
203 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
210 * adg_arrow_style_get_slot:
212 * Gets the slot id for this style class.
214 * Return value: the slot
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
);
228 * adg_arrow_style_new:
230 * Constructs a new arrow style initialized with default params.
232 * Return value: a new arrow style
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.
250 adg_arrow_style_render (AdgArrowStyle
*arrow_style
,
254 g_return_if_fail (arrow_style
!= NULL
);
255 g_return_if_fail (cr
!= NULL
);
256 g_return_if_fail (segment
!= NULL
);
259 if (arrow_style
->priv
->renderer
== NULL
)
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
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
290 adg_arrow_style_set_size (AdgArrowStyle
*arrow_style
,
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
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
323 adg_arrow_style_set_angle (AdgArrowStyle
*arrow_style
,
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
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
357 adg_arrow_style_set_margin (AdgArrowStyle
*arrow_style
,
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.
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");
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
,
412 pool
->pdata
[ADG_ARROW_STYLE_TRIANGLE
] = g_object_new (ADG_TYPE_ARROW_STYLE
,
413 "renderer", triangle_renderer
,
415 pool
->pdata
[ADG_ARROW_STYLE_DOT
] = g_object_new (ADG_TYPE_ARROW_STYLE
,
419 "renderer", dot_renderer
,
421 pool
->pdata
[ADG_ARROW_STYLE_CIRCLE
] = g_object_new (ADG_TYPE_ARROW_STYLE
,
425 "renderer", circle_renderer
,
427 pool
->pdata
[ADG_ARROW_STYLE_BLOCK
] = g_object_new (ADG_TYPE_ARROW_STYLE
,
431 "renderer", block_renderer
,
433 pool
->pdata
[ADG_ARROW_STYLE_SQUARE
] = g_object_new (ADG_TYPE_ARROW_STYLE
,
437 "renderer", square_renderer
,
439 pool
->pdata
[ADG_ARROW_STYLE_TICK
] = g_object_new (ADG_TYPE_ARROW_STYLE
,
443 "renderer", tick_renderer
,
446 pool
->len
= ADG_ARROW_STYLE_LAST
;
453 arrow_renderer (AdgArrowStyle
*arrow_style
,
457 draw_triangle (cr
, arrow_style
, segment
);
462 triangle_renderer (AdgArrowStyle
*arrow_style
,
466 draw_triangle (cr
, arrow_style
, segment
);
471 dot_renderer (AdgArrowStyle
*arrow_style
,
475 draw_circle (cr
, arrow_style
, segment
);
480 circle_renderer (AdgArrowStyle
*arrow_style
,
484 draw_circle (cr
, arrow_style
, segment
);
489 block_renderer (AdgArrowStyle
*arrow_style
,
497 square_renderer (AdgArrowStyle
*arrow_style
,
505 tick_renderer (AdgArrowStyle
*arrow_style
,
513 draw_triangle (cairo_t
*cr
,
514 AdgArrowStyle
*arrow_style
,
517 double length
, height_2
;
519 CpmlPair tail
, tail1
, tail2
;
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
;
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
);
553 case CAIRO_PATH_CURVE_TO
:
557 g_assert_not_reached ();
562 draw_circle (cairo_t
*cr
,
563 AdgArrowStyle
*arrow_style
,
566 double radius
= arrow_style
->priv
->size
/ 2.;
569 cairo_device_to_user_distance (cr
, &radius
, &dummy
);
571 cairo_arc (cr
, segment
->org
.x
, segment
->org
.y
, radius
, 0., M_PI
);