diff --git a/pd/src/g_scalar.c b/pd/src/g_scalar.c index 3483758fa0a2ac54e4cee17bdf12c6cac07f364f..02d2e78b1dc3d592fac20fcfbf729d106adcceaa 100644 --- a/pd/src/g_scalar.c +++ b/pd/src/g_scalar.c @@ -712,13 +712,16 @@ static void scalar_vis(t_gobj *z, t_glist *owner, int vis) /* we translate the .scalar%lx group to displace it on the tk side. This is the outermost group for the scalar, something like a poor man's viewport. - Also, the default stroke is supposed to be "none" and default - fill is supposed to be black. Unfortunately tkpath does the - opposite. To fix this, we set the correct fill/stroke options - here on the .scalar%lx group. Notice also that tkpath doesn't - understand "None"-- instead we must send an empty symbol. */ + Also: + * the default stroke is supposed to be "none" + * default fill is supposed to be black. + * stroke-linejoin should be "miter", not "round" + To fix these, we set the correct fill/stroke/strokelinjoin options + here on the .scalar%lx group. (Notice also that tkpath doesn't + understand "None"-- instead we must send an empty symbol.) */ sys_vgui(".x%lx.c create group -tags {.scalar%lx %s} " - "-matrix { {%g %g} {%g %g} {%d %d} } -stroke \"\" -fill black\n", + "-matrix { {%g %g} {%g %g} {%d %d} } " + "-stroke \"\" -fill black -strokelinejoin miter\n", glist_getcanvas(owner), x->sc_vec, (glist_isselected(owner, &x->sc_gobj) ? "scalar_selected" : ""), xscale, 0.0, 0.0, yscale, (int)glist_xtopixels(owner, basex), @@ -787,6 +790,68 @@ void scalar_redraw(t_scalar *x, t_glist *glist) //sys_queuegui(x, glist, scalar_doredraw); } +/* here we call the parentclickfns for drawing commands. + We recurse all the way to the end of the glist (and, for the + groups, as deep as they go) and then call the functions from the bottom up. + This way the clicks can "bubble" up from the bottom. This has the effect + that the shape visually closest to the front gets called first. + + This is called "event bubbling" in the HTML5 DOM. You can also call + events in top down order in HTML5/SVG as well (called "capturing" or + "trickling"). But because some old version of Internet Explorer only did + bubbling, that is the most widely used model today, and the only one + I decided to implement here. + + However, [group] doesn't yet have an outlet to report events. Only a + single [draw] should report a click here atm. +*/ +int scalar_groupclick(struct _glist *groupcanvas, + t_word *data, t_template *template, t_scalar *sc, + t_array *ap, struct _glist *owner, + t_float xloc, t_float yloc, int xpix, int ypix, + int shift, int alt, int dbl, int doit, t_float basex, t_float basey, + t_gobj *obj) +{ + int hit = 0; + t_gobj *nextobj = obj->g_next; + /* let's skip over any objects that aren't drawing instructions + or groups */ + while (nextobj && + !class_isdrawcommand(pd_class((t_pd *)nextobj)) && + !(pd_class(&nextobj->g_pd) == canvas_class && + ((t_glist *)nextobj)->gl_svg)) + nextobj = nextobj->g_next; + /* If there's another link in the list go ahead and recurse with it */ + if (nextobj) + { + hit = (scalar_groupclick(groupcanvas, data, template, sc, ap, + owner, xloc, yloc, xpix, ypix, + shift, alt, dbl, doit, basex, basey, nextobj)); + if (hit) return hit; + } + /* recurse inside a [group] object to look for more objects */ + if (pd_class(&obj->g_pd) == canvas_class && ((t_glist *)obj)->gl_svg) + { + t_canvas *cnv = (t_canvas *)obj; + obj = cnv->gl_list; + if (obj) + return (scalar_groupclick(cnv, data, template, sc, ap, + owner, xloc, yloc, xpix, ypix, + shift, alt, dbl, doit, basex, basey, obj)); + } + else /* finally, try to call the parent click function ... */ + { + t_parentwidgetbehavior *wb = pd_getparentwidget(&obj->g_pd); + if (!wb) return hit; + if ((*wb->w_parentclickfn)(obj, owner, + data, template, sc, ap, basex + xloc, basey + yloc, + xpix, ypix, shift, alt, dbl, doit)) + hit = 1; + } + return (hit); +} + +/* int scalar_groupclick(struct _glist *groupcanvas, t_word *data, t_template *template, t_scalar *sc, t_array *ap, struct _glist *owner, @@ -818,6 +883,7 @@ int scalar_groupclick(struct _glist *groupcanvas, } return 0; } +*/ int scalar_doclick(t_word *data, t_template *template, t_scalar *sc, t_array *ap, struct _glist *owner, @@ -827,6 +893,7 @@ int scalar_doclick(t_word *data, t_template *template, t_scalar *sc, int hit = 0; t_canvas *templatecanvas = template_findcanvas(template); t_atom at[2]; + t_gobj *obj; t_float basex = template_getfloat(template, gensym("x"), data, 0); t_float basey = template_getfloat(template, gensym("y"), data, 0); //fprintf(stderr,"=================scalar_doclick %f %f %f %f %d\n", @@ -851,9 +918,12 @@ int scalar_doclick(t_word *data, t_template *template, t_scalar *sc, } if (templatecanvas) + { + if (!(obj = templatecanvas->gl_list)) return 0; hit = scalar_groupclick(templatecanvas, data, template, sc, ap, owner, xloc, yloc, xpix, ypix, - shift, alt, dbl, doit, basex, basey); + shift, alt, dbl, doit, basex, basey, obj); + } return hit; } diff --git a/pd/src/g_template.c b/pd/src/g_template.c index b106a95d4fb5fe02445e99acb8631ecf3ec67efc..08fba1d1ec2acb4b9fefd880dbeae4ddd03c5425 100644 --- a/pd/src/g_template.c +++ b/pd/src/g_template.c @@ -1042,12 +1042,39 @@ t_class *draw_class; t_class *svg_class; +/* this is a wrapper around t_fielddesc-- it adds a flag for two reasons: + 1) tkpath defaults to inheriting values for options from the parent until + you specify them-- after that, there's no way to get back to "inherit". + We set the flag to "0" to mean "inherit"-- that way we don't send a tcl + string for that option. There's still the bug that the user can't set + an attribute back to "inherit" after they've set something explicitly, + however. + 2) This might be generally useful even with Qt, so that if the user calls + a method for an attribute without any arguments, Qt goes back to + inheriting the value from the parent. That gives us a way to + differentiate "inherit" from fielddescriptors, the value "none" and + "". (Similar to the way "set" resets a message box.) +*/ typedef struct _svg_attr { int a_flag; t_fielddesc a_attr; } t_svg_attr; +/* events on which to output a notification from the outlet of [draw] */ +typedef struct _svg_event +{ + t_fielddesc e_focusin, + e_focusout, + e_activate, + e_click, + e_mousedown, + e_mouseup, + e_mouseover, + e_mousemove, + e_mouseout; +} t_svg_event; + /* svg attributes */ typedef struct _svg { @@ -1063,6 +1090,9 @@ typedef struct _svg int x_stroketype; int x_ndash; t_fielddesc *x_strokedasharray; /* array of lengths */ + t_svg_event x_events; + t_fielddesc x_drag; /* convenience event, not part of the svg spec */ + t_svg_attr x_pointerevents; t_svg_attr x_strokelinecap; t_svg_attr x_strokelinejoin; t_svg_attr x_strokemiterlimit; @@ -1074,6 +1104,7 @@ typedef struct _svg t_fielddesc *x_transform; t_fielddesc x_width; t_svg_attr x_vis; + t_fielddesc x_bbox; /* turn bbox calculation on or off */ int x_pathrect_cache; /* 0 to recalc on next draw_getrect call 1 for cached -1 to turn off caching */ @@ -1112,6 +1143,18 @@ typedef struct _drawimage t_pd *x_attr; } t_drawimage; +void draw_notifyforscalar(t_draw *x, t_glist *owner, + t_scalar *sc, t_symbol *s, int argc, t_atom *argv) +{ + t_gpointer gp; + gpointer_init(&gp); + gpointer_setglist(&gp, owner, &sc->sc_gobj); + SETPOINTER(argv, &gp); + if (x) + outlet_anything(x->x_obj.ob_outlet, s, argc, argv); + gpointer_unset(&gp); +} + static int is_svgpath_cmd(t_symbol *s) { /* 1 for absolute cmd, 2 for relative */ @@ -1248,9 +1291,13 @@ void *svg_new(t_pd *parent, t_symbol *s, int argc, t_atom *argv) } if (argc & 1 && x->x_type != gensym("path")) fielddesc_setfloat_const(fd, 0); + fielddesc_setfloat_const(&x->x_bbox, 1); + fielddesc_setfloat_const(&x->x_drag, 0); x->x_filltype = 0; x->x_fillopacity.a_flag = 0; x->x_fillrule.a_flag = 0; + fielddesc_setfloat_const(&x->x_pointerevents.a_attr, 1); + x->x_pointerevents.a_flag = 0; x->x_stroketype = 0; x->x_strokelinecap.a_flag = 0; x->x_strokelinejoin.a_flag = 0; @@ -1268,6 +1315,16 @@ void *svg_new(t_pd *parent, t_symbol *s, int argc, t_atom *argv) x->x_transform_n = 0; x->x_transform = (t_fielddesc *)t_getbytes(x->x_transform_n * sizeof(t_fielddesc)); + /* initialize events */ + fielddesc_setfloat_const(&x->x_events.e_focusin, 0); + fielddesc_setfloat_const(&x->x_events.e_focusout, 0); + fielddesc_setfloat_const(&x->x_events.e_activate, 0); + fielddesc_setfloat_const(&x->x_events.e_click, 0); + fielddesc_setfloat_const(&x->x_events.e_mousedown, 0); + fielddesc_setfloat_const(&x->x_events.e_mouseup, 0); + fielddesc_setfloat_const(&x->x_events.e_mouseover, 0); + fielddesc_setfloat_const(&x->x_events.e_mousemove, 0); + fielddesc_setfloat_const(&x->x_events.e_mouseout, 0); return (x); } @@ -1312,6 +1369,9 @@ static void *draw_new(t_symbol *classsym, t_int argc, t_atom *argv) t_draw *x = (t_draw *)pd_new(draw_class); + /* outlet for event notifications */ + outlet_new(&x->x_obj, &s_anything); + /* create a proxy for drawing/svg attributes */ if (!(x->x_attr = (t_pd *)svg_new((t_pd *)x, type, argc, argv))) { @@ -1422,7 +1482,9 @@ void svg_sendupdate(t_svg *x, t_canvas *c, t_symbol *s, (long unsigned int)x->x_parent, (long unsigned int)data); } - if (s == gensym("fill")) + if (s == gensym("bbox")) + *predraw_bbox = 1; + else if (s == gensym("fill")) { t_symbol *fill; t_fielddesc *fd = x->x_fill; @@ -1466,6 +1528,8 @@ void svg_sendupdate(t_svg *x, t_canvas *c, t_symbol *s, glist_getcanvas(c), tag, (int)fielddesc_getcoord( &x->x_fillrule.a_attr, template, data, 1) ? "evenodd" : "nonzero"); + else if (s == gensym("pointer-events")) + *predraw_bbox = 1; else if (s == gensym("stroke-linecap")) sys_vgui(".x%lx.c itemconfigure %s -strokelinecap %s\n", glist_getcanvas(c), tag, get_strokelinecap( @@ -1648,7 +1712,7 @@ void svg_updatevec(t_canvas *c, t_word *data, t_template *template, t_template *target, void *parent, t_symbol *s, t_svg *x, t_scalar *sc, int *predraw_bbox) { - post("updateing vec..."); + // post("updateing vec..."); int i, j; for (i = 0; i < template->t_n; i++) { @@ -1962,8 +2026,55 @@ void svg_stroke(t_svg *x, t_symbol *s, t_int argc, t_atom *argv) svg_update(x, s); } -void svg_strokelinecap(t_svg *x, t_symbol *s, - t_int argc, t_atom *argv) +/* "drag" is a convenience method-- to use it the user must turn on the + "mousedown" event, too. */ +void svg_drag(t_svg *x, t_symbol *s, int argc, t_atom *argv) +{ + if (argc > 0 && (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL)) + { + fielddesc_setfloatarg(&x->x_drag, argc, argv); + } +} + +void svg_event(t_svg *x, t_symbol *s, int argc, t_atom *argv) +{ + if (argc > 0 && (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL)) + { + if (s == gensym("focusin")) + fielddesc_setfloatarg(&x->x_events.e_focusin, argc, argv); + else if (s == gensym("focusout")) + fielddesc_setfloatarg(&x->x_events.e_focusout, argc, argv); + else if (s == gensym("activate")) + fielddesc_setfloatarg(&x->x_events.e_activate, argc, argv); + else if (s == gensym("click")) + fielddesc_setfloatarg(&x->x_events.e_click, argc, argv); + else if (s == gensym("mousedown")) + fielddesc_setfloatarg(&x->x_events.e_mousedown, argc, argv); + else if (s == gensym("mouseup")) + fielddesc_setfloatarg(&x->x_events.e_mouseup, argc, argv); + else if (s == gensym("mouseover")) + fielddesc_setfloatarg(&x->x_events.e_mouseover, argc, argv); + else if (s == gensym("mousemove")) + fielddesc_setfloatarg(&x->x_events.e_mousemove, argc, argv); + else if (s == gensym("mouseout")) + fielddesc_setfloatarg(&x->x_events.e_mouseout, argc, argv); +// svg_update(x, s); + } +} + +void svg_pointerevents(t_svg *x, t_symbol *s, t_int argc, t_atom *argv) +{ + if (argc < 1) + x->x_pointerevents.a_flag = 0; + else if (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL) + { + fielddesc_setfloatarg(&x->x_pointerevents.a_attr, argc, argv); + x->x_pointerevents.a_flag = 1; + svg_update(x, s); + } +} + +void svg_strokelinecap(t_svg *x, t_symbol *s, t_int argc, t_atom *argv) { if (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL) { @@ -2120,6 +2231,17 @@ void svg_rectpoints(t_svg *x, t_symbol *s, int argc, t_atom *argv) } } +/* selectively do bbox calculation: 0 = off, 1 = on, instance variable per + instance */ +void svg_bbox(t_svg *x, t_symbol *s, t_int argc, t_atom *argv) +{ + if (argc > 0 && (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL)) + { + fielddesc_setfloatarg(&x->x_bbox, argc, argv); + svg_update(x, s); + } +} + void svg_ellipsepoints(t_svg *x, t_symbol *s, int argc, t_atom *argv) { if (x->x_type == gensym("circle") || x->x_type == gensym("ellipse")) @@ -2299,14 +2421,16 @@ void svg_parsetransform(t_svg *x, t_template *template, t_word *data, } else if (type == gensym("skewx")) { - t_float a = fielddesc_getfloat(fd++, template, data, 0); + t_float a = fielddesc_getfloat(fd++, template, data, 0) * + 3.14159 / 180; argc--; mset(m2, 1, 0, tan(a), 1, 0, 0); mmult(m, m2, m); } else if (type == gensym("skewy")) { - t_float a = fielddesc_getfloat(fd++, template, data, 0); + t_float a = fielddesc_getfloat(fd++, template, data, 0) * + 3.14159 / 180; argc--; mset(m2, 1, tan(a), 0, 1, 0, 0); mmult(m, m2, m); @@ -3111,7 +3235,22 @@ static void draw_getrect(t_gobj *z, t_glist *glist, { t_draw *x = (t_draw *)z; t_svg *sa = (t_svg *)x->x_attr; - /* todo: put this after the var inits below */ + + /* So in the svg spec, the "display" attribute doesn't actually + calculate a bbox, whereas the "visibility" still calcs the bbox. + tkpath doesn't have a function for "display" so currently "vis" + is filling in for it + + */ + if (!fielddesc_getfloat(&sa->x_vis.a_attr, template, data, 0) || + !fielddesc_getfloat(&sa->x_bbox, template, data, 0) || + (sa->x_type == gensym("group"))) + { + *xp1 = *yp1 = 0x7fffffff; + *xp2 = *yp2 = -0x7fffffff; + return; + } + if (sa->x_pathrect_cache == 1) { *xp1 = glist_xtopixels(glist, basex + sa->x_x1); @@ -3129,13 +3268,6 @@ static void draw_getrect(t_gobj *z, t_glist *glist, int i, n = sa->x_nargs; t_fielddesc *f = sa->x_vec; int x1 = 0x7fffffff, x2 = -0x7fffffff, y1 = 0x7fffffff, y2 = -0x7fffffff; - if (!fielddesc_getfloat(&sa->x_vis.a_attr, template, data, 0) || - (sa->x_flags & NOMOUSE) || (sa->x_type == gensym("group"))) - { - *xp1 = *yp1 = 0x7fffffff; - *xp2 = *yp2 = -0x7fffffff; - return; - } svg_groupmtx(sa, template, data, mtx1); if (sa->x_type == gensym("path")) @@ -3592,6 +3724,70 @@ static t_gpointer draw_motion_gpointer; /* LATER protect against the template changing or the scalar disappearing probably by attaching a gpointer here ... */ +static void draw_motion(void *z, t_floatarg dx, t_floatarg dy) +{ + t_draw *x = (t_draw *)z; + t_svg *sa = (t_svg *)x->x_attr; + t_atom at[5]; + SETFLOAT(at+1, (t_float)dx); + SETFLOAT(at+2, (t_float)dy); + t_float mtx1[3][3]; + t_float mtx2[3][3]; + t_float m1, m2, m3, m4, m5, m6, tdx, tdy; + + /* might use this to output the ctm */ + svg_groupmtx(sa, draw_motion_template, draw_motion_wp, mtx1); + svg_parsetransform(sa, draw_motion_template, draw_motion_wp, + &m1, &m2, &m3, &m4, &m5, &m6); + mset(mtx2, m1, m2, m3, m4, m5, m6); + mmult(mtx1, mtx2, mtx1); + minv(mtx1, mtx1); + /* get rid of translation so it doesn't factor + in to our deltas */ + mtx1[0][2] = 0; + mtx1[1][2] = 0; + mset(mtx2, dx, dy, 0, 0, 0, 0); + mtx2[2][0] = 1; + mmult(mtx1, mtx2, mtx2); + tdx = mtx2[0][0]; + tdy = mtx2[1][0]; + SETFLOAT(at+3, tdx); + SETFLOAT(at+4, tdy); + t_fielddesc *f = sa->x_vec; //+ draw_motion_field; + if (!gpointer_check(&draw_motion_gpointer, 0)) + { + post("draw_motion: scalar disappeared"); + return; + } + draw_motion_xcumulative += dx; + draw_motion_ycumulative += dy; +// if (f->fd_var && (tdx != 0)) +// { +// fielddesc_setcoord(f, draw_motion_template, draw_motion_wp, +// draw_motion_xbase + draw_motion_xcumulative * draw_motion_xper, +// 1); +// } +// if ((f+1)->fd_var && (tdy != 0)) +// { +// fielddesc_setcoord(f+1, draw_motion_template, draw_motion_wp, +// draw_motion_ybase + draw_motion_ycumulative * draw_motion_yper, +// 1); +// } + /* LATER figure out what to do to notify for an array? */ + if (draw_motion_scalar) + { + template_notifyforscalar(draw_motion_template, draw_motion_glist, + draw_motion_scalar, gensym("change"), 1, at); + draw_notifyforscalar(x, draw_motion_glist, draw_motion_scalar, + gensym("drag"), 5, at); + } +// if (draw_motion_scalar) +// scalar_redraw(draw_motion_scalar, draw_motion_glist); +// if (draw_motion_array) +// array_redraw(draw_motion_array, draw_motion_glist); +} + +/* static void draw_motion(void *z, t_floatarg dx, t_floatarg dy) { t_draw *x = (t_draw *)z; @@ -3607,8 +3803,10 @@ static void draw_motion(void *z, t_floatarg dx, t_floatarg dy) mset(mtx2, m1, m2, m3, m4, m5, m6); mmult(mtx1, mtx2, mtx1); minv(mtx1, mtx1); + */ /* get rid of translation so it doesn't factor in to our deltas */ +/* mtx1[0][2] = 0; mtx1[1][2] = 0; mset(mtx2, dx, dy, 0, 0, 0, 0); @@ -3637,7 +3835,9 @@ static void draw_motion(void *z, t_floatarg dx, t_floatarg dy) draw_motion_ybase + draw_motion_ycumulative * draw_motion_yper, 1); } + */ /* LATER figure out what to do to notify for an array? */ + /* if (draw_motion_scalar) template_notifyforscalar(draw_motion_template, draw_motion_glist, draw_motion_scalar, gensym("change"), 1, &at); @@ -3646,12 +3846,94 @@ static void draw_motion(void *z, t_floatarg dx, t_floatarg dy) if (draw_motion_array) array_redraw(draw_motion_array, draw_motion_glist); } +*/ + +static int draw_click(t_gobj *z, t_glist *glist, + t_word *data, t_template *template, t_scalar *sc, t_array *ap, + t_float basex, t_float basey, + int xpix, int ypix, int shift, int alt, int dbl, int doit) +{ + //fprintf(stderr,"draw_click %f %f %d %d %g %g %lx\n", + // basex, basey, xpix, ypix, glist_xtopixels(glist, basex), + // glist_ytopixels(glist, basey), (t_int)data); + t_draw *x = (t_draw *)z; + t_svg *sa = (t_svg *)x->x_attr; + int x1, y1, x2, y2; + /* don't register a click if we don't have an event listener, or + if our pointer-event is "none" */ + if (!fielddesc_getfloat(&sa->x_pointerevents.a_attr, template, data, 1) || + (!fielddesc_getfloat(&sa->x_events.e_mousedown, template, data, 1) && + !fielddesc_getfloat(&sa->x_drag, template, data, 1))) + return 0; + draw_getrect(z, glist, data, template, basex, basey, + &x1, &y1, &x2, &y2); + if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2) + { + if (doit) + { + t_atom at[5]; + SETFLOAT(at+1, xpix - glist_xtopixels(glist, basex)); + SETFLOAT(at+2, ypix - glist_ytopixels(glist, basey)); + t_float mtx1[3][3]; + t_float mtx2[3][3]; + t_float m1, m2, m3, m4, m5, m6, tdx, tdy; + + t_svg *sa = (t_svg *)x->x_attr; + /* might use this to output the ctm */ + svg_groupmtx(sa, template, data, mtx1); + svg_parsetransform(sa, template, data, + &m1, &m2, &m3, &m4, &m5, &m6); + mset(mtx2, m1, m2, m3, m4, m5, m6); + mmult(mtx1, mtx2, mtx1); + minv(mtx1, mtx1); + /* get rid of translation so it doesn't factor + in to our deltas */ + // mtx1[0][2] = 0; + // mtx1[1][2] = 0; + /* maybe needs units per pixel here? */ + mset(mtx2, xpix - glist_xtopixels(glist, basex), + ypix - glist_ytopixels(glist, basey), 0, 0, 0, 0); + mtx2[2][0] = 1; + mmult(mtx1, mtx2, mtx2); + SETFLOAT(at+3, mtx2[0][0]); /* user-coordinate x */ + SETFLOAT(at+4, mtx2[1][0]); /* user-coordinate y */ + + if (fielddesc_getfloat(&sa->x_drag, template, data, 1)) + { + draw_motion_xper = glist_pixelstox(glist, 1) + - glist_pixelstox(glist, 0); + draw_motion_yper = glist_pixelstoy(glist, 1) + - glist_pixelstoy(glist, 0); + draw_motion_xcumulative = 0; + draw_motion_ycumulative = 0; + draw_motion_glist = glist; + draw_motion_scalar = sc; + draw_motion_array = ap; + draw_motion_wp = data; + // draw_motion_field = 2*bestn; + draw_motion_template = template; + if (draw_motion_scalar) + gpointer_setglist(&draw_motion_gpointer, draw_motion_glist, + &draw_motion_scalar->sc_gobj); + else gpointer_setarray(&draw_motion_gpointer, + draw_motion_array, draw_motion_wp); + glist_grab(glist, z, draw_motion, 0, xpix, ypix); + // outlet_anything(x->x_obj.ob_outlet, gensym("click"), 0, 0); + } + draw_notifyforscalar(x, glist, sc, gensym("mousedown"), 5, at); + } + return (1); + } + return (0); +} +/* static int draw_click(t_gobj *z, t_glist *glist, t_word *data, t_template *template, t_scalar *sc, t_array *ap, t_float basex, t_float basey, int xpix, int ypix, int shift, int alt, int dbl, int doit) { + post("hello?"); //fprintf(stderr,"draw_click %f %f %d %d %lx\n", // basex, basey, xpix, ypix, (t_int)data); t_draw *x = (t_draw *)z; @@ -3722,8 +4004,11 @@ static int draw_click(t_gobj *z, t_glist *glist, draw_motion_array, draw_motion_wp); glist_grab(glist, z, draw_motion, 0, xpix, ypix); } + post("we got clicked"); + outlet_anything(x->x_obj.ob_outlet, gensym("click"), 0, 0); return (1); } +*/ t_parentwidgetbehavior draw_widgetbehavior = { @@ -3779,12 +4064,20 @@ static void draw_setup(void) /* methods for svg_class-- these will be accessible from the inlet of [draw] and the (rightmost) inlet of [group] */ + /* I don't find anything in the spec that will render the + shape while turning off the bbox calculations-- i.e., something + like the "-n" flag of [drawcurve]. So I've introduced the + "bbox" method for this */ + class_addmethod(svg_class, (t_method)svg_bbox, + gensym("bbox"), A_GIMME, 0); class_addmethod(svg_class, (t_method)svg_ellipsepoints, gensym("cx"), A_GIMME, 0); class_addmethod(svg_class, (t_method)svg_ellipsepoints, gensym("cy"), A_GIMME, 0); class_addmethod(svg_class, (t_method)svg_data, gensym("data"), A_GIMME, 0); + class_addmethod(svg_class, (t_method)svg_drag, + gensym("drag"), A_GIMME, 0); class_addmethod(svg_class, (t_method)svg_fill, gensym("fill"), A_GIMME, 0); class_addmethod(svg_class, (t_method)svg_fillopacity, @@ -3793,6 +4086,10 @@ static void draw_setup(void) gensym("fill-rule"), A_GIMME, 0); class_addmethod(svg_class, (t_method)svg_rectpoints, gensym("height"), A_GIMME, 0); + class_addmethod(svg_class, (t_method)svg_event, + gensym("mousedown"), A_GIMME, 0); + class_addmethod(svg_class, (t_method)svg_pointerevents, + gensym("pointer-events"), A_GIMME, 0); class_addmethod(svg_class, (t_method)svg_data, gensym("points"), A_GIMME, 0); class_addmethod(svg_class, (t_method)svg_r, diff --git a/pd/src/g_traversal.c b/pd/src/g_traversal.c index 4e6aeef8c82b91f318ad929174b609a6d487c5b1..49488dd169d8074a249aa7fbacf32935014769d8 100644 --- a/pd/src/g_traversal.c +++ b/pd/src/g_traversal.c @@ -414,14 +414,19 @@ static void *get_new(t_symbol *why, int argc, t_atom *argv) t_get *x = (t_get *)pd_new(get_class); int i; t_getvariable *sp; + int varcount; x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv)); if (argc) argc--, argv++; + varcount = argc ? argc : 1; /* have at least one outlet */ x->x_variables - = (t_getvariable *)getbytes(argc * sizeof (*x->x_variables)); - x->x_nout = argc; - for (i = 0, sp = x->x_variables; i < argc; i++, sp++) + = (t_getvariable *)getbytes(varcount * sizeof (*x->x_variables)); + x->x_nout = varcount; + for (i = 0, sp = x->x_variables; i < varcount; i++, sp++) { - sp->gv_sym = atom_getsymbolarg(i, argc, argv); + if (argc) + sp->gv_sym = atom_getsymbolarg(i, argc, argv); + else + sp->gv_sym = &s_; /* just set field to empty symbol if no args */ sp->gv_outlet = outlet_new(&x->x_obj, 0); /* LATER connect with the template and set the outlet's type correctly. We can't yet guarantee that the template is there @@ -430,6 +435,20 @@ static void *get_new(t_symbol *why, int argc, t_atom *argv) return (x); } +static void get_set(t_get *x, t_symbol *templatesym, t_symbol *field) +{ + if (x->x_nout != 1) + { + pd_error(x, "get: cannot set multiple fields."); + return; + } + else + { + x->x_templatesym = canvas_makebindsym(templatesym); + x->x_variables->gv_sym = field; + } +} + static void get_pointer(t_get *x, t_gpointer *gp) { int nitems = x->x_nout, i; @@ -480,6 +499,8 @@ static void get_setup(void) get_class = class_new(gensym("get"), (t_newmethod)get_new, (t_method)get_free, sizeof(t_get), 0, A_GIMME, 0); class_addpointer(get_class, get_pointer); + class_addmethod(get_class, (t_method)get_set, gensym("set"), + A_SYMBOL, A_SYMBOL, 0); } /* ---------------------- set ----------------------------- */ @@ -507,6 +528,7 @@ static void *set_new(t_symbol *why, int argc, t_atom *argv) t_set *x = (t_set *)pd_new(set_class); int i; t_setvariable *sp; + int varcount; if (argc && (argv[0].a_type == A_SYMBOL) && !strcmp(argv[0].a_w.w_symbol->s_name, "-symbol")) { @@ -517,23 +539,24 @@ static void *set_new(t_symbol *why, int argc, t_atom *argv) else x->x_issymbol = 0; x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv)); if (argc) argc--, argv++; + varcount = argc ? argc : 1; /* have at least one variable */ x->x_variables - = (t_setvariable *)getbytes(argc * sizeof (*x->x_variables)); - x->x_nin = argc; - if (argc) + = (t_setvariable *)getbytes(varcount * sizeof (*x->x_variables)); + x->x_nin = varcount; + for (i = 0, sp = x->x_variables; i < varcount; i++, sp++) { - for (i = 0, sp = x->x_variables; i < argc; i++, sp++) - { + if (argc) sp->gv_sym = atom_getsymbolarg(i, argc, argv); + else + sp->gv_sym = &s_; + if (x->x_issymbol) + sp->gv_w.w_symbol = &s_; + else sp->gv_w.w_float = 0; + if (i) + { if (x->x_issymbol) - sp->gv_w.w_symbol = &s_; - else sp->gv_w.w_float = 0; - if (i) - { - if (x->x_issymbol) - symbolinlet_new(&x->x_obj, &sp->gv_w.w_symbol); - else floatinlet_new(&x->x_obj, &sp->gv_w.w_float); - } + symbolinlet_new(&x->x_obj, &sp->gv_w.w_symbol); + else floatinlet_new(&x->x_obj, &sp->gv_w.w_float); } } pointerinlet_new(&x->x_obj, &x->x_gp); @@ -541,6 +564,24 @@ static void *set_new(t_symbol *why, int argc, t_atom *argv) return (x); } +static void set_set(t_set *x, t_symbol *templatesym, t_symbol *field) +{ + if (x->x_nin != 1) + { + pd_error(x, "set: cannot set multiple fields."); + return; + } + else + { + x->x_templatesym = canvas_makebindsym(templatesym); + x->x_variables->gv_sym = field; + if (x->x_issymbol) + x->x_variables->gv_w.w_symbol = &s_; + else + x->x_variables->gv_w.w_float = 0; + } +} + static void set_bang(t_set *x) { int nitems = x->x_nin, i; @@ -621,6 +662,8 @@ static void set_setup(void) class_addfloat(set_class, set_float); class_addsymbol(set_class, set_symbol); class_addbang(set_class, set_bang); + class_addmethod(set_class, (t_method)set_set, gensym("set"), + A_SYMBOL, A_SYMBOL, 0); } /* ---------------------- elem ----------------------------- */ @@ -648,6 +691,12 @@ static void *elem_new(t_symbol *templatesym, t_symbol *fieldsym) return (x); } +static void elem_set(t_elem *x, t_symbol *templatesym, t_symbol *fieldsym) +{ + x->x_templatesym = canvas_makebindsym(templatesym); + x->x_fieldsym = fieldsym; +} + static void elem_float(t_elem *x, t_float f) { int indx = f, nitems, onset; @@ -720,6 +769,8 @@ static void elem_setup(void) elem_class = class_new(gensym("element"), (t_newmethod)elem_new, (t_method)elem_free, sizeof(t_elem), 0, A_DEFSYM, A_DEFSYM, 0); class_addfloat(elem_class, elem_float); + class_addmethod(elem_class, (t_method)elem_set, gensym("set"), + A_SYMBOL, A_SYMBOL, 0); } /* ---------------------- getsize ----------------------------- */ @@ -742,6 +793,12 @@ static void *getsize_new(t_symbol *templatesym, t_symbol *fieldsym) return (x); } +static void getsize_set(t_getsize *x, t_symbol *templatesym, t_symbol *fieldsym) +{ + x->x_templatesym = canvas_makebindsym(templatesym); + x->x_fieldsym = fieldsym; +} + static void getsize_pointer(t_getsize *x, t_gpointer *gp) { int onset, type; @@ -790,6 +847,8 @@ static void getsize_setup(void) getsize_class = class_new(gensym("getsize"), (t_newmethod)getsize_new, 0, sizeof(t_getsize), 0, A_DEFSYM, A_DEFSYM, 0); class_addpointer(getsize_class, getsize_pointer); + class_addmethod(getsize_class, (t_method)getsize_set, gensym("set"), + A_SYMBOL, A_SYMBOL, 0); } /* ---------------------- setsize ----------------------------- */ @@ -816,6 +875,12 @@ static void *setsize_new(t_symbol *templatesym, t_symbol *fieldsym, return (x); } +static void setsize_set(t_setsize *x, t_symbol *templatesym, t_symbol *fieldsym) +{ + x->x_templatesym = canvas_makebindsym(templatesym); + x->x_fieldsym = fieldsym; +} + static void setsize_float(t_setsize *x, t_float f) { int nitems, onset, type; @@ -944,6 +1009,9 @@ static void setsize_setup(void) (t_method)setsize_free, sizeof(t_setsize), 0, A_DEFSYM, A_DEFSYM, A_DEFFLOAT, 0); class_addfloat(setsize_class, setsize_float); + class_addmethod(setsize_class, (t_method)setsize_set, gensym("set"), + A_SYMBOL, A_SYMBOL, 0); + } /* ---------------------- append ----------------------------- */ @@ -970,19 +1038,21 @@ static void *append_new(t_symbol *why, int argc, t_atom *argv) t_append *x = (t_append *)pd_new(append_class); int i; t_appendvariable *sp; + int varcount; x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv)); if (argc) argc--, argv++; + varcount = argc ? argc : 1; /* have at least one variable */ x->x_variables - = (t_appendvariable *)getbytes(argc * sizeof (*x->x_variables)); - x->x_nin = argc; - if (argc) + = (t_appendvariable *)getbytes(varcount * sizeof (*x->x_variables)); + x->x_nin = varcount; + for (i = 0, sp = x->x_variables; i < argc; i++, sp++) { - for (i = 0, sp = x->x_variables; i < argc; i++, sp++) - { + if (argc) sp->gv_sym = atom_getsymbolarg(i, argc, argv); - sp->gv_f = 0; - if (i) floatinlet_new(&x->x_obj, &sp->gv_f); - } + else + sp->gv_sym = &s_; + sp->gv_f = 0; + if (i) floatinlet_new(&x->x_obj, &sp->gv_f); } pointerinlet_new(&x->x_obj, &x->x_gp); outlet_new(&x->x_obj, &s_pointer); @@ -990,6 +1060,21 @@ static void *append_new(t_symbol *why, int argc, t_atom *argv) return (x); } +static void append_set(t_append *x, t_symbol *templatesym, t_symbol *field) +{ + if (x->x_nin != 1) + { + pd_error(x, "set: cannot set multiple fields."); + return; + } + else + { + x->x_templatesym = canvas_makebindsym(templatesym); + x->x_variables->gv_sym = field; + x->x_variables->gv_f = 0; + } +} + static void append_float(t_append *x, t_float f) { int nitems = x->x_nin, i; @@ -1070,6 +1155,8 @@ static void append_setup(void) append_class = class_new(gensym("append"), (t_newmethod)append_new, (t_method)append_free, sizeof(t_append), 0, A_GIMME, 0); class_addfloat(append_class, append_float); + class_addmethod(append_class, (t_method)append_set, gensym("set"), + A_SYMBOL, A_SYMBOL, 0); } /* ---------------------- sublist ----------------------------- */ diff --git a/pd/src/x_interface.c b/pd/src/x_interface.c index 2e8ca71191d984d4fa9981536fa833dafe170764..50609462c2815c043877195f6d664647e56fbcf4 100644 --- a/pd/src/x_interface.c +++ b/pd/src/x_interface.c @@ -828,6 +828,21 @@ void pdinfo_gui(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv) info_out((t_text *)x, s, 1, at); } +/* note: this might be wrong. Not sure whether "libdir" means + something like /usr/lib/pd or the path where all the libdir externals + live-- i.e., /usr/lib/pd/extra */ +void pdinfo_libdir(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv) +{ + t_atom at[1]; + t_symbol *nsym; + t_namelist *nl = pd_extrapath; + while (nl->nl_next) + nl = nl->nl_next; + nsym = gensym(nl->nl_string); + SETSYMBOL(at, nsym); + info_out((t_text *)x, s, 1, at); +} + void pdinfo_version(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv) { int major=0, minor=0, bugfix=0; @@ -892,6 +907,8 @@ void pdinfo_setup(void) gensym("dsp-status"), A_GIMME, 0); class_addmethod(pdinfo_class, (t_method)pdinfo_gui, gensym("gui"), A_GIMME, 0); + class_addmethod(pdinfo_class, (t_method)pdinfo_libdir, + gensym("libdir"), A_GIMME, 0); class_addmethod(pdinfo_class, (t_method)pdinfo_midi_api, gensym("midi-api"), A_GIMME, 0); class_addmethod(pdinfo_class, (t_method)pdinfo_midi_apilist,