aboutsummaryrefslogtreecommitdiff
path: root/externals/grill/dyn/dyn_create.cpp
blob: b53ed89aa6327a207034fbbe0979b3a60d04e435 (plain)
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
}