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