From 57045df5fe3ec557e57dc7434ac1a07b5521bffc Mon Sep 17 00:00:00 2001 From: Guenter Geiger Date: Mon, 29 Jul 2002 17:06:19 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r58, which included commits to RCS files with non-trunk default branches. svn path=/trunk/; revision=59 --- pd/src/g_canvas.c | 1482 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1482 insertions(+) create mode 100644 pd/src/g_canvas.c (limited to 'pd/src/g_canvas.c') diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c new file mode 100644 index 00000000..c63b2c0b --- /dev/null +++ b/pd/src/g_canvas.c @@ -0,0 +1,1482 @@ +/* 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.) */ + +/* changes by Thomas Musil IEM KUG Graz Austria 2001 */ + +/* improvement: line-delete-protection, look for "protect" */ +/* bug-fix: canvas_menuclose(): by Krzysztof Czaja */ +/* bug-fix: table_new(): I reversed the y-bounds */ + +/* IOhannes : + * changed the canvas_restore, so that it might accept $args as well + * (like "pd $0_test") + * so you can make multiple & distinguishable templates + * 1511:forum::für::umläute:2001 + * changes marked with IOhannes + */ + +#include +#include +#include "m_imp.h" +#include "g_canvas.h" +#include +#include "g_all_guis.h" + +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" */ +}; + +#define GLIST_DEFCANVASWIDTH 450 +#define GLIST_DEFCANVASHEIGHT 300 + +#ifdef MACOSX +#define GLIST_DEFCANVASYLOC 20 +#else +#define GLIST_DEFCANVASYLOC 0 +#endif + +/* ---------------------- variables --------------------------- */ + +extern t_pd *newest; +t_class *canvas_class; +static 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); +static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2); +static 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); +void canvas_create_editor(t_glist *x, int createit); + +/* --------- 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 (!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%x} ", 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); + strcat(sbuf, "}\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", x); + 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 *realizedollsym(t_symbol *s, int ac, t_atom *av, int tonew); + +t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s) +{ + t_symbol *ret; + char *name = s->s_name; + if (*name == '$' && name[1] >= '0' && name[1] <= '9') + { + t_canvasenvironment *env = canvas_getenv(x); + canvas_setcurrent(x); + ret = realizedollsym(gensym(name+1), 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 *dir = canvas_getenv(x)->ce_dir->s_name; + if (file[0] == '/' || (file[0] && file[1] == ':') || !*dir) + { + strncpy(result, file, resultsize); + result[resultsize-1] = 0; + } + else + { + int nleft; + strncpy(result, dir, resultsize); + result[resultsize-1] = 0; + nleft = resultsize - strlen(result) - 1; + if (nleft <= 0) return; + strcat(result, "/"); + strncat(result, file, nleft); + result[resultsize-1] = 0; + } +} + +void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir) +{ + if (strcmp(x->gl_name->s_name, "Pd")) + pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name)); + x->gl_name = s; + if (strcmp(x->gl_name->s_name, "Pd")) + pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name)); + if (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 ----------- */ + +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 + its parent will be a "text" object in another window... we don't + know which yet. */ +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_obj.te_type = T_OBJECT; + if (!owner) + canvas_addtolist(x); + /* post("canvas %x, owner %x", 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)); + env->ce_dir = canvas_newdirectory; + env->ce_argc = canvas_newargc; + env->ce_argv = canvas_newargv; + env->ce_dollarzero = dollarzero++; + canvas_newdirectory = &s_; + canvas_newargc = 0; + canvas_newargv = 0; + } + else x->gl_env = 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"))); + if (strcmp(x->gl_name->s_name, "Pd")) + pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name)); + x->gl_loading = 1; + 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); + return(x); +} + +void canvas_setgraph(t_glist *x, int flag); + +static void canvas_coords(t_glist *x, t_symbol *s, int argc, t_atom *argv) +{ + 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); + canvas_setgraph(x, atom_getintarg(6, argc, argv)); +} + + /* 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, + float x1, float y1, float x2, float y2, + float px1, float py1, float px2, 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) + { + 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 >= 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; + if (strcmp(x->gl_name->s_name, "Pd")) + pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name)); + x->gl_owner = g; + x->gl_stretch = 1; + x->gl_isgraph = 1; + 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 (glist_isvisible(g)) + canvas_create_editor(x, 1); + return (x); +} + + /* call glist_addglist from a Pd message */ +void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv) +{ + t_symbol *sym = atom_getsymbolarg(0, argc, argv); + float x1 = atom_getfloatarg(1, argc, argv); + float y1 = atom_getfloatarg(2, argc, argv); + float x2 = atom_getfloatarg(3, argc, argv); + float y2 = atom_getfloatarg(4, argc, argv); + float px1 = atom_getfloatarg(5, argc, argv); + float py1 = atom_getfloatarg(6, argc, argv); + float px2 = atom_getfloatarg(7, argc, argv); + float py2 = atom_getfloatarg(8, argc, argv); + glist_addglist(g, sym, x1, y1, x2, y2, px1, py1, px2, py2); +} + + /* 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) +{ + return (x->gl_isgraph); +} + + /* This is sent from the GUI to inform a toplevel that its window has been + moved or resized. */ +static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2) +{ + 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. */ + float diff = x->gl_y1 - x->gl_y2; + x->gl_y1 = x->gl_screeny2 * diff; + x->gl_y2 = x->gl_y1 - diff; + 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) +{ + 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; + sys_vgui("wm title .x%x {%s%c%s - %s}\n", + x, x->gl_name->s_name, (x->gl_dirty? '*' : ' '), namebuf, + canvas_getdir(x)->s_name); +} + +void canvas_dirty(t_canvas *x, t_int n) +{ + t_canvas *x2 = canvas_getrootfor(x); + if ((unsigned)n != x2->gl_dirty) + { + x2->gl_dirty = n; + canvas_reflecttitle(x2); + } +} + +extern t_gobj *canvas_selectme; /* HACK */ + + /* the window becomes "mapped" (visible and not miniaturized) or + "unmapped" (either miniaturized or just plain gone.) This should be + called from the GUI after the fact to "notify" us that we're mapped. */ +void canvas_map(t_canvas *x, t_floatarg f) +{ + int flag = (f != 0); + t_gobj *y; + if (flag) + { + if (!glist_isvisible(x)) + { + t_selection *sel; + if (!x->gl_havewindow) + { + bug("canvas_map"); + canvas_vis(x, 1); + } + for (y = x->gl_list; y; y = y->g_next) + gobj_vis(y, x, 1); + for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next) + gobj_select(sel->sel_what, x, 1); + x->gl_mapped = 1; + if (canvas_selectme) + { + glist_noselect(x); + glist_select(x, canvas_selectme); + canvas_selectme = 0; + } + canvas_drawlines(x); + } + } + else + { + if (glist_isvisible(x)) + { + for (y = x->gl_list; y; y = y->g_next) + gobj_vis(y, x, 0); + x->gl_mapped = 0; + } + } +} + +void canvas_redraw(t_canvas *x) +{ + if (glist_isvisible(x)) + { + canvas_map(x, 0); + canvas_map(x, 1); + } +} + +/* ---- editors -- perhaps this and "vis" should go to g_editor.c ------- */ + +static t_editor *editor_new(t_glist *owner) +{ + char buf[40]; + t_editor *x = (t_editor *)getbytes(sizeof(*x)); + x->e_connectbuf = binbuf_new(); + x->e_deleted = binbuf_new(); + x->e_glist = owner; + sprintf(buf, ".x%x", (t_int)owner); + x->e_guiconnect = guiconnect_new(&owner->gl_pd, gensym(buf)); + return (x); +} + +static void editor_free(t_editor *x, t_glist *y) +{ + glist_noselect(y); + guiconnect_notarget(x->e_guiconnect, 1000); + binbuf_free(x->e_connectbuf); + binbuf_free(x->e_deleted); + freebytes((void *)x, sizeof(*x)); +} + + /* recursively create or destroy all editors of a glist and its + sub-glists, as long as they aren't toplevels. */ +void canvas_create_editor(t_glist *x, int createit) +{ + t_gobj *y; + if (createit) + { + if (x->gl_editor) + bug("canvas_create_editor"); + else x->gl_editor = editor_new(x); + } + else + { + if (!x->gl_editor) + bug("canvas_create_editor"); + else editor_free(x->gl_editor, x); + x->gl_editor = 0; + } + for (y = x->gl_list; y; y = y->g_next) + if (pd_class(&y->g_pd) == canvas_class && + ((t_canvas *)y)->gl_isgraph) + canvas_create_editor((t_canvas *)y, createit); +} + + /* we call this when we want the window to become visible, mapped, and + in front of all windows; or with "f" zero, when we want to get rid of + the window. */ +void canvas_vis(t_canvas *x, t_floatarg f) +{ + char buf[30]; + int flag = (f != 0); + if (flag) + { + /* test if we're already visible and toplevel */ + if (glist_isvisible(x) && !x->gl_isgraph) + { /* just put us in front */ +#ifdef NT + canvas_vis(x, 0); + canvas_vis(x, 1); +#else + sys_vgui("raise .x%x\n", x); + sys_vgui("focus .x%x.c\n", x); + sys_vgui("wm deiconify .x%x\n", x); +#endif + } + else + { + canvas_create_editor(x, 1); + sys_vgui("pdtk_canvas_new .x%x %d %d +%d+%d\n", x, + (int)(x->gl_screenx2 - x->gl_screenx1), + (int)(x->gl_screeny2 - x->gl_screeny1), + (int)(x->gl_screenx1), (int)(x->gl_screeny1) + ); + canvas_reflecttitle(x); + /* simulate a mouse up so u_main will calculate scrollbars... + ugly! */ + sys_vgui("pdtk_canvas_mouseup .x%x.c 0 0 0\n", x); + x->gl_havewindow = 1; + canvas_updatewindowlist(); + } + } + else /* make invisible */ + { + int i; + t_canvas *x2; + if (!x->gl_havewindow) + { + /* bug workaround -- a graph in a visible patch gets "invised" + when the patch is closed, and must lost the editor here. It's + probably not the natural place to do this. Other cases like + subpatches fall here too but don'd need the editor freed, so + we check if it exists. */ + if (x->gl_editor) + canvas_create_editor(x, 0); + return; + } + glist_noselect(x); + if (glist_isvisible(x)) + canvas_map(x, 0); + canvas_create_editor(x, 0); + sys_vgui("destroy .x%x\n", x); + for (i = 1, x2 = x; x2; x2 = x2->gl_next, i++) + ; + sys_vgui(".mbar.find.menu delete %d\n", i); + /* if we're a graph on our parent, and if the parent exists + and is visible, show ourselves on parent. */ + if (glist_isgraph(x) && x->gl_owner) + { + t_glist *gl2 = x->gl_owner; + canvas_create_editor(x, 1); + if (glist_isvisible(gl2)) + gobj_vis(&x->gl_gobj, gl2, 0); + x->gl_havewindow = 0; + if (glist_isvisible(gl2)) + gobj_vis(&x->gl_gobj, gl2, 1); + } + else x->gl_havewindow = 0; + canvas_updatewindowlist(); + } +} + + /* we call this on a non-toplevel glist to "open" it into its + own window. */ +void glist_menu_open(t_glist *x) +{ + if (glist_isvisible(x) && !glist_istoplevel(x)) + { + t_glist *gl2 = x->gl_owner; + if (!gl2) + bug("canvas_vis"); /* shouldn't happen but don't get too upset. */ + else + { + /* erase ourself in parent window */ + gobj_vis(&x->gl_gobj, gl2, 0); + /* get rid of our editor (and subeditors) */ + canvas_create_editor(x, 0); + x->gl_havewindow = 1; + /* redraw ourself in parent window (blanked out this time) */ + gobj_vis(&x->gl_gobj, gl2, 1); + } + } + canvas_vis(x, 1); +} + +int glist_isvisible(t_glist *x) +{ + return ((!x->gl_loading) && glist_getcanvas(x)->gl_mapped); +} + +int glist_istoplevel(t_glist *x) +{ + /* we consider a graph "toplevel" if it has its own window + or if it appears as a box in its parent window so that we + don't draw the actual contents there. */ + return (x->gl_havewindow || !x->gl_isgraph); +} + +int glist_getfont(t_glist *x) +{ + return (glist_getcanvas(x)->gl_font); +} + +void canvas_free(t_canvas *x) +{ + t_gobj *y; + int dspstate = canvas_suspend_dsp(); + + if (canvas_editing == x) + canvas_editing = 0; + if (canvas_whichfind == x) + canvas_whichfind = 0; + glist_noselect(x); + while (y = x->gl_list) + glist_delete(x, y); + canvas_vis(x, 0); + + if (strcmp(x->gl_name->s_name, "Pd")) + pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name)); + if (x->gl_env) + { + freebytes(x->gl_env->ce_argv, x->gl_env->ce_argc * sizeof(t_atom)); + freebytes(x->gl_env, sizeof(*x->gl_env)); + } + canvas_resume_dsp(dspstate); + glist_cleanup(x); + gfxstub_deleteforkey(x); /* probably unnecessary */ + if (!x->gl_owner) + canvas_takeofflist(x); +} + +/* ----------------- lines ---------- */ + +static void canvas_drawlines(t_canvas *x) +{ + t_linetraverser t; + t_outconnect *oc; + { + linetraverser_start(&t, x); + while (oc = linetraverser_next(&t)) + sys_vgui(".x%x.c create line %d %d %d %d -tags l%x\n", + glist_getcanvas(x), + t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2, oc); + } +} + +void canvas_fixlinesfor(t_canvas *x, t_text *text) +{ + t_linetraverser t; + t_outconnect *oc; + + linetraverser_start(&t, x); + while (oc = linetraverser_next(&t)) + { + if (t.tr_ob == text || t.tr_ob2 == text) + { + sys_vgui(".x%x.c coords l%x %d %d %d %d\n", + glist_getcanvas(x), oc, + t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2); + } + } +} + + /* kill all lines for the object */ +void canvas_deletelinesfor(t_canvas *x, t_text *text) +{ + t_linetraverser t; + t_outconnect *oc; + linetraverser_start(&t, x); + while (oc = linetraverser_next(&t)) + { + if (t.tr_ob == text || t.tr_ob2 == text) + { + if (x->gl_editor) + { + sys_vgui(".x%x.c delete l%x\n", + glist_getcanvas(x), oc); + } + obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno); + } + } +} + + /* kill all lines for one inlet or outlet */ +void canvas_deletelinesforio(t_canvas *x, t_text *text, + t_inlet *inp, t_outlet *outp) +{ + t_linetraverser t; + t_outconnect *oc; + linetraverser_start(&t, x); + while (oc = linetraverser_next(&t)) + { + if ((t.tr_ob == text && t.tr_outlet == outp) || + (t.tr_ob2 == text && t.tr_inlet == inp)) + { + if (x->gl_editor) + { + sys_vgui(".x%x.c delete l%x\n", + glist_getcanvas(x), oc); + } + obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno); + } + } +} + +static void canvas_pop(t_canvas *x, t_floatarg fvis) +{ + if (fvis != 0) + canvas_vis(x, 1); + pd_popsym(&x->gl_pd); + canvas_resortinlets(x); + canvas_resortoutlets(x); + x->gl_loading = 0; +} + +void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv); + + +void canvas_restore(t_canvas *x, t_symbol *s, int argc, t_atom *argv) +{ /* IOhannes */ + t_pd *z; + /* this should be unnecessary, but sometimes the canvas's name gets + out of sync with the owning box's argument; this fixes that */ + if (argc > 3) + { + t_atom *ap=argv+3; + if (ap->a_type == A_SYMBOL) + { + char *buf=ap->a_w.w_symbol->s_name, *bufp; + if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9') + { + for (bufp = buf+2; *bufp; bufp++) + if (*bufp < '0' || *bufp > '9') + { + SETDOLLSYM(ap, gensym(buf+1)); + goto didit; + } + SETDOLLAR(ap, atoi(buf+1)); + didit: ; + } + } + + if (ap->a_type == A_DOLLSYM) + { + t_canvasenvironment *e = canvas_getenv(canvas_getcurrent()); + canvas_rename(x, realizedollsym(ap->a_w.w_symbol, + e->ce_argc, e->ce_argv, 1), 0); + } + else if (ap->a_type == A_SYMBOL) + canvas_rename(x, argv[3].a_w.w_symbol, 0); + } + canvas_pop(x, x->gl_willvis); + + if (!(z = gensym("#X")->s_thing)) error("canvas_restore: out of context"); + else if (*z != canvas_class) error("canvas_restore: wasn't a canvas"); + else + { + t_canvas *x2 = (t_canvas *)z; + x->gl_owner = x2; + canvas_objfor(x2, &x->gl_obj, argc, argv); + } +} + +static void canvas_loadbangabstractions(t_canvas *x) +{ + t_gobj *y; + t_symbol *s = gensym("loadbang"); + for (y = x->gl_list; y; y = y->g_next) + if (pd_class(&y->g_pd) == canvas_class) + { + if (canvas_isabstraction((t_canvas *)y)) + canvas_loadbang((t_canvas *)y); + else + canvas_loadbangabstractions((t_canvas *)y); + } +} + +void canvas_loadbangsubpatches(t_canvas *x) +{ + t_gobj *y; + t_symbol *s = gensym("loadbang"); + for (y = x->gl_list; y; y = y->g_next) + if (pd_class(&y->g_pd) == canvas_class) + { + if (!canvas_isabstraction((t_canvas *)y)) + canvas_loadbangsubpatches((t_canvas *)y); + } + for (y = x->gl_list; y; y = y->g_next) + if ((pd_class(&y->g_pd) != canvas_class) && + zgetfn(&y->g_pd, s)) + pd_vmess(&y->g_pd, s, ""); +} + +void canvas_loadbang(t_canvas *x) +{ + t_gobj *y; + canvas_loadbangabstractions(x); + canvas_loadbangsubpatches(x); +} + + /* When you ask a canvas its size the result is 2 pixels more than what + you gave it to open it; perhaps there's a 1-pixel border all around it + or something. Anyway, we just add the 2 pixels back here: */ + +#ifdef NT +#define HORIZBORDER 2 +#define VERTBORDER 2 +#else +#define HORIZBORDER 2 +#define VERTBORDER 2 +#endif + +static void canvas_relocate(t_canvas *x, t_symbol *canvasgeom, + t_symbol *topgeom) +{ + int cxpix, cypix, cw, ch, txpix, typix, tw, th; + if (sscanf(canvasgeom->s_name, "%dx%d+%d+%d", &cw, &ch, &cxpix, &cypix) + < 4 || + sscanf(topgeom->s_name, "%dx%d+%d+%d", &tw, &th, &txpix, &typix) < 4) + bug("canvas_relocate"); + /* for some reason this is initially called with cw=ch=1 so + we just suppress that here. */ + if (cw > 5 && ch > 5) + canvas_setbounds(x, txpix, typix, + txpix + cw - HORIZBORDER, typix + ch - VERTBORDER); +} + +void canvas_popabstraction(t_canvas *x) +{ + newest = &x->gl_pd; + pd_popsym(&x->gl_pd); + x->gl_loading = 0; + canvas_resortinlets(x); + canvas_resortoutlets(x); +} + +void canvas_logerror(t_object *y) +{ +#ifdef LATER + canvas_vis(x, 1); + if (!glist_isselected(x, &y->ob_g)) + glist_select(x, &y->ob_g); +#endif +} + +/* -------------------------- subcanvases ---------------------- */ + +static void *subcanvas_new(t_symbol *s) +{ + t_atom a[6]; + t_canvas *x, *z = canvas_getcurrent(); + if (!*s->s_name) s = gensym("/SUBPATCH/"); + SETFLOAT(a, 0); + SETFLOAT(a+1, GLIST_DEFCANVASYLOC); + SETFLOAT(a+2, GLIST_DEFCANVASWIDTH); + SETFLOAT(a+3, GLIST_DEFCANVASHEIGHT); + SETSYMBOL(a+4, s); + SETFLOAT(a+5, 1); + x = canvas_new(0, 0, 6, a); + x->gl_owner = z; + canvas_pop(x, 1); + return (x); +} + +static void canvas_click(t_canvas *x, + t_floatarg xpos, t_floatarg ypos, + t_floatarg shift, t_floatarg ctrl, t_floatarg alt) +{ + canvas_vis(x, 1); +} + + + /* find out from subcanvas contents how much to fatten the box */ +void canvas_fattensub(t_canvas *x, + int *xp1, int *yp1, int *xp2, int *yp2) +{ + t_gobj *y; + *xp2 += 50; /* fake for now */ + *yp2 += 50; +} + +static void canvas_rename_method(t_canvas *x, t_symbol *s, int ac, t_atom *av) +{ + if (ac && av->a_type == A_SYMBOL) + canvas_rename(x, av->a_w.w_symbol, 0); + else canvas_rename(x, gensym("Pd"), 0); +} + +/* ------------------ table ---------------------------*/ + +static int tabcount = 0; + +static void *table_new(t_symbol *s, t_floatarg f) +{ + t_atom a[9]; + t_glist *gl; + t_canvas *x, *z = canvas_getcurrent(); + if (s == &s_) + { + char tabname[255]; + t_symbol *t = gensym("table"); + sprintf(tabname, "%s%d", t->s_name, tabcount++); + s = gensym(tabname); + } + if (f <= 1) + f = 100; + SETFLOAT(a, 0); + SETFLOAT(a+1, GLIST_DEFCANVASYLOC); + SETFLOAT(a+2, 600); + SETFLOAT(a+3, 400); + SETSYMBOL(a+4, s); + SETFLOAT(a+5, 0); + x = canvas_new(0, 0, 6, a); + + x->gl_owner = z; + + /* create a graph for the table */ + gl = glist_addglist((t_glist*)x, &s_, 0, -1, (f > 1 ? f-1 : 1), 1, + 50, 350, 550, 50); + + graph_array(gl, s, &s_float, f, 0); + + canvas_pop(x, 0); + + return (x); +} + + /* return true if the "canvas" object is an abstraction (so we don't + save its contents, fogr example.) */ +int canvas_isabstraction(t_canvas *x) +{ + return (x->gl_env != 0); +} + + /* return true if the "canvas" object is a "table". */ +int canvas_istable(t_canvas *x) +{ + t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0); + int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0); + int istable = (argc && argv[0].a_type == A_SYMBOL && + argv[0].a_w.w_symbol == gensym("table")); + return (istable); +} + + /* return true if the "canvas" object should be treated as a text + object. This is true for abstractions but also for "table"s... */ +int canvas_showtext(t_canvas *x) +{ + t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0); + int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0); + int isarray = (argc && argv[0].a_type == A_SYMBOL && + argv[0].a_w.w_symbol == gensym("graph")); + return (!isarray); +} + +static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp); +static void canvas_dsp(t_canvas *x, t_signal **sp) +{ + canvas_dodsp(x, 0, sp); +} + + /* get the document containing this canvas */ +t_canvas *canvas_getrootfor(t_canvas *x) +{ + if ((!x->gl_owner) || canvas_isabstraction(x)) + return (x); + else return (canvas_getrootfor(x->gl_owner)); +} + +/* ------------------------- DSP chain handling ------------------------- */ + +EXTERN_STRUCT _dspcontext; +#define t_dspcontext struct _dspcontext + +void ugen_start(void); +void ugen_stop(void); + +t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp, + int ninlets, int noutlets); +void ugen_add(t_dspcontext *dc, t_object *x); +void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, + t_object *x2, int inno); +void ugen_done_graph(t_dspcontext *dc); + +int obj_issignaloutlet(t_object *x, int outno); +int obj_nsiginlets(t_object *x); +int obj_nsigoutlets(t_object *x); + + /* schedule one canvas for DSP. This is called below for all "root" + canvases, but is also called from the "dsp" method for sub- + canvases, which are treated almost like any other tilde object. */ + +static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp) +{ + t_linetraverser t; + t_outconnect *oc; + t_gobj *y; + t_object *ob; + t_symbol *dspsym = gensym("dsp"); + t_dspcontext *dc; + + /* create a new "DSP graph" object to use in sorting this canvas. + If we aren't toplevel, there are already other dspcontexts around. */ + + dc = ugen_start_graph(toplevel, sp, + obj_nsiginlets(&x->gl_obj), + obj_nsigoutlets(&x->gl_obj)); + + /* find all the "dsp" boxes and add them to the graph */ + + for (y = x->gl_list; y; y = y->g_next) + if ((ob = pd_checkobject(&y->g_pd)) && zgetfn(&y->g_pd, dspsym)) + ugen_add(dc, ob); + + /* ... and all dsp interconnections */ + linetraverser_start(&t, x); + while (oc = linetraverser_next(&t)) + if (obj_issignaloutlet(t.tr_ob, t.tr_outno)) + ugen_connect(dc, t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno); + + /* finally, sort them and add them to the DSP chain */ + ugen_done_graph(dc); +} + + /* this routine starts DSP for all root canvases. */ +static void canvas_start_dsp(void) +{ + t_canvas *x; + if (canvas_dspstate) ugen_stop(); + else sys_gui("pdtk_pd_dsp ON\n"); + ugen_start(); + + for (x = canvas_list; x; x = x->gl_next) + canvas_dodsp(x, 1, 0); + + canvas_dspstate = 1; +} + +static void canvas_stop_dsp(void) +{ + if (canvas_dspstate) + { + ugen_stop(); + sys_gui("pdtk_pd_dsp OFF\n"); + canvas_dspstate = 0; + } +} + + /* DSP can be suspended before, and resumed after, operations which + might affect the DSP chain. For example, we suspend before loading and + resume afterward, so that DSP doesn't get resorted for every DSP object + int the patch. */ + +int canvas_suspend_dsp(void) +{ + int rval = canvas_dspstate; + if (rval) canvas_stop_dsp(); + return (rval); +} + +void canvas_resume_dsp(int oldstate) +{ + if (oldstate) canvas_start_dsp(); +} + + /* this is equivalent to suspending and resuming in one step. */ +void canvas_update_dsp(void) +{ + if (canvas_dspstate) canvas_start_dsp(); +} + +void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv) +{ + int newstate; + if (argc) + { + newstate = atom_getintarg(0, argc, argv); + if (newstate && !canvas_dspstate) + canvas_start_dsp(); + else if (!newstate && canvas_dspstate) + canvas_stop_dsp(); + } + else post("dsp state %d", canvas_dspstate); +} + + /* LATER replace this with a queueing scheme */ +void glist_redrawitem(t_glist *owner, t_gobj *gobj) +{ + if (glist_isvisible(owner)) + { + gobj_vis(gobj, owner, 0); + gobj_vis(gobj, owner, 1); + } +} + + /* redraw all "scalars" (do this if a drawing command is changed.) + LATER we'll use the "template" information to select which ones we + redraw. */ +static void glist_redrawall(t_glist *gl) +{ + t_gobj *g; + int vis = glist_isvisible(gl); + for (g = gl->gl_list; g; g = g->g_next) + { + t_class *cl; + if (vis && g->g_pd == scalar_class) + glist_redrawitem(gl, g); + else if (g->g_pd == canvas_class) + glist_redrawall((t_glist *)g); + } +} + + /* public interface for above */ +void canvas_redrawallfortemplate(t_canvas *template) +{ + t_canvas *x; + if (!template->gl_imatemplate) return; + /* find all root canvases */ + for (x = canvas_list; x; x = x->gl_next) + glist_redrawall(x); +} + + /* Same as above but just zap them. Call this if a template + is changed by adding or removing a field. LATER we'll just + modify all the items appropriately. */ +static void glist_zapall(t_glist *gl) +{ + t_gobj *g; + for (g = gl->gl_list; g; g = g->g_next) + { + t_class *cl; + if (g->g_pd == canvas_class) + glist_zapall((t_glist *)g); + } + /* do we have any scalars? */ + for (g = gl->gl_list; g; g = g->g_next) + { + if (g->g_pd == scalar_class) + break; + } + if (!g) return; + /* delete all the scalars. This is inefficient if for some reason + you've mixed scalars with other items in a single glist. */ + while (1) + { + for (g = gl->gl_list; g; g = g->g_next) + { + if (g->g_pd == scalar_class) + { + glist_delete(gl, g); + break; + } + } + if (!g) break; + } +} + + /* public interface for above */ +void canvas_zapallfortemplate(t_canvas *template) +{ + t_canvas *x; + if (!template->gl_imatemplate) return; + /* find all root canvases */ + for (x = canvas_list; x; x = x->gl_next) + glist_zapall(x); +} + + /* warn a canvas that some datum has used it as a template. If a + canvas has no data associated with it (at load time, for instance) + we don't have to search through the world for instances as it changes. */ +void canvas_setusedastemplate(t_canvas *x) +{ + x->gl_imatemplate = 1; +} + +/* ------------------------------- setup routine ------------------------ */ + + /* why are some of these "glist" and others "canvas"? */ +extern void glist_text(t_glist *x, t_symbol *s, int argc, t_atom *argv); +extern void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void glist_scalar(t_glist *canvas, t_symbol *s, int argc, t_atom *argv); + +void g_graph_setup(void); +void g_editor_setup(void); +void g_readwrite_setup(void); + +void g_canvas_setup(void) +{ + /* we prevent the user from typing "canvas" in an object box + by sending 0 for a creator function. */ + canvas_class = class_new(gensym("canvas"), 0, + (t_method)canvas_free, sizeof(t_canvas), CLASS_NOINLET, 0); + /* here is the real creator function, invoked in patch files + by sending the "canvas" message to #N, which is bound + to pd_camvasmaker. */ + class_addmethod(pd_canvasmaker, (t_method)canvas_new, gensym("canvas"), + A_GIMME, 0); + class_addmethod(canvas_class, (t_method)canvas_restore, + gensym("restore"), A_GIMME, 0); + class_addmethod(canvas_class, (t_method)canvas_coords, + gensym("coords"), A_GIMME, 0); + +/* -------------------------- objects ----------------------------- */ + class_addmethod(canvas_class, (t_method)canvas_obj, + gensym("obj"), A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_msg, + gensym("msg"), A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_floatatom, + gensym("floatatom"), A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_symbolatom, + gensym("symbolatom"), A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)glist_text, + gensym("text"), A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)glist_glist, gensym("graph"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)glist_scalar, + gensym("scalar"), A_GIMME, A_NULL); + + /* -------------- Thomas Musil's GUI objects ------------ */ + class_addmethod(canvas_class, (t_method)canvas_bng, gensym("bng"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_toggle, gensym("toggle"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_vslider, gensym("vslider"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_hslider, gensym("hslider"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_hdial, gensym("hdial"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_vdial, gensym("vdial"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_vumeter, gensym("vumeter"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_mycnv, gensym("mycnv"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_numbox, gensym("numbox"), + A_GIMME, A_NULL); + +/* ------------------------ gui stuff --------------------------- */ + class_addmethod(canvas_class, (t_method)canvas_pop, gensym("pop"), + A_DEFFLOAT, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_loadbang, + gensym("loadbang"), A_NULL); + class_addmethod(canvas_class, (t_method)canvas_relocate, + gensym("relocate"), A_SYMBOL, A_SYMBOL, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_vis, + gensym("vis"), A_FLOAT, A_NULL); + class_addmethod(canvas_class, (t_method)glist_menu_open, + gensym("menu-open"), A_NULL); + class_addmethod(canvas_class, (t_method)canvas_map, + gensym("map"), A_FLOAT, A_NULL); + +/* ---------------------- list handling ------------------------ */ + class_addmethod(canvas_class, (t_method)glist_clear, gensym("clear"), + A_NULL); + +/* ----- subcanvases, which you get by typing "pd" in a box ---- */ + class_addcreator((t_newmethod)subcanvas_new, gensym("pd"), A_DEFSYMBOL, 0); + class_addcreator((t_newmethod)subcanvas_new, gensym("page"), A_DEFSYMBOL, 0); + + class_addmethod(canvas_class, (t_method)canvas_click, + gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); + class_addmethod(canvas_class, (t_method)canvas_dsp, gensym("dsp"), 0); + class_addmethod(canvas_class, (t_method)canvas_rename_method, + gensym("rename"), A_GIMME, 0); + +/*---------------------------- tables -- GG ------------------- */ + + class_addcreator((t_newmethod)table_new, gensym("table"), + A_DEFSYM, A_DEFFLOAT, 0); + +/* -------------- setups from other files for canvas_class ---------------- */ + g_graph_setup(); + g_editor_setup(); + g_readwrite_setup(); + +} -- cgit v1.2.1