diff --git a/pd/src/g_template.c b/pd/src/g_template.c index 72005e4ca44fa9e76447c85da5bf11df953e6291..c2b41e2c715c0d2f7b20104e3b83f748f6fa68c8 100644 --- a/pd/src/g_template.c +++ b/pd/src/g_template.c @@ -797,6 +797,7 @@ static void fielddesc_setfloat_var(t_fielddesc *fd, t_symbol *s) #define CLOSED 1 #define BEZ 2 #define NOMOUSE 4 +#define BBOX 8 /* pair of coords for rectangles and ellipses */ #define A_ARRAY 55 /* LATER decide whether to enshrine this in m_pd.h */ static void fielddesc_setfloatarg(t_fielddesc *fd, int argc, t_atom *argv) @@ -964,6 +965,7 @@ typedef struct _curve t_object x_obj; int x_flags; /* CLOSED and/or BEZ and/or NOMOUSE */ t_fielddesc x_fillcolor; + t_fielddesc x_fillopacity; t_fielddesc x_outlinecolor; t_fielddesc x_width; t_fielddesc x_vis; @@ -986,7 +988,8 @@ static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv) flags |= CLOSED; } else classname += 4; - if (classname[0] == 'c') flags |= BEZ; + if (classname[0] == 'c' || classname[0] == 'e') flags |= BEZ; + if (classname[0] == 'e' || classname[0] == 'r') flags |= BBOX; fielddesc_setfloat_const(&x->x_vis, 1); while (1) { @@ -1018,7 +1021,7 @@ static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv) for (i = 0, fd = x->x_vec; i < argc; i++, fd++, argv++) fielddesc_setfloatarg(fd, 1, argv); if (argc & 1) fielddesc_setfloat_const(fd, 0); - + fielddesc_setfloat_const(&x->x_fillopacity, 1); return (x); } @@ -1039,6 +1042,17 @@ void curve_float(t_curve *x, t_floatarg f) canvas_redrawallfortemplatecanvas(x->x_canvas, 1); } +void curve_fillopacity(t_curve *x, t_symbol *s, t_int argc, t_atom *argv) +{ + char *classname = s->s_name; + if (classname[0] == 'd' || argc < 1) return; + if (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL) + { + fielddesc_setfloatarg(&x->x_fillopacity, argc, argv); + canvas_redrawallfortemplatecanvas(x->x_canvas, 0); + } +} + /* -------------------- widget behavior for curve ------------ */ static void curve_getrect(t_gobj *z, t_glist *glist, @@ -1067,6 +1081,23 @@ static void curve_getrect(t_gobj *z, t_glist *glist, if (xloc > x2) x2 = xloc; if (yloc < y1) y1 = yloc; if (yloc > y2) y2 = yloc; + } + if ((x->x_flags & BEZ) && (x->x_flags & BBOX)) + { + int cx = glist_xtopixels(glist, + basex + fielddesc_getcoord(x->x_vec, template, + data, 0)); + int cy = glist_ytopixels(glist, + basey + fielddesc_getcoord(x->x_vec+1, template, + data, 0)); + int rx = fielddesc_getfloat(x->x_vec+2, template, + data, 0); + int ry = fielddesc_getfloat(x->x_vec+3, template, + data, 0); + x1 = cx - rx; + y1 = cy - ry; + x2 = cx + rx; + y2 = cy + ry; } //fprintf(stderr,"FINAL curve_getrect %d %d %d %d\n", x1, y1, x2, y2); *xp1 = x1; @@ -1172,17 +1203,52 @@ static void curve_vis(t_gobj *z, t_glist *glist, numbertocolor( fielddesc_getfloat(&x->x_fillcolor, template, data, 1), fill); - sys_vgui(".x%lx.c create ppolygon\\\n", - glist_getcanvas(glist)); + if (flags & CLOSED && !(flags & BBOX)) + { + sys_vgui(".x%lx.c create ppolygon\\\n", + glist_getcanvas(glist)); + } + else if (flags & BBOX) /* rectangles and ellipses */ + { + n = 2; /* silently truncate extra coordinates */ + if(flags & BEZ) + sys_vgui(".x%lx.c create ellipse\\\n", + glist_getcanvas(glist)); + else + sys_vgui(".x%lx.c create prect\\\n", + glist_getcanvas(glist)); + } + } + else + { + if(flags & BBOX) + { + if(flags & BEZ) + sys_vgui(".x%lx.c create ellipse\\\n", glist_getcanvas(glist)); + else + sys_vgui(".x%lx.c create prect\\\n", glist_getcanvas(glist)); + } else + sys_vgui(".x%lx.c create polyline\\\n", glist_getcanvas(glist)); } - else sys_vgui(".x%lx.c create polyline\\\n", glist_getcanvas(glist)); for (i = 0; i < n; i++) + { sys_vgui("%d %d\\\n", pix[2*i], pix[2*i+1]); + if ((flags & BEZ) && (flags & BBOX)) + { + sys_vgui("-rx %d -ry %d\\\n", + (t_int)fielddesc_getfloat(x->x_vec+2, + template, data, 1), + (t_int)fielddesc_getfloat(x->x_vec+3, + template, data, 1)); + break; + } + } sys_vgui("-strokewidth %f\\\n", width); - if (flags & CLOSED) sys_vgui("-fill %s -stroke %s\\\n", - fill, outline); + if (flags & CLOSED) sys_vgui("-fill %s -stroke %s -fillopacity %g\\\n", + fill, outline, fielddesc_getfloat(&x->x_fillopacity, template, data, 1)); + else if(flags & BBOX) sys_vgui("-stroke %s\\\n", outline); else sys_vgui("-stroke %s\\\n", outline); - //if (flags & BEZ) sys_vgui("-smooth 1\\\n"); //this doesn't work with tkpath + //if ((flags & BEZ) && !(flags & BBOX)) sys_vgui("-smooth 1\\\n"); //this doesn't work with tkpath sys_vgui("-tags {.x%lx.x%lx.template%lx}\n", glist_getcanvas(glist), glist, data); if (!glist_istoplevel(glist)) { @@ -1344,8 +1410,18 @@ static void curve_setup(void) A_GIMME, 0); class_addcreator((t_newmethod)curve_new, gensym("filledcurve"), A_GIMME, 0); + class_addcreator((t_newmethod)curve_new, gensym("drawrectangle"), + A_GIMME, 0); + class_addcreator((t_newmethod)curve_new, gensym("filledrectangle"), + A_GIMME, 0); + class_addcreator((t_newmethod)curve_new, gensym("drawellipse"), + A_GIMME, 0); + class_addcreator((t_newmethod)curve_new, gensym("filledellipse"), + A_GIMME, 0); class_setparentwidget(curve_class, &curve_widgetbehavior); class_addfloat(curve_class, curve_float); + class_addmethod(curve_class, (t_method)curve_fillopacity, + gensym("fillopacity"), A_GIMME, 0); } /* --------- plots for showing arrays --------------- */ @@ -2764,6 +2840,381 @@ static void drawsymbol_setup(void) class_setparentwidget(drawsymbol_class, &drawsymbol_widgetbehavior); } +/* ---------------- drawimage: draw an image ---------------- */ +/* ---------------- drawsprite: draw a sprite ---------------- */ + +/* + drawimage draws an image (gif) at controllable locations. + invocation: + (drawimage|drawsprite) [-v <visible>] variable x y directory +*/ + +t_class *drawimage_class; + +#define DRAW_SPRITE 1 + +typedef struct _drawimage +{ + t_object x_obj; + t_fielddesc x_value; + t_fielddesc x_xloc; + t_fielddesc x_yloc; + t_fielddesc x_vis; + t_symbol *x_img; + t_float x_w; + t_float x_h; + int x_flags; + t_canvas *x_canvas; +} t_drawimage; + +static void *drawimage_new(t_symbol *classsym, t_int argc, t_atom *argv) +{ + t_drawimage *x = (t_drawimage *)pd_new(drawimage_class); + char *classname = classsym->s_name; + char buf[50]; + sprintf(buf, ".x%lx", (t_int)x); + pd_bind(&x->x_obj.ob_pd, gensym(buf)); + int flags = 0; + + if (classname[4] == 's') + flags |= DRAW_SPRITE; + x->x_flags = flags; + fielddesc_setfloat_const(&x->x_vis, 1); + x->x_canvas = canvas_getcurrent(); + t_symbol *dir = canvas_getdir(x->x_canvas); + while (1) + { + t_symbol *firstarg = atom_getsymbolarg(0, argc, argv); + if (!strcmp(firstarg->s_name, "-v") && argc > 1) + { + fielddesc_setfloatarg(&x->x_vis, 1, argv+1); + argc -= 2; argv += 2; + } + else break; + } + if (argc && argv->a_type == A_SYMBOL) + x->x_img = atom_getsymbolarg(0, argc--, argv++); + else x->x_img = &s_; + if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++); + else fielddesc_setfloat_const(&x->x_xloc, 0); + if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++); + else fielddesc_setfloat_const(&x->x_yloc, 0); + if (argc) + { + fielddesc_setfloatarg(&x->x_value, argc--, argv++); + if (!(x->x_flags & DRAW_SPRITE)) + post("drawimage warning: sequence variable is only " + "used with drawsprite"); + } + else fielddesc_setfloat_const(&x->x_value, 0); + + /* [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. + */ + sys_vgui("pdtk_drawimage_new .x%lx {%s} {%s} %d\n", (t_int)x, + x->x_img->s_name, dir->s_name, x->x_flags); + return (x); +} + +void drawimage_float(t_drawimage *x, t_floatarg f) +{ + int viswas; + if (x->x_vis.fd_type != A_FLOAT || x->x_vis.fd_var) + { + pd_error(x, "global vis/invis for a template with variable visibility"); + return; + } + viswas = (x->x_vis.fd_un.fd_float != 0); + + if ((f != 0 && viswas) || (f == 0 && !viswas)) + return; + canvas_redrawallfortemplatecanvas(x->x_canvas, 2); + fielddesc_setfloat_const(&x->x_vis, (f != 0)); + canvas_redrawallfortemplatecanvas(x->x_canvas, 1); +} + +void drawimage_size(t_drawimage *x, t_float w, t_float h) +{ + x->x_w = w; + x->x_h = h; +} + +/* -------------------- widget behavior for drawimage ------------ */ + + +/* +static void drawimage_sprintf(t_drawimage *x, char *buf, t_atom *ap) +{ + int nchars; + strncpy(buf, x->x_label->s_name, MAXPDSTRING); + buf[DRAWNUMBER_BUFSIZE - 1] = 0; + nchars = strlen(buf); + atom_string(ap, buf + nchars, DRAWNUMBER_BUFSIZE - nchars); +} +*/ + + +static void drawimage_getrect(t_gobj *z, t_glist *glist, + t_word *data, t_template *template, t_float basex, t_float basey, + int *xp1, int *yp1, int *xp2, int *yp2) +{ + t_drawimage *x = (t_drawimage *)z; + int xloc, yloc; +// char buf[DRAWNUMBER_BUFSIZE]; + + if (!fielddesc_getfloat(&x->x_vis, template, data, 0)) + { + *xp1 = *yp1 = 0x7fffffff; + *xp2 = *yp2 = -0x7fffffff; + return; + } + xloc = glist_xtopixels(glist, + basex + fielddesc_getcoord(&x->x_xloc, template, data, 0)); + yloc = glist_ytopixels(glist, + basey + fielddesc_getcoord(&x->x_yloc, template, data, 0)); + *xp1 = xloc; + *yp1 = yloc; + + *xp2 = xloc + x->x_w; + *yp2 = yloc + x->x_h; +} + +static void drawimage_displace(t_gobj *z, t_glist *glist, + t_word *data, t_template *template, t_float basex, t_float basey, + int dx, int dy) +{ + /* refuse */ +} + +static void drawimage_select(t_gobj *z, t_glist *glist, + t_word *data, t_template *template, t_float basex, t_float basey, + int state) +{ + post("drawimage_select %d", state); + /* fill in later */ +} + +static void drawimage_activate(t_gobj *z, t_glist *glist, + t_word *data, t_template *template, t_float basex, t_float basey, + int state) +{ + post("drawimage_activate %d", state); +} + +static void drawimage_vis(t_gobj *z, t_glist *glist, + t_word *data, t_template *template, t_float basex, t_float basey, + int vis) +{ + t_drawimage *x = (t_drawimage *)z; + + /* see comment in plot_vis() */ + if (vis && !fielddesc_getfloat(&x->x_vis, template, data, 0)) + return; + if (vis) + { + t_atom at; + int xloc = glist_xtopixels(glist, + basex + fielddesc_getcoord(&x->x_xloc, template, data, 0)); + int yloc = glist_ytopixels(glist, + basey + fielddesc_getcoord(&x->x_yloc, template, data, 0)); + sys_vgui("pdtk_drawimage_vis .x%lx.c %d %d .x%lx .x%lx.i %d ", + glist_getcanvas(glist), xloc, yloc, x, data, + (int)fielddesc_getfloat(&x->x_value, template, data, 0)); + sys_vgui(".x%lx.x%lx.template%lx\n", glist_getcanvas(glist), + glist, data); + } + else sys_vgui("pdtk_drawimage_unvis .x%lx.c .x%lx.i\n", + glist_getcanvas(glist), data); +} + +static t_float drawimage_motion_ycumulative; +static t_glist *drawimage_motion_glist; +static t_scalar *drawimage_motion_scalar; +static t_array *drawimage_motion_array; +static t_word *drawimage_motion_wp; +static t_template *drawimage_motion_template; +static t_gpointer drawimage_motion_gpointer; +static int drawimage_motion_sprite; +static int drawimage_motion_firstkey; + + /* LATER protect against the template changing or the scalar disappearing + probably by attaching a gpointer here ... */ + +static void drawimage_motion(void *z, t_floatarg dx, t_floatarg dy) +{ + t_drawimage *x = (t_drawimage *)z; + t_fielddesc *f = &x->x_value; + t_atom at; + if (!gpointer_check(&drawimage_motion_gpointer, 0)) + { + post("drawimage_motion: scalar disappeared"); + return; + } + if (!drawimage_motion_sprite) + { + /* post("drawimage_motion: image"); */ + return; + } + drawimage_motion_ycumulative -= dy; + template_setfloat(drawimage_motion_template, + f->fd_un.fd_varsym, + drawimage_motion_wp, + drawimage_motion_ycumulative, + 1); + if (drawimage_motion_scalar) + template_notifyforscalar(drawimage_motion_template, + drawimage_motion_glist, drawimage_motion_scalar, + gensym("change"), 1, &at); + + if (drawimage_motion_scalar) + scalar_redraw(drawimage_motion_scalar, drawimage_motion_glist); + if (drawimage_motion_array) + array_redraw(drawimage_motion_array, drawimage_motion_glist); +} + +static void drawimage_key(void *z, t_floatarg fkey) +{ + return; + t_drawnumber *x = (t_drawnumber *)z; + t_fielddesc *f = &x->x_value; + int key = fkey; + char sbuf[MAXPDSTRING]; + t_atom at; + if (!gpointer_check(&drawnumber_motion_gpointer, 0)) + { + post("drawnumber_motion: scalar disappeared"); + return; + } + if (key == 0) + return; + if (drawnumber_motion_symbol) + { + /* key entry for a symbol field */ + if (drawnumber_motion_firstkey) + sbuf[0] = 0; + else strncpy(sbuf, template_getsymbol(drawnumber_motion_template, + f->fd_un.fd_varsym, drawnumber_motion_wp, 1)->s_name, + MAXPDSTRING); + sbuf[MAXPDSTRING-1] = 0; + if (key == '\b') + { + if (*sbuf) + sbuf[strlen(sbuf)-1] = 0; + } + else + { + sbuf[strlen(sbuf)+1] = 0; + sbuf[strlen(sbuf)] = key; + } + } + else + { + /* key entry for a numeric field. This is just a stopgap. */ + double newf; + if (drawnumber_motion_firstkey) + sbuf[0] = 0; + else sprintf(sbuf, "%g", template_getfloat(drawnumber_motion_template, + f->fd_un.fd_varsym, drawnumber_motion_wp, 1)); + drawnumber_motion_firstkey = (key == '\n'); + if (key == '\b') + { + if (*sbuf) + sbuf[strlen(sbuf)-1] = 0; + } + else + { + sbuf[strlen(sbuf)+1] = 0; + sbuf[strlen(sbuf)] = key; + } + if (sscanf(sbuf, "%lg", &newf) < 1) + newf = 0; + template_setfloat(drawnumber_motion_template, + f->fd_un.fd_varsym, drawnumber_motion_wp, (t_float)newf, 1); + if (drawnumber_motion_scalar) + template_notifyforscalar(drawnumber_motion_template, + drawnumber_motion_glist, drawnumber_motion_scalar, + gensym("change"), 1, &at); + if (drawnumber_motion_scalar) + scalar_redraw(drawnumber_motion_scalar, drawnumber_motion_glist); + if (drawnumber_motion_array) + array_redraw(drawnumber_motion_array, drawnumber_motion_glist); + } +} + +static int drawimage_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) +{ + t_drawimage *x = (t_drawimage *)z; + int x1, y1, x2, y2; + drawimage_getrect(z, glist, + data, template, basex, basey, + &x1, &y1, &x2, &y2); + if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2 + && x->x_value.fd_var && + fielddesc_getfloat(&x->x_vis, template, data, 0)) + { + if (doit) + { + drawimage_motion_glist = glist; + drawimage_motion_wp = data; + drawimage_motion_template = template; + drawimage_motion_scalar = sc; + drawimage_motion_array = ap; + drawimage_motion_firstkey = 1; + drawimage_motion_ycumulative = + fielddesc_getfloat(&x->x_value, template, data, 0); + drawimage_motion_sprite = ((x->x_flags & DRAW_SPRITE) != 0); + if (drawimage_motion_scalar) + gpointer_setglist(&drawimage_motion_gpointer, + drawimage_motion_glist, drawimage_motion_scalar); + else gpointer_setarray(&drawimage_motion_gpointer, + drawimage_motion_array, drawimage_motion_wp); + glist_grab(glist, z, drawimage_motion, drawimage_key, + xpix, ypix); + } + return (1); + } + else return (0); +} + +t_parentwidgetbehavior drawimage_widgetbehavior = +{ + drawimage_getrect, + drawimage_displace, + drawimage_select, + drawimage_activate, + drawimage_vis, + drawimage_click, +}; + +static void drawimage_free(t_drawimage *x) +{ + /* delete the parent image in the gui */ + char buf[50]; + sprintf(buf, ".x%lx", (t_int)x); + pd_unbind(&x->x_obj.ob_pd, gensym(buf)); + sys_vgui("pdtk_drawimage_free .x%lx\n", (t_int)x); +} + +static void drawimage_setup(void) +{ + drawimage_class = class_new(gensym("drawimage"), + (t_newmethod)drawimage_new, (t_method)drawimage_free, + sizeof(t_drawimage), 0, A_GIMME, 0); + class_setdrawcommand(drawimage_class); + class_addfloat(drawimage_class, drawimage_float); + class_addmethod(drawimage_class, (t_method)drawimage_size, + gensym("size"), A_FLOAT, A_FLOAT, 0); + class_addcreator((t_newmethod)drawimage_new, gensym("drawsprite"), + A_GIMME, 0); + class_setparentwidget(drawimage_class, &drawimage_widgetbehavior); +} + /* ---------------------- setup function ---------------------------- */ void g_template_setup(void) @@ -2773,6 +3224,7 @@ void g_template_setup(void) curve_setup(); plot_setup(); drawnumber_setup(); - drawsymbol_setup(); + drawsymbol_setup(); + drawimage_setup(); } diff --git a/pd/src/pd.tk b/pd/src/pd.tk index 082c61d696da6e4d394a92dba51bdf84526a0cb0..cb6284da197c024334e76588302ec6cbf7ddb716 100644 --- a/pd/src/pd.tk +++ b/pd/src/pd.tk @@ -9013,4 +9013,8 @@ proc pdtk_check_unique {unique filenames} { #puts stderr "this is unique instance [tk appname]" } +# Search plugin source [file join [file dirname [info script]] search-plugin.tcl] + +# Tcl/tk code for drawimage and drawsprite +source [file join [file dirname [info script]] pdtk_drawimage.tcl] diff --git a/pd/src/pdtk_drawimage.tcl b/pd/src/pdtk_drawimage.tcl new file mode 100644 index 0000000000000000000000000000000000000000..d8b2e9a3bfa3a78456f694c6c9b7d71e0ca4b2ba --- /dev/null +++ b/pd/src/pdtk_drawimage.tcl @@ -0,0 +1,88 @@ +#todo: rename img to imgprefix + +# package provide pdtk_drawimage 0.1 +# package require tkpng + +namespace eval ::pdtk_drawimage:: { + namespace export pdtk_drawimage_new + namespace export pdtk_drawimage_vis +} + +# Some GUI procs for [drawimage] and [drawsprite] + +# Draw an image +proc pdtk_drawimage_new {obj path canvasdir flags} { + set drawsprite 1 + set image_seq [expr {$flags & $drawsprite}] + # obj - .x%lx name for [drawimage] instance + # path - this is absolute or relative + # for [drawsprite] this is the directory of the image sequence + # for [drawimage] this is the file path of the image + # canvasdir - relative paths should be relative to this + # (any other possibilities?) + set i 0 + set matchchar * + # this will discard $canvasdir for absolute paths, which is nice + set path [file normalize [file join $canvasdir $path]] + if {[file isdir $path]} { + # put a final directory separator for a dir + set path [string trimright [file join $path { }]] + } else { + # if it's a file we don't want a wildcard character + set matchchar {} + } + if {![file exists $path]} { + pdtk_post "drawimage: warning: path doesn't exist: $path\n" + pd [concat $obj size 1 1 \;] + return + } + foreach filename [lsort -dictionary [glob -nocomplain -type {f r} \ + -path $path $matchchar]] { + if {[file extension $filename] eq ".gif" || + [file extension $filename] eq ".png"} { + image create photo ::drawimage_${obj}$i -file "$filename" + pdtk_post "image is ::drawimage_${obj}$i\n" + incr i + } + if {$i > 1000 || !$image_seq} {break} + } + pdtk_post "no of files: $i\n" + # we bound a symbol to $img in drawimage_new, so we + # can send back a message with the image dimensions + # to be used for the selection bbox. This is dumb-- + # pd has no business handling a gui issue like size + # of a selection rectangle. That's what Tk is for. + # But that's a bigger issue to be dealt with later. + if {$i > 0} { + pdtk_post "image width is [image width ::drawimage_${obj}0]\n" + pdtk_post "image height is [image height ::drawimage_${obj}0]\n" + pdtk_post "obj is $obj\n" + pd [concat $obj size [image width ::drawimage_${obj}0] \ + [image height ::drawimage_${obj}0] \;] + } else { + pdtk_post "drawimage: warning: no images loaded" + } +} + +proc pdtk_drawimage_vis {c x y obj tag seqno l2orktag} { + set img ::drawimage_${obj} + set len [llength [lsearch -glob -all [image names] ${img}*]] + if {$len < 1} {return} + if {$seqno >= $len || $seqno < 0} {set seqno [expr {$seqno % $len}]} + $c create image $x $y -image ${img}$seqno -anchor nw -tags [list $tag $l2orktag] +} + +proc pdtk_drawimage_unvis {c tag} { + $c delete $tag +} + +proc pdtk_drawimage_free {img} { +# image delete [lsearch -glob -all -inline [image names] ::drawimage_${img}*] + + foreach globalimage [image names] { + if {[lsearch -glob $globalimage ::drawimage_${img}*] != -1} { + image delete $globalimage + pdtk_post "Deleted $globalimage\n" + } + } +}