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