1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
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
}
|