7 static void parse_args (gint
*p_argc
,
10 duplicate_and_stroke (cairo_t
*cr
);
11 static void stroke_and_destroy (cairo_t
*cr
,
14 static void browsing (GtkWidget
*widget
,
15 GdkEventExpose
*event
,
17 static void browsing_segment (GtkToggleButton
*togglebutton
,
19 static void browsing_primitive (GtkToggleButton
*togglebutton
,
21 static void browsing_reset (GtkButton
*button
,
23 static void browsing_next (GtkButton
*button
,
26 static void arcs (GtkWidget
*widget
,
27 GdkEventExpose
*event
,
29 static void arc3p (cairo_t
*cr
,
37 static void intersections (GtkWidget
*widget
,
38 GdkEventExpose
*event
,
41 static void offset_curves (GtkWidget
*widget
,
42 GdkEventExpose
*event
,
45 static void offset_segments (GtkWidget
*widget
,
46 GdkEventExpose
*event
,
49 static void circle_callback (cairo_t
*cr
);
50 static void piston_callback (cairo_t
*cr
);
51 static void curve1_callback (cairo_t
*cr
);
52 static void line1_callback (cairo_t
*cr
);
56 cairo_path_t
*cairo_path
;
59 CpmlPrimitive primitive
;
64 static CpmlPair bezier_samples
[][4] = {
65 { { 0, 0 }, { 0, 40 }, { 120, 40 }, { 120, 0 } }, /* Simmetric low */
66 { { 40, 0 }, { 40, 160 }, { 80, 160 }, { 80, 0 } }, /* Simmetric high */
67 { { 0, 0 }, { 33.1371, 33.1371 }, { 86.8629, 33.1371 }, { 120, 0 } },
68 /* Arc approximation */
69 { { 0, 0 }, { 70, 120 }, { 50, 120 }, { 120, 0 } }, /* Twisted controls */
71 { { 0, 0 }, { 0, 120 }, { 60, 120 }, { 120, 0 } }, /* Vertical p1-p2 */
72 { { 0, 0 }, { 60, 120 }, { 120, 120 }, { 120, 0 } },/* Vertical p3-p4 */
73 { { 0, 120 }, { 120, 120 }, { 120, 60 }, { 0, 0 } },/* Horizontal p1-p2 */
74 { { 0, 120 }, { 120, 60 }, { 120, 0 }, { 0, 0 } }, /* Horizontal p3-p4 */
76 { { 0, 0 }, { 0, 120 }, { 120, 120 }, { 120, 0 } }, /* Down */
77 { { 0, 120 }, { 120, 120 }, { 120, 0 }, { 0, 0 } }, /* Right */
78 { { 0, 120 }, { 0, 0 }, { 120, 0 }, { 120, 120 } }, /* Up */
79 { { 120, 120 }, { 0, 120 }, { 0, 0 }, { 120, 0 } }, /* Left */
81 { { 0, 60 }, { 60, 120 }, { 120, 60 }, { 60, 0 } }, /* Down-right */
82 { { 60, 120 }, { 120, 60 }, { 60, 0 }, { 0, 60 } }, /* Up-right */
83 { { 120, 60 }, { 60, 0 }, { 0, 60 }, { 60, 120 } }, /* Up-left */
84 { { 60, 0 }, { 0, 60 }, { 60, 120 }, { 120, 60 } }, /* Down-left*/
86 { { 0, 0 }, { 60, 0 }, { 60, 120 }, { 120, 120 } }, /* Step left */
87 { { 120, 0 }, { 60, 0 }, { 60, 120 }, { 0, 120 } }, /* Step right */
88 { { 0, 0 }, { 60, 90 }, { 90, 120 }, { 120, 90 } }, /* Unbalanced opened */
89 { { 0, 0 }, { 40, 120 }, { 120, 120 }, { 60, 80 } } /* Unbalanced closed */
92 static void (*path_samples
[]) (cairo_t
*cr
) = {
101 main(gint argc
, gchar
**argv
)
108 parse_args(&argc
, &argv
);
110 path
= demo_find_data_file("cpml-demo.ui", argv
[0]);
112 g_print("cpml-demo.ui not found!\n");
116 builder
= gtk_builder_new();
119 gtk_builder_add_from_file(builder
, path
, &error
);
121 g_print("%s\n", error
->message
);
125 window
= (GtkWidget
*) gtk_builder_get_object(builder
, "wndMain");
127 /* Connect signals */
128 g_signal_connect(window
, "delete-event", G_CALLBACK(gtk_main_quit
), NULL
);
129 g_signal_connect(gtk_builder_get_object(builder
, "areaBrowsing"),
130 "expose-event", G_CALLBACK(browsing
), NULL
);
131 g_signal_connect(gtk_builder_get_object(builder
, "optBrowsingSegment"),
132 "toggled", G_CALLBACK(browsing_segment
), NULL
);
133 g_signal_connect(gtk_builder_get_object(builder
, "optBrowsingPrimitive"),
134 "toggled", G_CALLBACK(browsing_primitive
), NULL
);
135 g_signal_connect(gtk_builder_get_object(builder
, "btnBrowsingReset"),
136 "clicked", G_CALLBACK(browsing_reset
), NULL
);
137 g_signal_connect(gtk_builder_get_object(builder
, "btnBrowsingNext"),
138 "clicked", G_CALLBACK(browsing_next
), NULL
);
139 g_signal_connect(gtk_builder_get_object(builder
, "areaArcs"),
140 "expose-event", G_CALLBACK(arcs
), NULL
);
141 g_signal_connect(gtk_builder_get_object(builder
, "areaIntersections"),
142 "expose-event", G_CALLBACK(intersections
), NULL
);
143 g_signal_connect(gtk_builder_get_object(builder
, "areaOffsetCurves"),
144 "expose-event", G_CALLBACK(offset_curves
), NULL
);
145 g_signal_connect(gtk_builder_get_object(builder
, "areaOffsetSegments"),
146 "expose-event", G_CALLBACK(offset_segments
), NULL
);
147 g_signal_connect(gtk_builder_get_object(builder
, "btnQuit"),
148 "clicked", G_CALLBACK(gtk_main_quit
), NULL
);
150 g_object_unref(builder
);
152 gtk_widget_show_all(window
);
159 /**********************************************
160 * Command line options parser
161 **********************************************/
166 g_print("cpml-demo " PACKAGE_VERSION
"\n");
171 parse_args(gint
*p_argc
, gchar
**p_argv
[])
173 GError
*error
= NULL
;
174 GOptionEntry entries
[] = {
175 {"version", 'V', G_OPTION_FLAG_NO_ARG
, G_OPTION_ARG_CALLBACK
, version
,
176 "Display version information", NULL
},
180 gtk_init_with_args(p_argc
, p_argv
, "- CPML demonstration program",
181 entries
, NULL
, &error
);
184 gint error_code
= error
->code
;
186 g_printerr("%s\n", error
->message
);
194 static cairo_path_t
*
195 duplicate_and_stroke(cairo_t
*cr
)
197 cairo_path_t
*path
= cairo_copy_path(cr
);
199 cairo_set_line_width(cr
, 2.);
206 stroke_and_destroy(cairo_t
*cr
, cairo_path_t
*path
)
208 cairo_append_path(cr
, path
);
209 cairo_path_destroy(path
);
211 cairo_set_line_width(cr
, 1.);
217 browsing(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer user_data
)
222 cr
= gdk_cairo_create(widget
->window
);
224 if (browsing_data
.area
== NULL
) {
225 /* Initialize browsing_data */
226 browsing_data
.area
= widget
;
227 browsing_data
.use_segment
= TRUE
;
229 /* Append all the path samples to the cairo context */
231 cairo_translate(cr
, 270.5, -120.5);
232 for (n
= 0; n
< G_N_ELEMENTS(path_samples
); ++n
) {
234 cairo_translate(cr
, -270., 240.);
236 cairo_translate(cr
, 270., 0.);
239 (path_samples
[n
]) (cr
);
243 browsing_data
.cairo_path
= cairo_copy_path(cr
);
244 cpml_segment_from_cairo(&browsing_data
.segment
,
245 browsing_data
.cairo_path
);
246 cpml_primitive_from_segment(&browsing_data
.primitive
,
247 &browsing_data
.segment
);
249 cairo_append_path(cr
, browsing_data
.cairo_path
);
252 cairo_set_line_width(cr
, 2.);
255 cairo_set_source_rgb(cr
, 1., 0.4, 0.);
256 cairo_set_line_width(cr
, 5.);
258 if (browsing_data
.use_segment
)
259 cpml_segment_to_cairo(&browsing_data
.segment
, cr
);
261 cpml_primitive_to_cairo(&browsing_data
.primitive
, cr
);
268 browsing_segment(GtkToggleButton
*togglebutton
, gpointer user_data
)
270 if (!gtk_toggle_button_get_active(togglebutton
))
273 browsing_data
.use_segment
= TRUE
;
274 gtk_widget_queue_draw(browsing_data
.area
);
278 browsing_primitive(GtkToggleButton
*togglebutton
, gpointer user_data
)
280 if (!gtk_toggle_button_get_active(togglebutton
))
283 browsing_data
.use_segment
= FALSE
;
284 gtk_widget_queue_draw(browsing_data
.area
);
288 browsing_reset(GtkButton
*button
, gpointer user_data
)
290 if (browsing_data
.use_segment
) {
291 cpml_segment_reset(&browsing_data
.segment
);
292 cpml_primitive_from_segment(&browsing_data
.primitive
,
293 &browsing_data
.segment
);
295 cpml_primitive_reset(&browsing_data
.primitive
);
298 gtk_widget_queue_draw(browsing_data
.area
);
302 browsing_next(GtkButton
*button
, gpointer user_data
)
304 if (browsing_data
.use_segment
) {
305 cpml_segment_next(&browsing_data
.segment
);
306 cpml_primitive_from_segment(&browsing_data
.primitive
,
307 &browsing_data
.segment
);
309 cpml_primitive_next(&browsing_data
.primitive
);
312 gtk_widget_queue_draw(browsing_data
.area
);
317 arcs(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer user_data
)
319 cairo_t
*cr
= gdk_cairo_create(widget
->window
);
321 cairo_translate(cr
, 100.5, 100.5);
322 arc3p(cr
, 0, 0, 0, 120, 120, 120);
324 cairo_translate(cr
, 200, 0.);
325 arc3p(cr
, 0, 0, 120, 0, 120, 120);
327 cairo_translate(cr
, 200, 0.);
328 arc3p(cr
, 60, 0, 0, 120, 120, 120);
330 cairo_translate(cr
, -400, 200);
331 arc3p(cr
, 0, 50, -2, 85, 120, 0);
333 cairo_translate(cr
, 200, 0);
334 arc3p(cr
, -2, 85, 0, 50, 120, 0);
340 arc3p(cairo_t
*cr
, double x1
, double y1
,
341 double x2
, double y2
, double x3
, double y3
)
344 cairo_path_data_t p
[4];
346 double r
, start
, end
;
352 p
[1].header
.type
= CPML_ARC
;
353 p
[1].header
.length
= 3;
362 cpml_primitive_to_cairo(&arc
, cr
);
364 cairo_set_line_width(cr
, 1.);
367 /* Add an arc generated by cairo, just for reference */
368 if (!cpml_arc_info(&arc
, ¢er
, &r
, &start
, &end
)) {
369 g_print("Unable to get arc info (%lf, %lf) (%lf, %lf) (%lf, %lf)\n",
370 x1
, y1
, x2
, y2
, x3
, y3
);
375 cairo_arc(cr
, center
.x
, center
.y
, r
-5., start
, end
);
377 cairo_arc_negative(cr
, center
.x
, center
.y
, r
-5., start
, end
);
379 /* Show the inscribed triangle */
380 cairo_move_to(cr
, x1
, y1
);
381 cairo_line_to(cr
, x2
, y2
);
382 cairo_line_to(cr
, x3
, y3
);
384 cairo_set_line_width(cr
, 0.5);
390 intersections(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer user_data
)
394 CpmlSegment segment1
, segment2
;
395 CpmlPair intersection
;
397 cr
= gdk_cairo_create(widget
->window
);
398 cairo_translate(cr
, 10.5, 120.5);
402 path
= cairo_copy_path(cr
);
404 cairo_set_line_width(cr
, 1.);
407 cpml_segment_from_cairo(&segment1
, path
);
408 cpml_segment_from_cairo(&segment2
, path
);
410 while (cpml_segment_next(&segment2
)) {
411 cpml_segment_put_intersections(&segment1
, &segment2
, 1, &intersection
);
413 cairo_arc(cr
, intersection
.x
, intersection
.y
, 2.5, 0, 2 * M_PI
);
416 cpml_segment_next(&segment1
);
419 cairo_path_destroy(path
);
425 offset_curves(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer user_data
)
430 cairo_path_t
*path
, *path_copy
;
432 CpmlPrimitive primitive
;
437 cr
= gdk_cairo_create(widget
->window
);
439 /* Add the Bézier curve samples */
440 for (n
= 0; n
< G_N_ELEMENTS(bezier_samples
); ++n
) {
441 bezier
= &bezier_samples
[n
][0];
443 /* The samples are arranged in a 4x? matrix of 200x150 cells */
445 cairo_translate(cr
, 25., 25.);
447 cairo_translate(cr
, -600., 150.);
449 cairo_translate(cr
, 200., 0.);
451 /* Draw the Bézier curve */
452 cairo_move_to(cr
, bezier
[0].x
, bezier
[0].y
);
453 cairo_curve_to(cr
, bezier
[1].x
, bezier
[1].y
,
454 bezier
[2].x
, bezier
[2].y
, bezier
[3].x
, bezier
[3].y
);
456 /* Create a copy, to be used after */
457 path_copy
= cairo_copy_path(cr
);
459 path
= duplicate_and_stroke(cr
);
460 cpml_segment_from_cairo(&segment
, path
);
461 cpml_segment_offset(&segment
, 20.);
462 stroke_and_destroy(cr
, path
);
464 cpml_segment_from_cairo(&segment
, path_copy
);
465 cpml_primitive_from_segment(&primitive
, &segment
);
467 /* Checking cpml_curve_put_pair_at_time and cpml_curve_put_vector_at_time */
468 cairo_set_line_width(cr
, 1.);
469 for (t
= 0; t
< 1; t
+= 0.1) {
470 cpml_curve_put_pair_at_time(&primitive
, t
, &pair
);
471 cpml_curve_put_vector_at_time(&primitive
, t
, &vector
);
472 cpml_vector_set_length(&vector
, 20.);
473 cpml_vector_normal(&vector
);
475 cairo_new_sub_path(cr
);
476 cairo_arc(cr
, pair
.x
, pair
.y
, 2.5, 0, M_PI
*2);
479 cairo_move_to(cr
, pair
.x
, pair
.y
);
480 cairo_line_to(cr
, pair
.x
+ vector
.x
, pair
.y
+ vector
.y
);
484 cairo_path_destroy(path_copy
);
492 offset_segments(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer user_data
)
499 cr
= gdk_cairo_create(widget
->window
);
500 cairo_translate(cr
, 270.5, -120.5);
502 /* Offset the path samples */
503 for (n
= 0; n
< G_N_ELEMENTS(path_samples
); ++n
) {
505 cairo_translate(cr
, -270., 240.);
507 cairo_translate(cr
, 270., 0.);
510 /* Call the path callback */
511 (path_samples
[n
]) (cr
);
513 path
= duplicate_and_stroke(cr
);
514 cpml_segment_from_cairo(&segment
, path
);
515 cpml_segment_offset(&segment
, 15.);
516 stroke_and_destroy(cr
, path
);
524 circle_callback(cairo_t
*cr
)
526 cairo_new_sub_path(cr
);
527 cairo_arc(cr
, 120., 0., 100., 0., M_PI
*2);
531 piston_callback(cairo_t
*cr
)
533 cairo_path_t
*old_path
, *path
;
534 cairo_matrix_t matrix
;
537 /* Save the previous path, if any */
538 old_path
= cairo_copy_path(cr
);
541 cairo_move_to(cr
, 0., 46.5);
542 cairo_line_to(cr
, 210., 46.5);
543 cairo_line_to(cr
, 222.5, 35.);
544 cairo_line_to(cr
, 270., 35.);
545 cairo_line_to(cr
, 270., 56.);
546 cairo_line_to(cr
, 273., 59.);
547 cairo_line_to(cr
, 302., 59.);
548 cairo_line_to(cr
, 305., 56.);
549 cairo_arc(cr
, 325., 52.5, 20., G_PI
, 3. * G_PI_2
);
550 cairo_line_to(cr
, 400., 32.5);
551 cairo_line_to(cr
, 410., 22.5);
552 cairo_line_to(cr
, 450., 22.5);
553 cairo_arc_negative(cr
,
554 452., 34., 2., G_PI
, G_PI_2
);
555 cairo_line_to(cr
, 460., 36.);
556 cairo_line_to(cr
, 470., 30.);
557 cairo_line_to(cr
, 472., 12.5);
559 /* Mirror a reversed copy of the current path on the y = 0 axis */
560 path
= cairo_copy_path(cr
);
561 cpml_segment_from_cairo(&segment
, path
);
563 cpml_segment_reverse(&segment
);
564 cairo_matrix_init_scale(&matrix
, 1., -1.);
565 cpml_segment_transform(&segment
, &matrix
);
567 /* Join the mirrored path to the old path... */
568 path
->data
[0].header
.type
= CPML_LINE
;
569 cairo_append_path(cr
, path
);
570 cairo_path_destroy(path
);
572 /* ...and close the shape */
573 cairo_close_path(cr
);
575 /* Save the resulting path and clear the path memory */
576 path
= cairo_copy_path(cr
);
579 /* Restore the previous path and reappend the new path */
580 cairo_append_path(cr
, old_path
);
581 cairo_path_destroy(old_path
);
582 cairo_append_path(cr
, path
);
583 cairo_path_destroy(path
);
587 curve1_callback(cairo_t
*cr
)
589 cairo_move_to(cr
, 30., 0.);
590 cairo_curve_to(cr
, 120., 120., 180., 100., 180., 20.);
591 cairo_curve_to(cr
, 180., -20., 50., 40., 150., 40.);
592 cairo_curve_to(cr
, 220., 40., 190., -60., 150., -60.);
593 cairo_curve_to(cr
, 100., -60., 80., -40., 60., -60.);
597 line1_callback(cairo_t
*cr
)
599 cairo_move_to(cr
, 0, -50);
600 cairo_line_to(cr
, 100, 50);
602 cairo_move_to(cr
, 100, -50);
603 cairo_line_to(cr
, 0, 50);
605 cairo_move_to(cr
, 120, -50);
606 cairo_line_to(cr
, 200, -10);
608 cairo_move_to(cr
, 120, 50);
609 cairo_line_to(cr
, 200, 10);
611 cairo_move_to(cr
, 220, 0);
612 cairo_line_to(cr
, 280, 0);
614 cairo_move_to(cr
, 270, -40);
615 cairo_line_to(cr
, 270, 20);
617 cairo_move_to(cr
, 320, 60);
618 cairo_line_to(cr
, 380, 60);
620 cairo_move_to(cr
, 300, -40);
621 cairo_line_to(cr
, 340, 0);
623 cairo_move_to(cr
, 480, 10);
624 cairo_line_to(cr
, 400, 40);
626 cairo_move_to(cr
, 400, 40);
627 cairo_line_to(cr
, 450, -40);