Mercurial > MadButterfly
diff src/event.c @ 30:e06a4a667ce2
Accept mouse/pointer event and hint the shape that the pointer is over.
- add find_shape_at_pos()
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Tue, 05 Aug 2008 12:40:45 +0800 |
parents | |
children | 69c8e264890d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/event.c Tue Aug 05 12:40:45 2008 +0800 @@ -0,0 +1,131 @@ +#include <stdio.h> +#include <stdlib.h> +#include <cairo.h> +#include "mb_types.h" +#include "redraw_man.h" +#include "shapes.h" + +#define OK 0 +#define ERR -1 + + +static int extend_memblk(void **buf, int o_size, int n_size) { + void *new_buf; + + new_buf = realloc(*buf, n_size); + if(new_buf == NULL) + return ERR; + + *buf = new_buf; + + return OK; +} + +/*! \brief Add a geo_t object to general geo list. + * + * General geo list can use to temporary keep a list of geo_t + * objects for any purpose. It supposed to be reused by + * different modules that need to select part of geo_t objects + * from a redraw manager. + */ +static int add_gen_geo(redraw_man_t *rdman, geo_t *geo) { + int max_gen_geos; + int r; + + if(rdman->n_gen_geos >= rdman->max_gen_geos) { + max_gen_geos = rdman->n_geos; + r = extend_memblk((void **)&rdman->gen_geos, + sizeof(geo_t *) * rdman->n_gen_geos, + sizeof(geo_t *) * max_gen_geos); + if(r != OK) + return ERR; + rdman->max_gen_geos = max_gen_geos; + } + + rdman->gen_geos[rdman->n_gen_geos++] = geo; + return OK; +} + +static int collect_shapes_at_point(redraw_man_t *rdman, + co_aix x, co_aix y) { + geo_t *geo; + int r; + + r = rdman_force_clean(rdman); + if(r != OK) + return ERR; + + rdman->n_gen_geos = 0; + + for(geo = STAILQ_HEAD(rdman->all_geos); + geo != NULL; + geo = STAILQ_NEXT(geo_t, next, geo)) { + if(geo_pos_is_in(geo, x, y)) { + r = add_gen_geo(rdman, geo); + if(r != OK) + return ERR; + } + } + + return OK; +} + +static void draw_shape_path(shape_t *shape, cairo_t *cr) { + switch(shape->sh_type) { + case SHT_PATH: + sh_path_draw(shape, cr); + break; + case SHT_TEXT: + sh_text_draw(shape, cr); + break; + } +} + +static geo_t *find_pos_in_geo(redraw_man_t *rdman, + co_aix x, co_aix y, int *in_stroke) { + geo_t *geo; + geo_t **geos; + shape_t *shape; + cairo_t *cr; + int i; + + geos = rdman->gen_geos; + cr = rdman->cr; + for(i = rdman->n_gen_geos - 1; i >= 0; i--) { + geo = geos[i]; + shape = geo->shape; + draw_shape_path(shape, cr); + if(shape->fill) { + if(cairo_in_fill(cr, x, y)) { + *in_stroke = 0; + cairo_new_path(cr); + return geo; + } + } + if(shape->stroke) { + if(cairo_in_stroke(cr, x, y)) { + *in_stroke = 1; + cairo_new_path(cr); + return geo; + } + } + } + + return NULL; +} + +shape_t *find_shape_at_pos(redraw_man_t *rdman, + co_aix x, co_aix y, int *in_stroke) { + geo_t *geo; + int r; + + r = collect_shapes_at_point(rdman, x, y); + if(r != OK) + return NULL; + + geo = find_pos_in_geo(rdman, x, y, in_stroke); + if(geo == NULL) + return NULL; + + return geo->shape; +}