[AdgToyText] update_origin_cache() must return TRUE when succesfull
[adg.git] / demo / cpml-demo.c
blob175bcdae2f4e211c1665b917ce6d12afda6f29c7
1 #include <cpml/cpml.h>
2 #include <gtk/gtk.h>
3 #include <math.h>
5 #include "demo.h"
8 static cairo_path_t *
9 duplicate_and_stroke (cairo_t *cr);
10 static void stroke_and_destroy (cairo_t *cr,
11 cairo_path_t *path);
13 static void browsing (GtkWidget *widget,
14 GdkEventExpose *event,
15 gpointer data);
16 static void browsing_segment (GtkToggleButton*togglebutton,
17 gpointer user_data);
18 static void browsing_primitive (GtkToggleButton*togglebutton,
19 gpointer user_data);
20 static void browsing_reset (GtkButton *button,
21 gpointer user_data);
22 static void browsing_next (GtkButton *button,
23 gpointer user_data);
25 static void intersections (GtkWidget *widget,
26 GdkEventExpose *event,
27 gpointer data);
29 static void offset_curves (GtkWidget *widget,
30 GdkEventExpose *event,
31 gpointer data);
33 static void offset_segments (GtkWidget *widget,
34 GdkEventExpose *event,
35 gpointer data);
37 static void circle_callback (cairo_t *cr);
38 static void piston_callback (cairo_t *cr);
39 static void curve1_callback (cairo_t *cr);
40 static void line1_callback (cairo_t *cr);
42 static struct {
43 GtkWidget *area;
44 cairo_path_t *cairo_path;
45 gboolean use_segment;
46 CpmlSegment segment;
47 CpmlPrimitive primitive;
48 } browsing_data = {
49 NULL,
52 static CpmlPair bezier_samples[][4] = {
53 { { 0, 0 }, { 0, 40 }, { 120, 40 }, { 120, 0 } }, /* Simmetric low */
54 { { 40, 0 }, { 40, 160 }, { 80, 160 }, { 80, 0 } }, /* Simmetric high */
55 { { 0, 0 }, { 33.1371, 33.1371 }, { 86.8629, 33.1371 }, { 120, 0 } },
56 /* Arc approximation */
57 { { 0, 0 }, { 70, 120 }, { 50, 120 }, { 120, 0 } }, /* Twisted controls */
59 { { 0, 0 }, { 0, 120 }, { 60, 120 }, { 120, 0 } }, /* Vertical p1-p2 */
60 { { 0, 0 }, { 60, 120 }, { 120, 120 }, { 120, 0 } },/* Vertical p3-p4 */
61 { { 0, 120 }, { 120, 120 }, { 120, 60 }, { 0, 0 } },/* Horizontal p1-p2 */
62 { { 0, 120 }, { 120, 60 }, { 120, 0 }, { 0, 0 } }, /* Horizontal p3-p4 */
64 { { 0, 0 }, { 0, 120 }, { 120, 120 }, { 120, 0 } }, /* Down */
65 { { 0, 120 }, { 120, 120 }, { 120, 0 }, { 0, 0 } }, /* Right */
66 { { 0, 120 }, { 0, 0 }, { 120, 0 }, { 120, 120 } }, /* Up */
67 { { 120, 120 }, { 0, 120 }, { 0, 0 }, { 120, 0 } }, /* Left */
69 { { 0, 60 }, { 60, 120 }, { 120, 60 }, { 60, 0 } }, /* Down-right */
70 { { 60, 120 }, { 120, 60 }, { 60, 0 }, { 0, 60 } }, /* Up-right */
71 { { 120, 60 }, { 60, 0 }, { 0, 60 }, { 60, 120 } }, /* Up-left */
72 { { 60, 0 }, { 0, 60 }, { 60, 120 }, { 120, 60 } }, /* Down-left*/
74 { { 0, 0 }, { 60, 0 }, { 60, 120 }, { 120, 120 } }, /* Step left */
75 { { 120, 0 }, { 60, 0 }, { 60, 120 }, { 0, 120 } }, /* Step right */
76 { { 0, 0 }, { 60, 90 }, { 90, 120 }, { 120, 90 } }, /* Unbalanced opened */
77 { { 0, 0 }, { 40, 120 }, { 120, 120 }, { 60, 80 } } /* Unbalanced closed */
80 static void (*path_samples[]) (cairo_t *cr) = {
81 circle_callback,
82 piston_callback,
83 curve1_callback,
84 line1_callback,
88 int
89 main(gint argc, gchar **argv)
91 gchar *path;
92 GtkBuilder *builder;
93 GError *error;
94 GtkWidget *window;
96 gtk_init(&argc, &argv);
98 path = demo_find_data_file("cpml-demo.ui");
99 if (path == NULL) {
100 g_print("cpml-demo.ui not found!\n");
101 return 1;
104 builder = gtk_builder_new();
105 error = NULL;
107 gtk_builder_add_from_file(builder, path, &error);
108 if (error != NULL) {
109 g_print("%s\n", error->message);
110 return 2;
113 window = (GtkWidget *) gtk_builder_get_object(builder, "wndMain");
115 /* Connect signals */
116 g_signal_connect(window, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
117 g_signal_connect(gtk_builder_get_object(builder, "areaBrowsing"),
118 "expose-event", G_CALLBACK(browsing), NULL);
119 g_signal_connect(gtk_builder_get_object(builder, "optBrowsingSegment"),
120 "toggled", G_CALLBACK(browsing_segment), NULL);
121 g_signal_connect(gtk_builder_get_object(builder, "optBrowsingPrimitive"),
122 "toggled", G_CALLBACK(browsing_primitive), NULL);
123 g_signal_connect(gtk_builder_get_object(builder, "btnBrowsingReset"),
124 "clicked", G_CALLBACK(browsing_reset), NULL);
125 g_signal_connect(gtk_builder_get_object(builder, "btnBrowsingNext"),
126 "clicked", G_CALLBACK(browsing_next), NULL);
127 g_signal_connect(gtk_builder_get_object(builder, "areaIntersections"),
128 "expose-event", G_CALLBACK(intersections), NULL);
129 g_signal_connect(gtk_builder_get_object(builder, "areaOffsetCurves"),
130 "expose-event", G_CALLBACK(offset_curves), NULL);
131 g_signal_connect(gtk_builder_get_object(builder, "areaOffsetSegments"),
132 "expose-event", G_CALLBACK(offset_segments), NULL);
133 g_signal_connect(gtk_builder_get_object(builder, "btnQuit"),
134 "clicked", G_CALLBACK(gtk_main_quit), NULL);
136 g_object_unref(builder);
138 gtk_widget_show_all(window);
139 gtk_main();
141 return 0;
145 static cairo_path_t *
146 duplicate_and_stroke(cairo_t *cr)
148 cairo_path_t *path = cairo_copy_path(cr);
150 cairo_set_line_width(cr, 2.);
151 cairo_stroke(cr);
153 return path;
156 static void
157 stroke_and_destroy(cairo_t *cr, cairo_path_t *path)
159 cairo_append_path(cr, path);
160 cairo_path_destroy(path);
162 cairo_set_line_width(cr, 1.);
163 cairo_stroke(cr);
167 static void
168 browsing(GtkWidget *widget, GdkEventExpose *event, gpointer data)
170 cairo_t *cr;
171 int n;
173 cr = gdk_cairo_create(widget->window);
175 if (browsing_data.area == NULL) {
176 /* Initialize browsing_data */
177 browsing_data.area = widget;
178 browsing_data.use_segment = TRUE;
180 /* Append all the path samples to the cairo context */
181 cairo_save(cr);
182 cairo_translate(cr, 270.5, -120.5);
183 for (n = 0; n < G_N_ELEMENTS(path_samples); ++n) {
184 if ((n & 1) == 0) {
185 cairo_translate(cr, -270., 240.);
186 } else {
187 cairo_translate(cr, 270., 0.);
190 (path_samples[n]) (cr);
193 cairo_restore(cr);
194 browsing_data.cairo_path = cairo_copy_path(cr);
195 cpml_segment_from_cairo(&browsing_data.segment,
196 browsing_data.cairo_path);
197 cpml_primitive_from_segment(&browsing_data.primitive,
198 &browsing_data.segment);
199 } else {
200 cairo_append_path(cr, browsing_data.cairo_path);
203 cairo_set_line_width(cr, 2.);
204 cairo_stroke(cr);
206 cairo_set_source_rgb(cr, 1., 0.4, 0.);
207 cairo_set_line_width(cr, 5.);
209 if (browsing_data.use_segment)
210 cpml_segment_to_cairo(&browsing_data.segment, cr);
211 else
212 cpml_primitive_to_cairo(&browsing_data.primitive, cr);
214 cairo_stroke(cr);
215 cairo_destroy(cr);
218 static void
219 browsing_segment(GtkToggleButton *togglebutton, gpointer user_data)
221 if (!gtk_toggle_button_get_active(togglebutton))
222 return;
224 browsing_data.use_segment = TRUE;
225 gtk_widget_queue_draw(browsing_data.area);
228 static void
229 browsing_primitive(GtkToggleButton*togglebutton, gpointer user_data)
231 if (!gtk_toggle_button_get_active(togglebutton))
232 return;
234 browsing_data.use_segment = FALSE;
235 gtk_widget_queue_draw(browsing_data.area);
238 static void
239 browsing_reset(GtkButton *button, gpointer user_data)
241 if (browsing_data.use_segment) {
242 cpml_segment_reset(&browsing_data.segment);
243 cpml_primitive_from_segment(&browsing_data.primitive,
244 &browsing_data.segment);
245 } else {
246 cpml_primitive_reset(&browsing_data.primitive);
249 gtk_widget_queue_draw(browsing_data.area);
252 static void
253 browsing_next(GtkButton *button, gpointer user_data)
255 if (browsing_data.use_segment) {
256 cpml_segment_next(&browsing_data.segment);
257 cpml_primitive_from_segment(&browsing_data.primitive,
258 &browsing_data.segment);
259 } else {
260 cpml_primitive_next(&browsing_data.primitive);
263 gtk_widget_queue_draw(browsing_data.area);
267 static void
268 intersections(GtkWidget *widget, GdkEventExpose *event, gpointer data)
270 cairo_t *cr;
271 cairo_path_t *path;
272 CpmlSegment segment1, segment2;
273 CpmlPair intersection;
275 cr = gdk_cairo_create(widget->window);
276 cairo_translate(cr, 10.5, 120.5);
278 line1_callback(cr);
280 path = cairo_copy_path(cr);
282 cairo_set_line_width(cr, 1.);
283 cairo_stroke(cr);
285 cpml_segment_from_cairo(&segment1, path);
286 cpml_segment_from_cairo(&segment2, path);
288 while (cpml_segment_next(&segment2)) {
289 cpml_segment_intersection(&segment1, &segment2, &intersection, 1);
291 cairo_arc(cr, intersection.x, intersection.y, 2.5, 0, 2 * M_PI);
292 cairo_fill(cr);
294 cpml_segment_next(&segment1);
297 cairo_path_destroy(path);
298 cairo_destroy(cr);
302 static void
303 offset_curves(GtkWidget *widget, GdkEventExpose *event, gpointer data)
305 cairo_t *cr;
306 gint n;
307 CpmlPair *bezier;
308 cairo_path_t *path, *path_copy;
309 CpmlSegment segment;
310 CpmlPrimitive primitive;
311 CpmlPair pair;
312 CpmlVector vector;
313 double t;
315 cr = gdk_cairo_create(widget->window);
317 /* Add the Bézier curve samples */
318 for (n = 0; n < G_N_ELEMENTS(bezier_samples); ++n) {
319 bezier = &bezier_samples[n][0];
321 /* The samples are arranged in a 4x? matrix of 200x150 cells */
322 if (n == 0)
323 cairo_translate(cr, 25., 25.);
324 else if (n % 4 == 0)
325 cairo_translate(cr, -600., 150.);
326 else
327 cairo_translate(cr, 200., 0.);
329 /* Draw the Bézier curve */
330 cairo_move_to(cr, bezier[0].x, bezier[0].y);
331 cairo_curve_to(cr, bezier[1].x, bezier[1].y,
332 bezier[2].x, bezier[2].y, bezier[3].x, bezier[3].y);
334 /* Create a copy, to be used after */
335 path_copy = cairo_copy_path(cr);
337 path = duplicate_and_stroke(cr);
338 cpml_segment_from_cairo(&segment, path);
339 cpml_segment_offset(&segment, 20.);
340 stroke_and_destroy(cr, path);
342 cpml_segment_from_cairo(&segment, path_copy);
343 cpml_primitive_from_segment(&primitive, &segment);
345 /* Checking cpml_curve_pair_at_time and cpml_curve_vector_at_time */
346 cairo_set_line_width(cr, 1.);
347 for (t = 0; t < 1; t += 0.1) {
348 cpml_curve_pair_at_time(&primitive, &pair, t);
349 cpml_curve_vector_at_time(&primitive, &vector, t);
350 cpml_vector_set_length(&vector, 20.);
351 cpml_vector_normal(&vector);
353 cairo_new_sub_path(cr);
354 cairo_arc(cr, pair.x, pair.y, 2.5, 0, M_PI*2);
355 cairo_fill(cr);
357 cairo_move_to(cr, pair.x, pair.y);
358 cairo_line_to(cr, pair.x + vector.x, pair.y + vector.y);
359 cairo_stroke(cr);
362 cairo_path_destroy(path_copy);
365 cairo_destroy(cr);
369 static void
370 offset_segments(GtkWidget *widget, GdkEventExpose *event, gpointer data)
372 cairo_t *cr;
373 cairo_path_t *path;
374 CpmlSegment segment;
375 int n;
377 cr = gdk_cairo_create(widget->window);
378 cairo_translate(cr, 270.5, -120.5);
380 /* Offset the path samples */
381 for (n = 0; n < G_N_ELEMENTS(path_samples); ++n) {
382 if ((n & 1) == 0) {
383 cairo_translate(cr, -270., 240.);
384 } else {
385 cairo_translate(cr, 270., 0.);
388 /* Call the path callback */
389 (path_samples[n]) (cr);
391 path = duplicate_and_stroke(cr);
392 cpml_segment_from_cairo(&segment, path);
393 cpml_segment_offset(&segment, 15.);
394 stroke_and_destroy(cr, path);
397 cairo_destroy(cr);
401 static void
402 circle_callback(cairo_t *cr)
404 cairo_new_sub_path(cr);
405 cairo_arc(cr, 120., 0., 100., 0., M_PI*2);
408 static void
409 piston_callback(cairo_t *cr)
411 cairo_path_t *old_path, *path;
412 cairo_matrix_t matrix;
413 CpmlSegment segment;
415 /* Save the previous path, if any */
416 old_path = cairo_copy_path(cr);
418 cairo_new_path(cr);
419 cairo_move_to(cr, 0., 46.5);
420 cairo_line_to(cr, 210., 46.5);
421 cairo_line_to(cr, 222.5, 35.);
422 cairo_line_to(cr, 270., 35.);
423 cairo_line_to(cr, 270., 56.);
424 cairo_line_to(cr, 273., 59.);
425 cairo_line_to(cr, 302., 59.);
426 cairo_line_to(cr, 305., 56.);
427 cairo_arc(cr, 325., 52.5, 20., G_PI, 3. * G_PI_2);
428 cairo_line_to(cr, 400., 32.5);
429 cairo_line_to(cr, 410., 22.5);
430 cairo_line_to(cr, 450., 22.5);
431 cairo_arc_negative(cr,
432 452., 34., 2., G_PI, G_PI_2);
433 cairo_line_to(cr, 460., 36.);
434 cairo_line_to(cr, 470., 30.);
435 cairo_line_to(cr, 472., 12.5);
437 /* Mirror a reversed copy of the current path on the y = 0 axis */
438 path = cairo_copy_path(cr);
439 cpml_segment_from_cairo(&segment, path);
441 cpml_segment_reverse(&segment);
442 cairo_matrix_init_scale(&matrix, 1., -1.);
443 cpml_segment_transform(&segment, &matrix);
445 /* Join the mirrored path to the old path... */
446 path->data[0].header.type = CAIRO_PATH_LINE_TO;
447 cairo_append_path(cr, path);
448 cairo_path_destroy(path);
450 /* ...and close the shape */
451 cairo_close_path(cr);
453 /* Save the resulting path and clear the path memory */
454 path = cairo_copy_path(cr);
455 cairo_new_path(cr);
457 /* Restore the previous path and reappend the new path */
458 cairo_append_path(cr, old_path);
459 cairo_path_destroy(old_path);
460 cairo_append_path(cr, path);
461 cairo_path_destroy(path);
464 static void
465 curve1_callback(cairo_t *cr)
467 cairo_move_to(cr, 30., 0.);
468 cairo_curve_to(cr, 120., 120., 180., 100., 180., 20.);
469 cairo_curve_to(cr, 180., -20., 50., 40., 150., 40.);
470 cairo_curve_to(cr, 220., 40., 190., -60., 150., -60.);
471 cairo_curve_to(cr, 100., -60., 80., -40., 60., -60.);
474 static void
475 line1_callback(cairo_t *cr)
477 cairo_move_to(cr, 0, -50);
478 cairo_line_to(cr, 100, 50);
480 cairo_move_to(cr, 100, -50);
481 cairo_line_to(cr, 0, 50);
483 cairo_move_to(cr, 120, -50);
484 cairo_line_to(cr, 200, -10);
486 cairo_move_to(cr, 120, 50);
487 cairo_line_to(cr, 200, 10);
489 cairo_move_to(cr, 220, 0);
490 cairo_line_to(cr, 280, 0);
492 cairo_move_to(cr, 270, -40);
493 cairo_line_to(cr, 270, 20);
495 cairo_move_to(cr, 320, 60);
496 cairo_line_to(cr, 380, 60);
498 cairo_move_to(cr, 300, -40);
499 cairo_line_to(cr, 340, 0);
501 cairo_move_to(cr, 480, 10);
502 cairo_line_to(cr, 400, 40);
504 cairo_move_to(cr, 400, 40);
505 cairo_line_to(cr, 450, -40);