diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js index 41de49aed641786618325d1dd9d9b0820282ac7d..a9f5cbac0ff07ca5d99dcc5ea6a1cdc2e5f528c5 100644 --- a/pd/nw/pdgui.js +++ b/pd/nw/pdgui.js @@ -3760,6 +3760,7 @@ function gui_drawimage_vis(cid, x, y, obj, data, seqno, parent_tag) { len = image_array.length, i, image_container, + xy_container, obj_tag = "draw" + obj.slice(1) + "." + data.slice(1); if (len < 1) { return; @@ -3768,6 +3769,19 @@ function gui_drawimage_vis(cid, x, y, obj, data, seqno, parent_tag) { if (seqno >= len || seqno < 0) { seqno %= len; } + // Since sprites can have lots of images we don't want to + // set props on each one of them every time the user changes + // an attribute's value. So we use a "g" to receive all the + // relevant changes. + // Unfortunately "g" doesn't have x/y attys. So it can't propagate + // those values down to the child images. Thus we have to add + // another "g" as a parent and manually convert x/y changes + // the user makes to a transform. (And we can't use the inner g's + // transform because the user can set their own transform there.) + xy_container = create_item(cid, "g", { + id: obj_tag + "xy", + transform: "translate(" + x + "," + y + ")" + }); image_container = create_item(cid, "g", { id: obj_tag }); @@ -3784,7 +3798,8 @@ function gui_drawimage_vis(cid, x, y, obj, data, seqno, parent_tag) { image_array[i].data); image_container.appendChild(item); } - frag.appendChild(image_container); + xy_container.appendChild(image_container); + frag.appendChild(xy_container); // Hack to set correct width and height for (i = 0; i < len; i++) { img_size_setter(cid, obj_tag+i, pd_cache.get(obj)[i].type, @@ -3794,6 +3809,14 @@ function gui_drawimage_vis(cid, x, y, obj, data, seqno, parent_tag) { }); } +// Hack +function gui_drawimage_xy(cid, obj, data, x, y) { + var obj_tag = "draw" + obj.slice(1) + "." + data.slice(1); + gui(cid).get_elem(obj_tag + "xy", { + transform: "translate(" + x + "," + y + ")" + }); +} + function gui_drawimage_index(cid, obj, data, index) { var obj_tag = "draw" + obj.slice(1) + "." + data.slice(1); gui(cid).get_elem(obj_tag, function(image_container) { diff --git a/pd/src/g_template.c b/pd/src/g_template.c index 9e4997457c12d1b3371789dac66f0f55a731285c..f0dd2e4d5941b9ee1ee31a7b5e1c5c84556c15c1 100644 --- a/pd/src/g_template.c +++ b/pd/src/g_template.c @@ -1210,7 +1210,7 @@ typedef struct _draw typedef struct _drawimage { t_object x_obj; - t_fielddesc x_value; /* todo: rename to index */ + t_fielddesc x_index; t_fielddesc x_vis; t_symbol *x_img; t_float x_w; @@ -1964,6 +1964,18 @@ void svg_sendupdate(t_svg *x, t_canvas *c, t_symbol *s, gui_vmess("gui_drawimage_index", "xxxi", glist_getcanvas(c), parent, data, drawimage_getindex(parent, template, data)); } + else if (s == gensym("image_xy")) + { + /* Hack to deal with x/y for sprite/image. They have an extra + container so that we don't have to deal with changing each + image in the sequence here. */ + gui_vmess("gui_drawimage_xy", "xxxff", + glist_getcanvas(c), parent, data, + x->x_x.a_flag ? + fielddesc_getcoord(&x->x_x.a_attr, template, data, 0) : 0, + x->x_y.a_flag ? + fielddesc_getcoord(&x->x_y.a_attr, template, data, 0) : 0); + } else if (s == gensym("viewbox")) { gui_start_vmess("gui_draw_viewbox", "xss", @@ -3991,10 +4003,10 @@ static void svg_togui(t_svg *x, t_template *template, t_word *data) gui_f(fielddesc_getcoord(&x->x_rx.a_attr, template, data, 0)); } if (x->x_ry.a_flag) - { + { gui_s(x->x_type == gensym("ellipse") ? "ry" : "y2"); gui_f(fielddesc_getcoord(&x->x_ry.a_attr, template, data, 0)); - } + } if (x->x_x.a_flag) { gui_s(x->x_type == gensym("rect") || x->x_type == gensym("svg") ? "x" : @@ -8013,6 +8025,7 @@ static void *drawimage_new(t_symbol *classsym, int argc, t_atom *argv) x->x_flags = flags; x->x_attr = (t_pd *)sa; fielddesc_setfloat_const(&x->x_vis, 1); + fielddesc_setfloat_const(&x->x_index, 1); x->x_canvas = canvas_getcurrent(); t_symbol *dir = canvas_getdir(x->x_canvas); if (argc && argv->a_type == A_SYMBOL) @@ -8026,11 +8039,12 @@ static void *drawimage_new(t_symbol *classsym, int argc, t_atom *argv) /* outlet for event notifications */ outlet_new(&x->x_obj, &s_anything); - /* [drawimage] allocates memory for an image or image sequence - while the object is creating. The corresponding scalar gets - drawn as a canvas image item using the "parent" tk image as - the source. ".x%lx" is the name for the parent tk image and - ".x%lx.i" is the tag given to a scalar's canvas image item. + /* [drawimage] allocates memory for an image or image sequence in + the GUI. When we "vis" the scalar we fetch the data from the + loaded images in the sequence. Then we can change the image shown + by just sending an index to the GUI where it displays that particular + image in the sequence without having to touch I/O or even parse + image data and render a new image. */ gui_vmess("gui_drawimage_new", "xssi", x, @@ -8044,13 +8058,12 @@ void drawimage_size(t_drawimage *x, t_float w, t_float h) { x->x_w = w; x->x_h = h; - //post("w is %g and h is %g", w, h); } static int drawimage_getindex(void *z, t_template *template, t_word *data) { t_drawimage *x = (t_drawimage *)z; - int index = (int)fielddesc_getcoord(&x->x_value, template, data, 1); + int index = (int)fielddesc_getcoord(&x->x_index, template, data, 1); return (index); } @@ -8063,7 +8076,7 @@ static void drawimage_index(t_drawimage *x, t_symbol *s, int argc, if (!(x->x_flags & DRAW_SPRITE)) post("drawimage warning: sequence variable is only " "used with drawsprite"); - fielddesc_setfloatarg(&x->x_value, argc, argv); + fielddesc_setfloatarg(&x->x_index, argc, argv); svg_update((t_svg *)x->x_attr, gensym("index")); } } @@ -8089,19 +8102,30 @@ void drawimage_symbol(t_drawimage *x, t_symbol *s) attributes to the parent <g> for convenience, but <g> has no x/y atty. We could just forward everything to the child <image> element, but that - could get clunky when dealing with large image sequences. So for now we - just disallow setting the x/y with the knowledge that the user can get - the same functionality using a transform. */ -static void drawimage_x(t_drawimage *x, t_symbol *s, int argc, - t_atom *argv) -{ - pd_error(x, "draw: x attribute for image type not supported"); -} + could get clunky when dealing with large image sequences. -static void drawimage_y(t_drawimage *x, t_symbol *s, int argc, + So for now we hack around this by adding a <g> above our parent <g>, then + converting the x/y in the GUI to a transform for that <g>. This is ugly + and gets in the way of the interface built here, but it should work. +*/ +static void drawimage_xy(t_drawimage *x, t_symbol *s, int argc, t_atom *argv) { - pd_error(x, "draw: y attribute for image type not supported"); + t_svg *sa = (t_svg *)x->x_attr; + t_svg_attr *attr = svg_getattr(sa, s); + if (!attr) + { + pd_error(x, "draw: can't find attribute %s", s->s_name); + return; + } + if (argc < 1) + attr->a_flag = 0; + else if (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL) + { + fielddesc_setfloatarg(&attr->a_attr, argc, argv); + attr->a_flag = 1; + svg_update(sa, gensym("image_xy")); + } } static void drawimage_anything(t_drawimage *x, t_symbol *s, int argc, @@ -8262,7 +8286,7 @@ static void drawimage_vis(t_gobj *z, t_glist *glist, t_glist *parentglist, yloc, x, data, - (int)fielddesc_getfloat(&x->x_value, template, data, 0), + (int)fielddesc_getfloat(&x->x_index, template, data, 0), parent_tagbuf); gui_start_vmess("gui_draw_configure_all", "xs", @@ -8296,7 +8320,7 @@ static void drawimage_motion(void *z, t_floatarg dx, t_floatarg dy) { t_drawimage *x = (t_drawimage *)z; t_svg *sa = (t_svg *)x->x_attr; - t_fielddesc *f = &x->x_value; + t_fielddesc *f = &x->x_index; t_atom at; if (!gpointer_check(&drawimage_motion_gpointer, 0)) { @@ -8408,7 +8432,7 @@ static int drawimage_click(t_gobj *z, t_glist *glist, data, template, basex, basey, &x1, &y1, &x2, &y2); if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2 - && x->x_value.fd_var && + && x->x_index.fd_var && fielddesc_getfloat(&x->x_vis, template, data, 0)) { if (doit) @@ -8420,7 +8444,7 @@ static int drawimage_click(t_gobj *z, t_glist *glist, drawimage_motion_array = ap; drawimage_motion_firstkey = 1; drawimage_motion_ycumulative = - fielddesc_getfloat(&x->x_value, template, data, 0); + fielddesc_getfloat(&x->x_index, template, data, 0); drawimage_motion_sprite = ((x->x_flags & DRAW_SPRITE) != 0); if (drawimage_motion_scalar) gpointer_setglist(&drawimage_motion_gpointer, @@ -8457,15 +8481,12 @@ static void drawimage_free(t_drawimage *x) static void drawimage_setup(void) { - /* we need drawimage_class in order to get - a different set of widget behavior than - draw_class. But we also want to use the - [draw shape] syntax for consistency. So - for class_new we set the constructor to - zero and call drawimage_new from inside - draw_new. This way the user has to type - "draw image" or "draw sprite" to create - the objects. */ + /* we need drawimage_class in order to get a different set of + widget behavior than draw_class. But we also want to use the + [draw shape] syntax for consistency. So for class_new we set + the constructor to zero and call drawimage_new from inside + draw_new. This way the user has to type "draw image" or "draw sprite" + to create the objects. */ drawimage_class = class_new(gensym("drawimage"), 0, (t_method)drawimage_free, sizeof(t_drawimage), 0, A_GIMME, 0); @@ -8476,9 +8497,9 @@ static void drawimage_setup(void) gensym("size"), A_FLOAT, A_FLOAT, 0); class_addmethod(drawimage_class, (t_method)drawimage_index, gensym("index"), A_GIMME, 0); - class_addmethod(drawimage_class, (t_method)drawimage_x, + class_addmethod(drawimage_class, (t_method)drawimage_xy, gensym("x"), A_GIMME, 0); - class_addmethod(drawimage_class, (t_method)drawimage_y, + class_addmethod(drawimage_class, (t_method)drawimage_xy, gensym("y"), A_GIMME, 0); class_addanything(drawimage_class, drawimage_anything); class_setparentwidget(drawimage_class, &drawimage_widgetbehavior); @@ -8589,6 +8610,12 @@ void svg_parentwidgettogui(t_gobj *z, t_scalar *sc, t_glist *owner, gui_vmess("gui_drawimage_index", "xxxi", glist_getcanvas(owner), x, data, drawimage_getindex(x, template, data)); + gui_vmess("gui_drawimage_xy", "xxxff", + glist_getcanvas(owner), x, data, + fielddesc_getcoord(&((t_svg *)x->x_attr)->x_x.a_attr, + template, data, 0), + fielddesc_getcoord(&((t_svg *)x->x_attr)->x_y.a_attr, + template, data, 0)); } else if (pd_class(&z->g_pd) == curve_class) {