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,GtkAnchorType anchor)206 create_dimension (GtkWidget *canvas,
207 GooCanvasItemModel *root,
208 char *arrow_name,
209 char *text_name,
210 GtkAnchorType 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, GTK_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 GdkCursor *fleur;
303
304 fleur = gdk_cursor_new (GDK_FLEUR);
305 canvas = goo_canvas_item_get_canvas (item);
306 goo_canvas_pointer_grab (canvas, item,
307 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_RELEASE_MASK,
308 fleur,
309 event->time);
310 gdk_cursor_unref (fleur);
311
312 return TRUE;
313 }
314
315
316 static gboolean
on_button_release(GooCanvasItem * item,GooCanvasItem * target,GdkEventButton * event,gpointer data)317 on_button_release (GooCanvasItem *item,
318 GooCanvasItem *target,
319 GdkEventButton *event,
320 gpointer data)
321 {
322 GooCanvas *canvas;
323
324 canvas = goo_canvas_item_get_canvas (item);
325 goo_canvas_pointer_ungrab (canvas, item, event->time);
326
327 return TRUE;
328 }
329
330
331 static gboolean
on_motion(GooCanvasItem * item,GooCanvasItem * target,GdkEventMotion * event,gpointer data)332 on_motion (GooCanvasItem *item,
333 GooCanvasItem *target,
334 GdkEventMotion *event,
335 gpointer data)
336 {
337 GooCanvas *canvas = goo_canvas_item_get_canvas (item);
338 GooCanvasItemModel *model = goo_canvas_item_get_model (target);
339 int x, y, width, shape_a, shape_b, shape_c;
340 gboolean change = FALSE;
341
342 if (!(event->state & GDK_BUTTON1_MASK))
343 return FALSE;
344
345 if (model == g_object_get_data (G_OBJECT (canvas), "width_drag_box"))
346 {
347 y = event->y;
348 width = (MIDDLE - y) / 5;
349 if (width < 0)
350 return FALSE;
351 g_object_set_data (G_OBJECT (canvas), "width", GINT_TO_POINTER (width));
352 set_arrow_shape (canvas);
353 }
354 else if (model == g_object_get_data (G_OBJECT (canvas), "shape_a_drag_box"))
355 {
356 x = event->x;
357 width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (canvas), "width"));
358 shape_a = (RIGHT - x) / 10 / width;
359 if ((shape_a < 0) || (shape_a > 30))
360 return FALSE;
361 g_object_set_data (G_OBJECT (canvas), "shape_a",
362 GINT_TO_POINTER (shape_a));
363 set_arrow_shape (canvas);
364 }
365 else if (model == g_object_get_data (G_OBJECT (canvas), "shape_b_c_drag_box"))
366 {
367 width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (canvas), "width"));
368
369 x = event->x;
370 shape_b = (RIGHT - x) / 10 / width;
371 if ((shape_b >= 0) && (shape_b <= 30)) {
372 g_object_set_data (G_OBJECT (canvas), "shape_b",
373 GINT_TO_POINTER (shape_b));
374 change = TRUE;
375 }
376
377 y = event->y;
378 shape_c = (MIDDLE - y) * 2 / 10 / width;
379 if (shape_c >= 0) {
380 g_object_set_data (G_OBJECT (canvas), "shape_c",
381 GINT_TO_POINTER (shape_c));
382 change = TRUE;
383 }
384
385 if (change)
386 set_arrow_shape (canvas);
387 }
388
389 return TRUE;
390 }
391
392
393 static void
on_item_created(GooCanvas * canvas,GooCanvasItem * item,GooCanvasItemModel * model,gpointer data)394 on_item_created (GooCanvas *canvas,
395 GooCanvasItem *item,
396 GooCanvasItemModel *model,
397 gpointer data)
398 {
399 if (GOO_IS_CANVAS_RECT_MODEL (model))
400 {
401 g_signal_connect (item, "enter_notify_event",
402 G_CALLBACK (on_enter_notify),
403 NULL);
404 g_signal_connect (item, "leave_notify_event",
405 G_CALLBACK (on_leave_notify),
406 NULL);
407 g_signal_connect (item, "button_press_event",
408 G_CALLBACK (on_button_press),
409 NULL);
410 g_signal_connect (item, "button_release_event",
411 G_CALLBACK (on_button_release),
412 NULL);
413 g_signal_connect (item, "motion_notify_event",
414 G_CALLBACK (on_motion),
415 NULL);
416 }
417 }
418
419
420 GtkWidget *
create_canvas_arrowhead(void)421 create_canvas_arrowhead (void)
422 {
423 GtkWidget *vbox;
424 GtkWidget *w;
425 GtkWidget *frame;
426 GtkWidget *canvas;
427 GooCanvasItemModel *root, *item;
428
429 vbox = gtk_vbox_new (FALSE, 4);
430 gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
431 gtk_widget_show (vbox);
432
433 w = gtk_label_new ("This demo allows you to edit arrowhead shapes. Drag the little boxes\n"
434 "to change the shape of the line and its arrowhead. You can see the\n"
435 "arrows at their normal scale on the right hand side of the window.");
436 gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0);
437 gtk_widget_show (w);
438
439 w = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
440 gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0);
441 gtk_widget_show (w);
442
443 frame = gtk_frame_new (NULL);
444 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
445 gtk_container_add (GTK_CONTAINER (w), frame);
446 gtk_widget_show (frame);
447
448 canvas = goo_canvas_new ();
449
450 g_signal_connect (canvas, "item_created",
451 G_CALLBACK (on_item_created), NULL);
452
453 root = goo_canvas_group_model_new (NULL, NULL);
454 goo_canvas_set_root_item_model (GOO_CANVAS (canvas), root);
455 g_object_unref (root);
456
457 gtk_widget_set_size_request (canvas, 500, 350);
458 goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 500, 350);
459 gtk_container_add (GTK_CONTAINER (frame), canvas);
460 gtk_widget_show (canvas);
461
462
463 g_object_set_data (G_OBJECT (canvas), "width",
464 GINT_TO_POINTER (DEFAULT_WIDTH));
465 g_object_set_data (G_OBJECT (canvas), "shape_a",
466 GINT_TO_POINTER (DEFAULT_SHAPE_A));
467 g_object_set_data (G_OBJECT (canvas), "shape_b",
468 GINT_TO_POINTER (DEFAULT_SHAPE_B));
469 g_object_set_data (G_OBJECT (canvas), "shape_c",
470 GINT_TO_POINTER (DEFAULT_SHAPE_C));
471
472 /* Big arrow */
473
474 item = goo_canvas_polyline_model_new_line (root,
475 LEFT, MIDDLE, RIGHT, MIDDLE,
476 "stroke_color", "mediumseagreen",
477 "end-arrow", TRUE,
478 NULL);
479 g_object_set_data (G_OBJECT (canvas), "big_arrow", item);
480
481 /* Arrow outline */
482
483 item = goo_canvas_polyline_model_new (root, TRUE, 0,
484 "stroke_color", "black",
485 "line-width", 2.0,
486 "line-cap", CAIRO_LINE_CAP_ROUND,
487 "line-join", CAIRO_LINE_JOIN_ROUND,
488 NULL);
489 g_object_set_data (G_OBJECT (canvas), "outline", item);
490
491 /* Drag boxes */
492
493 create_drag_box (canvas, root, "width_drag_box");
494 create_drag_box (canvas, root, "shape_a_drag_box");
495 create_drag_box (canvas, root, "shape_b_c_drag_box");
496
497 /* Dimensions */
498
499 create_dimension (canvas, root, "width_arrow", "width_text", GTK_ANCHOR_E);
500 create_dimension (canvas, root, "shape_a_arrow", "shape_a_text", GTK_ANCHOR_N);
501 create_dimension (canvas, root, "shape_b_arrow", "shape_b_text", GTK_ANCHOR_N);
502 create_dimension (canvas, root, "shape_c_arrow", "shape_c_text", GTK_ANCHOR_W);
503
504 /* Info */
505
506 create_info (canvas, root, "width_info", LEFT, 260);
507 create_info (canvas, root, "shape_a_info", LEFT, 280);
508 create_info (canvas, root, "shape_b_info", LEFT, 300);
509 create_info (canvas, root, "shape_c_info", LEFT, 320);
510
511 /* Division line */
512
513 goo_canvas_polyline_model_new_line (root, RIGHT + 50, 0, RIGHT + 50, 1000,
514 "fill_color", "black",
515 "line-width", 2.0,
516 NULL);
517
518 /* Sample arrows */
519
520 create_sample_arrow (canvas, root, "sample_1",
521 RIGHT + 100, 30, RIGHT + 100, MIDDLE - 30);
522 create_sample_arrow (canvas, root, "sample_2",
523 RIGHT + 70, MIDDLE, RIGHT + 130, MIDDLE);
524 create_sample_arrow (canvas, root, "sample_3",
525 RIGHT + 70, MIDDLE + 30, RIGHT + 130, MIDDLE + 120);
526
527 /* Done! */
528
529 set_arrow_shape (GOO_CANVAS (canvas));
530 return vbox;
531 }
532