/* Copyright (c) 1997-2001 Miller Puckette and others. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ /* this file defines the "glist" class, also known as "canvas" (the two used to be different but are now unified except for some fossilized names.) */ #include #include #include "m_pd.h" #include "m_imp.h" #include "s_stuff.h" #include "g_magicglass.h" #include "g_canvas.h" #include "g_all_guis.h" #include extern int do_not_redraw; extern void canvas_drawconnection(t_canvas *x, int lx1, int ly1, int lx2, int ly2, t_int tag, int issignal); extern void canvas_updateconnection(t_canvas *x, int lx1, int ly1, int lx2, int ly2, t_int tag); /* LATER consider adding font size to this struct (see glist_getfont()) */ struct _canvasenvironment { t_symbol *ce_dir; /* directory patch lives in */ int ce_argc; /* number of "$" arguments */ t_atom *ce_argv; /* array of "$" arguments */ int ce_dollarzero; /* value of "$0" */ t_namelist *ce_path; /* search path */ }; #define GLIST_DEFCANVASWIDTH 450 #define GLIST_DEFCANVASHEIGHT 300 #ifdef __APPLE__ #define GLIST_DEFCANVASYLOC 22 #else #define GLIST_DEFCANVASYLOC 0 #endif /* ---------------------- variables --------------------------- */ extern t_pd *newest; t_class *canvas_class; int canvas_dspstate; /* whether DSP is on or off */ t_canvas *canvas_editing; /* last canvas to start text edting */ t_canvas *canvas_whichfind; /* last canvas we did a find in */ t_canvas *canvas_list; /* list of all root canvases */ /* ------------------ forward function declarations --------------- */ static void canvas_start_dsp(void); static void canvas_stop_dsp(void); static void canvas_drawlines(t_canvas *x); void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2); void canvas_reflecttitle(t_canvas *x); static void canvas_addtolist(t_canvas *x); static void canvas_takeofflist(t_canvas *x); static void canvas_pop(t_canvas *x, t_floatarg fvis); static int canvas_should_bind(t_canvas *x); static void canvas_bind(t_canvas *x); static void canvas_unbind(t_canvas *x); /* --------- functions to handle the canvas environment ----------- */ static t_symbol *canvas_newfilename = &s_; static t_symbol *canvas_newdirectory = &s_; static int canvas_newargc; static t_atom *canvas_newargv; static void glist_doupdatewindowlist(t_glist *gl, char *sbuf) { t_gobj *g; if (glist_amreloadingabstractions) /* not if we're in a reload */ return; if (!gl->gl_owner) { /* this is a canvas; if we have a window, put on "windows" list */ t_canvas *canvas = (t_canvas *)gl; if (canvas->gl_havewindow) { if (strlen(sbuf) + strlen(gl->gl_name->s_name) + 100 <= 1024) { char tbuf[1024]; sprintf(tbuf, "{{%s} .x%lx} ", gl->gl_name->s_name, (t_int)canvas); strcat(sbuf, tbuf); } } } for (g = gl->gl_list; g; g = g->g_next) { if (pd_class(&g->g_pd) == canvas_class) glist_doupdatewindowlist((t_glist *)g, sbuf); } return; } /* maintain the list of visible toplevels for the GUI's "windows" menu */ void canvas_updatewindowlist( void) { t_canvas *x; char sbuf[1024]; strcpy(sbuf, "set menu_windowlist {"); /* find all root canvases */ for (x = canvas_list; x; x = x->gl_next) glist_doupdatewindowlist(x, sbuf); /* next line updates the window menu state before -postcommand tries it */ strcat(sbuf, "}\npdtk_fixwindowmenu\n"); sys_gui(sbuf); } /* add a glist the list of "root" canvases (toplevels without parents.) */ static void canvas_addtolist(t_canvas *x) { x->gl_next = canvas_list; canvas_list = x; } static void canvas_takeofflist(t_canvas *x) { /* take it off the window list */ if (x == canvas_list) canvas_list = x->gl_next; else { t_canvas *z; for (z = canvas_list; z->gl_next != x; z = z->gl_next) ; z->gl_next = x->gl_next; } } void canvas_setargs(int argc, t_atom *argv) { /* if there's an old one lying around free it here. This happens if an abstraction is loaded but never gets as far as calling canvas_new(). */ if (canvas_newargv) freebytes(canvas_newargv, canvas_newargc * sizeof(t_atom)); canvas_newargc = argc; canvas_newargv = copybytes(argv, argc * sizeof(t_atom)); } void glob_setfilename(void *dummy, t_symbol *filesym, t_symbol *dirsym) { canvas_newfilename = filesym; canvas_newdirectory = dirsym; } t_canvas *canvas_getcurrent(void) { return ((t_canvas *)pd_findbyclass(&s__X, canvas_class)); } void canvas_setcurrent(t_canvas *x) { pd_pushsym(&x->gl_pd); } void canvas_unsetcurrent(t_canvas *x) { pd_popsym(&x->gl_pd); } t_canvasenvironment *canvas_getenv(t_canvas *x) { if (!x) bug("canvas_getenv"); while (!x->gl_env) if (!(x = x->gl_owner)) bug("t_canvasenvironment"); return (x->gl_env); } int canvas_getdollarzero( void) { t_canvas *x = canvas_getcurrent(); t_canvasenvironment *env = (x ? canvas_getenv(x) : 0); if (env) return (env->ce_dollarzero); else return (0); } void canvas_getargs(int *argcp, t_atom **argvp) { t_canvasenvironment *e = canvas_getenv(canvas_getcurrent()); *argcp = e->ce_argc; *argvp = e->ce_argv; } t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s) { t_symbol *ret; char *name = s->s_name; if (strchr(name, '$')) { t_canvasenvironment *env = canvas_getenv(x); canvas_setcurrent(x); ret = binbuf_realizedollsym(s, env->ce_argc, env->ce_argv, 1); canvas_unsetcurrent(x); } else ret = s; return (ret); } t_symbol *canvas_getcurrentdir(void) { t_canvasenvironment *e = canvas_getenv(canvas_getcurrent()); return (e->ce_dir); } t_symbol *canvas_getdir(t_canvas *x) { t_canvasenvironment *e = canvas_getenv(x); return (e->ce_dir); } void canvas_makefilename(t_canvas *x, char *file, char *result, int resultsize) { char interim[FILENAME_MAX]; sys_expandpathelems(file, interim); //fprintf(stderr,"interim = <%s>\n", interim); char *dir = canvas_getenv(x)->ce_dir->s_name; if (interim[0] == '/' || (interim[0] && interim[1] == ':') || !*dir) { //fprintf(stderr,"root file\n"); strncpy(result, interim, resultsize); result[resultsize-1] = 0; } else { //fprintf(stderr,"relative file\n"); int nleft; strncpy(result, dir, resultsize); result[resultsize-1] = 0; nleft = resultsize - strlen(result) - 1; if (nleft <= 0) return; strcat(result, "/"); strncat(result, interim, nleft); result[resultsize-1] = 0; } //fprintf(stderr,"resulting file = <%s>\n", result); } void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir) { canvas_unbind(x); x->gl_name = s; canvas_bind(x); if (glist_isvisible(x)) if (x->gl_havewindow) //was glist_isvisible(x) canvas_reflecttitle(x); if (dir && dir != &s_) { t_canvasenvironment *e = canvas_getenv(x); e->ce_dir = dir; } } /* --------------- traversing the set of lines in a canvas ----------- */ int canvas_getindex(t_canvas *x, t_gobj *y) { t_gobj *y2; int indexno; for (indexno = 0, y2 = x->gl_list; y2 && y2 != y; y2 = y2->g_next) indexno++; return (indexno); } void linetraverser_start(t_linetraverser *t, t_canvas *x) { t->tr_ob = 0; t->tr_x = x; t->tr_nextoc = 0; t->tr_nextoutno = t->tr_nout = 0; } t_outconnect *linetraverser_next(t_linetraverser *t) { t_outconnect *rval = t->tr_nextoc; int outno; while (!rval) { outno = t->tr_nextoutno; while (outno == t->tr_nout) { t_gobj *y; t_object *ob = 0; if (!t->tr_ob) y = t->tr_x->gl_list; else y = t->tr_ob->ob_g.g_next; for (; y; y = y->g_next) if (ob = pd_checkobject(&y->g_pd)) break; if (!ob) return (0); t->tr_ob = ob; t->tr_nout = obj_noutlets(ob); outno = 0; if (glist_isvisible(t->tr_x)) gobj_getrect(y, t->tr_x, &t->tr_x11, &t->tr_y11, &t->tr_x12, &t->tr_y12); else t->tr_x11 = t->tr_y11 = t->tr_x12 = t->tr_y12 = 0; } t->tr_nextoutno = outno + 1; rval = obj_starttraverseoutlet(t->tr_ob, &t->tr_outlet, outno); t->tr_outno = outno; } t->tr_nextoc = obj_nexttraverseoutlet(rval, &t->tr_ob2, &t->tr_inlet, &t->tr_inno); t->tr_nin = obj_ninlets(t->tr_ob2); if (!t->tr_nin) bug("drawline"); if (glist_isvisible(t->tr_x)) { int inplus = (t->tr_nin == 1 ? 1 : t->tr_nin - 1); int outplus = (t->tr_nout == 1 ? 1 : t->tr_nout - 1); gobj_getrect(&t->tr_ob2->ob_g, t->tr_x, &t->tr_x21, &t->tr_y21, &t->tr_x22, &t->tr_y22); t->tr_lx1 = t->tr_x11 + ((t->tr_x12 - t->tr_x11 - IOWIDTH) * t->tr_outno) / outplus + IOMIDDLE; t->tr_ly1 = t->tr_y12; t->tr_lx2 = t->tr_x21 + ((t->tr_x22 - t->tr_x21 - IOWIDTH) * t->tr_inno)/inplus + IOMIDDLE; t->tr_ly2 = t->tr_y21; } else { t->tr_x21 = t->tr_y21 = t->tr_x22 = t->tr_y22 = 0; t->tr_lx1 = t->tr_ly1 = t->tr_lx2 = t->tr_ly2 = 0; } return (rval); } void linetraverser_skipobject(t_linetraverser *t) { t->tr_nextoc = 0; t->tr_nextoutno = t->tr_nout; } /* -------------------- the canvas object -------------------------- */ int glist_valid = 10000; void glist_init(t_glist *x) { /* zero out everyone except "pd" field */ memset(((char *)x) + sizeof(x->gl_pd), 0, sizeof(*x) - sizeof(x->gl_pd)); x->gl_stub = gstub_new(x, 0); x->gl_valid = ++glist_valid; x->gl_xlabel = (t_symbol **)t_getbytes(0); x->gl_ylabel = (t_symbol **)t_getbytes(0); } /* 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.) */ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) { t_canvas *x = (t_canvas *)pd_new(canvas_class); t_canvas *owner = canvas_getcurrent(); t_symbol *s = &s_; int vis = 0, width = GLIST_DEFCANVASWIDTH, height = GLIST_DEFCANVASHEIGHT; int xloc = 0, yloc = GLIST_DEFCANVASYLOC; int font = (owner ? owner->gl_font : sys_defaultfont); glist_init(x); //x->gl_magic_glass = magicGlass_new(x); x->gl_obj.te_type = T_OBJECT; if (!owner) canvas_addtolist(x); /* post("canvas %lx, owner %lx", x, owner); */ if (argc == 5) /* toplevel: x, y, w, h, font */ { xloc = atom_getintarg(0, argc, argv); yloc = atom_getintarg(1, argc, argv); width = atom_getintarg(2, argc, argv); height = atom_getintarg(3, argc, argv); font = atom_getintarg(4, argc, argv); } else if (argc == 6) /* subwindow: x, y, w, h, name, vis */ { xloc = atom_getintarg(0, argc, argv); yloc = atom_getintarg(1, argc, argv); width = atom_getintarg(2, argc, argv); height = atom_getintarg(3, argc, argv); s = atom_getsymbolarg(4, argc, argv); vis = atom_getintarg(5, argc, argv); } /* (otherwise assume we're being created from the menu.) */ if (canvas_newdirectory->s_name[0]) { static int dollarzero = 1000; t_canvasenvironment *env = x->gl_env = (t_canvasenvironment *)getbytes(sizeof(*x->gl_env)); if (!canvas_newargv) canvas_newargv = getbytes(0); env->ce_dir = canvas_newdirectory; env->ce_argc = canvas_newargc; env->ce_argv = canvas_newargv; env->ce_dollarzero = dollarzero++; env->ce_path = 0; canvas_newdirectory = &s_; canvas_newargc = 0; canvas_newargv = 0; } else x->gl_env = 0; if (yloc < GLIST_DEFCANVASYLOC) yloc = GLIST_DEFCANVASYLOC; if (xloc < 0) xloc = 0; x->gl_x1 = 0; x->gl_y1 = 0; x->gl_x2 = 1; x->gl_y2 = 1; canvas_setbounds(x, xloc, yloc, xloc + width, yloc + height); x->gl_owner = owner; x->gl_name = (*s->s_name ? s : (canvas_newfilename ? canvas_newfilename : gensym("Pd"))); canvas_bind(x); x->gl_loading = 1; //fprintf(stderr,"loading = 1 .x%lx owner=.x%lx\n", (t_int)x, (t_int)x->gl_owner); x->gl_goprect = 0; /* no GOP rectangle unless it's turned on later */ /* cancel "vis" flag if we're a subpatch of an abstraction inside another patch. A separate mechanism prevents the toplevel abstraction from showing up. */ if (vis && gensym("#X")->s_thing && ((*gensym("#X")->s_thing) == canvas_class)) { t_canvas *zzz = (t_canvas *)(gensym("#X")->s_thing); while (zzz && !zzz->gl_env) zzz = zzz->gl_owner; if (zzz && canvas_isabstraction(zzz) && zzz->gl_owner) vis = 0; } x->gl_willvis = vis; x->gl_edit = !strncmp(x->gl_name->s_name, "Untitled", 8); x->gl_font = sys_nearestfontsize(font); pd_pushsym(&x->gl_pd); //dpsaha@vt.edu gop resize //resize blob t_scalehandle *sh; char buf[64]; x->x_handle = pd_new(scalehandle_class); sh = (t_scalehandle *)x->x_handle; sh->h_master = (t_gobj*)x; sprintf(buf, "_h%lx", (t_int)sh); pd_bind(x->x_handle, sh->h_bindsym = gensym(buf)); sprintf(sh->h_outlinetag, "h%lx", (t_int)sh); sh->h_dragon = 0; sh->h_scale = 1; x->scale_offset_x = 0; x->scale_offset_y = 0; x->scale_vis = 0; //move blob t_scalehandle *mh; char mbuf[64]; x->x_mhandle = pd_new(scalehandle_class); mh = (t_scalehandle *)x->x_mhandle; mh->h_master = (t_gobj*)x; sprintf(mbuf, "_h%lx", (t_int)mh); pd_bind(x->x_mhandle, mh->h_bindsym = gensym(mbuf)); sprintf(mh->h_outlinetag, "h%lx", (t_int)mh); mh->h_dragon = 0; mh->h_scale = 0; x->move_offset_x = 0; x->move_offset_y = 0; x->move_vis = 0; x->u_queue = canvas_undo_init(x); return(x); } void canvas_setgraph(t_glist *x, int flag, int nogoprect); static void canvas_coords(t_glist *x, t_symbol *s, int argc, t_atom *argv) { //IB: first delete the graph in case we are downsizing the object size via script canvas_setgraph(x, 0, 0); x->gl_x1 = atom_getfloatarg(0, argc, argv); x->gl_y1 = atom_getfloatarg(1, argc, argv); x->gl_x2 = atom_getfloatarg(2, argc, argv); x->gl_y2 = atom_getfloatarg(3, argc, argv); x->gl_pixwidth = atom_getintarg(4, argc, argv); x->gl_pixheight = atom_getintarg(5, argc, argv); if (argc <= 7) canvas_setgraph(x, atom_getintarg(6, argc, argv), 1); else { x->gl_xmargin = atom_getintarg(7, argc, argv); x->gl_ymargin = atom_getintarg(8, argc, argv); canvas_setgraph(x, atom_getintarg(6, argc, argv), 0); } } /* make a new glist and add it to this glist. It will appear as a "graph", not a text object. */ t_glist *glist_addglist(t_glist *g, t_symbol *sym, t_float x1, t_float y1, t_float x2, t_float y2, t_float px1, t_float py1, t_float px2, t_float py2) { static int gcount = 0; int zz; int menu = 0; char *str; t_glist *x = (t_glist *)pd_new(canvas_class); glist_init(x); x->gl_obj.te_type = T_OBJECT; if (!*sym->s_name) { char buf[40]; sprintf(buf, "graph%d", ++gcount); sym = gensym(buf); menu = 1; } else if (!strncmp((str = sym->s_name), "graph", 5) && (zz = atoi(str + 5)) > gcount) gcount = zz; /* in 0.34 and earlier, the pixel rectangle and the y bounds were reversed; this would behave the same, except that the dialog window would be confusing. The "correct" way is to have "py1" be the value that is higher on the screen. */ if (py2 < py1) { t_float zz; zz = y2; y2 = y1; y1 = zz; zz = py2; py2 = py1; py1 = zz; } if (x1 == x2 || y1 == y2) x1 = 0, x2 = 100, y1 = 1, y2 = -1; if (px1 != 0 && px2 == 0) px2 = px1 + GLIST_DEFGRAPHWIDTH; if (py1 != 0 && py2 == py1) py2 = py1 + GLIST_DEFGRAPHHEIGHT; if (px1 >= px2 || py1 >= py2) px1 = 100, py1 = 20, px2 = 100 + GLIST_DEFGRAPHWIDTH, py2 = 20 + GLIST_DEFGRAPHHEIGHT; x->gl_name = sym; x->gl_x1 = x1; x->gl_x2 = x2; x->gl_y1 = y1; x->gl_y2 = y2; x->gl_obj.te_xpix = px1; x->gl_obj.te_ypix = py1; x->gl_pixwidth = px2 - px1; x->gl_pixheight = py2 - py1; x->gl_font = (canvas_getcurrent() ? canvas_getcurrent()->gl_font : sys_defaultfont); x->gl_screenx1 = x->gl_screeny1 = 0; x->gl_screenx2 = 450; x->gl_screeny2 = 300; x->gl_owner = g; canvas_bind(x); x->gl_isgraph = 1; x->gl_goprect = 0; x->gl_obj.te_binbuf = binbuf_new(); binbuf_addv(x->gl_obj.te_binbuf, "s", gensym("graph")); if (!menu) pd_pushsym(&x->gl_pd); glist_add(g, &x->gl_gobj); if (!do_not_redraw) sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", (long unsigned int)glist_getcanvas(g)); return (x); } extern int we_are_undoing; /* call glist_addglist from a Pd message */ void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv) { pd_vmess(&g->gl_pd, gensym("editmode"), "i", 1); t_symbol *sym = atom_getsymbolarg(0, argc, argv); /* if we wish to put a graph where the mouse is we need to replace bogus name */ if (!strcmp(sym->s_name, "NULL")) sym = &s_; t_float x1 = atom_getfloatarg(1, argc, argv); t_float y1 = atom_getfloatarg(2, argc, argv); t_float x2 = atom_getfloatarg(3, argc, argv); t_float y2 = atom_getfloatarg(4, argc, argv); t_float px1 = atom_getfloatarg(5, argc, argv); t_float py1 = atom_getfloatarg(6, argc, argv); t_float px2 = atom_getfloatarg(7, argc, argv); t_float py2 = atom_getfloatarg(8, argc, argv); glist_addglist(g, sym, x1, y1, x2, y2, px1, py1, px2, py2); if (!we_are_undoing) canvas_undo_add(glist_getcanvas(g), 9, "create", (void *)canvas_undo_set_create(glist_getcanvas(g))); } /* return true if the glist should appear as a graph on parent; otherwise it appears as a text box. */ int glist_isgraph(t_glist *x) { // testing to see if we have an array and force hiding text (later update GUI accordingly) // we likely need this to silently update legacy arrays // (no regressions are expected but this needs to be tested) t_gobj *g = x->gl_list; int hasarray = 0; while (g) { if (pd_class(&g->g_pd) == garray_class) hasarray = 1; g = g->g_next; } if (hasarray) { x->gl_isgraph = 1; x->gl_hidetext = 1; } return (x->gl_isgraph|(x->gl_hidetext<<1)); } /* This is sent from the GUI to inform a toplevel that its window has been moved or resized. */ void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2) { //fprintf(stderr,"canvas_setbounds %d %d %d %d\n", x1, y1, x2, y2); int heightwas = y2 - y1; int heightchange = y2 - y1 - (x->gl_screeny2 - x->gl_screeny1); if (x->gl_screenx1 == x1 && x->gl_screeny1 == y1 && x->gl_screenx2 == x2 && x->gl_screeny2 == y2) return; x->gl_screenx1 = x1; x->gl_screeny1 = y1; x->gl_screenx2 = x2; x->gl_screeny2 = y2; if (!glist_isgraph(x) && (x->gl_y2 < x->gl_y1)) { /* if it's flipped so that y grows upward, fix so that zero is bottom edge and redraw. This is only appropriate if we're a regular "text" object on the parent. */ t_float diff = x->gl_y1 - x->gl_y2; t_gobj *y; x->gl_y1 = heightwas * diff; x->gl_y2 = x->gl_y1 - diff; /* and move text objects accordingly; they should stick to the bottom, not the top. */ for (y = x->gl_list; y; y = y->g_next) if (pd_checkobject(&y->g_pd)) gobj_displace(y, x, 0, heightchange); canvas_redraw(x); } } t_symbol *canvas_makebindsym(t_symbol *s) { char buf[MAXPDSTRING]; strcpy(buf, "pd-"); strcat(buf, s->s_name); return (gensym(buf)); } void canvas_reflecttitle(t_canvas *x) { //fprintf(stderr,"canvas_reflecttitle\n"); char namebuf[MAXPDSTRING]; t_canvasenvironment *env = canvas_getenv(x); if (env->ce_argc) { int i; strcpy(namebuf, " ("); for (i = 0; i < env->ce_argc; i++) { if (strlen(namebuf) > MAXPDSTRING/2 - 5) break; if (i != 0) strcat(namebuf, " "); atom_string(&env->ce_argv[i], namebuf + strlen(namebuf), MAXPDSTRING/2); } strcat(namebuf, ")"); } else namebuf[0] = 0; #ifdef __APPLE__ sys_vgui("wm attributes .x%lx -modified %d -titlepath {%s/%s}\n", x, x->gl_dirty, canvas_getdir(x)->s_name, x->gl_name->s_name); sys_vgui("wm title .x%lx {%s%s}\n", x, x->gl_name->s_name, namebuf); #else //if(glist_havewindow(x) || !x->gl_isgraph || x->gl_isgraph && x->gl_havewindow || x->gl_loading || x->gl_dirty) { /*fprintf(stderr,"%d %d %d %d %d\n", glist_istoplevel(x), !x->gl_isgraph, x->gl_isgraph && x->gl_havewindow, x->gl_loading, x->gl_dirty);*/ sys_vgui("wm title .x%lx {%s%c%s - %s}\n", x, x->gl_name->s_name, (x->gl_dirty? '*' : ' '), namebuf, canvas_getdir(x)->s_name); //} #endif } /* mark a glist dirty or clean */ void canvas_dirty(t_canvas *x, t_floatarg n) { t_canvas *x2 = canvas_getrootfor(x); if (glist_amreloadingabstractions) return; if ((unsigned)n != x2->gl_dirty) { x2->gl_dirty = n; if (glist_isvisible(x2)) canvas_reflecttitle(x2); } } extern void canvas_check_nlet_highlights(t_canvas *x); /*********** dpsaha@vt.edu resize move hooks ****************/ void canvas_draw_gop_resize_hooks(t_canvas* x) { t_scalehandle *sh = (t_scalehandle *)(x->x_handle); t_scalehandle *mh = (t_scalehandle *)(x->x_mhandle); if (!sh || !mh) return; //in case we are an array which does not initialize its hooks if(x->gl_edit && glist_isvisible(x) && glist_istoplevel(x) && x->gl_goprect && !x->gl_editor->e_selection) { //Drawing and Binding Resize_Blob for GOP //fprintf(stderr,"draw_gop_resize_hooks %lx %lx\n", (t_int)x, (t_int)glist_getcanvas(x)); sprintf(sh->h_pathname, ".x%lx.h%lx", (t_int)x, (t_int)sh); sys_vgui("destroy %s\n", sh->h_pathname); sys_vgui(".x%lx.c delete GOP_resblob\n", x); sys_vgui("canvas %s -width %d -height %d -bg $pd_colors(selection) -bd 0 -cursor bottom_right_corner\n", sh->h_pathname, SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT); sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxSCALE %lxGOP GOP_resblob}\n", x, x->gl_xmargin + x->gl_pixwidth - SCALEHANDLE_WIDTH - 1, x->gl_ymargin + 3 + x->gl_pixheight - SCALEHANDLE_HEIGHT - 4, SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT, sh->h_pathname, x, x); sys_vgui("bind %s