From de65f674480ebfeab651d9668131e7ab0d310484 Mon Sep 17 00:00:00 2001 From: Jonathan Wilkes <jon.w.wilkes@gmail.com> Date: Mon, 19 Oct 2015 22:35:38 -0400 Subject: [PATCH] add [event] class for canvas field --- pd/src/g_canvas.c | 17 +++++++++++++ pd/src/g_scalar.c | 32 +++++++++++++++-------- pd/src/g_template.c | 62 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 99 insertions(+), 12 deletions(-) diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c index d881b906c..40806943a 100644 --- a/pd/src/g_canvas.c +++ b/pd/src/g_canvas.c @@ -360,6 +360,13 @@ void canvasgop__clickhook(t_scalehandle *sh, int newstate); void canvasgop__motionhook(t_scalehandle *sh,t_floatarg f1, t_floatarg f2); extern void glist_setlastxy(t_glist *gl, int xval, int yval); +/* These globals are used to set state for the "canvas" field in a + struct. We try below to make sure they only get set for the toplevel + canvas, and then set them to NULL for everything else. */ +t_symbol *canvas_field_templatesym; /* for "canvas" data type */ +t_word *canvas_field_vec; /* for "canvas" data type */ +t_gpointer *canvas_field_gp; /* parent for "canvas" data type */ + /* make a new glist. It will either be a "root" canvas or else it appears as a "text" object in another window (canvas_getcurrent() tells us which.) */ @@ -465,6 +472,16 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) x->u_queue = canvas_undo_init(x); //glist_setlastxy(x, 20, 20); + + x->gl_templatesym = canvas_field_templatesym; + x->gl_vec = canvas_field_vec; + if (canvas_field_gp) gpointer_copy(canvas_field_gp, &x->gl_gp); + + // unset the globals in case this was a canvas field + canvas_field_templatesym = NULL; + canvas_field_vec = NULL; + canvas_field_gp = NULL; + return(x); } diff --git a/pd/src/g_scalar.c b/pd/src/g_scalar.c index 0e0561283..c53b45b04 100644 --- a/pd/src/g_scalar.c +++ b/pd/src/g_scalar.c @@ -18,6 +18,10 @@ t_class *scalar_class; void pd_doloadbang(void); +extern t_symbol *canvas_field_templatesym; /* for "canvas" data type */ +extern t_word *canvas_field_vec; /* for "canvas" data type */ +extern t_gpointer *canvas_field_gp; /* parent for "canvas" data type */ + void word_init(t_word *data, t_template *template, t_gpointer *gp) { int i, nitems = template->t_n; @@ -36,6 +40,23 @@ void word_init(t_word *data, t_template *template, t_gpointer *gp) } else if (type == DT_LIST) { + /* we feed these values to global vars so that we can + read them from inside canvas_new. This is very hacky, + but I couldn't figure out a better way to do it. */ + canvas_field_templatesym = template->t_sym; + /* this is bad-- we're storing a reference to a position in + a dynamically allocated byte array when realloc can potentially + move this data. Essentially, we're depending on gcc to never + move it, which is a bad assumption. Unfortunately gpointers + do the same thing, and I haven't heard back from Miller yet + on how he plans to deal with this problem. Hopefully that same + solution will be usable here. */ + canvas_field_vec = data; + /* Here too we're being dangerous-- I'm copying the gpointer + without recounting, and I'm not unsetting the one that's + part of the _glist struct (t_gpointer gl_gp). */ + canvas_field_gp = gp; + /* copied from glob_evalfile... */ t_pd *x = 0; /* even though binbuf_evalfile appears to take care of dspstate, @@ -62,17 +83,6 @@ void word_init(t_word *data, t_template *template, t_gpointer *gp) wp->w_list = canvas_getcurrent(); wp->w_list->gl_templatesym = template->t_sym; - /* this is bad-- we're storing a reference to a position in - a dynamically allocated byte array when realloc can potentially - move this data. Essentially, we're depending on gcc to never - move it, which is a bad assumption. Unfortunately gpointers - do the same thing, and I haven't heard back from Miller yet - on how he plans to deal with this problem. Hopefully that same - solution will be usable here. */ - wp->w_list->gl_vec = data; - /* Here too we're being dangerous-- I'm not unsetting this - gpointer yet. */ - gpointer_copy(gp, &wp->w_list->gl_gp); /* make the parent glist the parent of our canvas field */ wp->w_list->gl_owner = gp->gp_stub->gs_un.gs_glist; diff --git a/pd/src/g_template.c b/pd/src/g_template.c index 0ecb62ea5..1d972bd4b 100644 --- a/pd/src/g_template.c +++ b/pd/src/g_template.c @@ -4149,9 +4149,10 @@ static int draw_click(t_gobj *z, t_glist *glist, void draw_notify(t_canvas *x, t_symbol *s, int argc, t_atom *argv) { + char canvas_field_namebuf[20]; + t_symbol *canvas_field_event; t_symbol *scalarsym = atom_getsymbolarg(0, argc--, argv++); t_symbol *drawcommand_sym = atom_getsymbolarg(0, argc--, argv++); - t_symbol *event_name = atom_getsymbolarg(0, argc--, argv++); t_scalar *sc; t_object *ob = 0; if (scalarsym->s_thing) @@ -4161,6 +4162,20 @@ void draw_notify(t_canvas *x, t_symbol *s, int argc, t_atom *argv) error("draw_notify: can't get scalar from symbol"); return; } + + /* Generate the symbol that would be bound by any [event] inside + a canvas field. If there's any in existence, forward the event + notification. pd_bind takes care of the details of this-- if + there are multiple [event] objects it will dispatch to each */ + sprintf(canvas_field_namebuf, "%lx_event", (long unsigned int)sc->sc_vec); + canvas_field_event = gensym(canvas_field_namebuf); + t_pd *target = canvas_field_event->s_thing; + if (target) + pd_forwardmess(target, argc, argv); + + /* need to revisit popping this off the args, it's a little confusing... */ + t_symbol *event_name = atom_getsymbolarg(0, argc--, argv++); + if (drawcommand_sym->s_thing) { t_pd *drawcommand = (t_pd *)drawcommand_sym->s_thing; @@ -4406,6 +4421,50 @@ static void draw_setup(void) gensym("y2"), A_GIMME, 0); } +/* ------------------------------ event --------------------------------- */ +/* This is a very simple class used to dispatch events inside a + canvas field. */ + +t_class *event_class; + +typedef struct _event +{ + t_object x_obj; + t_symbol *x_bindsym; +} t_event; + +static void event_anything(t_event *x, t_symbol *s, int argc, t_atom *argv) +{ + outlet_anything(x->x_obj.ob_outlet, s, argc, argv); +} + +static void *event_new(void) +{ + char namebuf[20]; + t_event *x = (t_event *)pd_new(event_class); + t_canvas *c = canvas_getcurrent(); + if (c->gl_vec) + { + sprintf(namebuf, "%lx_event", (long unsigned int)c->gl_vec); + x->x_bindsym = gensym(namebuf); + pd_bind(&x->x_obj.ob_pd, x->x_bindsym); + } + outlet_new(&x->x_obj, &s_anything); + return (x); +} + +static void event_free(t_event *x) +{ + pd_unbind(&x->x_obj.ob_pd, x->x_bindsym); +} + +void event_setup(void) +{ + event_class = class_new(gensym("event"), (t_newmethod)event_new, + (t_method)event_free, sizeof(t_event), 0, 0); + class_addanything(event_class, event_anything); +} + /* ---------------- curves and polygons (joined segments) ---------------- */ /* @@ -7749,6 +7808,7 @@ void g_template_setup(void) gtemplate_setup(); curve_setup(); draw_setup(); + event_setup(); plot_setup(); drawnumber_setup(); drawsymbol_setup(); -- GitLab