[demo] Updated adg-demo to use the new AdgPath APIs
[adg.git] / demo / adg-demo.c
blobd8fcd08cd3b189022e993bed11405afd3d8ddc2d
1 #include <adg/adg.h>
2 #include <math.h>
4 #include "demo.h"
7 static AdgCanvas * ldim_canvas (void);
8 static void ldim_expose (GtkWidget *widget,
9 GdkEventExpose *event,
10 AdgCanvas *canvas);
11 static AdgCanvas * drawing_canvas (void);
12 static void drawing_expose (GtkWidget *widget,
13 GdkEventExpose *event,
14 AdgCanvas *canvas);
15 static void to_pdf (AdgCanvas *canvas,
16 GtkWidget *caller);
17 static void to_png (AdgCanvas *canvas,
18 GtkWidget *caller);
19 static void to_ps (AdgCanvas *canvas,
20 GtkWidget *caller);
23 int
24 main(gint argc, gchar **argv)
26 gchar *path;
27 GtkBuilder *builder;
28 GError *error;
29 GtkWidget *window;
30 AdgCanvas *ldim, *drawing;
32 gtk_init(&argc, &argv);
34 /* Get the canvas populated by the examples */
35 ldim = ldim_canvas();
36 drawing = drawing_canvas();
38 /* User interface stuff */
39 path = demo_find_data_file("adg-demo.ui");
40 if (path == NULL) {
41 g_print("adg-demo.ui not found!\n");
42 return 1;
45 builder = gtk_builder_new();
46 error = NULL;
48 gtk_builder_add_from_file(builder, path, &error);
49 if (error != NULL) {
50 g_print("%s\n", error->message);
51 return 2;
54 window = (GtkWidget *) gtk_builder_get_object(builder, "wndMain");
56 /* Connect signals */
57 g_signal_connect(window, "delete-event",
58 G_CALLBACK(gtk_main_quit), NULL);
59 g_signal_connect(gtk_builder_get_object(builder, "btnQuit"),
60 "clicked", G_CALLBACK(gtk_main_quit), NULL);
62 g_signal_connect(gtk_builder_get_object(builder, "areaLDim"),
63 "expose-event", G_CALLBACK(ldim_expose), ldim);
65 g_signal_connect(gtk_builder_get_object(builder, "areaDrawing"),
66 "expose-event", G_CALLBACK(drawing_expose), drawing);
67 g_signal_connect_swapped(gtk_builder_get_object(builder, "btnPng"),
68 "clicked", G_CALLBACK(to_png), drawing);
69 g_signal_connect_swapped(gtk_builder_get_object(builder, "btnPdf"),
70 "clicked", G_CALLBACK(to_pdf), drawing);
71 g_signal_connect_swapped(gtk_builder_get_object(builder, "btnPs"),
72 "clicked", G_CALLBACK(to_ps), drawing);
74 g_object_unref(builder);
76 gtk_widget_show_all(window);
77 gtk_main();
79 return 0;
83 /**********************************************
84 * A simple example
85 **********************************************/
87 static AdgCanvas *
88 ldim_canvas(void)
90 AdgPath *path;
91 AdgCanvas *canvas;
92 AdgEntity *entity;
94 /* Build the path model */
95 path = (AdgPath *) adg_path_new();
97 adg_path_move_to(path, 0, 0);
98 adg_path_line_to(path, 0, -5);
99 adg_path_line_to(path, 2, -5);
100 adg_path_line_to(path, 2, -10);
101 adg_path_line_to(path, 8, -10);
102 adg_path_line_to(path, 8, -5);
103 adg_path_line_to(path, 10, -5);
104 adg_path_line_to(path, 10, 0);
105 adg_path_close(path);
107 /* Populate the canvas */
108 canvas = adg_canvas_new();
110 entity = adg_stroke_new(path);
111 adg_container_add(ADG_CONTAINER(canvas), entity);
113 entity = adg_ldim_new_full_explicit(2, -10, 8, -10, ADG_DIR_UP, 0, -10);
114 adg_container_add(ADG_CONTAINER(canvas), entity);
116 entity = adg_ldim_new_full_explicit(0, -5, 10, -5, ADG_DIR_UP, 0, -10);
117 adg_dim_set_level(ADG_DIM(entity), 2);
118 adg_container_add(ADG_CONTAINER(canvas), entity);
120 return canvas;
123 static void
124 ldim_expose(GtkWidget *widget, GdkEventExpose *event, AdgCanvas *canvas)
126 cairo_t *cr;
127 gint width, height;
128 double xscale, yscale, scale;
129 AdgMatrix matrix;
131 cr = gdk_cairo_create(widget->window);
132 width = widget->allocation.width;
133 height = widget->allocation.height;
135 /* Fit ldim in horizontal or vertical space keeping the aspect ratio:
136 * the lesser scale factor will be used */
137 xscale = (double) (width - 20) / 10;
138 yscale = (double) (height - 90) / 10;
140 if (xscale < yscale)
141 scale = xscale;
142 else
143 scale = yscale;
145 cairo_matrix_init_translate(&matrix, 10, 80);
146 cairo_matrix_scale(&matrix, scale, scale);
147 cairo_matrix_translate(&matrix, 0, 10);
148 adg_container_set_model_transformation(ADG_CONTAINER(canvas), &matrix);
150 /* Rendering process */
151 adg_entity_render(ADG_ENTITY(canvas), cr);
153 cairo_destroy(cr);
157 /**********************************************
158 * A more complex example
159 **********************************************/
161 #define SQRT3 1.732050808
162 #define CHAMFER 0.3
164 typedef struct _DrawingData DrawingData;
166 struct _DrawingData {
167 gdouble A, B, C;
168 gdouble D1, D2, D3, D4, D5, D6, D7;
169 gdouble RD34, RD56;
170 gdouble LD2, LD3, LD5, LD6, LD7;
173 static void drawing_get (DrawingData *data);
174 static AdgPath *drawing_path (const DrawingData *data);
175 static void drawing_add_dimensions (AdgCanvas *canvas,
176 const DrawingData *data);
177 static void drawing_add_stuff (AdgCanvas *canvas,
178 const DrawingData *data);
181 static AdgCanvas *
182 drawing_canvas(void)
184 DrawingData data;
185 AdgPath *path;
186 AdgCanvas *canvas;
187 AdgEntity *entity;
189 drawing_get(&data);
190 path = drawing_path(&data);
191 canvas = adg_canvas_new();
193 entity = adg_stroke_new(path);
194 adg_container_add(ADG_CONTAINER(canvas), entity);
196 drawing_add_dimensions(canvas, &data);
197 drawing_add_stuff(canvas, &data);
199 return canvas;
202 static void
203 drawing_expose(GtkWidget *widget, GdkEventExpose *event, AdgCanvas *canvas)
205 cairo_t *cr;
206 gint width, height;
207 double scale;
208 AdgMatrix matrix;
210 cr = gdk_cairo_create(widget->window);
211 width = widget->allocation.width;
212 height = widget->allocation.height;
214 /* Hardcoding sizes is a really ugly way to scale a drawing but... */
215 scale = (double) (width - 100 - 180) / 52.3;
217 cairo_matrix_init_translate(&matrix, 100, 70);
218 cairo_matrix_scale(&matrix, scale, scale);
219 cairo_matrix_translate(&matrix, 0, 6);
220 adg_container_set_model_transformation(ADG_CONTAINER(canvas), &matrix);
222 /* Rendering process */
223 adg_entity_render(ADG_ENTITY(canvas), cr);
225 cairo_destroy(cr);
228 static void
229 drawing_get(DrawingData *data)
231 data->A = 52.3;
232 data->B = 20.6;
233 data->C = 2;
234 data->D1 = 9.3;
235 data->D2 = 6.5;
236 data->D3 = 11.9;
237 data->D4 = 6.5;
238 data->D5 = 4.5;
239 data->D6 = 7.2;
240 data->D7 = 3.;
241 data->RD34 = 1.;
242 data->LD2 = 7.;
243 data->LD3 = 3.5;
244 data->LD5 = 5.;
245 data->LD6 = 1.;
246 data->LD7 = 0.5;
249 static AdgPath *
250 drawing_path(const DrawingData *data)
252 AdgPath *path;
253 double x, y;
254 cairo_path_t *cairo_path;
255 CpmlSegment segment;
256 cairo_matrix_t matrix;
258 path = (AdgPath *) adg_path_new();
260 adg_path_move_to(path, 0, data->D1 / 2);
261 adg_path_line_to(path, data->A - data->B - data->LD2, data->D1 / 2);
262 y = (data->D1 - data->D2) / 2;
263 adg_path_line_to(path, data->A - data->B - data->LD2 + y * SQRT3, data->D1 / 2 - y);
264 adg_path_line_to(path, data->A - data->B, data->D2 / 2);
265 adg_path_line_to(path, data->A - data->B, data->D3 / 2 - CHAMFER);
266 adg_path_line_to(path, data->A - data->B + CHAMFER, data->D3 / 2);
267 adg_path_line_to(path, data->A - data->B + data->LD3 - CHAMFER, data->D3 / 2);
268 adg_path_line_to(path, data->A - data->B + data->LD3, data->D3 / 2 - CHAMFER);
269 x = data->A - data->B + data->LD3 + data->RD34;
270 y = data->D4 / 2 + data->RD34;
271 adg_path_arc(path, x, y, data->RD34, G_PI, -G_PI_2);
272 adg_path_line_to(path, data->A - data->C - data->LD5, data->D4 / 2);
273 y = (data->D4 - data->D5) / 2;
274 adg_path_line_to(path, data->A - data->C - data->LD5 + y, data->D4 / 2 - y);
275 adg_path_line_to(path, data->A - data->C, data->D5 / 2);
276 adg_path_line_to(path, data->A - data->C, data->D6 / 2);
277 adg_path_line_to(path, data->A - data->C + data->LD6, data->D6 / 2);
278 x = data->C - data->LD7 - data->LD6;
279 y = x / SQRT3;
280 adg_path_line_to(path, data->A - data->C + data->LD6 + x, data->D6 / 2 - y);
281 adg_path_line_to(path, data->A - data->LD7, data->D7 / 2);
282 adg_path_line_to(path, data->A, data->D7 / 2);
284 /* Build the shape by reflecting the current path, reversing the order
285 * and joining the result to the current path */
286 cairo_path = adg_path_dup_cpml_path(path);
288 cpml_segment_from_cairo(&segment, cairo_path);
289 cpml_segment_reverse(&segment);
290 adg_matrix_init_reflection(&matrix, 0);
291 cpml_segment_transform(&segment, &matrix);
292 cairo_path->data[0].header.type = CAIRO_PATH_LINE_TO;
294 adg_path_append_cairo_path(path, cairo_path);
296 g_free(cairo_path);
298 adg_path_close(path);
299 return path;
302 static void
303 drawing_add_dimensions(AdgCanvas *canvas, const DrawingData *data)
305 AdgEntity *entity;
306 double x, y;
308 /* NORTH */
310 /* LD2 */
311 entity = adg_ldim_new_full_explicit(data->A - data->B - data->LD2, -data->D1 / 2, data->A - data->B,
312 -data->D3 / 2 + CHAMFER, ADG_DIR_UP, 0,
313 -data->D3 / 2);
314 adg_container_add(ADG_CONTAINER(canvas), entity);
316 /* LD3 */
317 entity = adg_ldim_new_full_explicit(data->A - data->B, -data->D3 / 2 + CHAMFER, data->A - data->B + data->LD3,
318 -data->D3 / 2 + CHAMFER, ADG_DIR_UP, 0,
319 -data->D3 / 2);
320 adg_container_add(ADG_CONTAINER(canvas), entity);
322 /* SOUTH */
324 /* B */
325 entity = adg_ldim_new_full_explicit(data->A - data->B, data->D3 / 2 - CHAMFER, data->A, data->D7 / 2,
326 ADG_DIR_DOWN, 0, data->D3 / 2);
327 adg_dim_set_tolerances(ADG_DIM(entity), "+0.1", NULL);
328 adg_container_add(ADG_CONTAINER(canvas), entity);
330 /* A */
331 entity = adg_ldim_new_full_explicit(0, data->D1 / 2, data->A, data->D7 / 2,
332 ADG_DIR_DOWN, 0, data->D3 / 2);
333 adg_dim_set_tolerances(ADG_DIM(entity), "+0.05", "-0.05");
334 adg_dim_set_level(ADG_DIM(entity), 2);
335 adg_container_add(ADG_CONTAINER(canvas), entity);
337 /* EAST */
339 /* D3 */
340 x = data->A - data->B + data->LD3 - CHAMFER;
341 entity = adg_ldim_new_full_explicit(x, -data->D3 / 2, x, data->D3 / 2,
342 ADG_DIR_RIGHT, data->A, 0);
343 adg_dim_set_tolerances(ADG_DIM(entity), "-0.25", NULL);
344 adg_dim_set_level(ADG_DIM(entity), 5);
345 adg_container_add(ADG_CONTAINER(canvas), entity);
347 /* D6 */
348 x = data->A - data->C + data->LD6;
349 entity = adg_ldim_new_full_explicit(x, -data->D6 / 2, x, data->D6 / 2,
350 ADG_DIR_RIGHT, data->A, 0);
351 adg_dim_set_tolerances(ADG_DIM(entity), "-0.1", NULL);
352 adg_dim_set_level(ADG_DIM(entity), 4);
353 adg_container_add(ADG_CONTAINER(canvas), entity);
355 /* D4 */
356 x = data->A - data->C - data->LD5;
357 entity = adg_ldim_new_full_explicit(x, -data->D4 / 2, x, data->D4 / 2,
358 ADG_DIR_RIGHT, data->A, 0);
359 adg_dim_set_level(ADG_DIM(entity), 3);
360 adg_container_add(ADG_CONTAINER(canvas), entity);
362 /* D5 */
363 x = data->A - data->C;
364 entity = adg_ldim_new_full_explicit(x, -data->D5 / 2, x, data->D5 / 2,
365 ADG_DIR_RIGHT, data->A, 0);
366 adg_dim_set_tolerances(ADG_DIM(entity), "-0.1", NULL);
367 adg_dim_set_level(ADG_DIM(entity), 2);
368 adg_container_add(ADG_CONTAINER(canvas), entity);
370 /* D7 */
371 entity = adg_ldim_new_full_explicit(data->A, -data->D7 / 2, data->A, data->D7 / 2,
372 ADG_DIR_RIGHT, data->A, 0);
373 adg_container_add(ADG_CONTAINER(canvas), entity);
375 /* WEST */
377 /* D1 */
378 entity = adg_ldim_new_full_explicit(0, -data->D1 / 2, 0, data->D1 / 2,
379 ADG_DIR_LEFT, 0, 0);
380 adg_dim_set_tolerances(ADG_DIM(entity), "+0.05", "-0.05");
381 adg_dim_set_level(ADG_DIM(entity), 2);
382 adg_container_add(ADG_CONTAINER(canvas), entity);
384 /* D2 */
385 y = (data->D1 - data->D2) / 2;
386 x = data->A - data->B - data->LD2 + y * SQRT3;
387 entity = adg_ldim_new_full_explicit(x, -data->D2 / 2, x, data->D2 / 2,
388 ADG_DIR_LEFT, 0, 0);
389 adg_dim_set_tolerances(ADG_DIM(entity), "-0.1", NULL);
390 adg_container_add(ADG_CONTAINER(canvas), entity);
393 static void
394 drawing_add_stuff(AdgCanvas *canvas, const DrawingData *data)
396 AdgEntity *toy_text;
398 toy_text = adg_toy_text_new("Horizontal toy_text above the piston");
399 adg_translatable_set_origin_explicit(ADG_TRANSLATABLE(toy_text),
400 0., -data->D1 / 2,
401 0., -5.);
402 adg_container_add(ADG_CONTAINER(canvas), toy_text);
404 toy_text = adg_toy_text_new("toy_text");
405 adg_translatable_set_origin_explicit(ADG_TRANSLATABLE(toy_text),
406 0., data->D1 / 2,
407 0., -5.);
408 adg_rotable_set_angle(ADG_ROTABLE(toy_text), M_PI * 3./2.);
409 adg_container_add(ADG_CONTAINER(canvas), toy_text);
413 #if defined(CAIRO_HAS_PNG_FUNCTIONS) || defined(CAIRO_HAS_PDF_SURFACE) || defined(CAIRO_HAS_PS_SURFACE)
415 /* Only needed if there is at least one supported surface */
416 static void
417 file_generated(GtkWidget *caller, const gchar *file)
419 GtkWindow *window;
420 GtkWidget *dialog;
422 window = (GtkWindow *) gtk_widget_get_toplevel(caller);
423 dialog = gtk_message_dialog_new_with_markup(window, GTK_DIALOG_MODAL,
424 GTK_MESSAGE_INFO,
425 GTK_BUTTONS_CLOSE,
426 "The requested operation generated\n"
427 "<b>%s</b> in the current directory.",
428 file);
429 gtk_window_set_title(GTK_WINDOW(dialog), "Operation completed");
430 gtk_dialog_run(GTK_DIALOG(dialog));
431 gtk_widget_destroy(dialog);
434 #endif
436 #if !defined(CAIRO_HAS_PNG_FUNCTIONS) || !defined(CAIRO_HAS_PDF_SURFACE) || !defined(CAIRO_HAS_PS_SURFACE)
438 /* Only needed if there is a missing surface */
439 static void
440 missing_feature(GtkWidget *caller, const gchar *feature)
442 GtkWindow *window;
443 GtkWidget *dialog;
445 window = (GtkWindow *) gtk_widget_get_toplevel(caller);
446 dialog = gtk_message_dialog_new(window, GTK_DIALOG_MODAL,
447 GTK_MESSAGE_WARNING,
448 GTK_BUTTONS_OK,
449 "The provided cairo library\n"
450 "was compiled with no %s support!",
451 feature);
452 gtk_window_set_title(GTK_WINDOW(dialog), "Missing feature");
453 gtk_dialog_run(GTK_DIALOG(dialog));
454 gtk_widget_destroy(dialog);
457 #endif
460 #ifdef CAIRO_HAS_PNG_FUNCTIONS
462 static void
463 to_png(AdgCanvas *canvas, GtkWidget *caller)
465 cairo_surface_t *surface;
466 cairo_t *cr;
468 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 800, 600);
469 cr = cairo_create(surface);
470 cairo_surface_destroy(surface);
472 /* Rendering process */
473 adg_entity_render(ADG_ENTITY(canvas), cr);
475 cairo_show_page(cr);
476 cairo_surface_write_to_png(surface, "test.png");
477 cairo_destroy(cr);
479 file_generated(caller, "test.png");
482 #else
484 static void
485 to_png(AdgCanvas *canvas, GtkWidget *caller)
487 missing_feature(caller, "PNG");
490 #endif
492 #ifdef CAIRO_HAS_PDF_SURFACE
494 #include <cairo-pdf.h>
496 static void
497 to_pdf(AdgCanvas *canvas, GtkWidget *caller)
499 cairo_surface_t *surface;
500 cairo_t *cr;
502 surface = cairo_pdf_surface_create("test.pdf", 841, 595);
503 cr = cairo_create(surface);
504 cairo_surface_destroy(surface);
506 adg_entity_render(ADG_ENTITY(canvas), cr);
508 cairo_show_page(cr);
509 cairo_destroy(cr);
511 file_generated(caller, "test.pdf");
514 #else
516 static void
517 to_pdf(AdgCanvas *canvas, GtkWidget *caller)
519 missing_feature(caller, "PDF");
522 #endif
524 #ifdef CAIRO_HAS_PS_SURFACE
526 #include <cairo-ps.h>
528 static void
529 to_ps(AdgCanvas *canvas, GtkWidget *caller)
531 cairo_surface_t *surface;
532 cairo_t *cr;
534 /* Surface creation: A4 size */
535 surface = cairo_ps_surface_create("test.ps", 841, 595);
536 cairo_ps_surface_dsc_comment(surface,
537 "%%Title: Automatic Drawing Generation (Adg) demo");
538 cairo_ps_surface_dsc_comment(surface,
539 "%%Copyright: Copyright (C) 2006 Fontana Nicola");
540 cairo_ps_surface_dsc_comment(surface, "%%Orientation: Portrait");
542 cairo_ps_surface_dsc_begin_setup(surface);
544 cairo_ps_surface_dsc_begin_page_setup(surface);
545 cairo_ps_surface_dsc_comment(surface,
546 "%%IncludeFeature: *PageSize A4");
548 cr = cairo_create(surface);
549 cairo_surface_destroy(surface);
551 adg_entity_render(ADG_ENTITY(canvas), cr);
553 cairo_show_page(cr);
554 cairo_destroy(cr);
556 file_generated(caller, "test.ps");
559 #else
561 static void
562 to_ps(AdgCanvas *canvas, GtkWidget *caller)
564 missing_feature(caller, "PostScript");
567 #endif