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