1 #include <math.h>
2 #include <stdlib.h>
3 #include <goocanvas.h>
4 
5 #if 1
6 #define N_GROUP_COLS 25
7 #define N_GROUP_ROWS 200
8 #define N_COLS 10
9 #define N_ROWS 10
10 #define ITEM_WIDTH 400
11 #define PADDING 10
12 #if 1
13 #define ROTATE
14 #endif
15 #else
16 /* This tests a very wide canvas, nearly up to the 31-bit GDK window size
17    limit. */
18 #define N_GROUP_COLS 100000
19 #define N_GROUP_ROWS 1
20 #define N_COLS 10
21 #define N_ROWS 1
22 #define ITEM_WIDTH 1000
23 #define PADDING 100
24 #endif
25 
26 #define N_TOTAL_ID_ITEMS (N_GROUP_COLS * N_GROUP_ROWS) * (N_COLS * N_ROWS)
27 
28 /* The maximum length of a string identifying an item (i.e. its coords). */
29 #define MAX_ID_LEN 20
30 
31 #if 1
32 #define SET_STYLE
33 #endif
34 
35 #if 1
36 #define USE_TEXT
37 #endif
38 
39 #if 1
40 #define SET_IDS
41 #endif
42 
43 #if 0
44 #define USE_PIXMAP
45 #endif
46 
47 #if 0
48 #define ONLY_ONE
49 #endif
50 
51 double total_width, total_height;
52 double left_offset, top_offset;
53 char ids[N_TOTAL_ID_ITEMS][MAX_ID_LEN];
54 
55 GdkPixbuf *pixbuf = NULL;
56 cairo_pattern_t *pattern = NULL;
57 double item_width, item_height;
58 double cell_width, cell_height;
59 double group_width, group_height;
60 
61 static clock_t start;
62 
63 static gboolean
on_motion_notify(GooCanvasItem * item,GooCanvasItem * target,GdkEventMotion * event,gpointer data)64 on_motion_notify (GooCanvasItem *item,
65 		  GooCanvasItem *target,
66 		  GdkEventMotion *event,
67 		  gpointer data)
68 {
69   GooCanvasItem *ancestor = target;
70   gchar *id;
71 
72   while (ancestor)
73     {
74       id = g_object_get_data (G_OBJECT (ancestor), "id");
75       if (id)
76 	{
77 	  g_print ("%s item received 'motion-notify' signal\n", id);
78 	  return TRUE;
79 	}
80 
81       ancestor = goo_canvas_item_get_parent (ancestor);
82     }
83 
84   return TRUE;
85 }
86 
87 
88 static void
init_ids(void)89 init_ids (void)
90 {
91   int group_i, group_j, i, j;
92   int id_item_num = 0;;
93 
94   for (group_i = 0; group_i < N_GROUP_COLS; group_i++)
95     {
96       for (group_j = 0; group_j < N_GROUP_ROWS; group_j++)
97 	{
98 	  double group_x = left_offset + (group_i * group_width);
99 	  double group_y = top_offset + (group_j * group_height);
100 
101 	  for (i = 0; i < N_COLS; i++)
102 	    {
103 	      for (j = 0; j < N_ROWS; j++)
104 		{
105 		  double item_x = (i * cell_width) + PADDING;
106 		  double item_y = (j * cell_height) + PADDING;
107 
108 		  sprintf (ids[id_item_num++], "%.10g, %.10g",
109 			   group_x + item_x, group_y + item_y);
110 		}
111 	    }
112 	}
113     }
114 }
115 
116 
117 static void
setup_canvas(GtkWidget * canvas)118 setup_canvas (GtkWidget *canvas)
119 {
120   GooCanvasItemModel *root, *group, *model;
121   GooCanvasItem *item;
122   int group_i, group_j, i, j;
123   int total_items = 0, id_item_num = 0;;
124   GdkColor color = { 0, 0, 0, 0, };
125   GooCanvasStyle *style, *style2;
126   GValue tmpval = { 0 };
127   cairo_matrix_t item_matrix;
128   GQuark id_quark = g_quark_from_static_string ("id");
129 
130   root = goo_canvas_group_model_new (NULL,
131 				     "font", "Sans 8",
132 				     NULL);
133   goo_canvas_set_root_item_model (GOO_CANVAS (canvas), root);
134   g_object_unref (root);
135 
136   item = goo_canvas_get_item (GOO_CANVAS (canvas), root);
137   g_signal_connect (item, "motion_notify_event",
138 		    G_CALLBACK (on_motion_notify), NULL);
139 
140   style = goo_canvas_style_new ();
141   gdk_color_parse ("mediumseagreen", &color);
142   pattern = cairo_pattern_create_rgb (color.red / 65535.0,
143 				      color.green / 65535.0,
144 				      color.blue / 65535.0);
145   g_value_init (&tmpval, GOO_TYPE_CAIRO_PATTERN);
146   g_value_take_boxed (&tmpval, pattern);
147   goo_canvas_style_set_property (style, goo_canvas_style_fill_pattern_id, &tmpval);
148   g_value_unset (&tmpval);
149 
150   style2 = goo_canvas_style_new ();
151   gdk_color_parse ("steelblue", &color);
152   pattern = cairo_pattern_create_rgb (color.red / 65535.0,
153 				      color.green / 65535.0,
154 				      color.blue / 65535.0);
155   g_value_init (&tmpval, GOO_TYPE_CAIRO_PATTERN);
156   g_value_take_boxed (&tmpval, pattern);
157   goo_canvas_style_set_property (style2, goo_canvas_style_fill_pattern_id, &tmpval);
158   g_value_unset (&tmpval);
159 
160   for (group_i = 0; group_i < N_GROUP_COLS; group_i++)
161     {
162       for (group_j = 0; group_j < N_GROUP_ROWS; group_j++)
163 	{
164 	  double group_x = left_offset + (group_i * group_width);
165 	  double group_y = top_offset + (group_j * group_height);
166 
167 	  group = goo_canvas_group_model_new (root, NULL);
168 	  total_items++;
169 	  goo_canvas_item_model_translate (group, group_x, group_y);
170 
171 	  for (i = 0; i < N_COLS; i++)
172 	    {
173 	      for (j = 0; j < N_ROWS; j++)
174 		{
175 		  double item_x = (i * cell_width) + PADDING;
176 		  double item_y = (j * cell_height) + PADDING;
177 #ifdef ROTATE
178 		  double rotation = (i % 10 * 2) * M_PI / 180;
179 		  double rotation_x = item_x + item_width / 2;
180 		  double rotation_y = item_y + item_height / 2;
181 #endif
182 
183 #ifdef USE_PIXMAP
184 		  model = goo_canvas_image_model_new (group, NULL,
185 						      item_x, item_y,
186 						      "pattern", pattern,
187 						      "width", item_width,
188 						      "height", item_height,
189 						      NULL);
190 #else
191 		  model = goo_canvas_rect_model_new (group, item_x, item_y,
192 						     item_width, item_height,
193 						     NULL);
194 #ifdef SET_STYLE
195 		  goo_canvas_item_model_set_style (model, (j % 2) ? style : style2);
196 #endif
197 #ifdef ROTATE
198 		  cairo_matrix_init_identity (&item_matrix);
199 		  cairo_matrix_translate (&item_matrix, rotation_x, rotation_y);
200 		  cairo_matrix_rotate (&item_matrix, rotation);
201 		  cairo_matrix_translate (&item_matrix, -rotation_x, -rotation_y);
202 		  goo_canvas_item_model_set_transform (model, &item_matrix);
203 #endif
204 #endif
205 #ifdef SET_IDS
206 		  item = goo_canvas_get_item (GOO_CANVAS (canvas), model);
207 		  g_object_set_qdata (G_OBJECT (item), id_quark,
208 				      ids[id_item_num]);
209 #endif
210 #if 0
211 		  g_signal_connect (item, "motion_notify_event",
212 				    G_CALLBACK (on_motion_notify), NULL);
213 #endif
214 
215 #ifdef USE_TEXT
216 		  model = goo_canvas_text_model_new (group, ids[id_item_num],
217 						     item_x + item_width / 2,
218 						     item_y + item_height / 2,
219 						     item_width, GTK_ANCHOR_CENTER,
220 						     "height", item_height,
221 						     /*"alignment", PANGO_ALIGN_CENTER,*/
222 						     NULL);
223 		  /* FIXME: This is slightly naughty, but much faster. */
224 		  GOO_CANVAS_TEXT_MODEL (model)->text_data.alignment = PANGO_ALIGN_CENTER;
225 #else
226 		  model = goo_canvas_rect_model_new (group,
227 						     item_x + 20,
228 						     item_y + 4,
229 						     item_width - 40,
230 						     item_height - 8,
231 						     NULL);
232 #endif
233 
234 #ifdef ROTATE
235 		  goo_canvas_item_model_set_transform (model, &item_matrix);
236 #endif
237 		  id_item_num++;
238 		  total_items += 2;
239 
240 #ifdef ONLY_ONE
241 		  break;
242 #endif
243 		}
244 #ifdef ONLY_ONE
245 	      break;
246 #endif
247 	    }
248 #ifdef ONLY_ONE
249 	  break;
250 #endif
251 	}
252 #ifdef ONLY_ONE
253       break;
254 #endif
255     }
256 
257   if (pattern)
258     cairo_pattern_destroy (pattern);
259 
260   g_print ("Total items: %i\n", total_items);
261 
262 }
263 
264 
265 static gboolean
on_expose_event(GtkWidget * canvas,GdkEvent * event,gpointer unused_data)266 on_expose_event (GtkWidget *canvas,
267 		 GdkEvent  *event,
268 		 gpointer   unused_data)
269 {
270   static gboolean first_time = TRUE;
271 
272   if (first_time)
273     {
274       printf ("Update Canvas Time Used: %g\n",
275 	      (double) (clock() - start) / CLOCKS_PER_SEC);
276       first_time = FALSE;
277     }
278 
279   return FALSE;
280 }
281 
282 
283 GtkWidget *
create_canvas(void)284 create_canvas (void)
285 {
286   GtkWidget *canvas;
287 
288 #ifdef USE_PIXMAP
289   pixbuf = gdk_pixbuf_new_from_file("toroid.png", NULL);
290   item_width = gdk_pixbuf_get_width (pixbuf);
291   item_height = gdk_pixbuf_get_height (pixbuf);
292   pattern = goo_canvas_cairo_pattern_from_pixbuf (pixbuf);
293 #else
294   pixbuf = NULL;
295   item_width = ITEM_WIDTH;
296   item_height = 19;
297 #endif
298 
299   cell_width = item_width + PADDING * 2;
300   cell_height = item_height + PADDING * 2;
301 
302   group_width = N_COLS * cell_width;
303   group_height = N_ROWS * cell_height;
304 
305   total_width = N_GROUP_COLS * group_width;
306   total_height = N_GROUP_ROWS * group_height;
307 
308   /* We use -ve offsets to test if -ve coords are handled correctly. */
309   left_offset = -total_width / 2;
310   top_offset = -total_height / 2;
311 
312 #ifdef SET_IDS
313   init_ids ();
314 #endif
315 
316   /* Create the canvas. */
317   canvas = goo_canvas_new ();
318   gtk_widget_set_size_request (canvas, 600, 450);
319 
320   start = clock();
321   setup_canvas (canvas);
322   printf ("Create Canvas Time Used: %g\n",
323 	  (double) (clock() - start) / CLOCKS_PER_SEC);
324 
325   start = clock();
326   goo_canvas_set_bounds (GOO_CANVAS (canvas), left_offset, top_offset,
327 			 left_offset + total_width, top_offset + total_height);
328   gtk_widget_show (canvas);
329 
330   g_signal_connect (canvas, "expose_event",
331 		    G_CALLBACK (on_expose_event), NULL);
332 
333   return canvas;
334 }
335 
336 
337 static gboolean
on_delete_event(GtkWidget * window,GdkEvent * event,gpointer unused_data)338 on_delete_event (GtkWidget *window,
339 		 GdkEvent  *event,
340 		 gpointer   unused_data)
341 {
342   gtk_main_quit ();
343   return FALSE;
344 }
345 
346 
347 int
main(int argc,char * argv[])348 main (int argc, char *argv[])
349 {
350   GtkWidget *window, *scrolled_win, *canvas;
351 
352   gtk_set_locale ();
353   gtk_init (&argc, &argv);
354 
355   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
356   gtk_window_set_default_size (GTK_WINDOW (window), 640, 600);
357   gtk_widget_show (window);
358   g_signal_connect (window, "delete_event", G_CALLBACK (on_delete_event),
359 		    NULL);
360 
361   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
362   gtk_widget_show (scrolled_win);
363   gtk_container_add (GTK_CONTAINER (window), scrolled_win);
364 
365   canvas = create_canvas ();
366 
367 #if 0
368   exit (0);
369 #endif
370 
371   gtk_container_add (GTK_CONTAINER (scrolled_win), canvas);
372 
373   gtk_main ();
374 
375   return 0;
376 }
377 
378 
379