comparison src/event.c @ 235:65cabbdd5284

termporary revision
author Thinker K.F. Li <thinker@branda.to>
date Thu, 25 Dec 2008 18:40:27 +0800
parents 527894c2ad39
children 104d83378582
comparison
equal deleted inserted replaced
234:889cdc5f23c5 235:65cabbdd5284
1 /*! \file 1 /*! \file
2 * \brief Convenience functions for event relative work. 2 * \brief Convenience functions for event relative work.
3 */ 3 */
4 #include <stdio.h> 4 #include <stdio.h>
5 #include <stdlib.h> 5 #include <stdlib.h>
6 #ifndef UNITTEST
6 #include <cairo.h> 7 #include <cairo.h>
7 #include "mb_types.h" 8 #include "mb_types.h"
8 #include "mb_redraw_man.h" 9 #include "mb_redraw_man.h"
9 #include "mb_shapes.h" 10 #include "mb_shapes.h"
11 #endif
10 12
11 #define OK 0 13 #define OK 0
12 #define ERR -1 14 #define ERR -1
13 #define FALSE 0 15 #define FALSE 0
14 #define TRUE 1 16 #define TRUE 1
15 17
16 #define ARRAY_EXT_SZ 64 18 #define ARRAY_EXT_SZ 64
17 19
18 20 #define ASSERT(x)
19 DARRAY_DEFINE(geos, geo_t *); 21
20 22 #ifdef UNITTEST
21 /*! \brief Add a geo_t object to general geo list. 23 /* ============================================================ */
22 * 24
23 * General geo list can use to temporary keep a list of geo_t 25 typedef struct shape shape_t;
24 * objects for any purpose. It supposed to be reused by 26
25 * different modules that need to select part of geo_t objects 27 typedef struct cairo cairo_t;
26 * from a redraw manager. 28 struct cairo {
27 */ 29 shape_t *drawed;
28 static int _add_gen_geo(redraw_man_t *rdman, geo_t *geo) { 30 };
29 int r; 31 #define cairo_in_fill(cr, x, y) 0
30 32 #define cairo_in_stroke(cr, x, y) 0
31 r = geos_add(&rdman->gen_geos, geo); 33 #define cairo_new_path(cr)
32 return r == 0? OK: ERR; 34 #define cairo_get_target(cr) NULL
33 } 35 #define cairo_create(target) NULL
34 36 #define cairo_destroy(cr)
35 static int _collect_geos_at_point(redraw_man_t *rdman, 37 #define cairo_clip(cr)
38 #define cairo_fill(cr)
39 #define cairo_image_surface_get_data(cr) NULL
40 #define cairo_image_surface_get_stride(cr) 1
41
42 struct cairo_surface {
43 };
44 typedef struct cairo_surface cairo_surface_t;
45 #define cairo_image_surface_get_width(surface) 0
46 #define cairo_image_surface_get_height(surface) 0
47 #define cairo_image_surface_create(surface, w, h) NULL
48 #define cairo_surface_destroy(surface)
49
50
51 typedef float co_aix;
52
53 typedef struct _area area_t;
54 struct _area {
55 co_aix x, y;
56 co_aix w, h;
57 };
58
59 struct mb_obj {
60 int obj_type;
61 };
62 typedef struct mb_obj mb_obj_t;
63
64 #define GEF_OV_DRAW 0x1
65 #define GEF_HIDDEN 0x2
66
67 struct shape {
68 mb_obj_t obj;
69
70 void *fill, *stroke;
71 struct shape *sibling;
72 int flags;
73
74 int num_points;
75 co_aix points[32][2];
76 };
77 enum { MBO_DUMMY,
78 MBO_COORD,
79 MBO_SHAPES=0x1000,
80 MBO_PATH,
81 MBO_TEXT,
82 MBO_RECT
83 };
84 #define MBO_TYPE(x) (((mb_obj_t *)(x))->obj_type)
85 #define IS_MBO_SHAPES(x) (((mb_obj_t *)(x))->obj_type & MBO_SHAPES)
86 #define sh_get_geo(x) ((x)->geo)
87 static int sh_pos_is_in(shape_t *shape, co_aix x, co_aix y) {
88 int i;
89
90 for(i = 0; i < shape->num_points; i++)
91 if(shape->points[i][0] == x && shape->points[i][1] == y)
92 return TRUE;
93 return FALSE;
94 }
95 #define sh_get_flags(shape, mask) ((shape)->flags & mask)
96 #define sh_set_flags(shape, mask) do { (shape)->flags |= mask; } while(0)
97 #define sh_clear_flags(shape, mask) do { (shape)->flags &= ~(mask); } while(0)
98
99 typedef struct coord coord_t;
100 struct coord {
101 mb_obj_t obj;
102
103 coord_t *children;
104 coord_t *sibling;
105 shape_t *shapes;
106 };
107
108
109 static
110 coord_t *postorder_coord_subtree(coord_t *root, coord_t *last) {
111 if(last == NULL)
112 return root;
113 }
114
115 #define sh_path_draw(path, cr)
116 #define sh_text_draw(path, cr)
117 #define sh_rect_draw(path, cr)
118
119
120 struct redraw_man {
121 cairo_t *cr;
122 int shape_gl_sz;
123 shape_t *shape_gl[32];
124 };
125 typedef struct redraw_man redraw_man_t;
126 #define rdman_get_cr(rdman) ((rdman)->cr)
127 #define rdman_get_gen_geos(rdman) (&(rdman)->gen_geos)
128 #define rdman_force_clean(rdman) OK
129 #define rdman_geos(rdman, geo) NULL
130 #define rdman_clear_shape_gl(rdman) \
131 do {(rdman)->shape_gl_sz = 0; } while(0)
132 static int rdman_add_shape_gl(redraw_man_t *rdman, shape_t *shape) {
133 (rdman)->shape_gl[(rdman)->shape_gl_sz++] = shape;
134 return OK;
135 }
136 #define rdman_get_shape_gl(rdman, idx) \
137 (rdman)->shape_gl[idx]
138 #define rdman_shape_gl_len(rdman) (rdman)->shape_gl_sz
139 static shape_t *rdman_shapes(redraw_man_t *rdman, shape_t *last_shape);
140
141
142 /* ============================================================ */
143 #endif /* UNITTEST */
144
145
146 static int _collect_shapes_at_point(redraw_man_t *rdman,
36 co_aix x, co_aix y) { 147 co_aix x, co_aix y) {
37 geo_t *geo; 148 shape_t *shape;
38 int r; 149 int r;
39 150
40 r = rdman_force_clean(rdman); 151 r = rdman_force_clean(rdman);
41 if(r != OK) 152 if(r != OK)
42 return ERR; 153 return ERR;
43 154
44 rdman->gen_geos.num = 0; 155 rdman_clear_shape_gl(rdman);
45 156
46 for(geo = rdman_geos(rdman, NULL); 157 for(shape = rdman_shapes(rdman, (shape_t *)NULL);
47 geo != NULL; 158 shape != NULL;
48 geo = rdman_geos(rdman, geo)) { 159 shape = rdman_shapes(rdman, shape)) {
49 if(geo_pos_is_in(geo, x, y)) { 160 if(sh_pos_is_in(shape, x, y)) {
50 r = _add_gen_geo(rdman, geo); 161 r = rdman_add_shape_gl(rdman, shape);
51 if(r != OK) 162 if(r != 0)
52 return ERR; 163 return ERR;
53 } 164 }
54 } 165 }
55 166
56 return OK; 167 return OK;
86 } 197 }
87 } 198 }
88 return FALSE; 199 return FALSE;
89 } 200 }
90 201
91 static geo_t *find_geo_in_pos(redraw_man_t *rdman, 202 static
92 co_aix x, co_aix y, int *in_stroke) { 203 int _shape_pos_is_in(shape_t *shape, co_aix x, co_aix y,
93 geo_t *geo; 204 int *in_stroke, cairo_t *cr) {
94 geo_t **geos; 205 int r;
206
207 r = sh_pos_is_in(shape, x, y);
208 if(!r)
209 return FALSE;
210
211 r = _shape_pos_is_in_cairo(shape, x, y, in_stroke, cr);
212 cairo_new_path(cr);
213 if(!r)
214 return FALSE;
215
216 return TRUE;
217 }
218
219 static shape_t *_find_shape_in_pos(redraw_man_t *rdman,
220 co_aix x, co_aix y, int *in_stroke) {
95 shape_t *shape; 221 shape_t *shape;
96 cairo_t *cr; 222 cairo_t *cr;
97 int i, r; 223 int i, r;
98 224
99 geos = rdman->gen_geos.ds; 225 cr = rdman_get_cr(rdman);
100 cr = rdman->cr; 226 for(i = rdman_shape_gl_len(rdman) - 1; i >= 0; i--) {
101 for(i = rdman->gen_geos.num - 1; i >= 0; i--) { 227 shape = rdman_get_shape_gl(rdman, i);
102 geo = geos[i]; 228 if(sh_get_flags(shape, GEF_HIDDEN))
103 if(geo->flags & GEF_HIDDEN)
104 continue; 229 continue;
105 shape = geo_get_shape(geo);
106 r = _shape_pos_is_in_cairo(shape, x, y, in_stroke, cr); 230 r = _shape_pos_is_in_cairo(shape, x, y, in_stroke, cr);
107 cairo_new_path(cr);
108 if(r) 231 if(r)
109 return geo; 232 return shape;
110 } 233 }
111 234
112 return NULL; 235 return NULL;
113 } 236 }
114 237
115 shape_t *find_shape_at_pos(redraw_man_t *rdman, 238 shape_t *find_shape_at_pos(redraw_man_t *rdman,
116 co_aix x, co_aix y, int *in_stroke) { 239 co_aix x, co_aix y, int *in_stroke) {
117 geo_t *geo; 240 shape_t *shape;
118 int r; 241 int r;
119 242
120 r = _collect_geos_at_point(rdman, x, y); 243 r = _collect_shapes_at_point(rdman, x, y);
121 if(r != OK) 244 if(r != OK)
122 return NULL; 245 return NULL;
123 246
124 geo = find_geo_in_pos(rdman, x, y, in_stroke); 247 shape = _find_shape_in_pos(rdman, x, y, in_stroke);
125 if(geo == NULL) 248 return shape;
126 return NULL;
127
128 return geo_get_shape(geo);
129 }
130
131 static
132 int _shape_pos_is_in(redraw_man_t *rdman, shape_t *shape,
133 co_aix x, co_aix y, int *in_stroke) {
134 geo_t *geo;
135 int r;
136
137 geo = sh_get_geo(shape);
138 r = geo_pos_is_in(geo, x, y);
139 if(!r)
140 return FALSE;
141
142 r = _shape_pos_is_in_cairo(shape, x, y, in_stroke, rdman->cr);
143 if(!r)
144 return FALSE;
145
146 return TRUE;
147 } 249 }
148 250
149 /*! \brief Test if an object and descendants cover the position 251 /*! \brief Test if an object and descendants cover the position
150 * specified by x,y. 252 * specified by x,y.
151 * 253 *
153 */ 255 */
154 int mb_obj_pos_is_in(redraw_man_t *rdman, mb_obj_t *obj, 256 int mb_obj_pos_is_in(redraw_man_t *rdman, mb_obj_t *obj,
155 co_aix x, co_aix y, int *in_stroke) { 257 co_aix x, co_aix y, int *in_stroke) {
156 coord_t *cur_coord, *root; 258 coord_t *cur_coord, *root;
157 shape_t *shape; 259 shape_t *shape;
158 geo_t *geo;
159 int r; 260 int r;
160 261
161 if(IS_MBO_SHAPES(obj)) { 262 if(IS_MBO_SHAPES(obj)) {
162 shape = (shape_t *)obj; 263 shape = (shape_t *)obj;
163 r = _shape_pos_is_in_cairo(shape, x, y, in_stroke, rdman->cr); 264 r = _shape_pos_is_in(shape, x, y, in_stroke, rdman_get_cr(rdman));
164 return r; 265 return r;
165 } 266 }
166 root = (coord_t *)obj; 267 root = (coord_t *)obj;
167 for(cur_coord = postorder_coord_subtree(root, NULL); 268 for(cur_coord = postorder_coord_subtree(root, NULL);
168 cur_coord != NULL; 269 cur_coord != NULL;
169 cur_coord = postorder_coord_subtree(root, cur_coord)) { 270 cur_coord = postorder_coord_subtree(root, cur_coord)) {
170 FOR_COORD_MEMBERS(cur_coord, geo) { 271 FOR_COORD_SHAPES(cur_coord, shape) {
171 shape = geo_get_shape(geo); 272 r = _shape_pos_is_in(shape, x, y, in_stroke, rdman_get_cr(rdman));
172 r = _shape_pos_is_in_cairo(shape, x, y, in_stroke, rdman->cr);
173 if(r) 273 if(r)
174 return TRUE; 274 return TRUE;
175 } 275 }
176 } 276 }
177 return FALSE; 277 return FALSE;
181 cairo_t * _prepare_cairo_for_testing(redraw_man_t *rdman) { 281 cairo_t * _prepare_cairo_for_testing(redraw_man_t *rdman) {
182 cairo_surface_t *surface, *rdman_surface; 282 cairo_surface_t *surface, *rdman_surface;
183 cairo_t *cr; 283 cairo_t *cr;
184 int w, h; 284 int w, h;
185 285
186 rdman_surface = cairo_get_target(rdman->cr); 286 rdman_surface = cairo_get_target(rdman_get_cr(rdman));
187 w = cairo_image_surface_get_width(rdman_surface); 287 w = cairo_image_surface_get_width(rdman_surface);
188 h = cairo_image_surface_get_height(rdman_surface); 288 h = cairo_image_surface_get_height(rdman_surface);
189 289
190 surface = cairo_image_surface_create(CAIRO_FORMAT_A1, w, h); 290 surface = cairo_image_surface_create(CAIRO_FORMAT_A1, w, h);
191 if(surface == NULL) 291 if(surface == NULL)
201 static 301 static
202 void _release_cairo_for_testing(cairo_t *cr) { 302 void _release_cairo_for_testing(cairo_t *cr) {
203 cairo_destroy(cr); 303 cairo_destroy(cr);
204 } 304 }
205 305
206 static _draw_to_mask(shape_t *shape, cairo_t *cr) { 306 static
207 geo_t *geo; 307 void _draw_to_mask(shape_t *shape, cairo_t *cr) {
208 308 if(sh_get_flags(shape, GEF_OV_DRAW))
209 geo = sh_get_geo(shape);
210 if(geo->flags & GEF_OV_DRAW)
211 return; 309 return;
212 310
213 draw_shape_path(shape, cr); 311 draw_shape_path(shape, cr);
214 cairo_clip(cr); 312 cairo_clip(cr);
215 313
216 geo->flags |= GEF_OV_DRAW; 314 sh_set_flags(shape, GEF_OV_DRAW);
217 } 315 }
218 316
219 static 317 static
220 int _fill_and_check(shape_t *shape, cairo_t *cr) { 318 int _fill_and_check(shape_t *shape, cairo_t *cr) {
221 int h, stride; 319 int h, stride;
239 } 337 }
240 338
241 return FALSE; 339 return FALSE;
242 } 340 }
243 341
244 /*! \brief Is a mb_obj_t overlaid with another mb_object_t and 342 /*! \brief Is a mb_obj_t overlaid with another mb_obj_t and
245 * descendants. 343 * descendants.
246 * 344 *
247 * coord is relative less than shapes. Check areas of coord can 345 * coord is relative less than shapes. Check areas of coord can
248 * havily avoid useless computation. For shapes, it not only check 346 * skip sub-trees and avoid useless heavy computation. For shapes,
249 * overlay of area. It also check overlay by actually drawing on a 347 * it not only check overlay of area. It also check overlay by
250 * cairo surface. 348 * actually drawing on a cairo surface.
251 */ 349 */
252 static 350 static
253 int _is_obj_objs_overlay(mb_obj_t *obj, mb_obj_t *others_root, 351 int _is_obj_objs_overlay(mb_obj_t *obj, mb_obj_t *others_root,
254 cairo_t *cr) { 352 cairo_t *cr) {
255 area_t *area, *candi_area; 353 area_t *area, *candi_area;
256 coord_t *coord, *candi_coord, *root; 354 coord_t *coord, *candi_coord, *root;
257 shape_t *shape, *candi_shape; 355 shape_t *shape, *candi_shape;
258 geo_t *geo, *candi_geo;
259 int obj_is_shape; 356 int obj_is_shape;
260 int r; 357 int r;
261 /*
262 */
263 358
264 obj_is_shape = IS_MBO_SHAPES(obj); 359 obj_is_shape = IS_MBO_SHAPES(obj);
265 360
266 if(obj_is_shape) { 361 if(obj_is_shape) {
267 shape = (shape_t *)obj; 362 shape = (shape_t *)obj;
268 geo = sh_get_geo(shape); 363 area = sh_get_area(shape);
269 area = geo_get_area(geo);
270 } else { 364 } else {
271 coord = (coord_t *)obj; 365 coord = (coord_t *)obj;
272 area = coord_get_area(coord); 366 area = coord_get_area(coord);
273 } 367 }
274 368
275 if(IS_MBO_SHAPES(others_root)) { 369 if(IS_MBO_SHAPES(others_root)) {
276 candi_shape = (shape_t *)others_root; 370 candi_shape = (shape_t *)others_root;
277 candi_geo = sh_get_geo(candi_shape); 371 candi_area = sh_get_area(candi_shape);
278 candi_area = geo_get_area(candi_geo);
279 372
280 r = is_overlay(area, candi_area); 373 r = areas_are_overlay(area, candi_area);
281 if(!r) 374 if(!r)
282 return FALSE; 375 return FALSE;
283 376
284 if(!obj_is_shape) 377 if(!obj_is_shape)
285 return TRUE; 378 return TRUE;
288 r = _fill_and_check(shape, cr); 381 r = _fill_and_check(shape, cr);
289 382
290 return r; 383 return r;
291 } 384 }
292 385
386 ASSERT(IS_MBO_COORD(others_root));
387
293 root = (coord_t *)others_root; 388 root = (coord_t *)others_root;
294 FOR_COORDS_PREORDER(root, candi_coord) { 389 FOR_COORDS_PREORDER(root, candi_coord) {
295 candi_area = coord_get_area(candi_coord); 390 candi_area = coord_get_area(candi_coord);
296 r = is_overlay(area, candi_area); 391 r = areas_are_overlay(area, candi_area);
297 if(!r) { 392 if(!r) {
298 preorder_coord_skip_subtree(coord); 393 preorder_coord_skip_subtree(candi_coord);
299 continue; 394 continue;
300 } 395 }
301 396
302 FOR_COORD_MEMBERS(coord, candi_geo) { 397 FOR_COORD_SHAPES(candi_coord, candi_shape) {
303 candi_area = geo_get_area(candi_geo); 398 candi_area = sh_get_area(candi_shape);
304 r = is_overlay(area, candi_area); 399 r = areas_are_overlay(area, candi_area);
305 if(!r) 400 if(!r)
306 continue; 401 continue;
307 402
308 if(!obj_is_shape) 403 if(!obj_is_shape)
309 return TRUE; 404 return TRUE;
316 } 411 }
317 412
318 return FALSE; 413 return FALSE;
319 } 414 }
320 415
416 static
417 void _clear_ov_draw(mb_obj_t *obj) {
418 coord_t *coord, *root;
419 shape_t *shape;
420
421 if(IS_MBO_SHAPES(obj)) {
422 shape = (shape_t *)obj;
423 sh_clear_flags(shape, GEF_OV_DRAW);
424 return;
425 }
426
427 root = (coord_t *)obj;
428 FOR_COORDS_PREORDER(root, coord) {
429 FOR_COORD_SHAPES(coord, shape) {
430 sh_clear_flags(shape, GEF_OV_DRAW);
431 }
432 }
433 }
434
321 /*! \brief Test if two objects are overlaid. 435 /*! \brief Test if two objects are overlaid.
322 * 436 *
323 * \todo Detect overlay in better way with cairo. 437 * \todo Detect overlay in better way with cairo.
324 * \note This function cost heavy on CPU power. 438 * \note This function cost heavy on CPU power.
325 */ 439 */
326 int mb_objs_is_overlay(redraw_man_t *rdman, 440 int mb_objs_are_overlay(redraw_man_t *rdman,
327 mb_obj_t *obj1, mb_obj_t *obj2) { 441 mb_obj_t *obj1, mb_obj_t *obj2) {
328 cairo_t *cr; 442 cairo_t *cr;
329 area_t *area; 443 area_t *area;
330 shape_t *shape; 444 shape_t *shape;
331 geo_t *geo;
332 coord_t *coord, *root; 445 coord_t *coord, *root;
333 int r; 446 int r;
334 447
335 cr = _prepare_cairo_for_testing(rdman); 448 cr = _prepare_cairo_for_testing(rdman);
336 449
347 if(!r) { 460 if(!r) {
348 preorder_coord_skip_subtree(coord); 461 preorder_coord_skip_subtree(coord);
349 continue; 462 continue;
350 } 463 }
351 464
352 FOR_COORD_MEMBERS(coord, geo) { 465 FOR_COORD_SHAPES(coord, shape) {
353 shape = geo_get_shape(geo);
354 r = _is_obj_objs_overlay((mb_obj_t *)shape, obj2, cr); 466 r = _is_obj_objs_overlay((mb_obj_t *)shape, obj2, cr);
355 if(r) 467 if(r)
356 goto out; 468 goto out;
357 } 469 }
358 } 470 }
359 r = FALSE; 471 r = FALSE;
360 472
361 out: 473 out:
474 _clear_ov_draw(obj2); /* marked by _is_obj_objs_overlay() */
362 _release_cairo_for_testing(cr); 475 _release_cairo_for_testing(cr);
363 return r; 476 return r;
364 } 477 }
478
479 #ifdef UNITTEST
480
481 #include <CUnit/Basic.h>
482
483 static
484 redraw_man_t *_fake_rdman(void) {
485 redraw_man_t *rdman;
486 cairo_surface_t *surface;
487
488 rdman = (redraw_man_t *)malloc(sizeof(redraw_man_t));
489 surface = cairo_image_surface_create(CAIRO_FORMAT_A1, 100, 100);
490 rdman->cr = cairo_create(surface);
491 DARRAY_INIT(&rdman->gen_geos);
492 return rdman;
493 }
494
495 static
496 void _free_fake_rdman(redraw_man_t *rdman) {
497 cairo_destroy(rdman->cr);
498 DARRAY_DESTROY(&rdman->gen_geos);
499 free(rdman);
500 }
501
502 static
503 void test_mb_obj_pos_is_in(void) {
504 redraw_man_t *rdman;
505 mb_obj_t *obj;
506
507 rdman = _fake_rdman();
508 CU_ASSERT(rdman != NULL);
509
510 _free_fake_rdman(rdman);
511 }
512
513 static
514 void test_is_obj_objs_overlay(void) {
515 }
516
517 static
518 void test_mb_objs_are_overlay(void) {
519 }
520
521 CU_pSuite get_event_suite(void) {
522 CU_pSuite suite;
523
524 suite = CU_add_suite("Suite_event", NULL, NULL);
525 CU_ADD_TEST(suite, test_mb_obj_pos_is_in);
526 CU_ADD_TEST(suite, test_is_obj_objs_overlay);
527 CU_ADD_TEST(suite, test_mb_objs_are_overlay);
528
529 return suite;
530 }
531
532 #endif /* UNITTEST */