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