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