[CpmlPrimitive] Added support for CAIRO_PATH_ARC_TO
[adg.git] / demo / adg-demo.c
blob70a7bd2c8af28a1d7f84cc34ccf115f0016983be
1 #include <adg/adg.h>
2 #include <math.h>
4 #include "demo.h"
7 #ifndef G_SQRT3
8 #define G_SQRT3 1.732050808
9 #endif
11 #define CHAMFER 0.3
14 /* Dummy model */
15 typedef struct _Piston Piston;
17 struct _Piston {
18 gdouble A, B, C;
19 gdouble D1, D2, D3, D4, D5, D6, D7;
20 gdouble RD34, RD56;
21 gdouble LD2, LD3, LD5, LD6, LD7;
25 static void ldim_path (AdgEntity *entity,
26 cairo_t *cr,
27 gpointer user_data);
28 static void ldim_expose (GtkWidget *widget,
29 GdkEventExpose *event,
30 AdgCanvas *canvas);
32 static void drawing_fill_model (Piston *piston);
33 static void drawing_add_dimensions (AdgCanvas *canvas,
34 Piston *piston);
35 static void drawing_add_stuff (AdgCanvas *canvas);
36 static void drawing_path (AdgEntity *entity,
37 cairo_t *cr,
38 gpointer user_data);
39 static void drawing_expose (GtkWidget *widget,
40 GdkEventExpose *event,
41 AdgCanvas *canvas);
43 static void to_pdf (AdgCanvas *canvas,
44 GtkWidget *caller);
45 static void to_png (AdgCanvas *canvas,
46 GtkWidget *caller);
47 static void to_ps (AdgCanvas *canvas,
48 GtkWidget *caller);
50 static Piston model;
53 int
54 main(gint argc, gchar **argv)
56 gchar *path;
57 GtkBuilder *builder;
58 GError *error;
59 GtkWidget *window;
60 AdgCanvas *ldim_canvas, *drawing_canvas;
61 AdgEntity *entity;
63 gtk_init(&argc, &argv);
66 /* LDim demo */
67 ldim_canvas = adg_canvas_new();
69 entity = adg_stroke_new(ldim_path, NULL);
70 adg_container_add(ADG_CONTAINER(ldim_canvas), entity);
72 entity = adg_ldim_new_full_explicit(2, -10, 8, -10, ADG_DIR_UP, 0, -10);
73 adg_container_add(ADG_CONTAINER(ldim_canvas), entity);
75 entity = adg_ldim_new_full_explicit(0, -5, 10, -5, ADG_DIR_UP, 0, -10);
76 adg_dim_set_level(ADG_DIM(entity), 2);
77 adg_container_add(ADG_CONTAINER(ldim_canvas), entity);
80 /* Drawing demo */
81 drawing_canvas = adg_canvas_new();
83 drawing_fill_model(&model);
85 entity = adg_stroke_new(drawing_path, NULL);
86 adg_container_add(ADG_CONTAINER(drawing_canvas), entity);
88 drawing_add_dimensions(drawing_canvas, &model);
89 drawing_add_stuff(drawing_canvas);
92 /* User interface stuff */
93 path = demo_find_data_file("adg-demo.ui");
94 if (path == NULL) {
95 g_print("adg-demo.ui not found!\n");
96 return 1;
99 builder = gtk_builder_new();
100 error = NULL;
102 gtk_builder_add_from_file(builder, path, &error);
103 if (error != NULL) {
104 g_print("%s\n", error->message);
105 return 2;
108 window = (GtkWidget *) gtk_builder_get_object(builder, "wndMain");
110 /* Connect signals */
111 g_signal_connect(window, "delete-event",
112 G_CALLBACK(gtk_main_quit), NULL);
113 g_signal_connect(gtk_builder_get_object(builder, "btnQuit"),
114 "clicked", G_CALLBACK(gtk_main_quit), NULL);
116 g_signal_connect(gtk_builder_get_object(builder, "areaLDim"),
117 "expose-event", G_CALLBACK(ldim_expose), ldim_canvas);
119 g_signal_connect(gtk_builder_get_object(builder, "areaDrawing"),
120 "expose-event", G_CALLBACK(drawing_expose), drawing_canvas);
121 g_signal_connect_swapped(gtk_builder_get_object(builder, "btnPng"),
122 "clicked", G_CALLBACK(to_png), drawing_canvas);
123 g_signal_connect_swapped(gtk_builder_get_object(builder, "btnPdf"),
124 "clicked", G_CALLBACK(to_pdf), drawing_canvas);
125 g_signal_connect_swapped(gtk_builder_get_object(builder, "btnPs"),
126 "clicked", G_CALLBACK(to_ps), drawing_canvas);
128 g_object_unref(builder);
130 gtk_widget_show_all(window);
131 gtk_main();
133 return 0;
137 static void
138 ldim_path(AdgEntity *entity, cairo_t *cr, gpointer user_data)
140 cairo_move_to(cr, 0, 0);
141 cairo_line_to(cr, 0, -5);
142 cairo_line_to(cr, 2, -5);
143 cairo_line_to(cr, 2, -10);
144 cairo_line_to(cr, 8, -10);
145 cairo_line_to(cr, 8, -5);
146 cairo_line_to(cr, 10., -5);
147 cairo_line_to(cr, 10., 0);
148 cairo_close_path(cr);
151 static void
152 ldim_expose(GtkWidget *widget, GdkEventExpose *event, AdgCanvas *canvas)
154 cairo_t *cr;
155 gint width, height;
156 double xscale, yscale, scale;
157 AdgMatrix matrix;
159 cr = gdk_cairo_create(widget->window);
160 width = widget->allocation.width;
161 height = widget->allocation.height;
163 /* Fit ldim in horizontal or vertical space keeping the aspect ratio:
164 * the lesser scale factor will be used */
165 xscale = (double) (width - 20) / 10;
166 yscale = (double) (height - 90) / 10;
168 if (xscale < yscale)
169 scale = xscale;
170 else
171 scale = yscale;
173 cairo_matrix_init_translate(&matrix, 10, 80);
174 cairo_matrix_scale(&matrix, scale, scale);
175 cairo_matrix_translate(&matrix, 0, 10);
176 adg_container_set_model_transformation(ADG_CONTAINER(canvas), &matrix);
178 /* Rendering process */
179 adg_entity_render(ADG_ENTITY(canvas), cr);
181 cairo_destroy(cr);
185 static void
186 drawing_fill_model(Piston *piston)
188 piston->A = 52.3;
189 piston->B = 20.6;
190 piston->C = 2;
191 piston->D1 = 9.3;
192 piston->D2 = 6.5;
193 piston->D3 = 11.9;
194 piston->D4 = 6.5;
195 piston->D5 = 4.5;
196 piston->D6 = 7.2;
197 piston->D7 = 3.;
198 piston->RD34 = 1.;
199 piston->LD2 = 7.;
200 piston->LD3 = 3.5;
201 piston->LD5 = 5.;
202 piston->LD6 = 1.;
203 piston->LD7 = 0.5;
206 static void
207 drawing_add_dimensions(AdgCanvas *canvas, Piston *piston)
209 double A, B, C;
210 double D1, D2, D3, D4, D5, D6, D7;
211 double LD2, LD3, LD5, LD6, LD7;
212 double RD34, RD56;
213 AdgEntity *entity;
214 double x, y;
216 A = piston->A;
217 B = piston->B;
218 C = piston->C;
219 D1 = piston->D1;
220 D2 = piston->D2;
221 D3 = piston->D3;
222 D4 = piston->D4;
223 D5 = piston->D5;
224 D6 = piston->D6;
225 D7 = piston->D7;
226 LD2 = piston->LD2;
227 LD3 = piston->LD3;
228 LD5 = piston->LD5;
229 LD6 = piston->LD6;
230 LD7 = piston->LD7;
231 RD34 = piston->RD34;
232 RD56 = piston->RD56;
235 /* North */
237 /* LD2 */
238 entity = adg_ldim_new_full_explicit(A - B - LD2, -D1 / 2, A - B,
239 -D3 / 2 + CHAMFER, ADG_DIR_UP, 0,
240 -D3 / 2);
241 adg_container_add(ADG_CONTAINER(canvas), entity);
243 /* LD3 */
244 entity = adg_ldim_new_full_explicit(A - B, -D3 / 2 + CHAMFER, A - B + LD3,
245 -D3 / 2 + CHAMFER, ADG_DIR_UP, 0,
246 -D3 / 2);
247 adg_container_add(ADG_CONTAINER(canvas), entity);
250 /* South */
252 /* B */
253 entity = adg_ldim_new_full_explicit(A - B, D3 / 2 - CHAMFER, A, D7 / 2,
254 ADG_DIR_DOWN, 0, D3 / 2);
255 adg_dim_set_tolerances(ADG_DIM(entity), "+0.1", NULL);
256 adg_container_add(ADG_CONTAINER(canvas), entity);
258 /* A */
259 entity = adg_ldim_new_full_explicit(0, D1 / 2, A, D7 / 2,
260 ADG_DIR_DOWN, 0, D3 / 2);
261 adg_dim_set_tolerances(ADG_DIM(entity), "+0.05", "-0.05");
262 adg_dim_set_level(ADG_DIM(entity), 2);
263 adg_container_add(ADG_CONTAINER(canvas), entity);
266 /* East */
268 /* D3 */
269 x = A - B + LD3 - CHAMFER;
270 entity = adg_ldim_new_full_explicit(x, -D3 / 2, x, D3 / 2,
271 ADG_DIR_RIGHT, A, 0);
272 adg_dim_set_tolerances(ADG_DIM(entity), "-0.25", NULL);
273 adg_dim_set_level(ADG_DIM(entity), 5);
274 adg_container_add(ADG_CONTAINER(canvas), entity);
276 /* D6 */
277 x = A - C + LD6;
278 entity = adg_ldim_new_full_explicit(x, -D6 / 2, x, D6 / 2,
279 ADG_DIR_RIGHT, A, 0);
280 adg_dim_set_tolerances(ADG_DIM(entity), "-0.1", NULL);
281 adg_dim_set_level(ADG_DIM(entity), 4);
282 adg_container_add(ADG_CONTAINER(canvas), entity);
284 /* D4 */
285 x = A - C - LD5;
286 entity = adg_ldim_new_full_explicit(x, -D4 / 2, x, D4 / 2,
287 ADG_DIR_RIGHT, A, 0);
288 adg_dim_set_level(ADG_DIM(entity), 3);
289 adg_container_add(ADG_CONTAINER(canvas), entity);
291 /* D5 */
292 x = A - C;
293 entity = adg_ldim_new_full_explicit(x, -D5 / 2, x, D5 / 2,
294 ADG_DIR_RIGHT, A, 0);
295 adg_dim_set_tolerances(ADG_DIM(entity), "-0.1", NULL);
296 adg_dim_set_level(ADG_DIM(entity), 2);
297 adg_container_add(ADG_CONTAINER(canvas), entity);
299 /* D7 */
300 entity = adg_ldim_new_full_explicit(A, -D7 / 2, A, D7 / 2,
301 ADG_DIR_RIGHT, A, 0);
302 adg_container_add(ADG_CONTAINER(canvas), entity);
305 /* West */
307 /* D1 */
308 entity = adg_ldim_new_full_explicit(0, -D1 / 2, 0, D1 / 2,
309 ADG_DIR_LEFT, 0, 0);
310 adg_dim_set_tolerances(ADG_DIM(entity), "+0.05", "-0.05");
311 adg_dim_set_level(ADG_DIM(entity), 2);
312 adg_container_add(ADG_CONTAINER(canvas), entity);
314 /* D2 */
315 y = (D1 - D2) / 2;
316 x = A - B - LD2 + y * G_SQRT3;
317 entity = adg_ldim_new_full_explicit(x, -D2 / 2, x, D2 / 2,
318 ADG_DIR_LEFT, 0, 0);
319 adg_dim_set_tolerances(ADG_DIM(entity), "-0.1", NULL);
320 adg_container_add(ADG_CONTAINER(canvas), entity);
323 static void
324 drawing_add_stuff(AdgCanvas *canvas)
326 AdgEntity *toy_text;
328 toy_text = adg_toy_text_new("Horizontal toy_text above the piston");
329 adg_translatable_set_origin_explicit(ADG_TRANSLATABLE(toy_text),
330 0., -4.65,
331 0., -5.);
332 adg_container_add(ADG_CONTAINER(canvas), toy_text);
334 toy_text = adg_toy_text_new("toy_text");
335 adg_translatable_set_origin_explicit(ADG_TRANSLATABLE(toy_text),
336 0., 4.65,
337 0., -5.);
338 adg_rotable_set_angle(ADG_ROTABLE(toy_text), M_PI * 3./2.);
339 adg_container_add(ADG_CONTAINER(canvas), toy_text);
342 static void
343 drawing_path(AdgEntity *entity, cairo_t *cr, gpointer user_data)
345 Piston *piston;
346 double A, B, C;
347 double D1, D2, D3, D4, D5, D6, D7;
348 double LD2, LD3, LD5, LD6, LD7;
349 double RD34, RD56;
350 double x, y;
351 cairo_path_t *path;
352 CpmlSegment segment;
353 AdgMatrix matrix;
355 piston = &model;
357 A = piston->A;
358 B = piston->B;
359 C = piston->C;
360 D1 = piston->D1;
361 D2 = piston->D2;
362 D3 = piston->D3;
363 D4 = piston->D4;
364 D5 = piston->D5;
365 D6 = piston->D6;
366 D7 = piston->D7;
367 LD2 = piston->LD2;
368 LD3 = piston->LD3;
369 LD5 = piston->LD5;
370 LD6 = piston->LD6;
371 LD7 = piston->LD7;
372 RD34 = piston->RD34;
373 RD56 = piston->RD56;
375 cairo_move_to(cr, 0, D1 / 2);
376 cairo_line_to(cr, A - B - LD2, D1 / 2);
377 y = (D1 - D2) / 2;
378 cairo_line_to(cr, A - B - LD2 + y * G_SQRT3, D1 / 2 - y);
379 cairo_line_to(cr, A - B, D2 / 2);
380 cairo_line_to(cr, A - B, D3 / 2 - CHAMFER);
381 cairo_line_to(cr, A - B + CHAMFER, D3 / 2);
382 cairo_line_to(cr, A - B + LD3 - CHAMFER, D3 / 2);
383 cairo_line_to(cr, A - B + LD3, D3 / 2 - CHAMFER);
384 x = A - B + LD3 + RD34;
385 y = D4 / 2 + RD34;
386 cairo_arc(cr, x, y, RD34, G_PI, 3 * G_PI_2);
387 cairo_line_to(cr, A - C - LD5, D4 / 2);
388 y = (D4 - D5) / 2;
389 cairo_line_to(cr, A - C - LD5 + y, D4 / 2 - y);
390 cairo_line_to(cr, A - C, D5 / 2);
391 cairo_line_to(cr, A - C, D6 / 2);
392 cairo_line_to(cr, A - C + LD6, D6 / 2);
393 x = C - LD7 - LD6;
394 y = x / G_SQRT3;
395 cairo_line_to(cr, A - C + LD6 + x, D6 / 2 - y);
396 cairo_line_to(cr, A - LD7, D7 / 2);
397 cairo_line_to(cr, A, D7 / 2);
399 /* Build the shape by reflecting the current path, reversing the order
400 * and joining the result to the current path */
401 path = cairo_copy_path(cr);
402 cpml_segment_from_cairo(&segment, path);
403 cpml_segment_reverse(&segment);
404 adg_matrix_init_reflection(&matrix, 0);
405 cpml_segment_transform(&segment, &matrix);
406 path->data[0].header.type = CAIRO_PATH_LINE_TO;
407 cairo_append_path(cr, path);
408 cairo_path_destroy(path);
409 cairo_close_path(cr);
412 static void
413 drawing_expose(GtkWidget *widget, GdkEventExpose *event, AdgCanvas *canvas)
415 cairo_t *cr;
416 gint width, height;
417 double scale;
418 AdgMatrix matrix;
420 cr = gdk_cairo_create(widget->window);
421 width = widget->allocation.width;
422 height = widget->allocation.height;
424 /* Hardcoding sizes is a really ugly way to scale a drawing but... */
425 scale = (double) (width - 100 - 180) / 52.3;
427 cairo_matrix_init_translate(&matrix, 100, 70);
428 cairo_matrix_scale(&matrix, scale, scale);
429 cairo_matrix_translate(&matrix, 0, 6);
430 adg_container_set_model_transformation(ADG_CONTAINER(canvas), &matrix);
432 /* Rendering process */
433 adg_entity_render(ADG_ENTITY(canvas), cr);
435 cairo_destroy(cr);
439 #if defined(CAIRO_HAS_PNG_FUNCTIONS) || defined(CAIRO_HAS_PDF_SURFACE) || defined(CAIRO_HAS_PS_SURFACE)
441 /* Only needed if there is at least one supported surface */
442 static void
443 file_generated(GtkWidget *caller, const gchar *file)
445 GtkWindow *window;
446 GtkWidget *dialog;
448 window = (GtkWindow *) gtk_widget_get_toplevel(caller);
449 dialog = gtk_message_dialog_new_with_markup(window, GTK_DIALOG_MODAL,
450 GTK_MESSAGE_INFO,
451 GTK_BUTTONS_CLOSE,
452 "The requested operation generated\n"
453 "<b>%s</b> in the current directory.",
454 file);
455 gtk_window_set_title(GTK_WINDOW(dialog), "Operation completed");
456 gtk_dialog_run(GTK_DIALOG(dialog));
457 gtk_widget_destroy(dialog);
460 #endif
462 #if !defined(CAIRO_HAS_PNG_FUNCTIONS) || !defined(CAIRO_HAS_PDF_SURFACE) || !defined(CAIRO_HAS_PS_SURFACE)
464 /* Only needed if there is a missing surface */
465 static void
466 missing_feature(GtkWidget *caller, const gchar *feature)
468 GtkWindow *window;
469 GtkWidget *dialog;
471 window = (GtkWindow *) gtk_widget_get_toplevel(caller);
472 dialog = gtk_message_dialog_new(window, GTK_DIALOG_MODAL,
473 GTK_MESSAGE_WARNING,
474 GTK_BUTTONS_OK,
475 "The provided cairo library\n"
476 "was compiled with no %s support!",
477 feature);
478 gtk_window_set_title(GTK_WINDOW(dialog), "Missing feature");
479 gtk_dialog_run(GTK_DIALOG(dialog));
480 gtk_widget_destroy(dialog);
483 #endif
486 #ifdef CAIRO_HAS_PNG_FUNCTIONS
488 static void
489 to_png(AdgCanvas *canvas, GtkWidget *caller)
491 cairo_surface_t *surface;
492 cairo_t *cr;
494 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 800, 600);
495 cr = cairo_create(surface);
496 cairo_surface_destroy(surface);
498 /* Rendering process */
499 adg_entity_render(ADG_ENTITY(canvas), cr);
501 cairo_show_page(cr);
502 cairo_surface_write_to_png(surface, "test.png");
503 cairo_destroy(cr);
505 file_generated(caller, "test.png");
508 #else
510 static void
511 to_png(AdgCanvas *canvas, GtkWidget *caller)
513 missing_feature(caller, "PNG");
516 #endif
518 #ifdef CAIRO_HAS_PDF_SURFACE
520 #include <cairo-pdf.h>
522 static void
523 to_pdf(AdgCanvas *canvas, GtkWidget *caller)
525 cairo_surface_t *surface;
526 cairo_t *cr;
528 surface = cairo_pdf_surface_create("test.pdf", 841, 595);
529 cr = cairo_create(surface);
530 cairo_surface_destroy(surface);
532 adg_entity_render(ADG_ENTITY(canvas), cr);
534 cairo_show_page(cr);
535 cairo_destroy(cr);
537 file_generated(caller, "test.pdf");
540 #else
542 static void
543 to_pdf(AdgCanvas *canvas, GtkWidget *caller)
545 missing_feature(caller, "PDF");
548 #endif
550 #ifdef CAIRO_HAS_PS_SURFACE
552 #include <cairo-ps.h>
554 static void
555 to_ps(AdgCanvas *canvas, GtkWidget *caller)
557 cairo_surface_t *surface;
558 cairo_t *cr;
560 /* Surface creation: A4 size */
561 surface = cairo_ps_surface_create("test.ps", 841, 595);
562 cairo_ps_surface_dsc_comment(surface,
563 "%%Title: Automatic Drawing Generation (Adg) demo");
564 cairo_ps_surface_dsc_comment(surface,
565 "%%Copyright: Copyright (C) 2006 Fontana Nicola");
566 cairo_ps_surface_dsc_comment(surface, "%%Orientation: Portrait");
568 cairo_ps_surface_dsc_begin_setup(surface);
570 cairo_ps_surface_dsc_begin_page_setup(surface);
571 cairo_ps_surface_dsc_comment(surface,
572 "%%IncludeFeature: *PageSize A4");
574 cr = cairo_create(surface);
575 cairo_surface_destroy(surface);
577 adg_entity_render(ADG_ENTITY(canvas), cr);
579 cairo_show_page(cr);
580 cairo_destroy(cr);
582 file_generated(caller, "test.ps");
585 #else
587 static void
588 to_ps(AdgCanvas *canvas, GtkWidget *caller)
590 missing_feature(caller, "PostScript");
593 #endif