# HG changeset patch # User Thinker K.F. Li # Date 1217911245 -28800 # Node ID e06a4a667ce2e6844fc56d07b58100da15591f92 # Parent f56c96b035a89062c6c73835bd7e9a2e4e8ebfcb Accept mouse/pointer event and hint the shape that the pointer is over. - add find_shape_at_pos() diff -r f56c96b035a8 -r e06a4a667ce2 src/Makefile --- a/src/Makefile Mon Aug 04 21:13:32 2008 +0800 +++ b/src/Makefile Tue Aug 05 12:40:45 2008 +0800 @@ -1,4 +1,5 @@ -SRCS = coord.c geo.c shape_path.c shape_text.c redraw_man.c paint.c tools.c +SRCS = coord.c geo.c shape_path.c shape_text.c redraw_man.c \ + paint.c event.c tools.c OBJS = ${SRCS:C/(.*)\.c/\1.o/g} TESTCASE_OBJS = ${SRCS:C/(.*)\.c/testcase-\1.o/g} CFLAGS+= -Wall -I/usr/local/include `pkg-config --cflags cairo` diff -r f56c96b035a8 -r e06a4a667ce2 src/X_main.c --- a/src/X_main.c Mon Aug 04 21:13:32 2008 +0800 +++ b/src/X_main.c Tue Aug 05 12:40:45 2008 +0800 @@ -11,6 +11,47 @@ #include "paint.h" Display *display; +Window win; + +void hint_shape(redraw_man_t *rdman, shape_t *shape) { + static shape_t *last_shape = NULL; + if(last_shape != shape) { + if(last_shape != NULL && last_shape != NULL) { + last_shape->stroke_width -= 2; + rdman_shape_changed(rdman, last_shape); + } + if(shape != NULL && shape->stroke != NULL) { + shape->stroke_width += 2; + rdman_shape_changed(rdman, shape); + rdman_redraw_changed(rdman); + XFlush(display); + } + } + last_shape = shape; +} + +void event_interaction(Display *display, + redraw_man_t *rdman, int w, int h) { + XEvent evt; + XMotionEvent *mevt; + int r; + co_aix x, y; + shape_t *shape = NULL; + int in_stroke; + + XSelectInput(display, win, PointerMotionMask); + while((r = XNextEvent(display, &evt)) == 0) { + switch(evt.type) { + case MotionNotify: + mevt = (XMotionEvent *)&evt; + x = mevt->x; + y = mevt->y; + shape = find_shape_at_pos(rdman, x, y, &in_stroke); + hint_shape(rdman, shape); + break; + } + } +} void draw_path(cairo_t *cr, int w, int h) { cairo_t *tmpcr; @@ -168,6 +209,8 @@ XFlush(display); } + event_interaction(display, &rdman, w, h); + fill1->free(fill1); fill2->free(fill2); stroke->free(stroke); @@ -196,7 +239,6 @@ Visual *visual; int screen; XSetWindowAttributes wattr; - Window win; int depth; cairo_surface_t *surface; int w, h; diff -r f56c96b035a8 -r e06a4a667ce2 src/event.c --- /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 +#include +#include +#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; +} diff -r f56c96b035a8 -r e06a4a667ce2 src/mb_types.h --- a/src/mb_types.h Mon Aug 04 21:13:32 2008 +0800 +++ b/src/mb_types.h Tue Aug 05 12:40:45 2008 +0800 @@ -52,8 +52,8 @@ #define geo_set_shape(g, sh) do {(g)->shape = sh;} while(0) #define _geo_is_in(a, s, w) ((a) >= (s) && (a) < ((s) + (w))) #define geo_pos_is_in(g, _x, _y) \ - (_geo_is_in(_x, (g)->cur_area.x, (g)->cur_area.w) && \ - _geo_is_in(_y, (g)->cur_area.y, (g)->cur_area.h)) + (_geo_is_in(_x, (g)->cur_area->x, (g)->cur_area->w) && \ + _geo_is_in(_y, (g)->cur_area->y, (g)->cur_area->h)) /*! \brief A coordination system. diff -r f56c96b035a8 -r e06a4a667ce2 src/redraw_man.c --- a/src/redraw_man.c Mon Aug 04 21:13:32 2008 +0800 +++ b/src/redraw_man.c Tue Aug 05 12:40:45 2008 +0800 @@ -50,8 +50,7 @@ if(new_buf == NULL) return ERR; - if(new_buf != *buf) - *buf = new_buf; + *buf = new_buf; return OK; } @@ -142,6 +141,8 @@ free(rdman->dirty_coords); if(rdman->dirty_geos) free(rdman->dirty_geos); + if(rdman->gen_geos) + free(rdman->gen_geos); } @@ -710,6 +711,14 @@ return OK; } +int rdman_force_clean(redraw_man_t *rdman) { + int r; + + r = clean_rdman_dirties(rdman); + + return r; +} + shnode_t *shnode_new(redraw_man_t *rdman, shape_t *shape) { shnode_t *node; diff -r f56c96b035a8 -r e06a4a667ce2 src/redraw_man.h --- a/src/redraw_man.h Mon Aug 04 21:13:32 2008 +0800 +++ b/src/redraw_man.h Tue Aug 05 12:40:45 2008 +0800 @@ -47,6 +47,10 @@ int n_dirty_areas; area_t **dirty_areas; + int max_gen_geos; + int n_gen_geos; + geo_t **gen_geos; /* general geo list */ + cairo_t *cr; cairo_t *backend; } redraw_man_t; @@ -66,6 +70,7 @@ extern int rdman_shape_changed(redraw_man_t *rdman, shape_t *shape); extern int rdman_redraw_changed(redraw_man_t *rdman); extern int rdman_redraw_all(redraw_man_t *rdman); +extern int rdman_force_clean(redraw_man_t *rdman); extern shnode_t *shnode_new(redraw_man_t *rdman, shape_t *shape); #define shnode_free(rdman, node) elmpool_elm_free((rdman)->shnode_pool, node) #define shnode_list_free(rdman, q) \ @@ -103,5 +108,8 @@ } while(0) extern int rdman_paint_changed(redraw_man_t *rdman, paint_t *paint); +extern shape_t *find_shape_at_pos(redraw_man_t *rdman, + co_aix x, co_aix y, int *in_stroke); + #endif /* __REDRAW_MAN_H_ */ diff -r f56c96b035a8 -r e06a4a667ce2 src/shape_path.c --- a/src/shape_path.c Mon Aug 04 21:13:32 2008 +0800 +++ b/src/shape_path.c Tue Aug 05 12:40:45 2008 +0800 @@ -544,6 +544,10 @@ } } +void sh_path_draw(shape_t *shape, cairo_t *cr) { + sh_path_path(shape, cr); +} + void sh_path_fill(shape_t *shape, cairo_t *cr) { sh_path_path(shape, cr); cairo_fill(cr); diff -r f56c96b035a8 -r e06a4a667ce2 src/shape_text.c --- a/src/shape_text.c Mon Aug 04 21:13:32 2008 +0800 +++ b/src/shape_text.c Tue Aug 05 12:40:45 2008 +0800 @@ -128,6 +128,10 @@ } +void sh_text_draw(shape_t *shape, cairo_t *cr) { + draw_text((sh_text_t *)shape, cr); +} + void sh_text_fill(shape_t *shape, cairo_t *cr) { sh_text_t *text = (sh_text_t *)shape; diff -r f56c96b035a8 -r e06a4a667ce2 src/shapes.h --- a/src/shapes.h Mon Aug 04 21:13:32 2008 +0800 +++ b/src/shapes.h Tue Aug 05 12:40:45 2008 +0800 @@ -9,14 +9,18 @@ * A shape must include * - *_new() and *_free() * - *_transform() + * - *_draw() * - *_fill() * - *_stroke() * - struct of shape must include an shape_t as type of first member. */ +/* TODO: remove *_fill() and *_stroke() */ + extern void sh_path_free(shape_t *path); extern shape_t *sh_path_new(char *data); extern void sh_path_transform(shape_t *shape); +extern void sh_path_draw(shape_t *shape, cairo_t *cr); extern void sh_path_fill(shape_t *shape, cairo_t *cr); extern void sh_path_stroke(shape_t *shape, cairo_t *cr); @@ -25,6 +29,7 @@ extern shape_t *sh_text_new(const char *txt, co_aix x, co_aix y, co_aix font_size, cairo_font_face_t *face); extern void sh_text_transform(shape_t *shape); +extern void sh_text_draw(shape_t *shape, cairo_t *cr); extern void sh_text_fill(shape_t *shape, cairo_t *cr); extern void sh_text_stroke(shape_t *shape, cairo_t *cr); diff -r f56c96b035a8 -r e06a4a667ce2 src/tools.c --- a/src/tools.c Mon Aug 04 21:13:32 2008 +0800 +++ b/src/tools.c Tue Aug 05 12:40:45 2008 +0800 @@ -108,6 +108,7 @@ } } + #ifdef UNITTEST #include