1 #include <config.h>
2 #include <glib/gi18n.h>
3 #include <gtk/gtk.h>
4 #include <goocanvas.h>
5
6
7 #define LEFT 50.0
8 #define RIGHT 350.0
9 #define MIDDLE 150.0
10 #define DEFAULT_WIDTH 2
11 #define DEFAULT_SHAPE_A 4
12 #define DEFAULT_SHAPE_B 5
13 #define DEFAULT_SHAPE_C 4
14
15
16 static void
set_dimension(GooCanvas * canvas,char * arrow_name,char * text_name,double x1,double y1,double x2,double y2,double tx,double ty,int dim)17 set_dimension (GooCanvas *canvas, char *arrow_name, char *text_name,
18 double x1, double y1, double x2, double y2,
19 double tx, double ty, int dim)
20 {
21 GooCanvasPoints *points;
22 char buf[100];
23
24 points = goo_canvas_points_new (2);
25 points->coords[0] = x1;
26 points->coords[1] = y1;
27 points->coords[2] = x2;
28 points->coords[3] = y2;
29
30 g_object_set (g_object_get_data (G_OBJECT (canvas), arrow_name),
31 "points", points,
32 NULL);
33
34 sprintf (buf, "%d", dim);
35 g_object_set (g_object_get_data (G_OBJECT (canvas), text_name),
36 "text", buf,
37 "x", tx,
38 "y", ty,
39 NULL);
40
41 goo_canvas_points_unref (points);
42 }
43
44 static void
move_drag_box(GooCanvasItem * item,double x,double y)45 move_drag_box (GooCanvasItem *item, double x, double y)
46 {
47 g_object_set (item,
48 "x", x - 5.0,
49 "y", y - 5.0,
50 NULL);
51 }
52
53
54 static void
set_arrow_shape(GooCanvas * canvas)55 set_arrow_shape (GooCanvas *canvas)
56 {
57 int width;
58 int shape_a, shape_b, shape_c;
59 GooCanvasPoints *points;
60 char buf[100];
61
62 width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (canvas), "width"));
63 shape_a = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (canvas), "shape_a"));
64 shape_b = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (canvas), "shape_b"));
65 shape_c = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (canvas), "shape_c"));
66
67 /* Big arrow */
68
69 g_object_set (g_object_get_data (G_OBJECT (canvas), "big_arrow"),
70 "line-width", 10.0 * width,
71 "arrow-tip-length", (double) (shape_a),
72 "arrow-length", (double) (shape_b),
73 "arrow-width", (double) (shape_c),
74 NULL);
75
76 /* Outline */
77
78 points = goo_canvas_points_new (5);
79 points->coords[0] = RIGHT - 10 * shape_a * width;
80 points->coords[1] = MIDDLE - 10 * width / 2;
81 points->coords[2] = RIGHT - 10 * shape_b * width;
82 points->coords[3] = MIDDLE - 10 * (shape_c * width / 2.0);
83 points->coords[4] = RIGHT;
84 points->coords[5] = MIDDLE;
85 points->coords[6] = points->coords[2];
86 points->coords[7] = MIDDLE + 10 * (shape_c * width / 2.0);
87 points->coords[8] = points->coords[0];
88 points->coords[9] = MIDDLE + 10 * width / 2;
89 g_object_set (g_object_get_data (G_OBJECT (canvas), "outline"),
90 "points", points,
91 NULL);
92 goo_canvas_points_unref (points);
93
94 /* Drag boxes */
95
96 move_drag_box (g_object_get_data (G_OBJECT (canvas), "width_drag_box"),
97 LEFT,
98 MIDDLE - 10 * width / 2.0);
99
100 move_drag_box (g_object_get_data (G_OBJECT (canvas), "shape_a_drag_box"),
101 RIGHT - 10 * shape_a * width,
102 MIDDLE);
103
104 move_drag_box (g_object_get_data (G_OBJECT (canvas), "shape_b_c_drag_box"),
105 RIGHT - 10 * shape_b * width,
106 MIDDLE - 10 * (shape_c * width / 2.0));
107
108 /* Dimensions */
109
110 set_dimension (canvas, "width_arrow", "width_text",
111 LEFT - 10,
112 MIDDLE - 10 * width / 2.0,
113 LEFT - 10,
114 MIDDLE + 10 * width / 2.0,
115 LEFT - 15,
116 MIDDLE,
117 width);
118
119 set_dimension (canvas, "shape_a_arrow", "shape_a_text",
120 RIGHT - 10 * shape_a * width,
121 MIDDLE + 10 * (shape_c * width / 2.0) + 10,
122 RIGHT,
123 MIDDLE + 10 * (shape_c * width / 2.0) + 10,
124 RIGHT - 10 * shape_a * width / 2.0,
125 MIDDLE + 10 * (shape_c * width / 2.0) + 15,
126 shape_a);
127
128 set_dimension (canvas, "shape_b_arrow", "shape_b_text",
129 RIGHT - 10 * shape_b * width,
130 MIDDLE + 10 * (shape_c * width / 2.0) + 35,
131 RIGHT,
132 MIDDLE + 10 * (shape_c * width / 2.0) + 35,
133 RIGHT - 10 * shape_b * width / 2.0,
134 MIDDLE + 10 * (shape_c * width / 2.0) + 40,
135 shape_b);
136
137 set_dimension (canvas, "shape_c_arrow", "shape_c_text",
138 RIGHT + 10,
139 MIDDLE - 10 * shape_c * width / 2.0,
140 RIGHT + 10,
141 MIDDLE + 10 * shape_c * width / 2.0,
142 RIGHT + 15,
143 MIDDLE,
144 shape_c);
145
146 /* Info */
147
148 sprintf (buf, "line-width: %d", width);
149 g_object_set (g_object_get_data (G_OBJECT (canvas), "width_info"),
150 "text", buf,
151 NULL);
152
153 sprintf (buf, "arrow-tip-length: %d (* line-width)", shape_a);
154 g_object_set (g_object_get_data (G_OBJECT (canvas), "shape_a_info"),
155 "text", buf,
156 NULL);
157
158 sprintf (buf, "arrow-length: %d (* line-width)", shape_b);
159 g_object_set (g_object_get_data (G_OBJECT (canvas), "shape_b_info"),
160 "text", buf,
161 NULL);
162 sprintf (buf, "arrow-width: %d (* line-width)", shape_c);
163 g_object_set (g_object_get_data (G_OBJECT (canvas), "shape_c_info"),
164 "text", buf,
165 NULL);
166
167 /* Sample arrows */
168
169 g_object_set (g_object_get_data (G_OBJECT (canvas), "sample_1"),
170 "line-width", (double) width,
171 "arrow-tip-length", (double) shape_a,
172 "arrow-length", (double) shape_b,
173 "arrow-width", (double) shape_c,
174 NULL);
175 g_object_set (g_object_get_data (G_OBJECT (canvas), "sample_2"),
176 "line-width", (double) width,
177 "arrow-tip-length", (double) shape_a,
178 "arrow-length", (double) shape_b,
179 "arrow-width", (double) shape_c,
180 NULL);
181 g_object_set (g_object_get_data (G_OBJECT (canvas), "sample_3"),
182 "line-width", (double) width,
183 "arrow-tip-length", (double) shape_a,
184 "arrow-length", (double) shape_b,
185 "arrow-width", (double) shape_c,
186 NULL);
187 }
188
189
190 static void
create_dimension(GtkWidget * canvas,GooCanvasItem * root,char * arrow_name,char * text_name,GtkAnchorType anchor)191 create_dimension (GtkWidget *canvas,
192 GooCanvasItem *root,
193 char *arrow_name,
194 char *text_name,
195 GtkAnchorType anchor)
196 {
197 GooCanvasItem *item;
198
199 item = goo_canvas_polyline_new (root, FALSE, 0,
200 "fill_color", "black",
201 "start-arrow", TRUE,
202 "end-arrow", TRUE,
203 NULL);
204 g_object_set_data (G_OBJECT (canvas), arrow_name, item);
205
206 item = goo_canvas_text_new (root, NULL, 0, 0, -1, anchor,
207 "fill_color", "black",
208 "font", "Sans 12",
209 NULL);
210 g_object_set_data (G_OBJECT (canvas), text_name, item);
211 }
212
213 static void
create_info(GtkWidget * canvas,GooCanvasItem * root,char * info_name,double x,double y)214 create_info (GtkWidget *canvas,
215 GooCanvasItem *root,
216 char *info_name,
217 double x,
218 double y)
219 {
220 GooCanvasItem *item;
221
222 item = goo_canvas_text_new (root, NULL, x, y, -1, GTK_ANCHOR_NW,
223 "fill_color", "black",
224 "font", "Sans 14",
225 NULL);
226 g_object_set_data (G_OBJECT (canvas), info_name, item);
227 }
228
229 static void
create_sample_arrow(GtkWidget * canvas,GooCanvasItem * root,char * sample_name,double x1,double y1,double x2,double y2)230 create_sample_arrow (GtkWidget *canvas,
231 GooCanvasItem *root,
232 char *sample_name,
233 double x1,
234 double y1,
235 double x2,
236 double y2)
237 {
238 GooCanvasItem *item;
239
240 item = goo_canvas_polyline_new_line (root, x1, y1, x2, y2,
241 "start-arrow", TRUE,
242 "end-arrow", TRUE,
243 NULL);
244 g_object_set_data (G_OBJECT (canvas), sample_name, item);
245 }
246
247
248 static gboolean
on_enter_notify(GooCanvasItem * item,GooCanvasItem * target,GdkEventCrossing * event,gpointer data)249 on_enter_notify (GooCanvasItem *item,
250 GooCanvasItem *target,
251 GdkEventCrossing *event,
252 gpointer data)
253 {
254 g_object_set (item,
255 "fill_color", "red",
256 NULL);
257
258 return TRUE;
259 }
260
261
262 static gboolean
on_leave_notify(GooCanvasItem * item,GooCanvasItem * target,GdkEvent * event,gpointer data)263 on_leave_notify (GooCanvasItem *item,
264 GooCanvasItem *target,
265 GdkEvent *event,
266 gpointer data)
267 {
268 g_object_set (item,
269 "fill_color", "black",
270 NULL);
271
272 return TRUE;
273 }
274
275
276 static gboolean
on_button_press(GooCanvasItem * item,GooCanvasItem * target,GdkEventButton * event,gpointer data)277 on_button_press (GooCanvasItem *item,
278 GooCanvasItem *target,
279 GdkEventButton *event,
280 gpointer data)
281 {
282 GooCanvas *canvas;
283 GdkCursor *fleur;
284
285 fleur = gdk_cursor_new (GDK_FLEUR);
286 canvas = goo_canvas_item_get_canvas (item);
287 goo_canvas_pointer_grab (canvas, item,
288 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_RELEASE_MASK,
289 fleur,
290 event->time);
291 gdk_cursor_unref (fleur);
292
293 return TRUE;
294 }
295
296
297 static gboolean
on_button_release(GooCanvasItem * item,GooCanvasItem * target,GdkEventButton * event,gpointer data)298 on_button_release (GooCanvasItem *item,
299 GooCanvasItem *target,
300 GdkEventButton *event,
301 gpointer data)
302 {
303 GooCanvas *canvas;
304
305 canvas = goo_canvas_item_get_canvas (item);
306 goo_canvas_pointer_ungrab (canvas, item, event->time);
307
308 return TRUE;
309 }
310
311
312 static gboolean
on_motion(GooCanvasItem * item,GooCanvasItem * target,GdkEventMotion * event,gpointer data)313 on_motion (GooCanvasItem *item,
314 GooCanvasItem *target,
315 GdkEventMotion *event,
316 gpointer data)
317 {
318 GooCanvas *canvas = goo_canvas_item_get_canvas (item);
319 int x, y, width, shape_a, shape_b, shape_c;
320 gboolean change = FALSE;
321
322 if (!(event->state & GDK_BUTTON1_MASK))
323 return FALSE;
324
325 if (item == g_object_get_data (G_OBJECT (canvas), "width_drag_box"))
326 {
327 y = event->y;
328 width = (MIDDLE - y) / 5;
329 if (width < 0)
330 return FALSE;
331 g_object_set_data (G_OBJECT (canvas), "width", GINT_TO_POINTER (width));
332 set_arrow_shape (canvas);
333 }
334 else if (item == g_object_get_data (G_OBJECT (canvas), "shape_a_drag_box"))
335 {
336 x = event->x;
337 width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (canvas), "width"));
338 shape_a = (RIGHT - x) / 10 / width;
339 if ((shape_a < 0) || (shape_a > 30))
340 return FALSE;
341 g_object_set_data (G_OBJECT (canvas), "shape_a",
342 GINT_TO_POINTER (shape_a));
343 set_arrow_shape (canvas);
344 }
345 else if (item == g_object_get_data (G_OBJECT (canvas), "shape_b_c_drag_box"))
346 {
347 width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (canvas), "width"));
348
349 x = event->x;
350 shape_b = (RIGHT - x) / 10 / width;
351 if ((shape_b >= 0) && (shape_b <= 30)) {
352 g_object_set_data (G_OBJECT (canvas), "shape_b",
353 GINT_TO_POINTER (shape_b));
354 change = TRUE;
355 }
356
357 y = event->y;
358 shape_c = (MIDDLE - y) * 2 / 10 / width;
359 if (shape_c >= 0) {
360 g_object_set_data (G_OBJECT (canvas), "shape_c",
361 GINT_TO_POINTER (shape_c));
362 change = TRUE;
363 }
364
365 if (change)
366 set_arrow_shape (canvas);
367 }
368
369 return TRUE;
370 }
371
372
373 static void
create_drag_box(GtkWidget * canvas,GooCanvasItem * root,char * box_name)374 create_drag_box (GtkWidget *canvas,
375 GooCanvasItem *root,
376 char *box_name)
377 {
378 GooCanvasItem *item;
379
380 item = goo_canvas_rect_new (root, 0, 0, 10, 10,
381 "fill_color", "black",
382 "stroke_color", "black",
383 "line_width", 1.0,
384 NULL);
385 g_object_set_data (G_OBJECT (canvas), box_name, item);
386
387 g_signal_connect (item, "enter_notify_event",
388 G_CALLBACK (on_enter_notify),
389 NULL);
390 g_signal_connect (item, "leave_notify_event",
391 G_CALLBACK (on_leave_notify),
392 NULL);
393 g_signal_connect (item, "button_press_event",
394 G_CALLBACK (on_button_press),
395 NULL);
396 g_signal_connect (item, "button_release_event",
397 G_CALLBACK (on_button_release),
398 NULL);
399 g_signal_connect (item, "motion_notify_event",
400 G_CALLBACK (on_motion),
401 NULL);
402 }
403
404
405 GtkWidget *
create_canvas_arrowhead(void)406 create_canvas_arrowhead (void)
407 {
408 GtkWidget *vbox;
409 GtkWidget *w;
410 GtkWidget *frame;
411 GtkWidget *canvas;
412 GooCanvasItem *root, *item;
413
414 vbox = gtk_vbox_new (FALSE, 4);
415 gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
416 gtk_widget_show (vbox);
417
418 w = gtk_label_new ("This demo allows you to edit arrowhead shapes. Drag the little boxes\n"
419 "to change the shape of the line and its arrowhead. You can see the\n"
420 "arrows at their normal scale on the right hand side of the window.");
421 gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0);
422 gtk_widget_show (w);
423
424 w = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
425 gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0);
426 gtk_widget_show (w);
427
428 frame = gtk_frame_new (NULL);
429 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
430 gtk_container_add (GTK_CONTAINER (w), frame);
431 gtk_widget_show (frame);
432
433 canvas = goo_canvas_new ();
434 root = goo_canvas_get_root_item (GOO_CANVAS (canvas));
435
436 gtk_widget_set_size_request (canvas, 500, 350);
437 goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 500, 350);
438 gtk_container_add (GTK_CONTAINER (frame), canvas);
439 gtk_widget_show (canvas);
440
441
442 g_object_set_data (G_OBJECT (canvas), "width",
443 GINT_TO_POINTER (DEFAULT_WIDTH));
444 g_object_set_data (G_OBJECT (canvas), "shape_a",
445 GINT_TO_POINTER (DEFAULT_SHAPE_A));
446 g_object_set_data (G_OBJECT (canvas), "shape_b",
447 GINT_TO_POINTER (DEFAULT_SHAPE_B));
448 g_object_set_data (G_OBJECT (canvas), "shape_c",
449 GINT_TO_POINTER (DEFAULT_SHAPE_C));
450
451 /* Big arrow */
452
453 item = goo_canvas_polyline_new_line (root,
454 LEFT, MIDDLE, RIGHT, MIDDLE,
455 "stroke_color", "mediumseagreen",
456 "end-arrow", TRUE,
457 NULL);
458 g_object_set_data (G_OBJECT (canvas), "big_arrow", item);
459
460 /* Arrow outline */
461
462 item = goo_canvas_polyline_new (root, TRUE, 0,
463 "stroke_color", "black",
464 "line-width", 2.0,
465 "line-cap", CAIRO_LINE_CAP_ROUND,
466 "line-join", CAIRO_LINE_JOIN_ROUND,
467 NULL);
468 g_object_set_data (G_OBJECT (canvas), "outline", item);
469
470 /* Drag boxes */
471
472 create_drag_box (canvas, root, "width_drag_box");
473 create_drag_box (canvas, root, "shape_a_drag_box");
474 create_drag_box (canvas, root, "shape_b_c_drag_box");
475
476 /* Dimensions */
477
478 create_dimension (canvas, root, "width_arrow", "width_text", GTK_ANCHOR_E);
479 create_dimension (canvas, root, "shape_a_arrow", "shape_a_text", GTK_ANCHOR_N);
480 create_dimension (canvas, root, "shape_b_arrow", "shape_b_text", GTK_ANCHOR_N);
481 create_dimension (canvas, root, "shape_c_arrow", "shape_c_text", GTK_ANCHOR_W);
482
483 /* Info */
484
485 create_info (canvas, root, "width_info", LEFT, 260);
486 create_info (canvas, root, "shape_a_info", LEFT, 280);
487 create_info (canvas, root, "shape_b_info", LEFT, 300);
488 create_info (canvas, root, "shape_c_info", LEFT, 320);
489
490 /* Division line */
491
492 goo_canvas_polyline_new_line (root, RIGHT + 50, 0, RIGHT + 50, 1000,
493 "fill_color", "black",
494 "line-width", 2.0,
495 NULL);
496
497 /* Sample arrows */
498
499 create_sample_arrow (canvas, root, "sample_1",
500 RIGHT + 100, 30, RIGHT + 100, MIDDLE - 30);
501 create_sample_arrow (canvas, root, "sample_2",
502 RIGHT + 70, MIDDLE, RIGHT + 130, MIDDLE);
503 create_sample_arrow (canvas, root, "sample_3",
504 RIGHT + 70, MIDDLE + 30, RIGHT + 130, MIDDLE + 120);
505
506 /* Done! */
507
508 set_arrow_shape (GOO_CANVAS (canvas));
509 return vbox;
510 }
511