diff options
Diffstat (limited to 'externals/grill/dyn/dyn_create.cpp')
-rw-r--r-- | externals/grill/dyn/dyn_create.cpp | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/externals/grill/dyn/dyn_create.cpp b/externals/grill/dyn/dyn_create.cpp new file mode 100644 index 00000000..b53ed89a --- /dev/null +++ b/externals/grill/dyn/dyn_create.cpp @@ -0,0 +1,246 @@ +/* +dyn - dynamical object management + +Copyright (c)2003-2004 Thomas Grill (gr@grrrr.org) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. +*/ + +#include "dyn_proto.h" +#include <list> + +static const t_symbol *k_obj = gensym("obj"); +static const t_symbol *k_msg = gensym("msg"); +static const t_symbol *k_text = gensym("text"); + +static const t_symbol *sym_vis = gensym("vis"); +static const t_symbol *sym_loadbang = gensym("loadbang"); +static const t_symbol *sym_pd = gensym("pd"); +static const t_symbol *sym_dsp = gensym("dsp"); + +static const t_symbol *sym_dyn = gensym("dyn"); +static const t_symbol *sym_dot = gensym("."); + + +static t_gobj *getlast(t_glist *gl) +{ + t_gobj *go = gl->gl_list; + if(go) + while(go->g_next) go = go->g_next; + return go; +} + + +void *NewPDObject(int type,t_glist *glist,const t_symbol *hdr,int _argc_,const t_atom *_argv_) +{ +// sys_lock(); + + const t_symbol *kind; + switch(type) { + case DYN_TYPE_PATCHER: + hdr = sym_pd; + // fall through + case DYN_TYPE_OBJECT: + kind = k_obj; + break; + case DYN_TYPE_MESSAGE: + kind = k_msg; + ASSERT(hdr == NULL); + break; + case DYN_TYPE_TEXT: + kind = k_text; + ASSERT(hdr == NULL); + break; + } + + void *newest = NULL; + t_gobj *last = NULL; + + if(type == DYN_TYPE_PATCHER && !glist) { + /* + For a dyn root canvas we can not simply put a [pd] into canvas_getcurrent + because the [pd] would be visible in this canvas then. + + On the other hand, we can also not simply create a new canvas with + canvas_getcurrent active because it would not be on the list of root dsp canvases + then. + + Hence, we have to pop all current canvases to be at the root, create our canvas + to be a real root canvas and then push back all the canvases. + */ + + /* + remember current directory - + abstractions residing in the directory of the current canvas + (which normally is the one hosting dyn) will be found + */ + t_symbol *dir; + if(canvas_getcurrent()) dir = canvas_getcurrentdir(); + else dir = const_cast<t_symbol *>(sym_dot); + + // pop current canvases + std::list<t_glist *> glstack; + for(;;) { + t_glist *gl = canvas_getcurrent(); + if(!gl) break; + glstack.push_front(gl); + canvas_unsetcurrent(gl); + } + + // set canvas environment + // this must be done manually if there is no owner + glob_setfilename(NULL,const_cast<t_symbol *>(sym_dyn),dir); + + t_atom arg[6]; + SETFLOAT(arg+0,0); // xpos + SETFLOAT(arg+1,0); // ypos + SETFLOAT(arg+2,1000); // xwidth + SETFLOAT(arg+3,1000); // xwidth + SETSYMBOL(arg+4,const_cast<t_symbol *>(sym_dyncanvas)); // canvas name + SETFLOAT(arg+5,0); // invisible + + t_glist *canvas = canvas_new(NULL,NULL,6,arg); + /* or, alternatively - but this needs some message processing + pd_typedmess(&pd_canvasmaker,gensym("canvas"),6,arg); + t_glist *canvas = canvas_getcurrent(); + */ + + // must do that.... + canvas_unsetcurrent(canvas); + + // push back all the canvases + for(std::list<t_glist *>::iterator it = glstack.begin(); it != glstack.end(); ++it) + canvas_setcurrent(*it); + + // clear environment + glob_setfilename(NULL,&s_,&s_); + + newest = canvas; + } + else { + ASSERT(glist); + + int argc = _argc_+(hdr?3:2); + t_atom *argv = new t_atom[argc]; + + // position x/y = 0/0 + t_atom *a = argv; + SETFLOAT(a,0); a++; + SETFLOAT(a,0); a++; + if(hdr) { SETSYMBOL(a,const_cast<t_symbol *>(hdr)); a++; } + memcpy(a,_argv_,_argc_*sizeof(t_atom)); + + last = getlast(glist); + + // set selected canvas as current + pd_typedmess((t_pd *)glist,(t_symbol *)kind,argc,argv); +// canvas_obj(glist,(t_symbol *)kind,argc,argv); + newest = getlast(glist); + + delete[] argv; + } + + if(kind == k_obj && glist) { + // check for created objects and abstractions + + t_object *o = (t_object *)pd_newest(); + + if(!o) { + // PD creates a text object when the intended object could not be created + t_gobj *trash = getlast(glist); + + // Test for newly created object.... + if(trash && last != trash) { + // Delete it! + glist_delete(glist,trash); + } + newest = NULL; + } + else + newest = &o->te_g; + } + + // look for latest created object + if(newest) { +// if(glist) canvas_setcurrent(glist); + + // send loadbang (if it is an abstraction) + if(pd_class(&((t_gobj *)newest)->g_pd) == canvas_class) { + // hide the sub-canvas + pd_vmess((t_pd *)newest,const_cast<t_symbol *>(sym_vis),"i",0); + + // loadbang the abstraction + pd_vmess((t_pd *)newest,const_cast<t_symbol *>(sym_loadbang),""); + } + + // restart dsp - that's necessary because ToCanvas is called manually + canvas_update_dsp(); + + // pop the current canvas +// if(glist) canvas_unsetcurrent(glist); + } + +// sys_unlock(); + + return newest; +} + +dyn_patcher *root = NULL; + +dyn_ident *NewObject(int type,dyn_callback cb,dyn_ident *owner,const t_symbol *hdr,int argc,const t_atom *argv) +{ + int err = DYN_ERROR_NONE; + dyn_ident *ret = NULL; + + dyn_patcher *p; + if(owner == DYN_ID_NONE) { + if(!root) { + void *newobj = NewPDObject(DYN_TYPE_PATCHER,NULL,NULL); + dyn_ident *id = new dyn_ident(DYN_TYPE_PATCHER,NULL); + root = new dyn_patcher(id,NULL,(t_glist *)newobj); + } + p = root; + } + else + p = owner->Patcher(); + + if(p) { + void *newobj = NewPDObject(type,p->glist(),hdr,argc,argv); + if(newobj) { + ret = new dyn_ident(type,cb); + + switch(type) { + case DYN_TYPE_PATCHER: + ret->Set(new dyn_patcher(ret,p,(t_glist *)newobj)); + break; + case DYN_TYPE_OBJECT: + ret->Set(new dyn_object(ret,p,(t_gobj *)newobj)); + break; + case DYN_TYPE_MESSAGE: + ret->Set(new dyn_message(ret,p,(t_gobj *)newobj)); + break; + case DYN_TYPE_TEXT: + ret->Set(new dyn_text(ret,p,(t_gobj *)newobj)); + break; + } + } + else + err = DYN_ERROR_NOTCREATED; + } + else + err = DYN_ERROR_NOSUB; + + if(err != DYN_ERROR_NONE) { + if(ret) delete ret; + throw err; + } + else + return ret; +} + +void DelObject(dyn_ident *obj) +{ + ASSERT(obj); + if(obj->data) Destroy(obj->data); // delete database object + delete obj; // delete ID +} |