1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2020 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.
26 static void parse_args (gint
*p_argc
,
29 duplicate_and_stroke (cairo_t
*cr
);
30 static void stroke_and_destroy (cairo_t
*cr
,
33 static void browsing (GtkWidget
*widget
,
36 static void browsing_segment (GtkToggleButton
*togglebutton
,
38 static void browsing_primitive (GtkToggleButton
*togglebutton
,
40 static void browsing_reset (GtkButton
*button
,
42 static void browsing_next (GtkButton
*button
,
45 static gboolean
arcs (GtkWidget
*widget
,
48 static void arc3p (cairo_t
*cr
,
56 static gboolean
intersections (GtkWidget
*widget
,
59 static void algorithm_changed (GtkRadioButton
*button
,
61 static gboolean
offset_curves (GtkWidget
*widget
,
64 static gboolean
offset_segments (GtkWidget
*widget
,
70 browsing_gtk2(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer user_data
)
72 cairo_t
*cr
= gdk_cairo_create(widget
->window
);
78 arcs_gtk2(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer user_data
)
80 cairo_t
*cr
= gdk_cairo_create(widget
->window
);
86 intersections_gtk2(GtkWidget
*widget
)
88 cairo_t
*cr
= gdk_cairo_create(widget
->window
);
89 intersections(widget
, cr
);
94 offset_curves_gtk2(GtkWidget
*widget
)
96 cairo_t
*cr
= gdk_cairo_create(widget
->window
);
97 offset_curves(widget
, cr
);
102 offset_segments_gtk2(GtkWidget
*widget
)
104 cairo_t
*cr
= gdk_cairo_create(widget
->window
);
105 offset_segments(widget
, cr
);
111 static void circle_callback (cairo_t
*cr
);
112 static void piston_callback (cairo_t
*cr
);
113 static void curve1_callback (cairo_t
*cr
);
114 static void line1_callback (cairo_t
*cr
);
118 cairo_path_t
*cairo_path
;
119 gboolean use_segment
;
121 CpmlPrimitive primitive
;
126 static CpmlPair bezier_samples
[][4] = {
127 { { 0, 0 }, { 0, 40 }, { 120, 40 }, { 120, 0 } }, /* Simmetric low */
128 { { 40, 0 }, { 40, 160 }, { 80, 160 }, { 80, 0 } }, /* Simmetric high */
129 { { 0, 0 }, { 33.1371, 33.1371 }, { 86.8629, 33.1371 }, { 120, 0 } },
130 /* Arc approximation */
131 { { 0, 0 }, { 70, 120 }, { 50, 120 }, { 120, 0 } }, /* Twisted controls */
133 { { 0, 0 }, { 0, 120 }, { 60, 120 }, { 120, 0 } }, /* Vertical p1-p2 */
134 { { 0, 0 }, { 60, 120 }, { 120, 120 }, { 120, 0 } },/* Vertical p3-p4 */
135 { { 0, 120 }, { 120, 120 }, { 120, 60 }, { 0, 0 } },/* Horizontal p1-p2 */
136 { { 0, 120 }, { 120, 60 }, { 120, 0 }, { 0, 0 } }, /* Horizontal p3-p4 */
138 { { 0, 0 }, { 0, 120 }, { 120, 120 }, { 120, 0 } }, /* Down */
139 { { 0, 120 }, { 120, 120 }, { 120, 0 }, { 0, 0 } }, /* Right */
140 { { 0, 120 }, { 0, 0 }, { 120, 0 }, { 120, 120 } }, /* Up */
141 { { 120, 120 }, { 0, 120 }, { 0, 0 }, { 120, 0 } }, /* Left */
143 { { 0, 60 }, { 60, 120 }, { 120, 60 }, { 60, 0 } }, /* Down-right */
144 { { 60, 120 }, { 120, 60 }, { 60, 0 }, { 0, 60 } }, /* Up-right */
145 { { 120, 60 }, { 60, 0 }, { 0, 60 }, { 60, 120 } }, /* Up-left */
146 { { 60, 0 }, { 0, 60 }, { 60, 120 }, { 120, 60 } }, /* Down-left*/
148 { { 0, 0 }, { 60, 0 }, { 60, 120 }, { 120, 120 } }, /* Step left */
149 { { 120, 0 }, { 60, 0 }, { 60, 120 }, { 0, 120 } }, /* Step right */
150 { { 0, 0 }, { 60, 90 }, { 90, 120 }, { 120, 90 } }, /* Unbalanced opened */
151 { { 0, 0 }, { 40, 120 }, { 120, 120 }, { 60, 80 } } /* Unbalanced closed */
154 static void (*path_samples
[]) (cairo_t
*cr
) = {
162 switch_page(GtkTreeSelection
*selection
, GtkNotebook
*notebook
)
164 GList
*list
= gtk_tree_selection_get_selected_rows(selection
, NULL
);
166 GtkTreePath
*path
= g_list_first(list
)->data
;
167 gint page
= path
!= NULL
? *gtk_tree_path_get_indices(path
) : -1;
168 g_list_free_full(list
, (GDestroyNotify
) gtk_tree_path_free
);
170 gtk_notebook_set_current_page(notebook
, page
);
175 main(gint argc
, gchar
**argv
)
182 _demo_init(argc
, argv
);
183 parse_args(&argc
, &argv
);
185 /* Prepend the package icons path */
186 path
= _demo_file("icons");
187 gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), path
);
190 path
= _demo_file("cpml-demo.ui");
192 g_printerr(_("cpml-demo.ui not found!\n"));
196 builder
= gtk_builder_new();
199 gtk_builder_set_translation_domain(builder
, GETTEXT_PACKAGE
);
200 gtk_builder_add_from_file(builder
, path
, &error
);
204 g_print("%s\n", error
->message
);
208 window
= (GtkWidget
*) gtk_builder_get_object(builder
, "wndMain");
210 /* Connect signals */
211 g_signal_connect(window
, "delete-event", G_CALLBACK(gtk_main_quit
), NULL
);
212 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(gtk_builder_get_object(builder
, "tvPages"))),
213 "changed", G_CALLBACK(switch_page
),
214 gtk_builder_get_object(builder
, "nbPages"));
215 g_signal_connect(gtk_builder_get_object(builder
, "optBrowsingSegment"),
216 "toggled", G_CALLBACK(browsing_segment
), NULL
);
217 g_signal_connect(gtk_builder_get_object(builder
, "optBrowsingPrimitive"),
218 "toggled", G_CALLBACK(browsing_primitive
), NULL
);
219 g_signal_connect(gtk_builder_get_object(builder
, "btnBrowsingReset"),
220 "clicked", G_CALLBACK(browsing_reset
), NULL
);
221 g_signal_connect(gtk_builder_get_object(builder
, "btnBrowsingNext"),
222 "clicked", G_CALLBACK(browsing_next
), NULL
);
223 g_signal_connect(gtk_builder_get_object(builder
, "optAlgorithmDefault"),
224 "toggled", G_CALLBACK(algorithm_changed
),
225 gtk_builder_get_object(builder
, "areaOffsetCurves"));
226 g_signal_connect(gtk_builder_get_object(builder
, "optAlgorithmBaioca"),
227 "toggled", G_CALLBACK(algorithm_changed
),
228 gtk_builder_get_object(builder
, "areaOffsetCurves"));
229 g_signal_connect(gtk_builder_get_object(builder
, "optAlgorithmHandcraft"),
230 "toggled", G_CALLBACK(algorithm_changed
),
231 gtk_builder_get_object(builder
, "areaOffsetCurves"));
232 g_signal_connect(gtk_builder_get_object(builder
, "optAlgorithmGeometrical"),
233 "toggled", G_CALLBACK(algorithm_changed
),
234 gtk_builder_get_object(builder
, "areaOffsetCurves"));
236 g_signal_connect(gtk_builder_get_object(builder
, "areaBrowsing"),
237 "expose-event", G_CALLBACK(browsing_gtk2
), NULL
);
238 g_signal_connect(gtk_builder_get_object(builder
, "areaArcs"),
239 "expose-event", G_CALLBACK(arcs_gtk2
), NULL
);
240 g_signal_connect(gtk_builder_get_object(builder
, "areaIntersections"),
241 "expose-event", G_CALLBACK(intersections_gtk2
), NULL
);
242 g_signal_connect(gtk_builder_get_object(builder
, "areaOffsetCurves"),
243 "expose-event", G_CALLBACK(offset_curves_gtk2
), NULL
);
244 g_signal_connect(gtk_builder_get_object(builder
, "areaOffsetSegments"),
245 "expose-event", G_CALLBACK(offset_segments_gtk2
), NULL
);
246 g_signal_connect(gtk_builder_get_object(builder
, "btnQuit"),
247 "clicked", G_CALLBACK(gtk_main_quit
), NULL
);
249 g_signal_connect(gtk_builder_get_object(builder
, "areaBrowsing"),
250 "draw", G_CALLBACK(browsing
), NULL
);
251 g_signal_connect(gtk_builder_get_object(builder
, "areaArcs"),
252 "draw", G_CALLBACK(arcs
), NULL
);
253 g_signal_connect(gtk_builder_get_object(builder
, "areaIntersections"),
254 "draw", G_CALLBACK(intersections
), NULL
);
255 g_signal_connect(gtk_builder_get_object(builder
, "areaOffsetCurves"),
256 "draw", G_CALLBACK(offset_curves
), NULL
);
257 g_signal_connect(gtk_builder_get_object(builder
, "areaOffsetSegments"),
258 "draw", G_CALLBACK(offset_segments
), NULL
);
259 g_signal_connect(gtk_builder_get_object(builder
, "btnQuit"),
260 "clicked", G_CALLBACK(gtk_main_quit
), NULL
);
263 g_object_unref(builder
);
265 gtk_widget_show_all(window
);
272 /**********************************************
273 * Command line options parser
274 **********************************************/
279 g_print("cpml-demo " PACKAGE_VERSION
"\n");
284 parse_args(gint
*p_argc
, gchar
**p_argv
[])
286 GError
*error
= NULL
;
287 GOptionEntry entries
[] = {
288 {"version", 'V', G_OPTION_FLAG_NO_ARG
, G_OPTION_ARG_CALLBACK
,
289 (gpointer
) version
, _("Display version information"), NULL
},
293 gtk_init_with_args(p_argc
, p_argv
, _("- CPML demonstration program"),
294 entries
, GETTEXT_PACKAGE
, &error
);
297 gint error_code
= error
->code
;
299 g_printerr("%s\n", error
->message
);
307 static cairo_path_t
*
308 duplicate_and_stroke(cairo_t
*cr
)
310 cairo_path_t
*path
= cairo_copy_path(cr
);
312 cairo_set_line_width(cr
, 2.);
319 stroke_and_destroy(cairo_t
*cr
, cairo_path_t
*path
)
321 cairo_append_path(cr
, path
);
322 cairo_path_destroy(path
);
324 cairo_set_line_width(cr
, 1.);
330 browsing(GtkWidget
*widget
, cairo_t
*cr
)
332 if (browsing_data
.area
== NULL
) {
335 /* Initialize browsing_data */
336 browsing_data
.area
= widget
;
337 browsing_data
.use_segment
= TRUE
;
339 /* Append all the path samples to the cairo context */
341 cairo_translate(cr
, 270.5, -120.5);
342 for (n
= 0; n
< G_N_ELEMENTS(path_samples
); ++n
) {
344 cairo_translate(cr
, -270., 240.);
346 cairo_translate(cr
, 270., 0.);
349 (path_samples
[n
]) (cr
);
353 browsing_data
.cairo_path
= cairo_copy_path(cr
);
354 cpml_segment_from_cairo(&browsing_data
.segment
,
355 browsing_data
.cairo_path
);
356 cpml_primitive_from_segment(&browsing_data
.primitive
,
357 &browsing_data
.segment
);
359 cairo_append_path(cr
, browsing_data
.cairo_path
);
362 cairo_set_line_width(cr
, 2.);
365 cairo_set_source_rgb(cr
, 1., 0.4, 0.);
366 cairo_set_line_width(cr
, 5.);
368 if (browsing_data
.use_segment
)
369 cpml_segment_to_cairo(&browsing_data
.segment
, cr
);
371 cpml_primitive_to_cairo(&browsing_data
.primitive
, cr
);
377 browsing_segment(GtkToggleButton
*togglebutton
, gpointer user_data
)
379 if (!gtk_toggle_button_get_active(togglebutton
))
382 browsing_data
.use_segment
= TRUE
;
383 gtk_widget_queue_draw(browsing_data
.area
);
387 browsing_primitive(GtkToggleButton
*togglebutton
, gpointer user_data
)
389 if (!gtk_toggle_button_get_active(togglebutton
))
392 browsing_data
.use_segment
= FALSE
;
393 gtk_widget_queue_draw(browsing_data
.area
);
397 browsing_reset(GtkButton
*button
, gpointer user_data
)
399 if (browsing_data
.use_segment
) {
400 cpml_segment_reset(&browsing_data
.segment
);
401 cpml_primitive_from_segment(&browsing_data
.primitive
,
402 &browsing_data
.segment
);
404 cpml_primitive_reset(&browsing_data
.primitive
);
407 gtk_widget_queue_draw(browsing_data
.area
);
411 browsing_next(GtkButton
*button
, gpointer user_data
)
413 if (browsing_data
.use_segment
) {
414 cpml_segment_next(&browsing_data
.segment
);
415 cpml_primitive_from_segment(&browsing_data
.primitive
,
416 &browsing_data
.segment
);
418 cpml_primitive_next(&browsing_data
.primitive
);
421 gtk_widget_queue_draw(browsing_data
.area
);
426 arcs(GtkWidget
*widget
, cairo_t
*cr
)
428 cairo_translate(cr
, 100.5, 100.5);
429 arc3p(cr
, 0, 0, 0, 120, 120, 120);
431 cairo_translate(cr
, 200, 0.);
432 arc3p(cr
, 0, 0, 120, 0, 120, 120);
434 cairo_translate(cr
, 200, 0.);
435 arc3p(cr
, 60, 0, 0, 120, 120, 120);
437 cairo_translate(cr
, -400, 200);
438 arc3p(cr
, 0, 50, -2, 85, 120, 0);
440 cairo_translate(cr
, 200, 0);
441 arc3p(cr
, -2, 85, 0, 50, 120, 0);
447 arc3p(cairo_t
*cr
, double x1
, double y1
,
448 double x2
, double y2
, double x3
, double y3
)
451 cairo_path_data_t p
[4];
453 double r
, start
, end
;
459 p
[1].header
.type
= CPML_ARC
;
460 p
[1].header
.length
= 3;
469 cpml_primitive_to_cairo(&arc
, cr
);
471 cairo_set_line_width(cr
, 1.);
474 /* Add an arc generated by cairo, just for reference */
475 if (!cpml_arc_info(&arc
, ¢er
, &r
, &start
, &end
)) {
476 g_warning(_("Unable to get arc info (%lf, %lf) (%lf, %lf) (%lf, %lf)\n"),
477 x1
, y1
, x2
, y2
, x3
, y3
);
482 cairo_arc(cr
, center
.x
, center
.y
, r
-5., start
, end
);
484 cairo_arc_negative(cr
, center
.x
, center
.y
, r
-5., start
, end
);
486 /* Show the inscribed triangle */
487 cairo_move_to(cr
, x1
, y1
);
488 cairo_line_to(cr
, x2
, y2
);
489 cairo_line_to(cr
, x3
, y3
);
491 cairo_set_line_width(cr
, 0.5);
497 intersections(GtkWidget
*widget
, cairo_t
*cr
)
500 CpmlSegment segment1
, segment2
;
501 CpmlPair intersection
;
503 cairo_translate(cr
, 10.5, 120.5);
507 path
= cairo_copy_path(cr
);
509 cairo_set_line_width(cr
, 1.);
512 cpml_segment_from_cairo(&segment1
, path
);
513 cpml_segment_from_cairo(&segment2
, path
);
515 while (cpml_segment_next(&segment2
)) {
516 cpml_segment_put_intersections(&segment1
, &segment2
, 1, &intersection
);
518 cairo_arc(cr
, intersection
.x
, intersection
.y
, 2.5, 0, 2 * M_PI
);
521 cpml_segment_next(&segment1
);
524 cairo_path_destroy(path
);
530 algorithm_changed(GtkRadioButton
*button
, GtkWidget
*area
)
532 const gchar
*button_name
;
533 CpmlCurveOffsetAlgorithm new_algorithm
;
535 if (! gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button
)))
539 button_name
= gtk_widget_get_name(GTK_WIDGET(button
));
541 if (g_strcmp0(button_name
, "DEFAULT") == 0) {
542 new_algorithm
= CPML_CURVE_OFFSET_ALGORITHM_DEFAULT
;
543 } else if (g_strcmp0(button_name
, "BAIOCA") == 0) {
544 new_algorithm
= CPML_CURVE_OFFSET_ALGORITHM_BAIOCA
;
545 } else if (g_strcmp0(button_name
, "HANDCRAFT") == 0) {
546 new_algorithm
= CPML_CURVE_OFFSET_ALGORITHM_HANDCRAFT
;
547 } else if (g_strcmp0(button_name
, "GEOMETRICAL") == 0) {
548 new_algorithm
= CPML_CURVE_OFFSET_ALGORITHM_GEOMETRICAL
;
550 g_warning("Unknown offset algorithm name (%s)", button_name
);
551 new_algorithm
= CPML_CURVE_OFFSET_ALGORITHM_NONE
;
554 cpml_curve_offset_algorithm(new_algorithm
);
555 gtk_widget_queue_draw(area
);
559 offset_curves(GtkWidget
*widget
, cairo_t
*cr
)
563 cairo_path_t
*path
, *path_copy
;
565 CpmlPrimitive primitive
;
569 /* Add the Bézier curve samples */
570 for (n
= 0; n
< G_N_ELEMENTS(bezier_samples
); ++n
) {
571 bezier
= &bezier_samples
[n
][0];
573 /* The samples are arranged in a 4x? matrix of 200x150 cells */
575 cairo_translate(cr
, 25., 25.);
577 cairo_translate(cr
, -600., 150.);
579 cairo_translate(cr
, 200., 0.);
581 /* Draw the Bézier curve */
582 cairo_move_to(cr
, bezier
[0].x
, bezier
[0].y
);
583 cairo_curve_to(cr
, bezier
[1].x
, bezier
[1].y
,
584 bezier
[2].x
, bezier
[2].y
, bezier
[3].x
, bezier
[3].y
);
586 /* Create a copy, to be used after */
587 path_copy
= cairo_copy_path(cr
);
589 path
= duplicate_and_stroke(cr
);
590 cpml_segment_from_cairo(&segment
, path
);
591 cpml_segment_offset(&segment
, 20.);
592 stroke_and_destroy(cr
, path
);
594 cpml_segment_from_cairo(&segment
, path_copy
);
595 cpml_primitive_from_segment(&primitive
, &segment
);
597 /* Draw the rays for visual debugging */
598 cairo_set_line_width(cr
, 1.);
599 for (t
= 0; t
< 1; t
+= 0.1) {
600 cpml_curve_put_pair_at_time(&primitive
, t
, &pair
);
602 cairo_new_sub_path(cr
);
603 cairo_arc(cr
, pair
.x
, pair
.y
, 2.5, 0, M_PI
*2);
606 cairo_move_to(cr
, pair
.x
, pair
.y
);
607 cpml_curve_put_offset_at_time(&primitive
, t
, 20., &pair
);
608 cairo_line_to(cr
, pair
.x
, pair
.y
);
612 cairo_path_destroy(path_copy
);
620 offset_segments(GtkWidget
*widget
, cairo_t
*cr
)
626 cairo_translate(cr
, 270.5, -120.5);
628 /* Offset the path samples */
629 for (n
= 0; n
< G_N_ELEMENTS(path_samples
); ++n
) {
631 cairo_translate(cr
, -270., 240.);
633 cairo_translate(cr
, 270., 0.);
636 /* Call the path callback */
637 (path_samples
[n
]) (cr
);
639 path
= duplicate_and_stroke(cr
);
640 cpml_segment_from_cairo(&segment
, path
);
641 cpml_segment_offset(&segment
, 15.);
642 stroke_and_destroy(cr
, path
);
650 circle_callback(cairo_t
*cr
)
652 cairo_new_sub_path(cr
);
653 cairo_arc(cr
, 120., 0., 100., 0., M_PI
*2);
657 piston_callback(cairo_t
*cr
)
659 cairo_path_t
*old_path
, *path
;
660 cairo_matrix_t matrix
;
663 /* Save the previous path, if any */
664 old_path
= cairo_copy_path(cr
);
667 cairo_move_to(cr
, 0., 46.5);
668 cairo_line_to(cr
, 210., 46.5);
669 cairo_line_to(cr
, 222.5, 35.);
670 cairo_line_to(cr
, 270., 35.);
671 cairo_line_to(cr
, 270., 56.);
672 cairo_line_to(cr
, 273., 59.);
673 cairo_line_to(cr
, 302., 59.);
674 cairo_line_to(cr
, 305., 56.);
675 cairo_arc(cr
, 325., 52.5, 20., G_PI
, 3. * G_PI_2
);
676 cairo_line_to(cr
, 400., 32.5);
677 cairo_line_to(cr
, 410., 22.5);
678 cairo_line_to(cr
, 450., 22.5);
679 cairo_arc_negative(cr
,
680 452., 34., 2., G_PI
, G_PI_2
);
681 cairo_line_to(cr
, 460., 36.);
682 cairo_line_to(cr
, 470., 30.);
683 cairo_line_to(cr
, 472., 12.5);
685 /* Mirror a reversed copy of the current path on the y = 0 axis */
686 path
= cairo_copy_path(cr
);
687 cpml_segment_from_cairo(&segment
, path
);
689 cpml_segment_reverse(&segment
);
690 cairo_matrix_init_scale(&matrix
, 1., -1.);
691 cpml_segment_transform(&segment
, &matrix
);
693 /* Join the mirrored path to the old path... */
694 path
->data
[0].header
.type
= CPML_LINE
;
695 cairo_append_path(cr
, path
);
696 cairo_path_destroy(path
);
698 /* ...and close the shape */
699 cairo_close_path(cr
);
701 /* Save the resulting path and clear the path memory */
702 path
= cairo_copy_path(cr
);
705 /* Restore the previous path and reappend the new path */
706 cairo_append_path(cr
, old_path
);
707 cairo_path_destroy(old_path
);
708 cairo_append_path(cr
, path
);
709 cairo_path_destroy(path
);
713 curve1_callback(cairo_t
*cr
)
715 cairo_move_to(cr
, 30., 0.);
716 cairo_curve_to(cr
, 120., 120., 180., 100., 180., 20.);
717 cairo_curve_to(cr
, 180., -20., 50., 40., 150., 40.);
718 cairo_curve_to(cr
, 220., 40., 190., -60., 150., -60.);
719 cairo_curve_to(cr
, 100., -60., 80., -40., 60., -60.);
723 line1_callback(cairo_t
*cr
)
725 cairo_move_to(cr
, 0, -50);
726 cairo_line_to(cr
, 100, 50);
728 cairo_move_to(cr
, 100, -50);
729 cairo_line_to(cr
, 0, 50);
731 cairo_move_to(cr
, 120, -50);
732 cairo_line_to(cr
, 200, -10);
734 cairo_move_to(cr
, 120, 50);
735 cairo_line_to(cr
, 200, 10);
737 cairo_move_to(cr
, 220, 0);
738 cairo_line_to(cr
, 280, 0);
740 cairo_move_to(cr
, 270, -40);
741 cairo_line_to(cr
, 270, 20);
743 cairo_move_to(cr
, 320, 60);
744 cairo_line_to(cr
, 380, 60);
746 cairo_move_to(cr
, 300, -40);
747 cairo_line_to(cr
, 340, 0);
749 cairo_move_to(cr
, 480, 10);
750 cairo_line_to(cr
, 400, 40);
752 cairo_move_to(cr
, 400, 40);
753 cairo_line_to(cr
, 450, -40);