Mercurial > MadButterfly
changeset 73:9ab15ebc9061
Observer for mouse events
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Mon, 18 Aug 2008 01:59:26 +0800 |
parents | 171a8cb7e4b5 |
children | 3e3e074120a7 |
files | examples/svg2code_ex/Makefile src/Makefile src/X_main.c src/mb_types.h src/observer.c src/observer.h src/redraw_man.c src/redraw_man.h src/shape_path.c src/shape_rect.c src/shape_text.c src/shapes.h src/testcase.c src/tools.h tools/mb_c_source.m4 |
diffstat | 15 files changed, 384 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/svg2code_ex/Makefile Wed Aug 13 09:25:57 2008 +0800 +++ b/examples/svg2code_ex/Makefile Mon Aug 18 01:59:26 2008 +0800 @@ -1,7 +1,12 @@ SVG=svg2code_ex.svg TOOLSDIR=../../tools +INCS=-I../../src +CFLAGS=-g `pkg-config --cflags cairo` $(INCS) -Wall -all: $(SVG:C/.svg/.mb/) $(SVG:C/.svg/.c/) $(SVG:C/.svg/.h/) +all: $(SVG:C/.svg/.o/) + +$(SVG:C/.svg/.o/): $(SVG:C/.svg/.c/) $(SVG:C/.svg/.h/) + $(CC) -c $(CFLAGS) -o $@ $(SVG:C/.svg/.c/) $(SVG:C/.svg/.mb/): $(SVG) $(TOOLSDIR)/svg2code.py $(.ALLSRC) $@ @@ -13,7 +18,7 @@ m4 -I $(TOOLSDIR) mb_c_header.m4 $(.ALLSRC) > $@ clean: - for i in *.mb *.o *~; do \ + for i in *.mb *.o *~ $(SVG:C/.svg/.c/) $(SVG:C/.svg/.h/); do \ if [ -e "$$i" ]; then \ echo "delete $$i"; \ rm -f "$$i"; \
--- a/src/Makefile Wed Aug 13 09:25:57 2008 +0800 +++ b/src/Makefile Mon Aug 18 01:59:26 2008 +0800 @@ -1,5 +1,6 @@ SRCS = coord.c geo.c shape_path.c shape_text.c shape_rect.c \ - redraw_man.c timer.c animate.c paint.c event.c tools.c + redraw_man.c timer.c animate.c paint.c event.c observer.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`
--- a/src/X_main.c Wed Aug 13 09:25:57 2008 +0800 +++ b/src/X_main.c Mon Aug 18 01:59:26 2008 +0800 @@ -250,10 +250,10 @@ text_stroke->free(text_stroke); text_fill->free(text_fill); redraw_man_destroy(&rdman); - sh_path_free(path1); - sh_path_free(path2); - sh_rect_free(rect); - sh_text_free(text); + path1->free(path1); + path2->free(path2); + rect->free(rect); + text->free(text); cairo_destroy(tmpcr); cairo_surface_destroy(tmpsuf); }
--- a/src/mb_types.h Wed Aug 13 09:25:57 2008 +0800 +++ b/src/mb_types.h Mon Aug 18 01:59:26 2008 +0800 @@ -3,6 +3,7 @@ #include <cairo.h> #include "tools.h" +#include "observer.h" typedef float co_aix; typedef struct _shape shape_t; @@ -47,6 +48,8 @@ area_t *cur_area, *last_area; area_t areas[2]; + + subject_t *mouse_event; }; #define GEF_DIRTY 0x1 #define GEF_HIDDEN 0x2 @@ -96,6 +99,7 @@ struct _coord *sibling; STAILQ(shape_t) members; /*!< All shape_t objects in this coord. */ + subject_t *mouse_event; } coord_t; #define COF_DIRTY 0x1 #define COF_HIDDEN 0x2 @@ -129,8 +133,9 @@ shape_t *coord_mem_next; paint_t *fill, *stroke; co_aix stroke_width; - int stroke_linecap; - int stroke_linejoin; + int stroke_linecap:2; + int stroke_linejoin:2; + void (*free)(shape_t *shape); }; enum { SHT_UNKNOW, SHT_PATH, SHT_TEXT, SHT_RECT };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/observer.c Mon Aug 18 01:59:26 2008 +0800 @@ -0,0 +1,149 @@ +#include <stdio.h> +#include "redraw_man.h" +#include "observer.h" +#include "tools.h" + +subject_t *subject_new(ob_factory_t *factory, void *obj, int obj_type) { + subject_t *subject; + + subject = factory->subject_alloc(factory); + if(subject == NULL) + return NULL; + + subject->obj = obj; + subject->obj_type = obj_type; + subject->flags = 0; + STAILQ_INIT(subject->observers); + + return subject; +} + +void subject_free(ob_factory_t *factory, subject_t *subject) { + observer_t *observer; + + while((observer = STAILQ_HEAD(subject->observers))) { + STAILQ_REMOVE(subject->observers, observer_t, next, observer); + factory->observer_free(factory, observer); + } + factory->subject_free(factory, subject); +} + + +void subject_notify(ob_factory_t *factory, subject_t *subject, event_t *evt) { + observer_t *observer; + + while(subject) { + for(observer = STAILQ_HEAD(subject->observers); + observer != NULL; + observer = STAILQ_NEXT(observer_t, next, observer)) { + observer->hdr(evt, observer->arg); + } + + if(subject->flags & SUBF_STOP_PROPAGATE) + break; + + subject = factory->get_parent_subject(factory, subject); + } +} + +observer_t *subject_add_observer(ob_factory_t *factory, + subject_t *subject, + evt_handler hdr, void *arg) { + observer_t *observer; + + observer = factory->observer_alloc(factory); + if(observer == NULL) + return NULL; + observer->hdr = hdr; + observer->arg = arg; + + STAILQ_INS_TAIL(subject->observers, observer_t, next, observer); + + return observer; +} + +void subject_remove_observer(ob_factory_t *factory, + subject_t *subject, + observer_t *observer) { + STAILQ_REMOVE(subject->observers, observer_t, next, observer); + factory->observer_free(factory, observer); +} + +#ifdef UNITTEST + +#include <CUnit/Basic.h> +#include <stdlib.h> + +static subject_t *test_subject_alloc(ob_factory_t *factory) { + subject_t *subject; + + subject = (subject_t *)malloc(sizeof(subject_t)); + return subject; +} + +static void test_subject_free(ob_factory_t *factory, subject_t *subject) { + free(subject); +} + +static observer_t *test_observer_alloc(ob_factory_t *factory) { + observer_t *observer; + + observer = (observer_t *)malloc(sizeof(observer_t)); + return observer; +} + +static void test_observer_free(ob_factory_t *factory, observer_t *observer) { + free(observer); +} + +static subject_t *test_get_parent_subject(ob_factory_t *factory, + subject_t *subject) { + return NULL; +} + +static ob_factory_t test_factory = { + test_subject_alloc, + test_subject_free, + test_observer_alloc, + test_observer_free, + test_get_parent_subject +}; + +static void handler(event_t *evt, void *arg) { + int *cnt = (int *)arg; + + CU_ASSERT(evt->type == EVT_MOUSE_OVER); + (*cnt)++; +} + +void test_observer(void) { + subject_t *subject; + observer_t *observer; + event_t evt; + int cnt = 0; + + subject = subject_new(&test_factory, NULL, 0); + subject->flags |= SUBF_STOP_PROPAGATE; + observer = subject_add_observer(&test_factory, subject, + handler, &cnt); + + evt.type = EVT_MOUSE_OVER; + evt.tgt = NULL; + evt.cur_tgt = NULL; + subject_notify(&test_factory, subject, &evt); + CU_ASSERT(cnt == 1); + + subject_remove_observer(&test_factory, subject, observer); + subject_free(&test_factory, subject); +} + +CU_pSuite get_observer_suite(void) { + CU_pSuite suite; + + suite = CU_add_suite("Suite_observer", NULL, NULL); + CU_ADD_TEST(suite, test_observer); + + return suite; +} + +#endif /* UNITTEST */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/observer.h Mon Aug 18 01:59:26 2008 +0800 @@ -0,0 +1,71 @@ +#ifndef __OBSERVER_H_ +#define __OBSERVER_H_ + +#include "tools.h" + +typedef struct _event event_t; +typedef struct _observer observer_t; +typedef struct _subject subject_t; +typedef struct _mouse_event mouse_event_t; +typedef struct _ob_factory ob_factory_t; +typedef void (*evt_handler)(event_t *event, void *arg); + +struct _event { + int type; + subject_t *tgt, *cur_tgt; +}; + +struct _observer { + evt_handler hdr; + void *arg; + observer_t *next; +}; + +struct _subject { + int obj_type; + void *obj; + int flags; + STAILQ(observer_t) observers; +}; +#define SUBF_STOP_PROPAGATE 0x1 + +enum {OBJT_GEO, OBJT_COORD}; + +struct _mouse_event { + event_t event; + int x, y; + int button; +}; + +/*! \brief Observer factory. + * + * It provides functions for allocation of subject and observer objects, + * and strategy function for getting the subject of parent coord object. + */ +struct _ob_factory { + subject_t *(*subject_alloc)(ob_factory_t *factory); + void (*subject_free)(ob_factory_t *factory, subject_t *subject); + observer_t *(*observer_alloc)(ob_factory_t *factory); + void (*observer_free)(ob_factory_t *factory, observer_t *observer); + /*! This is a strategy function to get subjects of parents. */ + subject_t *(*get_parent_subject)(ob_factory_t *factory, + subject_t *cur_subject); +}; + +enum {EVT_MOUSE_OVER, EVT_MOUSE_OUT, EVT_MOUSE_MOVE, + EVT_MOUSE_BUT_PRESS, EVT_MOUSE_BUT_RELEASE}; + +extern subject_t *subject_new(ob_factory_t *factory, + void *obj, int obj_type); +extern void subject_free(ob_factory_t *factory, subject_t *subject); +extern void subject_notify(ob_factory_t *factory, + subject_t *subject, event_t *evt); +extern observer_t *subject_add_observer(ob_factory_t *factory, + subject_t *subject, + evt_handler hdr, void *arg); +extern void subject_remove_observer(ob_factory_t *factory, + subject_t *subject, + observer_t *observer); + + +#endif /* __OBSERVER_H_ */
--- a/src/redraw_man.c Wed Aug 13 09:25:57 2008 +0800 +++ b/src/redraw_man.c Mon Aug 18 01:59:26 2008 +0800 @@ -6,6 +6,8 @@ #include "shapes.h" #include "tools.h" #include "redraw_man.h" +#include "observer.h" + /* NOTE: bounding box should also consider width of stroke. */ @@ -13,7 +15,6 @@ #define OK 0 #define ERR -1 -#define OFFSET(type, field) ((void *)&((type *)NULL)->field - (void *)NULL) #define SWAP(a, b, t) do { t c; c = a; a = b; b = c; } while(0) #ifdef UNITTEST @@ -23,6 +24,14 @@ extern void sh_dummy_fill(shape_t *, cairo_t *); #endif /* UNITTEST */ +static subject_t *ob_subject_alloc(ob_factory_t *factory); +static void ob_subject_free(ob_factory_t *factory, subject_t *subject); +static observer_t *ob_observer_alloc(ob_factory_t *factory); +static void ob_observer_free(ob_factory_t *factory, observer_t *observer); +static subject_t *ob_get_parent_subject(ob_factory_t *factory, + subject_t *cur_subject); + + /*! \brief Sort a list of element by a unsigned integer. * * The result is in ascend order. The unsigned integers is @@ -123,11 +132,37 @@ return ERR; } + rdman->observer_pool = elmpool_new(sizeof(observer_t), 16); + if(rdman->observer_pool == NULL) { + elmpool_free(rdman->geo_pool); + elmpool_free(rdman->coord_pool); + elmpool_free(rdman->shnode_pool); + return ERR; + } + + rdman->subject_pool = elmpool_new(sizeof(subject_t), 16); + if(rdman->subject_pool == NULL) { + elmpool_free(rdman->geo_pool); + elmpool_free(rdman->coord_pool); + elmpool_free(rdman->shnode_pool); + elmpool_free(rdman->observer_pool); + return ERR; + } + + rdman->ob_factory.subject_alloc = ob_subject_alloc; + rdman->ob_factory.subject_free = ob_subject_free; + rdman->ob_factory.observer_alloc = ob_observer_alloc; + rdman->ob_factory.observer_free = ob_observer_free; + rdman->ob_factory.get_parent_subject = ob_get_parent_subject; + rdman->root_coord = elmpool_elm_alloc(rdman->coord_pool); if(rdman->root_coord == NULL) redraw_man_destroy(rdman); rdman->n_coords = 1; coord_init(rdman->root_coord, NULL); + rdman->root_coord->mouse_event = subject_new(&rdman->ob_factory, + rdman->root_coord, + OBJT_COORD); rdman->cr = cr; rdman->backend = backend; @@ -139,6 +174,8 @@ elmpool_free(rdman->coord_pool); elmpool_free(rdman->geo_pool); elmpool_free(rdman->shnode_pool); + elmpool_free(rdman->observer_pool); + elmpool_free(rdman->subject_pool); if(rdman->dirty_coords) free(rdman->dirty_coords); if(rdman->dirty_geos) @@ -226,6 +263,7 @@ return ERR; geo_init(geo); + geo->mouse_event = subject_new(&rdman->ob_factory, geo, OBJT_GEO); sh_attach_geo(shape, geo); STAILQ_INS_TAIL(rdman->all_geos, geo_t, next, geo); @@ -261,6 +299,7 @@ */ int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape) { STAILQ_REMOVE(rdman->all_geos, geo_t, next, shape->geo); + subject_free(&rdman->ob_factory, shape->geo->mouse_event); elmpool_elm_free(rdman->geo_pool, shape->geo); sh_detach_geo(shape); rdman->n_geos--; @@ -277,6 +316,9 @@ return NULL; coord_init(coord, parent); + coord->mouse_event = subject_new(&rdman->ob_factory, + coord, + OBJT_COORD); rdman->n_coords++; coord->order = ++rdman->next_coord_order; @@ -313,6 +355,7 @@ return ERR; STAILQ_REMOVE(parent->children, coord_t, sibling, coord); + subject_free(&rdman->ob_factory, coord->mouse_event); elmpool_elm_free(rdman->coord_pool, coord); rdman->n_coords--; @@ -857,7 +900,71 @@ * - redraw changed */ +/* Implment factory and strategy functions for observers and subjects. + */ +static subject_t *ob_subject_alloc(ob_factory_t *factory) { + redraw_man_t *rdman; + subject_t *subject; + + rdman = MEM2OBJ(factory, redraw_man_t, ob_factory); + subject = elmpool_elm_alloc(rdman->subject_pool); + + return subject; +} + +static void ob_subject_free(ob_factory_t *factory, subject_t *subject) { + redraw_man_t *rdman; + + rdman = MEM2OBJ(factory, redraw_man_t, ob_factory); + elmpool_elm_free(rdman->subject_pool, subject); +} + +static observer_t *ob_observer_alloc(ob_factory_t *factory) { + redraw_man_t *rdman; + observer_t *observer; + + rdman = MEM2OBJ(factory, redraw_man_t, ob_factory); + observer = elmpool_elm_alloc(rdman->observer_pool); + + return observer; +} + +static void ob_observer_free(ob_factory_t *factory, observer_t *observer) { + redraw_man_t *rdman; + + rdman = MEM2OBJ(factory, redraw_man_t, ob_factory); + elmpool_elm_free(rdman->observer_pool, observer); +} + +static subject_t *ob_get_parent_subject(ob_factory_t *factory, + subject_t *cur_subject) { + redraw_man_t *rdman; + coord_t *coord; + geo_t *geo; + subject_t *parent; + + rdman = MEM2OBJ(factory, redraw_man_t, ob_factory); + switch(cur_subject->obj_type) { + case OBJT_GEO: + geo = (geo_t *)cur_subject->obj; + coord = geo->shape->coord; + parent = coord->mouse_event; + break; + case OBJT_COORD: + coord = (coord_t *)cur_subject->obj; + coord = coord->parent; + parent = coord->mouse_event; + break; + default: + parent = NULL; + break; + } + + return parent; +} + #ifdef UNITTEST +/* Test cases */ #include <CUnit/Basic.h> #include "paint.h"
--- a/src/redraw_man.h Wed Aug 13 09:25:57 2008 +0800 +++ b/src/redraw_man.h Mon Aug 18 01:59:26 2008 +0800 @@ -4,6 +4,7 @@ #include <cairo.h> #include "tools.h" #include "mb_types.h" +#include "observer.h" /*! \brief Manage redrawing of shapes (graphic elements). * @@ -34,6 +35,8 @@ elmpool_t *geo_pool; elmpool_t *coord_pool; elmpool_t *shnode_pool; + elmpool_t *observer_pool; + elmpool_t *subject_pool; int max_dirty_coords; int n_dirty_coords; @@ -53,6 +56,8 @@ cairo_t *cr; cairo_t *backend; + + ob_factory_t ob_factory; } redraw_man_t; extern int redraw_man_init(redraw_man_t *rdman, cairo_t *cr, @@ -112,6 +117,7 @@ extern shape_t *find_shape_at_pos(redraw_man_t *rdman, co_aix x, co_aix y, int *in_stroke); +#define rdman_get_ob_factory(rdman) (&(rdman)->ob_factory) #endif /* __REDRAW_MAN_H_ */
--- a/src/shape_path.c Wed Aug 13 09:25:57 2008 +0800 +++ b/src/shape_path.c Mon Aug 18 01:59:26 2008 +0800 @@ -37,7 +37,7 @@ #define OK 0 #define ERR -1 -void sh_path_free(shape_t *shape) { +static void sh_path_free(shape_t *shape) { sh_path_t *path = (sh_path_t *)shape; if(path->user_data) free(path->user_data); @@ -382,6 +382,8 @@ } memcpy(path->dev_data, path->user_data, cmd_cnt); + path->shape.free = sh_path_free; + return (shape_t *)path; } @@ -592,6 +594,7 @@ CU_ASSERT(strcmp(path->user_data, "MLCLZ") == 0); CU_ASSERT(strcmp(path->dev_data, "MLCLZ") == 0); + geo_init(&geo); path->shape.geo = &geo; geo.shape = (shape_t *)path;
--- a/src/shape_rect.c Wed Aug 13 09:25:57 2008 +0800 +++ b/src/shape_rect.c Mon Aug 18 01:59:26 2008 +0800 @@ -12,6 +12,10 @@ co_aix poses[12][2]; } sh_rect_t; +static void sh_rect_free(shape_t *shape) { + free(shape); +} + shape_t *sh_rect_new(co_aix x, co_aix y, co_aix w, co_aix h, co_aix rx, co_aix ry) { sh_rect_t *rect; @@ -29,14 +33,11 @@ rect->h = h; rect->rx = rx; rect->ry = ry; + rect->shape.free = sh_rect_free; return (shape_t *)rect; } -void sh_rect_free(shape_t *shape) { - free(shape); -} - void sh_rect_set(shape_t *shape, co_aix x, co_aix y, co_aix w, co_aix h, co_aix rx, co_aix ry) { sh_rect_t *rect = (sh_rect_t *)shape;
--- a/src/shape_text.c Wed Aug 13 09:25:57 2008 +0800 +++ b/src/shape_text.c Mon Aug 18 01:59:26 2008 +0800 @@ -23,6 +23,14 @@ #define TXF_SCALE_DIRTY 0x1 +static void sh_text_free(shape_t *shape) { + sh_text_t *text = (sh_text_t *)shape; + + if(text->scaled_font) + cairo_scaled_font_destroy(text->scaled_font); + cairo_font_face_destroy(text->face); +} + shape_t *sh_text_new(const char *txt, co_aix x, co_aix y, co_aix font_size, cairo_font_face_t *face) { sh_text_t *text; @@ -45,15 +53,9 @@ text->face = face; text->flags |= TXF_SCALE_DIRTY; - return (shape_t *)text; -} + text->shape.free = sh_text_free; -void sh_text_free(shape_t *shape) { - sh_text_t *text = (sh_text_t *)shape; - - if(text->scaled_font) - cairo_scaled_font_destroy(text->scaled_font); - cairo_font_face_destroy(text->face); + return (shape_t *)text; } static int get_extents(sh_text_t *text, cairo_text_extents_t *extents) {
--- a/src/shapes.h Wed Aug 13 09:25:57 2008 +0800 +++ b/src/shapes.h Mon Aug 18 01:59:26 2008 +0800 @@ -20,13 +20,11 @@ */ -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_text_free(shape_t *text); 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); @@ -34,7 +32,6 @@ extern shape_t *sh_rect_new(co_aix x, co_aix y, co_aix w, co_aix h, co_aix rx, co_aix ry); -extern void sh_rect_free(shape_t *shape); extern void sh_rect_transform(shape_t *shape); extern void sh_rect_draw(shape_t *shape, cairo_t *cr); extern void sh_rect_set(shape_t *shape, co_aix x, co_aix y,
--- a/src/testcase.c Wed Aug 13 09:25:57 2008 +0800 +++ b/src/testcase.c Mon Aug 18 01:59:26 2008 +0800 @@ -6,6 +6,7 @@ extern CU_pSuite get_shape_path_suite(void); extern CU_pSuite get_redraw_man_suite(void); extern CU_pSuite get_animate_suite(void); +extern CU_pSuite get_observer_suite(void); int main(int argc, char * const argv[]) { @@ -32,6 +33,9 @@ suite = get_animate_suite(); if(suite == NULL) return CU_get_error(); + suite = get_observer_suite(); + if(suite == NULL) + return CU_get_error(); CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests();
--- a/src/tools.h Wed Aug 13 09:25:57 2008 +0800 +++ b/src/tools.h Mon Aug 18 01:59:26 2008 +0800 @@ -66,4 +66,7 @@ #define O_ALLOC(type) ((type *)malloc(sizeof(type))) +#define OFFSET(type, mem) (((void *)&((type *)NULL)->mem) - NULL) +#define MEM2OBJ(var, type, mem) ((type *)((void *)var - OFFSET(type, mem))) + #endif /* __TOOLS_H_ */
--- a/tools/mb_c_source.m4 Wed Aug 13 09:25:57 2008 +0800 +++ b/tools/mb_c_source.m4 Mon Aug 18 01:59:26 2008 +0800 @@ -32,8 +32,8 @@ DIMPORT([ADD_LINEAR_PAINT]) DIMPORT([ADD_RADIAL_PAINT]) DIMPORT([COLOR_STOP]) -define([REF_STOPS],) -define([ADD_PATH],) +define([REF_STOPS]) +define([ADD_PATH]) define([ADD_RECT]) define([ADD_COORD]) define([FILL_SHAPE]) @@ -127,11 +127,11 @@ ]]) define([F_ADD_PATH],[[ - sh_path_free(obj->$1); + obj->$1->free(obj->$1); ]]); define([F_ADD_RECT],[[ - sh_rect_free(obj->$1); + obj->$1->free(obj->$1); ]]); define([F_FILL_SHAPE],[[