diff options
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/g_canvas.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/g_canvas.c | 2952 |
1 files changed, 2952 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/g_canvas.c b/apps/plugins/pdbox/PDa/src/g_canvas.c new file mode 100644 index 0000000000..f4ef8b14aa --- /dev/null +++ b/apps/plugins/pdbox/PDa/src/g_canvas.c | |||
@@ -0,0 +1,2952 @@ | |||
1 | /* Copyright (c) 1997-2001 Miller Puckette and others. | ||
2 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
3 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
4 | |||
5 | /* this file defines the "glist" class, also known as "canvas" (the two used | ||
6 | to be different but are now unified except for some fossilized names.) */ | ||
7 | |||
8 | /* changes by Thomas Musil IEM KUG Graz Austria 2001 */ | ||
9 | |||
10 | /* bug-fix: canvas_menuclose(): by Krzysztof Czaja */ | ||
11 | /* bug-fix: table_new(): I reversed the y-bounds */ | ||
12 | |||
13 | /* IOhannes : | ||
14 | * changed the canvas_restore, so that it might accept $args as well | ||
15 | * (like "pd $0_test") | ||
16 | * so you can make multiple & distinguishable templates | ||
17 | * 1511:forum::für::umläute:2001 | ||
18 | * changes marked with IOhannes | ||
19 | */ | ||
20 | |||
21 | #include <stdlib.h> | ||
22 | #include <stdio.h> | ||
23 | #include "m_pd.h" | ||
24 | #include "m_imp.h" | ||
25 | #include "s_stuff.h" | ||
26 | #include "g_canvas.h" | ||
27 | #include <string.h> | ||
28 | #include "g_all_guis.h" | ||
29 | |||
30 | struct _canvasenvironment | ||
31 | { | ||
32 | t_symbol *ce_dir; /* directory patch lives in */ | ||
33 | int ce_argc; /* number of "$" arguments */ | ||
34 | t_atom *ce_argv; /* array of "$" arguments */ | ||
35 | int ce_dollarzero; /* value of "$0" */ | ||
36 | }; | ||
37 | |||
38 | #define GLIST_DEFCANVASWIDTH 240 | ||
39 | #define GLIST_DEFCANVASHEIGHT 300 | ||
40 | |||
41 | #ifdef MACOSX | ||
42 | #define GLIST_DEFCANVASYLOC 22 | ||
43 | #else | ||
44 | #define GLIST_DEFCANVASYLOC 0 | ||
45 | #endif | ||
46 | |||
47 | /* ---------------------- variables --------------------------- */ | ||
48 | |||
49 | extern t_pd *newest; | ||
50 | t_class *canvas_class; | ||
51 | static int canvas_dspstate; /* whether DSP is on or off */ | ||
52 | t_canvas *canvas_editing; /* last canvas to start text edting */ | ||
53 | t_canvas *canvas_whichfind; /* last canvas we did a find in */ | ||
54 | t_canvas *canvas_list; /* list of all root canvases */ | ||
55 | |||
56 | /* ------------------ forward function declarations --------------- */ | ||
57 | static void canvas_start_dsp(void); | ||
58 | static void canvas_stop_dsp(void); | ||
59 | static void canvas_drawlines(t_canvas *x); | ||
60 | static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2); | ||
61 | static void canvas_reflecttitle(t_canvas *x); | ||
62 | static void canvas_addtolist(t_canvas *x); | ||
63 | static void canvas_takeofflist(t_canvas *x); | ||
64 | static void canvas_pop(t_canvas *x, t_floatarg fvis); | ||
65 | void canvas_create_editor(t_glist *x, int createit); | ||
66 | |||
67 | /* --------- functions to handle the canvas environment ----------- */ | ||
68 | |||
69 | static t_symbol *canvas_newfilename = &s_; | ||
70 | static t_symbol *canvas_newdirectory = &s_; | ||
71 | static int canvas_newargc; | ||
72 | static t_atom *canvas_newargv; | ||
73 | |||
74 | static void glist_doupdatewindowlist(t_glist *gl, char *sbuf) | ||
75 | { | ||
76 | t_gobj *g; | ||
77 | if (!gl->gl_owner) | ||
78 | { | ||
79 | /* this is a canvas; if we have a window, put on "windows" list */ | ||
80 | t_canvas *canvas = (t_canvas *)gl; | ||
81 | if (canvas->gl_havewindow) | ||
82 | { | ||
83 | if (strlen(sbuf) + strlen(gl->gl_name->s_name) + 100 <= 1024) | ||
84 | { | ||
85 | char tbuf[1024]; | ||
86 | sprintf(tbuf, "{%s .x%x} ", gl->gl_name->s_name, (t_int)canvas); | ||
87 | strcat(sbuf, tbuf); | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | for (g = gl->gl_list; g; g = g->g_next) | ||
92 | { | ||
93 | if (pd_class(&g->g_pd) == canvas_class) | ||
94 | glist_doupdatewindowlist((t_glist *)g, sbuf); | ||
95 | } | ||
96 | return; | ||
97 | } | ||
98 | |||
99 | /* maintain the list of visible toplevels for the GUI's "windows" menu */ | ||
100 | void canvas_updatewindowlist( void) | ||
101 | { | ||
102 | t_canvas *x; | ||
103 | char sbuf[1024]; | ||
104 | strcpy(sbuf, "set menu_windowlist {"); | ||
105 | /* find all root canvases */ | ||
106 | for (x = canvas_list; x; x = x->gl_next) | ||
107 | glist_doupdatewindowlist(x, sbuf); | ||
108 | /* next line updates the window menu state before -postcommand tries it */ | ||
109 | strcat(sbuf, "}\npdtk_fixwindowmenu\n"); | ||
110 | sys_gui(sbuf); | ||
111 | } | ||
112 | |||
113 | /* add a glist the list of "root" canvases (toplevels without parents.) */ | ||
114 | static void canvas_addtolist(t_canvas *x) | ||
115 | { | ||
116 | x->gl_next = canvas_list; | ||
117 | canvas_list = x; | ||
118 | } | ||
119 | |||
120 | static void canvas_takeofflist(t_canvas *x) | ||
121 | { | ||
122 | /* take it off the window list */ | ||
123 | if (x == canvas_list) canvas_list = x->gl_next; | ||
124 | else | ||
125 | { | ||
126 | t_canvas *z; | ||
127 | for (z = canvas_list; z->gl_next != x; z = z->gl_next) | ||
128 | ; | ||
129 | z->gl_next = x->gl_next; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | |||
134 | void canvas_setargs(int argc, t_atom *argv) | ||
135 | { | ||
136 | /* if there's an old one lying around free it here. This | ||
137 | happens if an abstraction is loaded but never gets as far | ||
138 | as calling canvas_new(). */ | ||
139 | if (canvas_newargv) | ||
140 | freebytes(canvas_newargv, canvas_newargc * sizeof(t_atom)); | ||
141 | canvas_newargc = argc; | ||
142 | canvas_newargv = copybytes(argv, argc * sizeof(t_atom)); | ||
143 | } | ||
144 | |||
145 | void glob_setfilename(void *dummy, t_symbol *filesym, t_symbol *dirsym) | ||
146 | { | ||
147 | canvas_newfilename = filesym; | ||
148 | canvas_newdirectory = dirsym; | ||
149 | } | ||
150 | |||
151 | t_canvas *canvas_getcurrent(void) | ||
152 | { | ||
153 | return ((t_canvas *)pd_findbyclass(&s__X, canvas_class)); | ||
154 | } | ||
155 | |||
156 | void canvas_setcurrent(t_canvas *x) | ||
157 | { | ||
158 | pd_pushsym(&x->gl_pd); | ||
159 | } | ||
160 | |||
161 | void canvas_unsetcurrent(t_canvas *x) | ||
162 | { | ||
163 | pd_popsym(&x->gl_pd); | ||
164 | } | ||
165 | |||
166 | t_canvasenvironment *canvas_getenv(t_canvas *x) | ||
167 | { | ||
168 | if (!x) bug("canvas_getenv"); | ||
169 | while (!x->gl_env) | ||
170 | if (!(x = x->gl_owner)) | ||
171 | bug("t_canvasenvironment", x); | ||
172 | return (x->gl_env); | ||
173 | } | ||
174 | |||
175 | int canvas_getdollarzero( void) | ||
176 | { | ||
177 | t_canvas *x = canvas_getcurrent(); | ||
178 | t_canvasenvironment *env = (x ? canvas_getenv(x) : 0); | ||
179 | if (env) | ||
180 | return (env->ce_dollarzero); | ||
181 | else return (0); | ||
182 | } | ||
183 | |||
184 | void canvas_getargs(int *argcp, t_atom **argvp) | ||
185 | { | ||
186 | t_canvasenvironment *e = canvas_getenv(canvas_getcurrent()); | ||
187 | *argcp = e->ce_argc; | ||
188 | *argvp = e->ce_argv; | ||
189 | } | ||
190 | |||
191 | t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s) | ||
192 | { | ||
193 | t_symbol *ret; | ||
194 | char *name = s->s_name; | ||
195 | if (*name == '$' && name[1] >= '0' && name[1] <= '9') | ||
196 | { | ||
197 | t_canvasenvironment *env = canvas_getenv(x); | ||
198 | canvas_setcurrent(x); | ||
199 | ret = binbuf_realizedollsym(gensym(name+1), | ||
200 | env->ce_argc, env->ce_argv, 1); | ||
201 | canvas_unsetcurrent(x); | ||
202 | } | ||
203 | else ret = s; | ||
204 | return (ret); | ||
205 | } | ||
206 | |||
207 | t_symbol *canvas_getcurrentdir(void) | ||
208 | { | ||
209 | t_canvasenvironment *e = canvas_getenv(canvas_getcurrent()); | ||
210 | return (e->ce_dir); | ||
211 | } | ||
212 | |||
213 | t_symbol *canvas_getdir(t_canvas *x) | ||
214 | { | ||
215 | t_canvasenvironment *e = canvas_getenv(x); | ||
216 | return (e->ce_dir); | ||
217 | } | ||
218 | |||
219 | void canvas_makefilename(t_canvas *x, char *file, char *result, int resultsize) | ||
220 | { | ||
221 | char *dir = canvas_getenv(x)->ce_dir->s_name; | ||
222 | if (file[0] == '/' || (file[0] && file[1] == ':') || !*dir) | ||
223 | { | ||
224 | strncpy(result, file, resultsize); | ||
225 | result[resultsize-1] = 0; | ||
226 | } | ||
227 | else | ||
228 | { | ||
229 | int nleft; | ||
230 | strncpy(result, dir, resultsize); | ||
231 | result[resultsize-1] = 0; | ||
232 | nleft = resultsize - strlen(result) - 1; | ||
233 | if (nleft <= 0) return; | ||
234 | strcat(result, "/"); | ||
235 | strncat(result, file, nleft); | ||
236 | result[resultsize-1] = 0; | ||
237 | } | ||
238 | } | ||
239 | |||
240 | void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir) | ||
241 | { | ||
242 | if (strcmp(x->gl_name->s_name, "Pd")) | ||
243 | pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name)); | ||
244 | x->gl_name = s; | ||
245 | if (strcmp(x->gl_name->s_name, "Pd")) | ||
246 | pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name)); | ||
247 | if (glist_isvisible(x)) | ||
248 | canvas_reflecttitle(x); | ||
249 | if (dir && dir != &s_) | ||
250 | { | ||
251 | t_canvasenvironment *e = canvas_getenv(x); | ||
252 | e->ce_dir = dir; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | /* --------------- traversing the set of lines in a canvas ----------- */ | ||
257 | |||
258 | int canvas_getindex(t_canvas *x, t_gobj *y) | ||
259 | { | ||
260 | t_gobj *y2; | ||
261 | int indexno; | ||
262 | for (indexno = 0, y2 = x->gl_list; y2 && y2 != y; y2 = y2->g_next) | ||
263 | indexno++; | ||
264 | return (indexno); | ||
265 | } | ||
266 | |||
267 | void linetraverser_start(t_linetraverser *t, t_canvas *x) | ||
268 | { | ||
269 | t->tr_ob = 0; | ||
270 | t->tr_x = x; | ||
271 | t->tr_nextoc = 0; | ||
272 | t->tr_nextoutno = t->tr_nout = 0; | ||
273 | } | ||
274 | |||
275 | t_outconnect *linetraverser_next(t_linetraverser *t) | ||
276 | { | ||
277 | t_outconnect *rval = t->tr_nextoc; | ||
278 | int outno; | ||
279 | while (!rval) | ||
280 | { | ||
281 | outno = t->tr_nextoutno; | ||
282 | while (outno == t->tr_nout) | ||
283 | { | ||
284 | t_gobj *y; | ||
285 | t_object *ob = 0; | ||
286 | if (!t->tr_ob) y = t->tr_x->gl_list; | ||
287 | else y = t->tr_ob->ob_g.g_next; | ||
288 | for (; y; y = y->g_next) | ||
289 | if (ob = pd_checkobject(&y->g_pd)) break; | ||
290 | if (!ob) return (0); | ||
291 | t->tr_ob = ob; | ||
292 | t->tr_nout = obj_noutlets(ob); | ||
293 | outno = 0; | ||
294 | if (glist_isvisible(t->tr_x)) | ||
295 | gobj_getrect(y, t->tr_x, | ||
296 | &t->tr_x11, &t->tr_y11, &t->tr_x12, &t->tr_y12); | ||
297 | else t->tr_x11 = t->tr_y11 = t->tr_x12 = t->tr_y12 = 0; | ||
298 | } | ||
299 | t->tr_nextoutno = outno + 1; | ||
300 | rval = obj_starttraverseoutlet(t->tr_ob, &t->tr_outlet, outno); | ||
301 | t->tr_outno = outno; | ||
302 | } | ||
303 | t->tr_nextoc = obj_nexttraverseoutlet(rval, &t->tr_ob2, | ||
304 | &t->tr_inlet, &t->tr_inno); | ||
305 | t->tr_nin = obj_ninlets(t->tr_ob2); | ||
306 | if (!t->tr_nin) bug("drawline"); | ||
307 | if (glist_isvisible(t->tr_x)) | ||
308 | { | ||
309 | int inplus = (t->tr_nin == 1 ? 1 : t->tr_nin - 1); | ||
310 | int outplus = (t->tr_nout == 1 ? 1 : t->tr_nout - 1); | ||
311 | gobj_getrect(&t->tr_ob2->ob_g, t->tr_x, | ||
312 | &t->tr_x21, &t->tr_y21, &t->tr_x22, &t->tr_y22); | ||
313 | t->tr_lx1 = t->tr_x11 + | ||
314 | ((t->tr_x12 - t->tr_x11 - IOWIDTH) * t->tr_outno) / | ||
315 | outplus + IOMIDDLE; | ||
316 | t->tr_ly1 = t->tr_y12; | ||
317 | t->tr_lx2 = t->tr_x21 + | ||
318 | ((t->tr_x22 - t->tr_x21 - IOWIDTH) * t->tr_inno)/inplus + | ||
319 | IOMIDDLE; | ||
320 | t->tr_ly2 = t->tr_y21; | ||
321 | } | ||
322 | else | ||
323 | { | ||
324 | t->tr_x21 = t->tr_y21 = t->tr_x22 = t->tr_y22 = 0; | ||
325 | t->tr_lx1 = t->tr_ly1 = t->tr_lx2 = t->tr_ly2 = 0; | ||
326 | } | ||
327 | |||
328 | return (rval); | ||
329 | } | ||
330 | |||
331 | void linetraverser_skipobject(t_linetraverser *t) | ||
332 | { | ||
333 | t->tr_nextoc = 0; | ||
334 | t->tr_nextoutno = t->tr_nout; | ||
335 | } | ||
336 | |||
337 | /* -------------------- the canvas object -------------------------- */ | ||
338 | int glist_valid = 10000; | ||
339 | |||
340 | void glist_init(t_glist *x) | ||
341 | { | ||
342 | /* zero out everyone except "pd" field */ | ||
343 | memset(((char *)x) + sizeof(x->gl_pd), 0, sizeof(*x) - sizeof(x->gl_pd)); | ||
344 | x->gl_stub = gstub_new(x, 0); | ||
345 | x->gl_valid = ++glist_valid; | ||
346 | x->gl_xlabel = (t_symbol **)t_getbytes(0); | ||
347 | x->gl_ylabel = (t_symbol **)t_getbytes(0); | ||
348 | } | ||
349 | |||
350 | /* make a new glist. It will either be a "root" canvas or else | ||
351 | its parent will be a "text" object in another window... we don't | ||
352 | know which yet. */ | ||
353 | t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) | ||
354 | { | ||
355 | t_canvas *x = (t_canvas *)pd_new(canvas_class); | ||
356 | t_canvas *owner = canvas_getcurrent(); | ||
357 | t_symbol *s = &s_; | ||
358 | int vis = 0, width = GLIST_DEFCANVASWIDTH, height = GLIST_DEFCANVASHEIGHT; | ||
359 | int xloc = 0, yloc = GLIST_DEFCANVASYLOC; | ||
360 | int font = (owner ? owner->gl_font : sys_defaultfont); | ||
361 | glist_init(x); | ||
362 | x->gl_obj.te_type = T_OBJECT; | ||
363 | if (!owner) | ||
364 | canvas_addtolist(x); | ||
365 | /* post("canvas %x, owner %x", x, owner); */ | ||
366 | |||
367 | if (argc == 5) /* toplevel: x, y, w, h, font */ | ||
368 | { | ||
369 | xloc = atom_getintarg(0, argc, argv); | ||
370 | yloc = atom_getintarg(1, argc, argv); | ||
371 | width = atom_getintarg(2, argc, argv); | ||
372 | height = atom_getintarg(3, argc, argv); | ||
373 | font = atom_getintarg(4, argc, argv); | ||
374 | } | ||
375 | else if (argc == 6) /* subwindow: x, y, w, h, name, vis */ | ||
376 | { | ||
377 | xloc = atom_getintarg(0, argc, argv); | ||
378 | yloc = atom_getintarg(1, argc, argv); | ||
379 | width = atom_getintarg(2, argc, argv); | ||
380 | height = atom_getintarg(3, argc, argv); | ||
381 | s = atom_getsymbolarg(4, argc, argv); | ||
382 | vis = atom_getintarg(5, argc, argv); | ||
383 | } | ||
384 | /* (otherwise assume we're being created from the menu.) */ | ||
385 | |||
386 | if (canvas_newdirectory->s_name[0]) | ||
387 | { | ||
388 | static int dollarzero = 1000; | ||
389 | t_canvasenvironment *env = x->gl_env = | ||
390 | (t_canvasenvironment *)getbytes(sizeof(*x->gl_env)); | ||
391 | env->ce_dir = canvas_newdirectory; | ||
392 | env->ce_argc = canvas_newargc; | ||
393 | env->ce_argv = canvas_newargv; | ||
394 | env->ce_dollarzero = dollarzero++; | ||
395 | canvas_newdirectory = &s_; | ||
396 | canvas_newargc = 0; | ||
397 | canvas_newargv = 0; | ||
398 | } | ||
399 | else x->gl_env = 0; | ||
400 | |||
401 | if (yloc < GLIST_DEFCANVASYLOC) | ||
402 | yloc = GLIST_DEFCANVASYLOC; | ||
403 | if (xloc < 0) | ||
404 | xloc = 0; | ||
405 | x->gl_x1 = 0; | ||
406 | x->gl_y1 = 0; | ||
407 | x->gl_x2 = 1; | ||
408 | x->gl_y2 = 1; | ||
409 | canvas_setbounds(x, xloc, yloc, xloc + width, yloc + height); | ||
410 | x->gl_owner = owner; | ||
411 | x->gl_name = (*s->s_name ? s : | ||
412 | (canvas_newfilename ? canvas_newfilename : gensym("Pd"))); | ||
413 | if (strcmp(x->gl_name->s_name, "Pd")) | ||
414 | pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name)); | ||
415 | x->gl_loading = 1; | ||
416 | x->gl_willvis = vis; | ||
417 | x->gl_edit = !strncmp(x->gl_name->s_name, "Untitled", 8); | ||
418 | x->gl_font = sys_nearestfontsize(font); | ||
419 | pd_pushsym(&x->gl_pd); | ||
420 | return(x); | ||
421 | } | ||
422 | |||
423 | void canvas_setgraph(t_glist *x, int flag); | ||
424 | |||
425 | static void canvas_coords(t_glist *x, t_symbol *s, int argc, t_atom *argv) | ||
426 | { | ||
427 | x->gl_x1 = atom_getfloatarg(0, argc, argv); | ||
428 | x->gl_y1 = atom_getfloatarg(1, argc, argv); | ||
429 | x->gl_x2 = atom_getfloatarg(2, argc, argv); | ||
430 | x->gl_y2 = atom_getfloatarg(3, argc, argv); | ||
431 | x->gl_pixwidth = atom_getintarg(4, argc, argv); | ||
432 | x->gl_pixheight = atom_getintarg(5, argc, argv); | ||
433 | canvas_setgraph(x, atom_getintarg(6, argc, argv)); | ||
434 | } | ||
435 | |||
436 | /* make a new glist and add it to this glist. It will appear as | ||
437 | a "graph", not a text object. */ | ||
438 | t_glist *glist_addglist(t_glist *g, t_symbol *sym, | ||
439 | float x1, float y1, float x2, float y2, | ||
440 | float px1, float py1, float px2, float py2) | ||
441 | { | ||
442 | static int gcount = 0; | ||
443 | int zz; | ||
444 | int menu = 0; | ||
445 | char *str; | ||
446 | t_glist *x = (t_glist *)pd_new(canvas_class); | ||
447 | glist_init(x); | ||
448 | x->gl_obj.te_type = T_OBJECT; | ||
449 | if (!*sym->s_name) | ||
450 | { | ||
451 | char buf[40]; | ||
452 | sprintf(buf, "graph%d", ++gcount); | ||
453 | sym = gensym(buf); | ||
454 | menu = 1; | ||
455 | } | ||
456 | else if (!strncmp((str = sym->s_name), "graph", 5) | ||
457 | && (zz = atoi(str + 5)) > gcount) | ||
458 | gcount = zz; | ||
459 | /* in 0.34 and earlier, the pixel rectangle and the y bounds were | ||
460 | reversed; this would behave the same, except that the dialog window | ||
461 | would be confusing. The "correct" way is to have "py1" be the value | ||
462 | that is higher on the screen. */ | ||
463 | if (py2 < py1) | ||
464 | { | ||
465 | float zz; | ||
466 | zz = y2; | ||
467 | y2 = y1; | ||
468 | y1 = zz; | ||
469 | zz = py2; | ||
470 | py2 = py1; | ||
471 | py1 = zz; | ||
472 | } | ||
473 | if (x1 == x2 || y1 == y2) | ||
474 | x1 = 0, x2 = 100, y1 = 1, y2 = -1; | ||
475 | if (px1 >= px2 || py1 >= py2) | ||
476 | px1 = 100, py1 = 20, px2 = 100 + GLIST_DEFGRAPHWIDTH, | ||
477 | py2 = 20 + GLIST_DEFGRAPHHEIGHT; | ||
478 | x->gl_name = sym; | ||
479 | x->gl_x1 = x1; | ||
480 | x->gl_x2 = x2; | ||
481 | x->gl_y1 = y1; | ||
482 | x->gl_y2 = y2; | ||
483 | x->gl_obj.te_xpix = px1; | ||
484 | x->gl_obj.te_ypix = py1; | ||
485 | x->gl_pixwidth = px2 - px1; | ||
486 | x->gl_pixheight = py2 - py1; | ||
487 | x->gl_font = (canvas_getcurrent() ? | ||
488 | canvas_getcurrent()->gl_font : sys_defaultfont); | ||
489 | x->gl_screenx1 = x->gl_screeny1 = 0; | ||
490 | x->gl_screenx2 = 240; | ||
491 | x->gl_screeny2 = 300; | ||
492 | if (strcmp(x->gl_name->s_name, "Pd")) | ||
493 | pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name)); | ||
494 | x->gl_owner = g; | ||
495 | x->gl_stretch = 1; | ||
496 | x->gl_isgraph = 1; | ||
497 | x->gl_obj.te_binbuf = binbuf_new(); | ||
498 | binbuf_addv(x->gl_obj.te_binbuf, "s", gensym("graph")); | ||
499 | if (!menu) | ||
500 | pd_pushsym(&x->gl_pd); | ||
501 | glist_add(g, &x->gl_gobj); | ||
502 | if (glist_isvisible(g)) | ||
503 | canvas_create_editor(x, 1); | ||
504 | return (x); | ||
505 | } | ||
506 | |||
507 | /* call glist_addglist from a Pd message */ | ||
508 | void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv) | ||
509 | { | ||
510 | t_symbol *sym = atom_getsymbolarg(0, argc, argv); | ||
511 | float x1 = atom_getfloatarg(1, argc, argv); | ||
512 | float y1 = atom_getfloatarg(2, argc, argv); | ||
513 | float x2 = atom_getfloatarg(3, argc, argv); | ||
514 | float y2 = atom_getfloatarg(4, argc, argv); | ||
515 | float px1 = atom_getfloatarg(5, argc, argv); | ||
516 | float py1 = atom_getfloatarg(6, argc, argv); | ||
517 | float px2 = atom_getfloatarg(7, argc, argv); | ||
518 | float py2 = atom_getfloatarg(8, argc, argv); | ||
519 | glist_addglist(g, sym, x1, y1, x2, y2, px1, py1, px2, py2); | ||
520 | } | ||
521 | |||
522 | /* return true if the glist should appear as a graph on parent; | ||
523 | otherwise it appears as a text box. */ | ||
524 | int glist_isgraph(t_glist *x) | ||
525 | { | ||
526 | return (x->gl_isgraph); | ||
527 | } | ||
528 | |||
529 | /* This is sent from the GUI to inform a toplevel that its window has been | ||
530 | moved or resized. */ | ||
531 | static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2) | ||
532 | { | ||
533 | int heightwas = y2 - y1; | ||
534 | int heightchange = y2 - y1 - (x->gl_screeny2 - x->gl_screeny1); | ||
535 | x->gl_screenx1 = x1; | ||
536 | x->gl_screeny1 = y1; | ||
537 | x->gl_screenx2 = x2; | ||
538 | x->gl_screeny2 = y2; | ||
539 | /* post("set bounds %d %d %d %d", x1, y1, x2, y2); */ | ||
540 | if (!glist_isgraph(x) && (x->gl_y2 < x->gl_y1)) | ||
541 | { | ||
542 | /* if it's flipped so that y grows upward, | ||
543 | fix so that zero is bottom edge and redraw. This is | ||
544 | only appropriate if we're a regular "text" object on the | ||
545 | parent. */ | ||
546 | float diff = x->gl_y1 - x->gl_y2; | ||
547 | t_gobj *y; | ||
548 | x->gl_y1 = heightwas * diff; | ||
549 | x->gl_y2 = x->gl_y1 - diff; | ||
550 | /* and move text objects accordingly; they should stick | ||
551 | to the bottom, not the top. */ | ||
552 | for (y = x->gl_list; y; y = y->g_next) | ||
553 | if (pd_checkobject(&y->g_pd)) | ||
554 | gobj_displace(y, x, 0, heightchange); | ||
555 | canvas_redraw(x); | ||
556 | } | ||
557 | } | ||
558 | |||
559 | t_symbol *canvas_makebindsym(t_symbol *s) | ||
560 | { | ||
561 | char buf[MAXPDSTRING]; | ||
562 | strcpy(buf, "pd-"); | ||
563 | strcat(buf, s->s_name); | ||
564 | return (gensym(buf)); | ||
565 | } | ||
566 | |||
567 | void canvas_reflecttitle(t_canvas *x) | ||
568 | { | ||
569 | char namebuf[MAXPDSTRING]; | ||
570 | t_canvasenvironment *env = canvas_getenv(x); | ||
571 | if (env->ce_argc) | ||
572 | { | ||
573 | int i; | ||
574 | strcpy(namebuf, " ("); | ||
575 | for (i = 0; i < env->ce_argc; i++) | ||
576 | { | ||
577 | if (strlen(namebuf) > MAXPDSTRING/2 - 5) | ||
578 | break; | ||
579 | if (i != 0) | ||
580 | strcat(namebuf, " "); | ||
581 | atom_string(&env->ce_argv[i], namebuf + strlen(namebuf), | ||
582 | MAXPDSTRING/2); | ||
583 | } | ||
584 | strcat(namebuf, ")"); | ||
585 | } | ||
586 | else namebuf[0] = 0; | ||
587 | sys_vgui("wm title .x%x {%s%c%s - %s}\n", | ||
588 | x, x->gl_name->s_name, (x->gl_dirty? '*' : ' '), namebuf, | ||
589 | canvas_getdir(x)->s_name); | ||
590 | } | ||
591 | |||
592 | void canvas_dirty(t_canvas *x, t_int n) | ||
593 | { | ||
594 | t_canvas *x2 = canvas_getrootfor(x); | ||
595 | if ((unsigned)n != x2->gl_dirty) | ||
596 | { | ||
597 | x2->gl_dirty = n; | ||
598 | canvas_reflecttitle(x2); | ||
599 | } | ||
600 | } | ||
601 | |||
602 | /* the window becomes "mapped" (visible and not miniaturized) or | ||
603 | "unmapped" (either miniaturized or just plain gone.) This should be | ||
604 | called from the GUI after the fact to "notify" us that we're mapped. */ | ||
605 | void canvas_map(t_canvas *x, t_floatarg f) | ||
606 | { | ||
607 | int flag = (f != 0); | ||
608 | t_gobj *y; | ||
609 | if (flag) | ||
610 | { | ||
611 | if (!glist_isvisible(x)) | ||
612 | { | ||
613 | t_selection *sel; | ||
614 | if (!x->gl_havewindow) | ||
615 | { | ||
616 | bug("canvas_map"); | ||
617 | canvas_vis(x, 1); | ||
618 | } | ||
619 | for (y = x->gl_list; y; y = y->g_next) | ||
620 | gobj_vis(y, x, 1); | ||
621 | for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next) | ||
622 | gobj_select(sel->sel_what, x, 1); | ||
623 | x->gl_mapped = 1; | ||
624 | canvas_drawlines(x); | ||
625 | /* simulate a mouse up so u_main will calculate scrollbars... | ||
626 | ugly! */ | ||
627 | sys_vgui("pdtk_canvas_mouseup .x%x.c 0 0 0\n", x); | ||
628 | } | ||
629 | } | ||
630 | else | ||
631 | { | ||
632 | if (glist_isvisible(x)) | ||
633 | { | ||
634 | /* just clear out the whole canvas... */ | ||
635 | sys_vgui(".x%x.c delete all\n", x); | ||
636 | /* alternatively, we could have erased them one by one... | ||
637 | for (y = x->gl_list; y; y = y->g_next) | ||
638 | gobj_vis(y, x, 0); | ||
639 | ... but we should go through and erase the lines as well | ||
640 | if we do it that way. */ | ||
641 | x->gl_mapped = 0; | ||
642 | } | ||
643 | } | ||
644 | } | ||
645 | |||
646 | void canvas_redraw(t_canvas *x) | ||
647 | { | ||
648 | if (glist_isvisible(x)) | ||
649 | { | ||
650 | canvas_map(x, 0); | ||
651 | canvas_map(x, 1); | ||
652 | } | ||
653 | } | ||
654 | |||
655 | /* ---- editors -- perhaps this and "vis" should go to g_editor.c ------- */ | ||
656 | |||
657 | static t_editor *editor_new(t_glist *owner) | ||
658 | { | ||
659 | char buf[40]; | ||
660 | t_editor *x = (t_editor *)getbytes(sizeof(*x)); | ||
661 | x->e_connectbuf = binbuf_new(); | ||
662 | x->e_deleted = binbuf_new(); | ||
663 | x->e_glist = owner; | ||
664 | sprintf(buf, ".x%x", (t_int)owner); | ||
665 | x->e_guiconnect = guiconnect_new(&owner->gl_pd, gensym(buf)); | ||
666 | return (x); | ||
667 | } | ||
668 | |||
669 | static void editor_free(t_editor *x, t_glist *y) | ||
670 | { | ||
671 | glist_noselect(y); | ||
672 | guiconnect_notarget(x->e_guiconnect, 1000); | ||
673 | binbuf_free(x->e_connectbuf); | ||
674 | binbuf_free(x->e_deleted); | ||
675 | freebytes((void *)x, sizeof(*x)); | ||
676 | } | ||
677 | |||
678 | /* recursively create or destroy all editors of a glist and its | ||
679 | sub-glists, as long as they aren't toplevels. */ | ||
680 | void canvas_create_editor(t_glist *x, int createit) | ||
681 | { | ||
682 | t_gobj *y; | ||
683 | t_object *ob; | ||
684 | if (createit) | ||
685 | { | ||
686 | if (x->gl_editor) | ||
687 | bug("canvas_create_editor"); | ||
688 | else | ||
689 | { | ||
690 | x->gl_editor = editor_new(x); | ||
691 | for (y = x->gl_list; y; y = y->g_next) | ||
692 | if (ob = pd_checkobject(&y->g_pd)) | ||
693 | rtext_new(x, ob); | ||
694 | } | ||
695 | } | ||
696 | else | ||
697 | { | ||
698 | if (!x->gl_editor) | ||
699 | bug("canvas_create_editor"); | ||
700 | else | ||
701 | { | ||
702 | for (y = x->gl_list; y; y = y->g_next) | ||
703 | if (ob = pd_checkobject(&y->g_pd)) | ||
704 | rtext_free(glist_findrtext(x, ob)); | ||
705 | editor_free(x->gl_editor, x); | ||
706 | x->gl_editor = 0; | ||
707 | } | ||
708 | } | ||
709 | for (y = x->gl_list; y; y = y->g_next) | ||
710 | if (pd_class(&y->g_pd) == canvas_class && | ||
711 | ((t_canvas *)y)->gl_isgraph) | ||
712 | canvas_create_editor((t_canvas *)y, createit); | ||
713 | } | ||
714 | |||
715 | /* we call this when we want the window to become visible, mapped, and | ||
716 | in front of all windows; or with "f" zero, when we want to get rid of | ||
717 | the window. */ | ||
718 | void canvas_vis(t_canvas *x, t_floatarg f) | ||
719 | { | ||
720 | char buf[30]; | ||
721 | int flag = (f != 0); | ||
722 | if (flag) | ||
723 | { | ||
724 | /* test if we're already visible and toplevel */ | ||
725 | if (glist_isvisible(x) && !x->gl_isgraph) | ||
726 | { /* just put us in front */ | ||
727 | #ifdef MSW | ||
728 | canvas_vis(x, 0); | ||
729 | canvas_vis(x, 1); | ||
730 | #else | ||
731 | sys_vgui("raise .x%x\n", x); | ||
732 | sys_vgui("focus .x%x.c\n", x); | ||
733 | sys_vgui("wm deiconify .x%x\n", x); | ||
734 | #endif | ||
735 | } | ||
736 | else | ||
737 | { | ||
738 | canvas_create_editor(x, 1); | ||
739 | sys_vgui("pdtk_canvas_new .x%x %d %d +%d+%d %d\n", x, | ||
740 | (int)(x->gl_screenx2 - x->gl_screenx1), | ||
741 | (int)(x->gl_screeny2 - x->gl_screeny1), | ||
742 | (int)(x->gl_screenx1), (int)(x->gl_screeny1), | ||
743 | x->gl_edit); | ||
744 | canvas_reflecttitle(x); | ||
745 | x->gl_havewindow = 1; | ||
746 | canvas_updatewindowlist(); | ||
747 | } | ||
748 | } | ||
749 | else /* make invisible */ | ||
750 | { | ||
751 | int i; | ||
752 | t_canvas *x2; | ||
753 | if (!x->gl_havewindow) | ||
754 | { | ||
755 | /* bug workaround -- a graph in a visible patch gets "invised" | ||
756 | when the patch is closed, and must lose the editor here. It's | ||
757 | probably not the natural place to do this. Other cases like | ||
758 | subpatches fall here too but don'd need the editor freed, so | ||
759 | we check if it exists. */ | ||
760 | if (x->gl_editor) | ||
761 | canvas_create_editor(x, 0); | ||
762 | return; | ||
763 | } | ||
764 | glist_noselect(x); | ||
765 | if (glist_isvisible(x)) | ||
766 | canvas_map(x, 0); | ||
767 | canvas_create_editor(x, 0); | ||
768 | sys_vgui("destroy .x%x\n", x); | ||
769 | for (i = 1, x2 = x; x2; x2 = x2->gl_next, i++) | ||
770 | ; | ||
771 | sys_vgui(".mbar.find delete %d\n", i); | ||
772 | /* if we're a graph on our parent, and if the parent exists | ||
773 | and is visible, show ourselves on parent. */ | ||
774 | if (glist_isgraph(x) && x->gl_owner) | ||
775 | { | ||
776 | t_glist *gl2 = x->gl_owner; | ||
777 | canvas_create_editor(x, 1); | ||
778 | if (glist_isvisible(gl2)) | ||
779 | gobj_vis(&x->gl_gobj, gl2, 0); | ||
780 | x->gl_havewindow = 0; | ||
781 | if (glist_isvisible(gl2)) | ||
782 | gobj_vis(&x->gl_gobj, gl2, 1); | ||
783 | } | ||
784 | else x->gl_havewindow = 0; | ||
785 | canvas_updatewindowlist(); | ||
786 | } | ||
787 | } | ||
788 | |||
789 | /* we call this on a non-toplevel glist to "open" it into its | ||
790 | own window. */ | ||
791 | void glist_menu_open(t_glist *x) | ||
792 | { | ||
793 | if (glist_isvisible(x) && !glist_istoplevel(x)) | ||
794 | { | ||
795 | t_glist *gl2 = x->gl_owner; | ||
796 | if (!gl2) | ||
797 | bug("canvas_vis"); /* shouldn't happen but don't get too upset. */ | ||
798 | else | ||
799 | { | ||
800 | /* erase ourself in parent window */ | ||
801 | gobj_vis(&x->gl_gobj, gl2, 0); | ||
802 | /* get rid of our editor (and subeditors) */ | ||
803 | canvas_create_editor(x, 0); | ||
804 | x->gl_havewindow = 1; | ||
805 | /* redraw ourself in parent window (blanked out this time) */ | ||
806 | gobj_vis(&x->gl_gobj, gl2, 1); | ||
807 | } | ||
808 | } | ||
809 | canvas_vis(x, 1); | ||
810 | } | ||
811 | |||
812 | int glist_isvisible(t_glist *x) | ||
813 | { | ||
814 | return ((!x->gl_loading) && glist_getcanvas(x)->gl_mapped); | ||
815 | } | ||
816 | |||
817 | int glist_istoplevel(t_glist *x) | ||
818 | { | ||
819 | /* we consider a graph "toplevel" if it has its own window | ||
820 | or if it appears as a box in its parent window so that we | ||
821 | don't draw the actual contents there. */ | ||
822 | return (x->gl_havewindow || !x->gl_isgraph); | ||
823 | } | ||
824 | |||
825 | int glist_getfont(t_glist *x) | ||
826 | { | ||
827 | return (glist_getcanvas(x)->gl_font); | ||
828 | } | ||
829 | |||
830 | void canvas_free(t_canvas *x) | ||
831 | { | ||
832 | t_gobj *y; | ||
833 | int dspstate = canvas_suspend_dsp(); | ||
834 | canvas_noundo(x); | ||
835 | if (canvas_editing == x) | ||
836 | canvas_editing = 0; | ||
837 | if (canvas_whichfind == x) | ||
838 | canvas_whichfind = 0; | ||
839 | glist_noselect(x); | ||
840 | while (y = x->gl_list) | ||
841 | glist_delete(x, y); | ||
842 | canvas_vis(x, 0); | ||
843 | |||
844 | if (strcmp(x->gl_name->s_name, "Pd")) | ||
845 | pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name)); | ||
846 | if (x->gl_env) | ||
847 | { | ||
848 | freebytes(x->gl_env->ce_argv, x->gl_env->ce_argc * sizeof(t_atom)); | ||
849 | freebytes(x->gl_env, sizeof(*x->gl_env)); | ||
850 | } | ||
851 | canvas_resume_dsp(dspstate); | ||
852 | glist_cleanup(x); | ||
853 | gfxstub_deleteforkey(x); /* probably unnecessary */ | ||
854 | if (!x->gl_owner) | ||
855 | canvas_takeofflist(x); | ||
856 | } | ||
857 | |||
858 | /* ----------------- lines ---------- */ | ||
859 | |||
860 | static void canvas_drawlines(t_canvas *x) | ||
861 | { | ||
862 | t_linetraverser t; | ||
863 | t_outconnect *oc; | ||
864 | { | ||
865 | linetraverser_start(&t, x); | ||
866 | while (oc = linetraverser_next(&t)) | ||
867 | sys_vgui(".x%x.c create line %d %d %d %d -width %d -tags l%x\n", | ||
868 | glist_getcanvas(x), | ||
869 | t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2, | ||
870 | (outlet_getsymbol(t.tr_outlet) == &s_signal ? 2:1), | ||
871 | oc); | ||
872 | } | ||
873 | } | ||
874 | |||
875 | void canvas_fixlinesfor(t_canvas *x, t_text *text) | ||
876 | { | ||
877 | t_linetraverser t; | ||
878 | t_outconnect *oc; | ||
879 | |||
880 | linetraverser_start(&t, x); | ||
881 | while (oc = linetraverser_next(&t)) | ||
882 | { | ||
883 | if (t.tr_ob == text || t.tr_ob2 == text) | ||
884 | { | ||
885 | sys_vgui(".x%x.c coords l%x %d %d %d %d\n", | ||
886 | glist_getcanvas(x), oc, | ||
887 | t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2); | ||
888 | } | ||
889 | } | ||
890 | } | ||
891 | |||
892 | /* kill all lines for the object */ | ||
893 | void canvas_deletelinesfor(t_canvas *x, t_text *text) | ||
894 | { | ||
895 | t_linetraverser t; | ||
896 | t_outconnect *oc; | ||
897 | linetraverser_start(&t, x); | ||
898 | while (oc = linetraverser_next(&t)) | ||
899 | { | ||
900 | if (t.tr_ob == text || t.tr_ob2 == text) | ||
901 | { | ||
902 | if (x->gl_editor) | ||
903 | { | ||
904 | sys_vgui(".x%x.c delete l%x\n", | ||
905 | glist_getcanvas(x), oc); | ||
906 | } | ||
907 | obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno); | ||
908 | } | ||
909 | } | ||
910 | } | ||
911 | |||
912 | /* kill all lines for one inlet or outlet */ | ||
913 | void canvas_deletelinesforio(t_canvas *x, t_text *text, | ||
914 | t_inlet *inp, t_outlet *outp) | ||
915 | { | ||
916 | t_linetraverser t; | ||
917 | t_outconnect *oc; | ||
918 | linetraverser_start(&t, x); | ||
919 | while (oc = linetraverser_next(&t)) | ||
920 | { | ||
921 | if ((t.tr_ob == text && t.tr_outlet == outp) || | ||
922 | (t.tr_ob2 == text && t.tr_inlet == inp)) | ||
923 | { | ||
924 | if (x->gl_editor) | ||
925 | { | ||
926 | sys_vgui(".x%x.c delete l%x\n", | ||
927 | glist_getcanvas(x), oc); | ||
928 | } | ||
929 | obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno); | ||
930 | } | ||
931 | } | ||
932 | } | ||
933 | |||
934 | static void canvas_pop(t_canvas *x, t_floatarg fvis) | ||
935 | { | ||
936 | if (fvis != 0) | ||
937 | canvas_vis(x, 1); | ||
938 | pd_popsym(&x->gl_pd); | ||
939 | canvas_resortinlets(x); | ||
940 | canvas_resortoutlets(x); | ||
941 | x->gl_loading = 0; | ||
942 | } | ||
943 | |||
944 | void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv); | ||
945 | |||
946 | |||
947 | void canvas_restore(t_canvas *x, t_symbol *s, int argc, t_atom *argv) | ||
948 | { /* IOhannes */ | ||
949 | t_pd *z; | ||
950 | /* this should be unnecessary, but sometimes the canvas's name gets | ||
951 | out of sync with the owning box's argument; this fixes that */ | ||
952 | if (argc > 3) | ||
953 | { | ||
954 | t_atom *ap=argv+3; | ||
955 | if (ap->a_type == A_SYMBOL) | ||
956 | { | ||
957 | char *buf=ap->a_w.w_symbol->s_name, *bufp; | ||
958 | if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9') | ||
959 | { | ||
960 | for (bufp = buf+2; *bufp; bufp++) | ||
961 | if (*bufp < '0' || *bufp > '9') | ||
962 | { | ||
963 | SETDOLLSYM(ap, gensym(buf+1)); | ||
964 | goto didit; | ||
965 | } | ||
966 | SETDOLLAR(ap, atoi(buf+1)); | ||
967 | didit: ; | ||
968 | } | ||
969 | } | ||
970 | |||
971 | if (ap->a_type == A_DOLLSYM) | ||
972 | { | ||
973 | t_canvasenvironment *e = canvas_getenv(canvas_getcurrent()); | ||
974 | canvas_rename(x, binbuf_realizedollsym(ap->a_w.w_symbol, | ||
975 | e->ce_argc, e->ce_argv, 1), 0); | ||
976 | } | ||
977 | else if (ap->a_type == A_SYMBOL) | ||
978 | canvas_rename(x, argv[3].a_w.w_symbol, 0); | ||
979 | } | ||
980 | canvas_pop(x, x->gl_willvis); | ||
981 | |||
982 | if (!(z = gensym("#X")->s_thing)) error("canvas_restore: out of context"); | ||
983 | else if (*z != canvas_class) error("canvas_restore: wasn't a canvas"); | ||
984 | else | ||
985 | { | ||
986 | t_canvas *x2 = (t_canvas *)z; | ||
987 | x->gl_owner = x2; | ||
988 | canvas_objfor(x2, &x->gl_obj, argc, argv); | ||
989 | } | ||
990 | } | ||
991 | |||
992 | static void canvas_loadbangabstractions(t_canvas *x) | ||
993 | { | ||
994 | t_gobj *y; | ||
995 | t_symbol *s = gensym("loadbang"); | ||
996 | for (y = x->gl_list; y; y = y->g_next) | ||
997 | if (pd_class(&y->g_pd) == canvas_class) | ||
998 | { | ||
999 | if (canvas_isabstraction((t_canvas *)y)) | ||
1000 | canvas_loadbang((t_canvas *)y); | ||
1001 | else | ||
1002 | canvas_loadbangabstractions((t_canvas *)y); | ||
1003 | } | ||
1004 | } | ||
1005 | |||
1006 | void canvas_loadbangsubpatches(t_canvas *x) | ||
1007 | { | ||
1008 | t_gobj *y; | ||
1009 | t_symbol *s = gensym("loadbang"); | ||
1010 | for (y = x->gl_list; y; y = y->g_next) | ||
1011 | if (pd_class(&y->g_pd) == canvas_class) | ||
1012 | { | ||
1013 | if (!canvas_isabstraction((t_canvas *)y)) | ||
1014 | canvas_loadbangsubpatches((t_canvas *)y); | ||
1015 | } | ||
1016 | for (y = x->gl_list; y; y = y->g_next) | ||
1017 | if ((pd_class(&y->g_pd) != canvas_class) && | ||
1018 | zgetfn(&y->g_pd, s)) | ||
1019 | pd_vmess(&y->g_pd, s, ""); | ||
1020 | } | ||
1021 | |||
1022 | void canvas_loadbang(t_canvas *x) | ||
1023 | { | ||
1024 | t_gobj *y; | ||
1025 | canvas_loadbangabstractions(x); | ||
1026 | canvas_loadbangsubpatches(x); | ||
1027 | } | ||
1028 | |||
1029 | /* When you ask a canvas its size the result is 2 pixels more than what | ||
1030 | you gave it to open it; perhaps there's a 1-pixel border all around it | ||
1031 | or something. Anyway, we just add the 2 pixels back here; seems we | ||
1032 | have to do this for linux but not MSW; not sure about MacOS. */ | ||
1033 | |||
1034 | #ifdef MSW | ||
1035 | #define HORIZBORDER 0 | ||
1036 | #define VERTBORDER 0 | ||
1037 | #else | ||
1038 | #define HORIZBORDER 2 | ||
1039 | #define VERTBORDER 2 | ||
1040 | #endif | ||
1041 | |||
1042 | static void canvas_relocate(t_canvas *x, t_symbol *canvasgeom, | ||
1043 | t_symbol *topgeom) | ||
1044 | { | ||
1045 | int cxpix, cypix, cw, ch, txpix, typix, tw, th; | ||
1046 | if (sscanf(canvasgeom->s_name, "%dx%d+%d+%d", &cw, &ch, &cxpix, &cypix) | ||
1047 | < 4 || | ||
1048 | sscanf(topgeom->s_name, "%dx%d+%d+%d", &tw, &th, &txpix, &typix) < 4) | ||
1049 | bug("canvas_relocate"); | ||
1050 | /* for some reason this is initially called with cw=ch=1 so | ||
1051 | we just suppress that here. */ | ||
1052 | if (cw > 5 && ch > 5) | ||
1053 | canvas_setbounds(x, txpix, typix, | ||
1054 | txpix + cw - HORIZBORDER, typix + ch - VERTBORDER); | ||
1055 | } | ||
1056 | |||
1057 | void canvas_popabstraction(t_canvas *x) | ||
1058 | { | ||
1059 | newest = &x->gl_pd; | ||
1060 | pd_popsym(&x->gl_pd); | ||
1061 | x->gl_loading = 0; | ||
1062 | canvas_resortinlets(x); | ||
1063 | canvas_resortoutlets(x); | ||
1064 | } | ||
1065 | |||
1066 | void canvas_logerror(t_object *y) | ||
1067 | { | ||
1068 | #ifdef LATER | ||
1069 | canvas_vis(x, 1); | ||
1070 | if (!glist_isselected(x, &y->ob_g)) | ||
1071 | glist_select(x, &y->ob_g); | ||
1072 | #endif | ||
1073 | } | ||
1074 | |||
1075 | /* -------------------------- subcanvases ---------------------- */ | ||
1076 | |||
1077 | static void *subcanvas_new(t_symbol *s) | ||
1078 | { | ||
1079 | t_atom a[6]; | ||
1080 | t_canvas *x, *z = canvas_getcurrent(); | ||
1081 | if (!*s->s_name) s = gensym("/SUBPATCH/"); | ||
1082 | SETFLOAT(a, 0); | ||
1083 | SETFLOAT(a+1, GLIST_DEFCANVASYLOC); | ||
1084 | SETFLOAT(a+2, GLIST_DEFCANVASWIDTH); | ||
1085 | SETFLOAT(a+3, GLIST_DEFCANVASHEIGHT); | ||
1086 | SETSYMBOL(a+4, s); | ||
1087 | SETFLOAT(a+5, 1); | ||
1088 | x = canvas_new(0, 0, 6, a); | ||
1089 | x->gl_owner = z; | ||
1090 | canvas_pop(x, 1); | ||
1091 | return (x); | ||
1092 | } | ||
1093 | |||
1094 | static void canvas_click(t_canvas *x, | ||
1095 | t_floatarg xpos, t_floatarg ypos, | ||
1096 | t_floatarg shift, t_floatarg ctrl, t_floatarg alt) | ||
1097 | { | ||
1098 | canvas_vis(x, 1); | ||
1099 | } | ||
1100 | |||
1101 | |||
1102 | /* find out from subcanvas contents how much to fatten the box */ | ||
1103 | void canvas_fattensub(t_canvas *x, | ||
1104 | int *xp1, int *yp1, int *xp2, int *yp2) | ||
1105 | { | ||
1106 | t_gobj *y; | ||
1107 | *xp2 += 50; /* fake for now */ | ||
1108 | *yp2 += 50; | ||
1109 | } | ||
1110 | |||
1111 | static void canvas_rename_method(t_canvas *x, t_symbol *s, int ac, t_atom *av) | ||
1112 | { | ||
1113 | if (ac && av->a_type == A_SYMBOL) | ||
1114 | canvas_rename(x, av->a_w.w_symbol, 0); | ||
1115 | else canvas_rename(x, gensym("Pd"), 0); | ||
1116 | } | ||
1117 | |||
1118 | /* ------------------ table ---------------------------*/ | ||
1119 | |||
1120 | static int tabcount = 0; | ||
1121 | |||
1122 | static void *table_new(t_symbol *s, t_floatarg f) | ||
1123 | { | ||
1124 | t_atom a[9]; | ||
1125 | t_glist *gl; | ||
1126 | t_canvas *x, *z = canvas_getcurrent(); | ||
1127 | if (s == &s_) | ||
1128 | { | ||
1129 | char tabname[255]; | ||
1130 | t_symbol *t = gensym("table"); | ||
1131 | sprintf(tabname, "%s%d", t->s_name, tabcount++); | ||
1132 | s = gensym(tabname); | ||
1133 | } | ||
1134 | if (f <= 1) | ||
1135 | f = 100; | ||
1136 | SETFLOAT(a, 0); | ||
1137 | SETFLOAT(a+1, GLIST_DEFCANVASYLOC); | ||
1138 | SETFLOAT(a+2, 600); | ||
1139 | SETFLOAT(a+3, 400); | ||
1140 | SETSYMBOL(a+4, s); | ||
1141 | SETFLOAT(a+5, 0); | ||
1142 | x = canvas_new(0, 0, 6, a); | ||
1143 | |||
1144 | x->gl_owner = z; | ||
1145 | |||
1146 | /* create a graph for the table */ | ||
1147 | gl = glist_addglist((t_glist*)x, &s_, 0, -1, (f > 1 ? f-1 : 1), 1, | ||
1148 | 50, 350, 550, 50); | ||
1149 | |||
1150 | graph_array(gl, s, &s_float, f, 0); | ||
1151 | |||
1152 | canvas_pop(x, 0); | ||
1153 | |||
1154 | return (x); | ||
1155 | } | ||
1156 | |||
1157 | /* return true if the "canvas" object is an abstraction (so we don't | ||
1158 | save its contents, fogr example.) */ | ||
1159 | int canvas_isabstraction(t_canvas *x) | ||
1160 | { | ||
1161 | return (x->gl_env != 0); | ||
1162 | } | ||
1163 | |||
1164 | /* return true if the "canvas" object is a "table". */ | ||
1165 | int canvas_istable(t_canvas *x) | ||
1166 | { | ||
1167 | t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0); | ||
1168 | int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0); | ||
1169 | int istable = (argc && argv[0].a_type == A_SYMBOL && | ||
1170 | argv[0].a_w.w_symbol == gensym("table")); | ||
1171 | return (istable); | ||
1172 | } | ||
1173 | |||
1174 | /* return true if the "canvas" object should be treated as a text | ||
1175 | object. This is true for abstractions but also for "table"s... */ | ||
1176 | int canvas_showtext(t_canvas *x) | ||
1177 | { | ||
1178 | t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0); | ||
1179 | int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0); | ||
1180 | int isarray = (argc && argv[0].a_type == A_SYMBOL && | ||
1181 | argv[0].a_w.w_symbol == gensym("graph")); | ||
1182 | return (!isarray); | ||
1183 | } | ||
1184 | |||
1185 | static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp); | ||
1186 | static void canvas_dsp(t_canvas *x, t_signal **sp) | ||
1187 | { | ||
1188 | canvas_dodsp(x, 0, sp); | ||
1189 | } | ||
1190 | |||
1191 | /* get the document containing this canvas */ | ||
1192 | t_canvas *canvas_getrootfor(t_canvas *x) | ||
1193 | { | ||
1194 | if ((!x->gl_owner) || canvas_isabstraction(x)) | ||
1195 | return (x); | ||
1196 | else return (canvas_getrootfor(x->gl_owner)); | ||
1197 | } | ||
1198 | |||
1199 | /* ------------------------- DSP chain handling ------------------------- */ | ||
1200 | |||
1201 | EXTERN_STRUCT _dspcontext; | ||
1202 | #define t_dspcontext struct _dspcontext | ||
1203 | |||
1204 | void ugen_start(void); | ||
1205 | void ugen_stop(void); | ||
1206 | |||
1207 | t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp, | ||
1208 | int ninlets, int noutlets); | ||
1209 | void ugen_add(t_dspcontext *dc, t_object *x); | ||
1210 | void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, | ||
1211 | t_object *x2, int inno); | ||
1212 | void ugen_done_graph(t_dspcontext *dc); | ||
1213 | |||
1214 | /* schedule one canvas for DSP. This is called below for all "root" | ||
1215 | canvases, but is also called from the "dsp" method for sub- | ||
1216 | canvases, which are treated almost like any other tilde object. */ | ||
1217 | |||
1218 | static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp) | ||
1219 | { | ||
1220 | t_linetraverser t; | ||
1221 | t_outconnect *oc; | ||
1222 | t_gobj *y; | ||
1223 | t_object *ob; | ||
1224 | t_symbol *dspsym = gensym("dsp"); | ||
1225 | t_dspcontext *dc; | ||
1226 | |||
1227 | /* create a new "DSP graph" object to use in sorting this canvas. | ||
1228 | If we aren't toplevel, there are already other dspcontexts around. */ | ||
1229 | |||
1230 | dc = ugen_start_graph(toplevel, sp, | ||
1231 | obj_nsiginlets(&x->gl_obj), | ||
1232 | obj_nsigoutlets(&x->gl_obj)); | ||
1233 | |||
1234 | /* find all the "dsp" boxes and add them to the graph */ | ||
1235 | |||
1236 | for (y = x->gl_list; y; y = y->g_next) | ||
1237 | if ((ob = pd_checkobject(&y->g_pd)) && zgetfn(&y->g_pd, dspsym)) | ||
1238 | ugen_add(dc, ob); | ||
1239 | |||
1240 | /* ... and all dsp interconnections */ | ||
1241 | linetraverser_start(&t, x); | ||
1242 | while (oc = linetraverser_next(&t)) | ||
1243 | if (obj_issignaloutlet(t.tr_ob, t.tr_outno)) | ||
1244 | ugen_connect(dc, t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno); | ||
1245 | |||
1246 | /* finally, sort them and add them to the DSP chain */ | ||
1247 | ugen_done_graph(dc); | ||
1248 | } | ||
1249 | |||
1250 | /* this routine starts DSP for all root canvases. */ | ||
1251 | static void canvas_start_dsp(void) | ||
1252 | { | ||
1253 | t_canvas *x; | ||
1254 | if (canvas_dspstate) ugen_stop(); | ||
1255 | else sys_gui("pdtk_pd_dsp ON\n"); | ||
1256 | ugen_start(); | ||
1257 | |||
1258 | for (x = canvas_list; x; x = x->gl_next) | ||
1259 | canvas_dodsp(x, 1, 0); | ||
1260 | |||
1261 | canvas_dspstate = 1; | ||
1262 | } | ||
1263 | |||
1264 | static void canvas_stop_dsp(void) | ||
1265 | { | ||
1266 | if (canvas_dspstate) | ||
1267 | { | ||
1268 | ugen_stop(); | ||
1269 | sys_gui("pdtk_pd_dsp OFF\n"); | ||
1270 | canvas_dspstate = 0; | ||
1271 | } | ||
1272 | } | ||
1273 | |||
1274 | /* DSP can be suspended before, and resumed after, operations which | ||
1275 | might affect the DSP chain. For example, we suspend before loading and | ||
1276 | resume afterward, so that DSP doesn't get resorted for every DSP object | ||
1277 | int the patch. */ | ||
1278 | |||
1279 | int canvas_suspend_dsp(void) | ||
1280 | { | ||
1281 | int rval = canvas_dspstate; | ||
1282 | if (rval) canvas_stop_dsp(); | ||
1283 | return (rval); | ||
1284 | } | ||
1285 | |||
1286 | void canvas_resume_dsp(int oldstate) | ||
1287 | { | ||
1288 | if (oldstate) canvas_start_dsp(); | ||
1289 | } | ||
1290 | |||
1291 | /* this is equivalent to suspending and resuming in one step. */ | ||
1292 | void canvas_update_dsp(void) | ||
1293 | { | ||
1294 | if (canvas_dspstate) canvas_start_dsp(); | ||
1295 | } | ||
1296 | |||
1297 | void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv) | ||
1298 | { | ||
1299 | int newstate; | ||
1300 | if (argc) | ||
1301 | { | ||
1302 | newstate = atom_getintarg(0, argc, argv); | ||
1303 | if (newstate && !canvas_dspstate) | ||
1304 | { | ||
1305 | sys_set_audio_state(1); | ||
1306 | canvas_start_dsp(); | ||
1307 | } | ||
1308 | else if (!newstate && canvas_dspstate) | ||
1309 | { | ||
1310 | canvas_stop_dsp(); | ||
1311 | sys_set_audio_state(0); | ||
1312 | } | ||
1313 | } | ||
1314 | else post("dsp state %d", canvas_dspstate); | ||
1315 | } | ||
1316 | |||
1317 | /* LATER replace this with a queueing scheme */ | ||
1318 | void glist_redrawitem(t_glist *owner, t_gobj *gobj) | ||
1319 | { | ||
1320 | if (glist_isvisible(owner)) | ||
1321 | { | ||
1322 | gobj_vis(gobj, owner, 0); | ||
1323 | gobj_vis(gobj, owner, 1); | ||
1324 | } | ||
1325 | } | ||
1326 | |||
1327 | /* redraw all "scalars" (do this if a drawing command is changed.) | ||
1328 | LATER we'll use the "template" information to select which ones we | ||
1329 | redraw. */ | ||
1330 | static void glist_redrawall(t_glist *gl) | ||
1331 | { | ||
1332 | t_gobj *g; | ||
1333 | int vis = glist_isvisible(gl); | ||
1334 | for (g = gl->gl_list; g; g = g->g_next) | ||
1335 | { | ||
1336 | t_class *cl; | ||
1337 | if (vis && g->g_pd == scalar_class) | ||
1338 | glist_redrawitem(gl, g); | ||
1339 | else if (g->g_pd == canvas_class) | ||
1340 | glist_redrawall((t_glist *)g); | ||
1341 | } | ||
1342 | } | ||
1343 | |||
1344 | /* public interface for above */ | ||
1345 | void canvas_redrawallfortemplate(t_canvas *templatecanvas) | ||
1346 | { | ||
1347 | t_canvas *x; | ||
1348 | /* find all root canvases */ | ||
1349 | for (x = canvas_list; x; x = x->gl_next) | ||
1350 | glist_redrawall(x); | ||
1351 | } | ||
1352 | |||
1353 | /* ------------------------------- setup routine ------------------------ */ | ||
1354 | |||
1355 | /* why are some of these "glist" and others "canvas"? */ | ||
1356 | extern void glist_text(t_glist *x, t_symbol *s, int argc, t_atom *argv); | ||
1357 | extern void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1358 | extern void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1359 | extern void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1360 | extern void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1361 | extern void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1362 | extern void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1363 | /* old version... */ | ||
1364 | extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1365 | extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1366 | /* new version: */ | ||
1367 | extern void canvas_hradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1368 | extern void canvas_vradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1369 | extern void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1370 | extern void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1371 | extern void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1372 | extern void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1373 | extern void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1374 | extern void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
1375 | extern void glist_scalar(t_glist *canvas, t_symbol *s, int argc, t_atom *argv); | ||
1376 | |||
1377 | void g_graph_setup(void); | ||
1378 | void g_editor_setup(void); | ||
1379 | void g_readwrite_setup(void); | ||
1380 | extern void graph_properties(t_gobj *z, t_glist *owner); | ||
1381 | |||
1382 | void g_canvas_setup(void) | ||
1383 | { | ||
1384 | /* we prevent the user from typing "canvas" in an object box | ||
1385 | by sending 0 for a creator function. */ | ||
1386 | canvas_class = class_new(gensym("canvas"), 0, | ||
1387 | (t_method)canvas_free, sizeof(t_canvas), CLASS_NOINLET, 0); | ||
1388 | /* here is the real creator function, invoked in patch files | ||
1389 | by sending the "canvas" message to #N, which is bound | ||
1390 | to pd_camvasmaker. */ | ||
1391 | class_addmethod(pd_canvasmaker, (t_method)canvas_new, gensym("canvas"), | ||
1392 | A_GIMME, 0); | ||
1393 | class_addmethod(canvas_class, (t_method)canvas_restore, | ||
1394 | gensym("restore"), A_GIMME, 0); | ||
1395 | class_addmethod(canvas_class, (t_method)canvas_coords, | ||
1396 | gensym("coords"), A_GIMME, 0); | ||
1397 | |||
1398 | /* -------------------------- objects ----------------------------- */ | ||
1399 | class_addmethod(canvas_class, (t_method)canvas_obj, | ||
1400 | gensym("obj"), A_GIMME, A_NULL); | ||
1401 | class_addmethod(canvas_class, (t_method)canvas_msg, | ||
1402 | gensym("msg"), A_GIMME, A_NULL); | ||
1403 | class_addmethod(canvas_class, (t_method)canvas_floatatom, | ||
1404 | gensym("floatatom"), A_GIMME, A_NULL); | ||
1405 | class_addmethod(canvas_class, (t_method)canvas_symbolatom, | ||
1406 | gensym("symbolatom"), A_GIMME, A_NULL); | ||
1407 | class_addmethod(canvas_class, (t_method)glist_text, | ||
1408 | gensym("text"), A_GIMME, A_NULL); | ||
1409 | class_addmethod(canvas_class, (t_method)glist_glist, gensym("graph"), | ||
1410 | A_GIMME, A_NULL); | ||
1411 | class_addmethod(canvas_class, (t_method)glist_scalar, | ||
1412 | gensym("scalar"), A_GIMME, A_NULL); | ||
1413 | |||
1414 | /* -------------- Thomas Musil's GUI objects ------------ */ | ||
1415 | class_addmethod(canvas_class, (t_method)canvas_bng, gensym("bng"), | ||
1416 | A_GIMME, A_NULL); | ||
1417 | class_addmethod(canvas_class, (t_method)canvas_toggle, gensym("toggle"), | ||
1418 | A_GIMME, A_NULL); | ||
1419 | class_addmethod(canvas_class, (t_method)canvas_vslider, gensym("vslider"), | ||
1420 | A_GIMME, A_NULL); | ||
1421 | class_addmethod(canvas_class, (t_method)canvas_hslider, gensym("hslider"), | ||
1422 | A_GIMME, A_NULL); | ||
1423 | class_addmethod(canvas_class, (t_method)canvas_hdial, gensym("hdial"), | ||
1424 | A_GIMME, A_NULL); | ||
1425 | class_addmethod(canvas_class, (t_method)canvas_vdial, gensym("vdial"), | ||
1426 | A_GIMME, A_NULL); | ||
1427 | class_addmethod(canvas_class, (t_method)canvas_hradio, gensym("hradio"), | ||
1428 | A_GIMME, A_NULL); | ||
1429 | class_addmethod(canvas_class, (t_method)canvas_vradio, gensym("vradio"), | ||
1430 | A_GIMME, A_NULL); | ||
1431 | class_addmethod(canvas_class, (t_method)canvas_vumeter, gensym("vumeter"), | ||
1432 | A_GIMME, A_NULL); | ||
1433 | class_addmethod(canvas_class, (t_method)canvas_mycnv, gensym("mycnv"), | ||
1434 | A_GIMME, A_NULL); | ||
1435 | class_addmethod(canvas_class, (t_method)canvas_numbox, gensym("numbox"), | ||
1436 | A_GIMME, A_NULL); | ||
1437 | |||
1438 | /* ------------------------ gui stuff --------------------------- */ | ||
1439 | class_addmethod(canvas_class, (t_method)canvas_pop, gensym("pop"), | ||
1440 | A_DEFFLOAT, A_NULL); | ||
1441 | class_addmethod(canvas_class, (t_method)canvas_loadbang, | ||
1442 | gensym("loadbang"), A_NULL); | ||
1443 | class_addmethod(canvas_class, (t_method)canvas_relocate, | ||
1444 | gensym("relocate"), A_SYMBOL, A_SYMBOL, A_NULL); | ||
1445 | class_addmethod(canvas_class, (t_method)canvas_vis, | ||
1446 | gensym("vis"), A_FLOAT, A_NULL); | ||
1447 | class_addmethod(canvas_class, (t_method)glist_menu_open, | ||
1448 | gensym("menu-open"), A_NULL); | ||
1449 | class_addmethod(canvas_class, (t_method)canvas_map, | ||
1450 | gensym("map"), A_FLOAT, A_NULL); | ||
1451 | class_setpropertiesfn(canvas_class, graph_properties); | ||
1452 | |||
1453 | /* ---------------------- list handling ------------------------ */ | ||
1454 | class_addmethod(canvas_class, (t_method)glist_clear, gensym("clear"), | ||
1455 | A_NULL); | ||
1456 | |||
1457 | /* ----- subcanvases, which you get by typing "pd" in a box ---- */ | ||
1458 | class_addcreator((t_newmethod)subcanvas_new, gensym("pd"), A_DEFSYMBOL, 0); | ||
1459 | class_addcreator((t_newmethod)subcanvas_new, gensym("page"), A_DEFSYMBOL, 0); | ||
1460 | |||
1461 | class_addmethod(canvas_class, (t_method)canvas_click, | ||
1462 | gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); | ||
1463 | class_addmethod(canvas_class, (t_method)canvas_dsp, gensym("dsp"), 0); | ||
1464 | class_addmethod(canvas_class, (t_method)canvas_rename_method, | ||
1465 | gensym("rename"), A_GIMME, 0); | ||
1466 | |||
1467 | /*---------------------------- tables -- GG ------------------- */ | ||
1468 | |||
1469 | class_addcreator((t_newmethod)table_new, gensym("table"), | ||
1470 | A_DEFSYM, A_DEFFLOAT, 0); | ||
1471 | |||
1472 | /* -------------- setups from other files for canvas_class ---------------- */ | ||
1473 | g_graph_setup(); | ||
1474 | g_editor_setup(); | ||
1475 | g_readwrite_setup(); | ||
1476 | } | ||
1477 | /* Copyright (c) 1997-2001 Miller Puckette and others. | ||
1478 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
1479 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
1480 | |||
1481 | /* this file defines the "glist" class, also known as "canvas" (the two used | ||
1482 | to be different but are now unified except for some fossilized names.) */ | ||
1483 | |||
1484 | /* changes by Thomas Musil IEM KUG Graz Austria 2001 */ | ||
1485 | |||
1486 | /* bug-fix: canvas_menuclose(): by Krzysztof Czaja */ | ||
1487 | /* bug-fix: table_new(): I reversed the y-bounds */ | ||
1488 | |||
1489 | /* IOhannes : | ||
1490 | * changed the canvas_restore, so that it might accept $args as well | ||
1491 | * (like "pd $0_test") | ||
1492 | * so you can make multiple & distinguishable templates | ||
1493 | * 1511:forum::für::umläute:2001 | ||
1494 | * changes marked with IOhannes | ||
1495 | */ | ||
1496 | |||
1497 | #include <stdlib.h> | ||
1498 | #include <stdio.h> | ||
1499 | #include "m_pd.h" | ||
1500 | #include "m_imp.h" | ||
1501 | #include "s_stuff.h" | ||
1502 | #include "g_canvas.h" | ||
1503 | #include <string.h> | ||
1504 | #include "g_all_guis.h" | ||
1505 | |||
1506 | struct _canvasenvironment | ||
1507 | { | ||
1508 | t_symbol *ce_dir; /* directory patch lives in */ | ||
1509 | int ce_argc; /* number of "$" arguments */ | ||
1510 | t_atom *ce_argv; /* array of "$" arguments */ | ||
1511 | int ce_dollarzero; /* value of "$0" */ | ||
1512 | }; | ||
1513 | |||
1514 | #define GLIST_DEFCANVASWIDTH 240 | ||
1515 | #define GLIST_DEFCANVASHEIGHT 300 | ||
1516 | |||
1517 | #ifdef MACOSX | ||
1518 | #define GLIST_DEFCANVASYLOC 22 | ||
1519 | #else | ||
1520 | #define GLIST_DEFCANVASYLOC 0 | ||
1521 | #endif | ||
1522 | |||
1523 | /* ---------------------- variables --------------------------- */ | ||
1524 | |||
1525 | extern t_pd *newest; | ||
1526 | t_class *canvas_class; | ||
1527 | static int canvas_dspstate; /* whether DSP is on or off */ | ||
1528 | t_canvas *canvas_editing; /* last canvas to start text edting */ | ||
1529 | t_canvas *canvas_whichfind; /* last canvas we did a find in */ | ||
1530 | t_canvas *canvas_list; /* list of all root canvases */ | ||
1531 | |||
1532 | /* ------------------ forward function declarations --------------- */ | ||
1533 | static void canvas_start_dsp(void); | ||
1534 | static void canvas_stop_dsp(void); | ||
1535 | static void canvas_drawlines(t_canvas *x); | ||
1536 | static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2); | ||
1537 | static void canvas_reflecttitle(t_canvas *x); | ||
1538 | static void canvas_addtolist(t_canvas *x); | ||
1539 | static void canvas_takeofflist(t_canvas *x); | ||
1540 | static void canvas_pop(t_canvas *x, t_floatarg fvis); | ||
1541 | void canvas_create_editor(t_glist *x, int createit); | ||
1542 | |||
1543 | /* --------- functions to handle the canvas environment ----------- */ | ||
1544 | |||
1545 | static t_symbol *canvas_newfilename = &s_; | ||
1546 | static t_symbol *canvas_newdirectory = &s_; | ||
1547 | static int canvas_newargc; | ||
1548 | static t_atom *canvas_newargv; | ||
1549 | |||
1550 | static void glist_doupdatewindowlist(t_glist *gl, char *sbuf) | ||
1551 | { | ||
1552 | t_gobj *g; | ||
1553 | if (!gl->gl_owner) | ||
1554 | { | ||
1555 | /* this is a canvas; if we have a window, put on "windows" list */ | ||
1556 | t_canvas *canvas = (t_canvas *)gl; | ||
1557 | if (canvas->gl_havewindow) | ||
1558 | { | ||
1559 | if (strlen(sbuf) + strlen(gl->gl_name->s_name) + 100 <= 1024) | ||
1560 | { | ||
1561 | char tbuf[1024]; | ||
1562 | sprintf(tbuf, "{%s .x%x} ", gl->gl_name->s_name, (t_int)canvas); | ||
1563 | strcat(sbuf, tbuf); | ||
1564 | } | ||
1565 | } | ||
1566 | } | ||
1567 | for (g = gl->gl_list; g; g = g->g_next) | ||
1568 | { | ||
1569 | if (pd_class(&g->g_pd) == canvas_class) | ||
1570 | glist_doupdatewindowlist((t_glist *)g, sbuf); | ||
1571 | } | ||
1572 | return; | ||
1573 | } | ||
1574 | |||
1575 | /* maintain the list of visible toplevels for the GUI's "windows" menu */ | ||
1576 | void canvas_updatewindowlist( void) | ||
1577 | { | ||
1578 | t_canvas *x; | ||
1579 | char sbuf[1024]; | ||
1580 | strcpy(sbuf, "set menu_windowlist {"); | ||
1581 | /* find all root canvases */ | ||
1582 | for (x = canvas_list; x; x = x->gl_next) | ||
1583 | glist_doupdatewindowlist(x, sbuf); | ||
1584 | /* next line updates the window menu state before -postcommand tries it */ | ||
1585 | strcat(sbuf, "}\npdtk_fixwindowmenu\n"); | ||
1586 | sys_gui(sbuf); | ||
1587 | } | ||
1588 | |||
1589 | /* add a glist the list of "root" canvases (toplevels without parents.) */ | ||
1590 | static void canvas_addtolist(t_canvas *x) | ||
1591 | { | ||
1592 | x->gl_next = canvas_list; | ||
1593 | canvas_list = x; | ||
1594 | } | ||
1595 | |||
1596 | static void canvas_takeofflist(t_canvas *x) | ||
1597 | { | ||
1598 | /* take it off the window list */ | ||
1599 | if (x == canvas_list) canvas_list = x->gl_next; | ||
1600 | else | ||
1601 | { | ||
1602 | t_canvas *z; | ||
1603 | for (z = canvas_list; z->gl_next != x; z = z->gl_next) | ||
1604 | ; | ||
1605 | z->gl_next = x->gl_next; | ||
1606 | } | ||
1607 | } | ||
1608 | |||
1609 | |||
1610 | void canvas_setargs(int argc, t_atom *argv) | ||
1611 | { | ||
1612 | /* if there's an old one lying around free it here. This | ||
1613 | happens if an abstraction is loaded but never gets as far | ||
1614 | as calling canvas_new(). */ | ||
1615 | if (canvas_newargv) | ||
1616 | freebytes(canvas_newargv, canvas_newargc * sizeof(t_atom)); | ||
1617 | canvas_newargc = argc; | ||
1618 | canvas_newargv = copybytes(argv, argc * sizeof(t_atom)); | ||
1619 | } | ||
1620 | |||
1621 | void glob_setfilename(void *dummy, t_symbol *filesym, t_symbol *dirsym) | ||
1622 | { | ||
1623 | canvas_newfilename = filesym; | ||
1624 | canvas_newdirectory = dirsym; | ||
1625 | } | ||
1626 | |||
1627 | t_canvas *canvas_getcurrent(void) | ||
1628 | { | ||
1629 | return ((t_canvas *)pd_findbyclass(&s__X, canvas_class)); | ||
1630 | } | ||
1631 | |||
1632 | void canvas_setcurrent(t_canvas *x) | ||
1633 | { | ||
1634 | pd_pushsym(&x->gl_pd); | ||
1635 | } | ||
1636 | |||
1637 | void canvas_unsetcurrent(t_canvas *x) | ||
1638 | { | ||
1639 | pd_popsym(&x->gl_pd); | ||
1640 | } | ||
1641 | |||
1642 | t_canvasenvironment *canvas_getenv(t_canvas *x) | ||
1643 | { | ||
1644 | if (!x) bug("canvas_getenv"); | ||
1645 | while (!x->gl_env) | ||
1646 | if (!(x = x->gl_owner)) | ||
1647 | bug("t_canvasenvironment", x); | ||
1648 | return (x->gl_env); | ||
1649 | } | ||
1650 | |||
1651 | int canvas_getdollarzero( void) | ||
1652 | { | ||
1653 | t_canvas *x = canvas_getcurrent(); | ||
1654 | t_canvasenvironment *env = (x ? canvas_getenv(x) : 0); | ||
1655 | if (env) | ||
1656 | return (env->ce_dollarzero); | ||
1657 | else return (0); | ||
1658 | } | ||
1659 | |||
1660 | void canvas_getargs(int *argcp, t_atom **argvp) | ||
1661 | { | ||
1662 | t_canvasenvironment *e = canvas_getenv(canvas_getcurrent()); | ||
1663 | *argcp = e->ce_argc; | ||
1664 | *argvp = e->ce_argv; | ||
1665 | } | ||
1666 | |||
1667 | t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s) | ||
1668 | { | ||
1669 | t_symbol *ret; | ||
1670 | char *name = s->s_name; | ||
1671 | if (*name == '$' && name[1] >= '0' && name[1] <= '9') | ||
1672 | { | ||
1673 | t_canvasenvironment *env = canvas_getenv(x); | ||
1674 | canvas_setcurrent(x); | ||
1675 | ret = binbuf_realizedollsym(gensym(name+1), | ||
1676 | env->ce_argc, env->ce_argv, 1); | ||
1677 | canvas_unsetcurrent(x); | ||
1678 | } | ||
1679 | else ret = s; | ||
1680 | return (ret); | ||
1681 | } | ||
1682 | |||
1683 | t_symbol *canvas_getcurrentdir(void) | ||
1684 | { | ||
1685 | t_canvasenvironment *e = canvas_getenv(canvas_getcurrent()); | ||
1686 | return (e->ce_dir); | ||
1687 | } | ||
1688 | |||
1689 | t_symbol *canvas_getdir(t_canvas *x) | ||
1690 | { | ||
1691 | t_canvasenvironment *e = canvas_getenv(x); | ||
1692 | return (e->ce_dir); | ||
1693 | } | ||
1694 | |||
1695 | void canvas_makefilename(t_canvas *x, char *file, char *result, int resultsize) | ||
1696 | { | ||
1697 | char *dir = canvas_getenv(x)->ce_dir->s_name; | ||
1698 | if (file[0] == '/' || (file[0] && file[1] == ':') || !*dir) | ||
1699 | { | ||
1700 | strncpy(result, file, resultsize); | ||
1701 | result[resultsize-1] = 0; | ||
1702 | } | ||
1703 | else | ||
1704 | { | ||
1705 | int nleft; | ||
1706 | strncpy(result, dir, resultsize); | ||
1707 | result[resultsize-1] = 0; | ||
1708 | nleft = resultsize - strlen(result) - 1; | ||
1709 | if (nleft <= 0) return; | ||
1710 | strcat(result, "/"); | ||
1711 | strncat(result, file, nleft); | ||
1712 | result[resultsize-1] = 0; | ||
1713 | } | ||
1714 | } | ||
1715 | |||
1716 | void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir) | ||
1717 | { | ||
1718 | if (strcmp(x->gl_name->s_name, "Pd")) | ||
1719 | pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name)); | ||
1720 | x->gl_name = s; | ||
1721 | if (strcmp(x->gl_name->s_name, "Pd")) | ||
1722 | pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name)); | ||
1723 | if (glist_isvisible(x)) | ||
1724 | canvas_reflecttitle(x); | ||
1725 | if (dir && dir != &s_) | ||
1726 | { | ||
1727 | t_canvasenvironment *e = canvas_getenv(x); | ||
1728 | e->ce_dir = dir; | ||
1729 | } | ||
1730 | } | ||
1731 | |||
1732 | /* --------------- traversing the set of lines in a canvas ----------- */ | ||
1733 | |||
1734 | int canvas_getindex(t_canvas *x, t_gobj *y) | ||
1735 | { | ||
1736 | t_gobj *y2; | ||
1737 | int indexno; | ||
1738 | for (indexno = 0, y2 = x->gl_list; y2 && y2 != y; y2 = y2->g_next) | ||
1739 | indexno++; | ||
1740 | return (indexno); | ||
1741 | } | ||
1742 | |||
1743 | void linetraverser_start(t_linetraverser *t, t_canvas *x) | ||
1744 | { | ||
1745 | t->tr_ob = 0; | ||
1746 | t->tr_x = x; | ||
1747 | t->tr_nextoc = 0; | ||
1748 | t->tr_nextoutno = t->tr_nout = 0; | ||
1749 | } | ||
1750 | |||
1751 | t_outconnect *linetraverser_next(t_linetraverser *t) | ||
1752 | { | ||
1753 | t_outconnect *rval = t->tr_nextoc; | ||
1754 | int outno; | ||
1755 | while (!rval) | ||
1756 | { | ||
1757 | outno = t->tr_nextoutno; | ||
1758 | while (outno == t->tr_nout) | ||
1759 | { | ||
1760 | t_gobj *y; | ||
1761 | t_object *ob = 0; | ||
1762 | if (!t->tr_ob) y = t->tr_x->gl_list; | ||
1763 | else y = t->tr_ob->ob_g.g_next; | ||
1764 | for (; y; y = y->g_next) | ||
1765 | if (ob = pd_checkobject(&y->g_pd)) break; | ||
1766 | if (!ob) return (0); | ||
1767 | t->tr_ob = ob; | ||
1768 | t->tr_nout = obj_noutlets(ob); | ||
1769 | outno = 0; | ||
1770 | if (glist_isvisible(t->tr_x)) | ||
1771 | gobj_getrect(y, t->tr_x, | ||
1772 | &t->tr_x11, &t->tr_y11, &t->tr_x12, &t->tr_y12); | ||
1773 | else t->tr_x11 = t->tr_y11 = t->tr_x12 = t->tr_y12 = 0; | ||
1774 | } | ||
1775 | t->tr_nextoutno = outno + 1; | ||
1776 | rval = obj_starttraverseoutlet(t->tr_ob, &t->tr_outlet, outno); | ||
1777 | t->tr_outno = outno; | ||
1778 | } | ||
1779 | t->tr_nextoc = obj_nexttraverseoutlet(rval, &t->tr_ob2, | ||
1780 | &t->tr_inlet, &t->tr_inno); | ||
1781 | t->tr_nin = obj_ninlets(t->tr_ob2); | ||
1782 | if (!t->tr_nin) bug("drawline"); | ||
1783 | if (glist_isvisible(t->tr_x)) | ||
1784 | { | ||
1785 | int inplus = (t->tr_nin == 1 ? 1 : t->tr_nin - 1); | ||
1786 | int outplus = (t->tr_nout == 1 ? 1 : t->tr_nout - 1); | ||
1787 | gobj_getrect(&t->tr_ob2->ob_g, t->tr_x, | ||
1788 | &t->tr_x21, &t->tr_y21, &t->tr_x22, &t->tr_y22); | ||
1789 | t->tr_lx1 = t->tr_x11 + | ||
1790 | ((t->tr_x12 - t->tr_x11 - IOWIDTH) * t->tr_outno) / | ||
1791 | outplus + IOMIDDLE; | ||
1792 | t->tr_ly1 = t->tr_y12; | ||
1793 | t->tr_lx2 = t->tr_x21 + | ||
1794 | ((t->tr_x22 - t->tr_x21 - IOWIDTH) * t->tr_inno)/inplus + | ||
1795 | IOMIDDLE; | ||
1796 | t->tr_ly2 = t->tr_y21; | ||
1797 | } | ||
1798 | else | ||
1799 | { | ||
1800 | t->tr_x21 = t->tr_y21 = t->tr_x22 = t->tr_y22 = 0; | ||
1801 | t->tr_lx1 = t->tr_ly1 = t->tr_lx2 = t->tr_ly2 = 0; | ||
1802 | } | ||
1803 | |||
1804 | return (rval); | ||
1805 | } | ||
1806 | |||
1807 | void linetraverser_skipobject(t_linetraverser *t) | ||
1808 | { | ||
1809 | t->tr_nextoc = 0; | ||
1810 | t->tr_nextoutno = t->tr_nout; | ||
1811 | } | ||
1812 | |||
1813 | /* -------------------- the canvas object -------------------------- */ | ||
1814 | int glist_valid = 10000; | ||
1815 | |||
1816 | void glist_init(t_glist *x) | ||
1817 | { | ||
1818 | /* zero out everyone except "pd" field */ | ||
1819 | memset(((char *)x) + sizeof(x->gl_pd), 0, sizeof(*x) - sizeof(x->gl_pd)); | ||
1820 | x->gl_stub = gstub_new(x, 0); | ||
1821 | x->gl_valid = ++glist_valid; | ||
1822 | x->gl_xlabel = (t_symbol **)t_getbytes(0); | ||
1823 | x->gl_ylabel = (t_symbol **)t_getbytes(0); | ||
1824 | } | ||
1825 | |||
1826 | /* make a new glist. It will either be a "root" canvas or else | ||
1827 | its parent will be a "text" object in another window... we don't | ||
1828 | know which yet. */ | ||
1829 | t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) | ||
1830 | { | ||
1831 | t_canvas *x = (t_canvas *)pd_new(canvas_class); | ||
1832 | t_canvas *owner = canvas_getcurrent(); | ||
1833 | t_symbol *s = &s_; | ||
1834 | int vis = 0, width = GLIST_DEFCANVASWIDTH, height = GLIST_DEFCANVASHEIGHT; | ||
1835 | int xloc = 0, yloc = GLIST_DEFCANVASYLOC; | ||
1836 | int font = (owner ? owner->gl_font : sys_defaultfont); | ||
1837 | glist_init(x); | ||
1838 | x->gl_obj.te_type = T_OBJECT; | ||
1839 | if (!owner) | ||
1840 | canvas_addtolist(x); | ||
1841 | /* post("canvas %x, owner %x", x, owner); */ | ||
1842 | |||
1843 | if (argc == 5) /* toplevel: x, y, w, h, font */ | ||
1844 | { | ||
1845 | xloc = atom_getintarg(0, argc, argv); | ||
1846 | yloc = atom_getintarg(1, argc, argv); | ||
1847 | width = atom_getintarg(2, argc, argv); | ||
1848 | height = atom_getintarg(3, argc, argv); | ||
1849 | font = atom_getintarg(4, argc, argv); | ||
1850 | } | ||
1851 | else if (argc == 6) /* subwindow: x, y, w, h, name, vis */ | ||
1852 | { | ||
1853 | xloc = atom_getintarg(0, argc, argv); | ||
1854 | yloc = atom_getintarg(1, argc, argv); | ||
1855 | width = atom_getintarg(2, argc, argv); | ||
1856 | height = atom_getintarg(3, argc, argv); | ||
1857 | s = atom_getsymbolarg(4, argc, argv); | ||
1858 | vis = atom_getintarg(5, argc, argv); | ||
1859 | } | ||
1860 | /* (otherwise assume we're being created from the menu.) */ | ||
1861 | |||
1862 | if (canvas_newdirectory->s_name[0]) | ||
1863 | { | ||
1864 | static int dollarzero = 1000; | ||
1865 | t_canvasenvironment *env = x->gl_env = | ||
1866 | (t_canvasenvironment *)getbytes(sizeof(*x->gl_env)); | ||
1867 | env->ce_dir = canvas_newdirectory; | ||
1868 | env->ce_argc = canvas_newargc; | ||
1869 | env->ce_argv = canvas_newargv; | ||
1870 | env->ce_dollarzero = dollarzero++; | ||
1871 | canvas_newdirectory = &s_; | ||
1872 | canvas_newargc = 0; | ||
1873 | canvas_newargv = 0; | ||
1874 | } | ||
1875 | else x->gl_env = 0; | ||
1876 | |||
1877 | if (yloc < GLIST_DEFCANVASYLOC) | ||
1878 | yloc = GLIST_DEFCANVASYLOC; | ||
1879 | if (xloc < 0) | ||
1880 | xloc = 0; | ||
1881 | x->gl_x1 = 0; | ||
1882 | x->gl_y1 = 0; | ||
1883 | x->gl_x2 = 1; | ||
1884 | x->gl_y2 = 1; | ||
1885 | canvas_setbounds(x, xloc, yloc, xloc + width, yloc + height); | ||
1886 | x->gl_owner = owner; | ||
1887 | x->gl_name = (*s->s_name ? s : | ||
1888 | (canvas_newfilename ? canvas_newfilename : gensym("Pd"))); | ||
1889 | if (strcmp(x->gl_name->s_name, "Pd")) | ||
1890 | pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name)); | ||
1891 | x->gl_loading = 1; | ||
1892 | x->gl_willvis = vis; | ||
1893 | x->gl_edit = !strncmp(x->gl_name->s_name, "Untitled", 8); | ||
1894 | x->gl_font = sys_nearestfontsize(font); | ||
1895 | pd_pushsym(&x->gl_pd); | ||
1896 | return(x); | ||
1897 | } | ||
1898 | |||
1899 | void canvas_setgraph(t_glist *x, int flag); | ||
1900 | |||
1901 | static void canvas_coords(t_glist *x, t_symbol *s, int argc, t_atom *argv) | ||
1902 | { | ||
1903 | x->gl_x1 = atom_getfloatarg(0, argc, argv); | ||
1904 | x->gl_y1 = atom_getfloatarg(1, argc, argv); | ||
1905 | x->gl_x2 = atom_getfloatarg(2, argc, argv); | ||
1906 | x->gl_y2 = atom_getfloatarg(3, argc, argv); | ||
1907 | x->gl_pixwidth = atom_getintarg(4, argc, argv); | ||
1908 | x->gl_pixheight = atom_getintarg(5, argc, argv); | ||
1909 | canvas_setgraph(x, atom_getintarg(6, argc, argv)); | ||
1910 | } | ||
1911 | |||
1912 | /* make a new glist and add it to this glist. It will appear as | ||
1913 | a "graph", not a text object. */ | ||
1914 | t_glist *glist_addglist(t_glist *g, t_symbol *sym, | ||
1915 | float x1, float y1, float x2, float y2, | ||
1916 | float px1, float py1, float px2, float py2) | ||
1917 | { | ||
1918 | static int gcount = 0; | ||
1919 | int zz; | ||
1920 | int menu = 0; | ||
1921 | char *str; | ||
1922 | t_glist *x = (t_glist *)pd_new(canvas_class); | ||
1923 | glist_init(x); | ||
1924 | x->gl_obj.te_type = T_OBJECT; | ||
1925 | if (!*sym->s_name) | ||
1926 | { | ||
1927 | char buf[40]; | ||
1928 | sprintf(buf, "graph%d", ++gcount); | ||
1929 | sym = gensym(buf); | ||
1930 | menu = 1; | ||
1931 | } | ||
1932 | else if (!strncmp((str = sym->s_name), "graph", 5) | ||
1933 | && (zz = atoi(str + 5)) > gcount) | ||
1934 | gcount = zz; | ||
1935 | /* in 0.34 and earlier, the pixel rectangle and the y bounds were | ||
1936 | reversed; this would behave the same, except that the dialog window | ||
1937 | would be confusing. The "correct" way is to have "py1" be the value | ||
1938 | that is higher on the screen. */ | ||
1939 | if (py2 < py1) | ||
1940 | { | ||
1941 | float zz; | ||
1942 | zz = y2; | ||
1943 | y2 = y1; | ||
1944 | y1 = zz; | ||
1945 | zz = py2; | ||
1946 | py2 = py1; | ||
1947 | py1 = zz; | ||
1948 | } | ||
1949 | if (x1 == x2 || y1 == y2) | ||
1950 | x1 = 0, x2 = 100, y1 = 1, y2 = -1; | ||
1951 | if (px1 >= px2 || py1 >= py2) | ||
1952 | px1 = 100, py1 = 20, px2 = 100 + GLIST_DEFGRAPHWIDTH, | ||
1953 | py2 = 20 + GLIST_DEFGRAPHHEIGHT; | ||
1954 | x->gl_name = sym; | ||
1955 | x->gl_x1 = x1; | ||
1956 | x->gl_x2 = x2; | ||
1957 | x->gl_y1 = y1; | ||
1958 | x->gl_y2 = y2; | ||
1959 | x->gl_obj.te_xpix = px1; | ||
1960 | x->gl_obj.te_ypix = py1; | ||
1961 | x->gl_pixwidth = px2 - px1; | ||
1962 | x->gl_pixheight = py2 - py1; | ||
1963 | x->gl_font = (canvas_getcurrent() ? | ||
1964 | canvas_getcurrent()->gl_font : sys_defaultfont); | ||
1965 | x->gl_screenx1 = x->gl_screeny1 = 0; | ||
1966 | x->gl_screenx2 = 240; | ||
1967 | x->gl_screeny2 = 300; | ||
1968 | if (strcmp(x->gl_name->s_name, "Pd")) | ||
1969 | pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name)); | ||
1970 | x->gl_owner = g; | ||
1971 | x->gl_stretch = 1; | ||
1972 | x->gl_isgraph = 1; | ||
1973 | x->gl_obj.te_binbuf = binbuf_new(); | ||
1974 | binbuf_addv(x->gl_obj.te_binbuf, "s", gensym("graph")); | ||
1975 | if (!menu) | ||
1976 | pd_pushsym(&x->gl_pd); | ||
1977 | glist_add(g, &x->gl_gobj); | ||
1978 | if (glist_isvisible(g)) | ||
1979 | canvas_create_editor(x, 1); | ||
1980 | return (x); | ||
1981 | } | ||
1982 | |||
1983 | /* call glist_addglist from a Pd message */ | ||
1984 | void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv) | ||
1985 | { | ||
1986 | t_symbol *sym = atom_getsymbolarg(0, argc, argv); | ||
1987 | float x1 = atom_getfloatarg(1, argc, argv); | ||
1988 | float y1 = atom_getfloatarg(2, argc, argv); | ||
1989 | float x2 = atom_getfloatarg(3, argc, argv); | ||
1990 | float y2 = atom_getfloatarg(4, argc, argv); | ||
1991 | float px1 = atom_getfloatarg(5, argc, argv); | ||
1992 | float py1 = atom_getfloatarg(6, argc, argv); | ||
1993 | float px2 = atom_getfloatarg(7, argc, argv); | ||
1994 | float py2 = atom_getfloatarg(8, argc, argv); | ||
1995 | glist_addglist(g, sym, x1, y1, x2, y2, px1, py1, px2, py2); | ||
1996 | } | ||
1997 | |||
1998 | /* return true if the glist should appear as a graph on parent; | ||
1999 | otherwise it appears as a text box. */ | ||
2000 | int glist_isgraph(t_glist *x) | ||
2001 | { | ||
2002 | return (x->gl_isgraph); | ||
2003 | } | ||
2004 | |||
2005 | /* This is sent from the GUI to inform a toplevel that its window has been | ||
2006 | moved or resized. */ | ||
2007 | static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2) | ||
2008 | { | ||
2009 | int heightwas = y2 - y1; | ||
2010 | int heightchange = y2 - y1 - (x->gl_screeny2 - x->gl_screeny1); | ||
2011 | x->gl_screenx1 = x1; | ||
2012 | x->gl_screeny1 = y1; | ||
2013 | x->gl_screenx2 = x2; | ||
2014 | x->gl_screeny2 = y2; | ||
2015 | /* post("set bounds %d %d %d %d", x1, y1, x2, y2); */ | ||
2016 | if (!glist_isgraph(x) && (x->gl_y2 < x->gl_y1)) | ||
2017 | { | ||
2018 | /* if it's flipped so that y grows upward, | ||
2019 | fix so that zero is bottom edge and redraw. This is | ||
2020 | only appropriate if we're a regular "text" object on the | ||
2021 | parent. */ | ||
2022 | float diff = x->gl_y1 - x->gl_y2; | ||
2023 | t_gobj *y; | ||
2024 | x->gl_y1 = heightwas * diff; | ||
2025 | x->gl_y2 = x->gl_y1 - diff; | ||
2026 | /* and move text objects accordingly; they should stick | ||
2027 | to the bottom, not the top. */ | ||
2028 | for (y = x->gl_list; y; y = y->g_next) | ||
2029 | if (pd_checkobject(&y->g_pd)) | ||
2030 | gobj_displace(y, x, 0, heightchange); | ||
2031 | canvas_redraw(x); | ||
2032 | } | ||
2033 | } | ||
2034 | |||
2035 | t_symbol *canvas_makebindsym(t_symbol *s) | ||
2036 | { | ||
2037 | char buf[MAXPDSTRING]; | ||
2038 | strcpy(buf, "pd-"); | ||
2039 | strcat(buf, s->s_name); | ||
2040 | return (gensym(buf)); | ||
2041 | } | ||
2042 | |||
2043 | void canvas_reflecttitle(t_canvas *x) | ||
2044 | { | ||
2045 | char namebuf[MAXPDSTRING]; | ||
2046 | t_canvasenvironment *env = canvas_getenv(x); | ||
2047 | if (env->ce_argc) | ||
2048 | { | ||
2049 | int i; | ||
2050 | strcpy(namebuf, " ("); | ||
2051 | for (i = 0; i < env->ce_argc; i++) | ||
2052 | { | ||
2053 | if (strlen(namebuf) > MAXPDSTRING/2 - 5) | ||
2054 | break; | ||
2055 | if (i != 0) | ||
2056 | strcat(namebuf, " "); | ||
2057 | atom_string(&env->ce_argv[i], namebuf + strlen(namebuf), | ||
2058 | MAXPDSTRING/2); | ||
2059 | } | ||
2060 | strcat(namebuf, ")"); | ||
2061 | } | ||
2062 | else namebuf[0] = 0; | ||
2063 | sys_vgui("wm title .x%x {%s%c%s - %s}\n", | ||
2064 | x, x->gl_name->s_name, (x->gl_dirty? '*' : ' '), namebuf, | ||
2065 | canvas_getdir(x)->s_name); | ||
2066 | } | ||
2067 | |||
2068 | void canvas_dirty(t_canvas *x, t_int n) | ||
2069 | { | ||
2070 | t_canvas *x2 = canvas_getrootfor(x); | ||
2071 | if ((unsigned)n != x2->gl_dirty) | ||
2072 | { | ||
2073 | x2->gl_dirty = n; | ||
2074 | canvas_reflecttitle(x2); | ||
2075 | } | ||
2076 | } | ||
2077 | |||
2078 | /* the window becomes "mapped" (visible and not miniaturized) or | ||
2079 | "unmapped" (either miniaturized or just plain gone.) This should be | ||
2080 | called from the GUI after the fact to "notify" us that we're mapped. */ | ||
2081 | void canvas_map(t_canvas *x, t_floatarg f) | ||
2082 | { | ||
2083 | int flag = (f != 0); | ||
2084 | t_gobj *y; | ||
2085 | if (flag) | ||
2086 | { | ||
2087 | if (!glist_isvisible(x)) | ||
2088 | { | ||
2089 | t_selection *sel; | ||
2090 | if (!x->gl_havewindow) | ||
2091 | { | ||
2092 | bug("canvas_map"); | ||
2093 | canvas_vis(x, 1); | ||
2094 | } | ||
2095 | for (y = x->gl_list; y; y = y->g_next) | ||
2096 | gobj_vis(y, x, 1); | ||
2097 | for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next) | ||
2098 | gobj_select(sel->sel_what, x, 1); | ||
2099 | x->gl_mapped = 1; | ||
2100 | canvas_drawlines(x); | ||
2101 | /* simulate a mouse up so u_main will calculate scrollbars... | ||
2102 | ugly! */ | ||
2103 | sys_vgui("pdtk_canvas_mouseup .x%x.c 0 0 0\n", x); | ||
2104 | } | ||
2105 | } | ||
2106 | else | ||
2107 | { | ||
2108 | if (glist_isvisible(x)) | ||
2109 | { | ||
2110 | /* just clear out the whole canvas... */ | ||
2111 | sys_vgui(".x%x.c delete all\n", x); | ||
2112 | /* alternatively, we could have erased them one by one... | ||
2113 | for (y = x->gl_list; y; y = y->g_next) | ||
2114 | gobj_vis(y, x, 0); | ||
2115 | ... but we should go through and erase the lines as well | ||
2116 | if we do it that way. */ | ||
2117 | x->gl_mapped = 0; | ||
2118 | } | ||
2119 | } | ||
2120 | } | ||
2121 | |||
2122 | void canvas_redraw(t_canvas *x) | ||
2123 | { | ||
2124 | if (glist_isvisible(x)) | ||
2125 | { | ||
2126 | canvas_map(x, 0); | ||
2127 | canvas_map(x, 1); | ||
2128 | } | ||
2129 | } | ||
2130 | |||
2131 | /* ---- editors -- perhaps this and "vis" should go to g_editor.c ------- */ | ||
2132 | |||
2133 | static t_editor *editor_new(t_glist *owner) | ||
2134 | { | ||
2135 | char buf[40]; | ||
2136 | t_editor *x = (t_editor *)getbytes(sizeof(*x)); | ||
2137 | x->e_connectbuf = binbuf_new(); | ||
2138 | x->e_deleted = binbuf_new(); | ||
2139 | x->e_glist = owner; | ||
2140 | sprintf(buf, ".x%x", (t_int)owner); | ||
2141 | x->e_guiconnect = guiconnect_new(&owner->gl_pd, gensym(buf)); | ||
2142 | return (x); | ||
2143 | } | ||
2144 | |||
2145 | static void editor_free(t_editor *x, t_glist *y) | ||
2146 | { | ||
2147 | glist_noselect(y); | ||
2148 | guiconnect_notarget(x->e_guiconnect, 1000); | ||
2149 | binbuf_free(x->e_connectbuf); | ||
2150 | binbuf_free(x->e_deleted); | ||
2151 | freebytes((void *)x, sizeof(*x)); | ||
2152 | } | ||
2153 | |||
2154 | /* recursively create or destroy all editors of a glist and its | ||
2155 | sub-glists, as long as they aren't toplevels. */ | ||
2156 | void canvas_create_editor(t_glist *x, int createit) | ||
2157 | { | ||
2158 | t_gobj *y; | ||
2159 | t_object *ob; | ||
2160 | if (createit) | ||
2161 | { | ||
2162 | if (x->gl_editor) | ||
2163 | bug("canvas_create_editor"); | ||
2164 | else | ||
2165 | { | ||
2166 | x->gl_editor = editor_new(x); | ||
2167 | for (y = x->gl_list; y; y = y->g_next) | ||
2168 | if (ob = pd_checkobject(&y->g_pd)) | ||
2169 | rtext_new(x, ob); | ||
2170 | } | ||
2171 | } | ||
2172 | else | ||
2173 | { | ||
2174 | if (!x->gl_editor) | ||
2175 | bug("canvas_create_editor"); | ||
2176 | else | ||
2177 | { | ||
2178 | for (y = x->gl_list; y; y = y->g_next) | ||
2179 | if (ob = pd_checkobject(&y->g_pd)) | ||
2180 | rtext_free(glist_findrtext(x, ob)); | ||
2181 | editor_free(x->gl_editor, x); | ||
2182 | x->gl_editor = 0; | ||
2183 | } | ||
2184 | } | ||
2185 | for (y = x->gl_list; y; y = y->g_next) | ||
2186 | if (pd_class(&y->g_pd) == canvas_class && | ||
2187 | ((t_canvas *)y)->gl_isgraph) | ||
2188 | canvas_create_editor((t_canvas *)y, createit); | ||
2189 | } | ||
2190 | |||
2191 | /* we call this when we want the window to become visible, mapped, and | ||
2192 | in front of all windows; or with "f" zero, when we want to get rid of | ||
2193 | the window. */ | ||
2194 | void canvas_vis(t_canvas *x, t_floatarg f) | ||
2195 | { | ||
2196 | char buf[30]; | ||
2197 | int flag = (f != 0); | ||
2198 | if (flag) | ||
2199 | { | ||
2200 | /* test if we're already visible and toplevel */ | ||
2201 | if (glist_isvisible(x) && !x->gl_isgraph) | ||
2202 | { /* just put us in front */ | ||
2203 | #ifdef MSW | ||
2204 | canvas_vis(x, 0); | ||
2205 | canvas_vis(x, 1); | ||
2206 | #else | ||
2207 | sys_vgui("raise .x%x\n", x); | ||
2208 | sys_vgui("focus .x%x.c\n", x); | ||
2209 | sys_vgui("wm deiconify .x%x\n", x); | ||
2210 | #endif | ||
2211 | } | ||
2212 | else | ||
2213 | { | ||
2214 | canvas_create_editor(x, 1); | ||
2215 | sys_vgui("pdtk_canvas_new .x%x %d %d +%d+%d %d\n", x, | ||
2216 | (int)(x->gl_screenx2 - x->gl_screenx1), | ||
2217 | (int)(x->gl_screeny2 - x->gl_screeny1), | ||
2218 | (int)(x->gl_screenx1), (int)(x->gl_screeny1), | ||
2219 | x->gl_edit); | ||
2220 | canvas_reflecttitle(x); | ||
2221 | x->gl_havewindow = 1; | ||
2222 | canvas_updatewindowlist(); | ||
2223 | } | ||
2224 | } | ||
2225 | else /* make invisible */ | ||
2226 | { | ||
2227 | int i; | ||
2228 | t_canvas *x2; | ||
2229 | if (!x->gl_havewindow) | ||
2230 | { | ||
2231 | /* bug workaround -- a graph in a visible patch gets "invised" | ||
2232 | when the patch is closed, and must lose the editor here. It's | ||
2233 | probably not the natural place to do this. Other cases like | ||
2234 | subpatches fall here too but don'd need the editor freed, so | ||
2235 | we check if it exists. */ | ||
2236 | if (x->gl_editor) | ||
2237 | canvas_create_editor(x, 0); | ||
2238 | return; | ||
2239 | } | ||
2240 | glist_noselect(x); | ||
2241 | if (glist_isvisible(x)) | ||
2242 | canvas_map(x, 0); | ||
2243 | canvas_create_editor(x, 0); | ||
2244 | sys_vgui("destroy .x%x\n", x); | ||
2245 | for (i = 1, x2 = x; x2; x2 = x2->gl_next, i++) | ||
2246 | ; | ||
2247 | sys_vgui(".mbar.find delete %d\n", i); | ||
2248 | /* if we're a graph on our parent, and if the parent exists | ||
2249 | and is visible, show ourselves on parent. */ | ||
2250 | if (glist_isgraph(x) && x->gl_owner) | ||
2251 | { | ||
2252 | t_glist *gl2 = x->gl_owner; | ||
2253 | canvas_create_editor(x, 1); | ||
2254 | if (glist_isvisible(gl2)) | ||
2255 | gobj_vis(&x->gl_gobj, gl2, 0); | ||
2256 | x->gl_havewindow = 0; | ||
2257 | if (glist_isvisible(gl2)) | ||
2258 | gobj_vis(&x->gl_gobj, gl2, 1); | ||
2259 | } | ||
2260 | else x->gl_havewindow = 0; | ||
2261 | canvas_updatewindowlist(); | ||
2262 | } | ||
2263 | } | ||
2264 | |||
2265 | /* we call this on a non-toplevel glist to "open" it into its | ||
2266 | own window. */ | ||
2267 | void glist_menu_open(t_glist *x) | ||
2268 | { | ||
2269 | if (glist_isvisible(x) && !glist_istoplevel(x)) | ||
2270 | { | ||
2271 | t_glist *gl2 = x->gl_owner; | ||
2272 | if (!gl2) | ||
2273 | bug("canvas_vis"); /* shouldn't happen but don't get too upset. */ | ||
2274 | else | ||
2275 | { | ||
2276 | /* erase ourself in parent window */ | ||
2277 | gobj_vis(&x->gl_gobj, gl2, 0); | ||
2278 | /* get rid of our editor (and subeditors) */ | ||
2279 | canvas_create_editor(x, 0); | ||
2280 | x->gl_havewindow = 1; | ||
2281 | /* redraw ourself in parent window (blanked out this time) */ | ||
2282 | gobj_vis(&x->gl_gobj, gl2, 1); | ||
2283 | } | ||
2284 | } | ||
2285 | canvas_vis(x, 1); | ||
2286 | } | ||
2287 | |||
2288 | int glist_isvisible(t_glist *x) | ||
2289 | { | ||
2290 | return ((!x->gl_loading) && glist_getcanvas(x)->gl_mapped); | ||
2291 | } | ||
2292 | |||
2293 | int glist_istoplevel(t_glist *x) | ||
2294 | { | ||
2295 | /* we consider a graph "toplevel" if it has its own window | ||
2296 | or if it appears as a box in its parent window so that we | ||
2297 | don't draw the actual contents there. */ | ||
2298 | return (x->gl_havewindow || !x->gl_isgraph); | ||
2299 | } | ||
2300 | |||
2301 | int glist_getfont(t_glist *x) | ||
2302 | { | ||
2303 | return (glist_getcanvas(x)->gl_font); | ||
2304 | } | ||
2305 | |||
2306 | void canvas_free(t_canvas *x) | ||
2307 | { | ||
2308 | t_gobj *y; | ||
2309 | int dspstate = canvas_suspend_dsp(); | ||
2310 | canvas_noundo(x); | ||
2311 | if (canvas_editing == x) | ||
2312 | canvas_editing = 0; | ||
2313 | if (canvas_whichfind == x) | ||
2314 | canvas_whichfind = 0; | ||
2315 | glist_noselect(x); | ||
2316 | while (y = x->gl_list) | ||
2317 | glist_delete(x, y); | ||
2318 | canvas_vis(x, 0); | ||
2319 | |||
2320 | if (strcmp(x->gl_name->s_name, "Pd")) | ||
2321 | pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name)); | ||
2322 | if (x->gl_env) | ||
2323 | { | ||
2324 | freebytes(x->gl_env->ce_argv, x->gl_env->ce_argc * sizeof(t_atom)); | ||
2325 | freebytes(x->gl_env, sizeof(*x->gl_env)); | ||
2326 | } | ||
2327 | canvas_resume_dsp(dspstate); | ||
2328 | glist_cleanup(x); | ||
2329 | gfxstub_deleteforkey(x); /* probably unnecessary */ | ||
2330 | if (!x->gl_owner) | ||
2331 | canvas_takeofflist(x); | ||
2332 | } | ||
2333 | |||
2334 | /* ----------------- lines ---------- */ | ||
2335 | |||
2336 | static void canvas_drawlines(t_canvas *x) | ||
2337 | { | ||
2338 | t_linetraverser t; | ||
2339 | t_outconnect *oc; | ||
2340 | { | ||
2341 | linetraverser_start(&t, x); | ||
2342 | while (oc = linetraverser_next(&t)) | ||
2343 | sys_vgui(".x%x.c create line %d %d %d %d -width %d -tags l%x\n", | ||
2344 | glist_getcanvas(x), | ||
2345 | t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2, | ||
2346 | (outlet_getsymbol(t.tr_outlet) == &s_signal ? 2:1), | ||
2347 | oc); | ||
2348 | } | ||
2349 | } | ||
2350 | |||
2351 | void canvas_fixlinesfor(t_canvas *x, t_text *text) | ||
2352 | { | ||
2353 | t_linetraverser t; | ||
2354 | t_outconnect *oc; | ||
2355 | |||
2356 | linetraverser_start(&t, x); | ||
2357 | while (oc = linetraverser_next(&t)) | ||
2358 | { | ||
2359 | if (t.tr_ob == text || t.tr_ob2 == text) | ||
2360 | { | ||
2361 | sys_vgui(".x%x.c coords l%x %d %d %d %d\n", | ||
2362 | glist_getcanvas(x), oc, | ||
2363 | t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2); | ||
2364 | } | ||
2365 | } | ||
2366 | } | ||
2367 | |||
2368 | /* kill all lines for the object */ | ||
2369 | void canvas_deletelinesfor(t_canvas *x, t_text *text) | ||
2370 | { | ||
2371 | t_linetraverser t; | ||
2372 | t_outconnect *oc; | ||
2373 | linetraverser_start(&t, x); | ||
2374 | while (oc = linetraverser_next(&t)) | ||
2375 | { | ||
2376 | if (t.tr_ob == text || t.tr_ob2 == text) | ||
2377 | { | ||
2378 | if (x->gl_editor) | ||
2379 | { | ||
2380 | sys_vgui(".x%x.c delete l%x\n", | ||
2381 | glist_getcanvas(x), oc); | ||
2382 | } | ||
2383 | obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno); | ||
2384 | } | ||
2385 | } | ||
2386 | } | ||
2387 | |||
2388 | /* kill all lines for one inlet or outlet */ | ||
2389 | void canvas_deletelinesforio(t_canvas *x, t_text *text, | ||
2390 | t_inlet *inp, t_outlet *outp) | ||
2391 | { | ||
2392 | t_linetraverser t; | ||
2393 | t_outconnect *oc; | ||
2394 | linetraverser_start(&t, x); | ||
2395 | while (oc = linetraverser_next(&t)) | ||
2396 | { | ||
2397 | if ((t.tr_ob == text && t.tr_outlet == outp) || | ||
2398 | (t.tr_ob2 == text && t.tr_inlet == inp)) | ||
2399 | { | ||
2400 | if (x->gl_editor) | ||
2401 | { | ||
2402 | sys_vgui(".x%x.c delete l%x\n", | ||
2403 | glist_getcanvas(x), oc); | ||
2404 | } | ||
2405 | obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno); | ||
2406 | } | ||
2407 | } | ||
2408 | } | ||
2409 | |||
2410 | static void canvas_pop(t_canvas *x, t_floatarg fvis) | ||
2411 | { | ||
2412 | if (fvis != 0) | ||
2413 | canvas_vis(x, 1); | ||
2414 | pd_popsym(&x->gl_pd); | ||
2415 | canvas_resortinlets(x); | ||
2416 | canvas_resortoutlets(x); | ||
2417 | x->gl_loading = 0; | ||
2418 | } | ||
2419 | |||
2420 | void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv); | ||
2421 | |||
2422 | |||
2423 | void canvas_restore(t_canvas *x, t_symbol *s, int argc, t_atom *argv) | ||
2424 | { /* IOhannes */ | ||
2425 | t_pd *z; | ||
2426 | /* this should be unnecessary, but sometimes the canvas's name gets | ||
2427 | out of sync with the owning box's argument; this fixes that */ | ||
2428 | if (argc > 3) | ||
2429 | { | ||
2430 | t_atom *ap=argv+3; | ||
2431 | if (ap->a_type == A_SYMBOL) | ||
2432 | { | ||
2433 | char *buf=ap->a_w.w_symbol->s_name, *bufp; | ||
2434 | if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9') | ||
2435 | { | ||
2436 | for (bufp = buf+2; *bufp; bufp++) | ||
2437 | if (*bufp < '0' || *bufp > '9') | ||
2438 | { | ||
2439 | SETDOLLSYM(ap, gensym(buf+1)); | ||
2440 | goto didit; | ||
2441 | } | ||
2442 | SETDOLLAR(ap, atoi(buf+1)); | ||
2443 | didit: ; | ||
2444 | } | ||
2445 | } | ||
2446 | |||
2447 | if (ap->a_type == A_DOLLSYM) | ||
2448 | { | ||
2449 | t_canvasenvironment *e = canvas_getenv(canvas_getcurrent()); | ||
2450 | canvas_rename(x, binbuf_realizedollsym(ap->a_w.w_symbol, | ||
2451 | e->ce_argc, e->ce_argv, 1), 0); | ||
2452 | } | ||
2453 | else if (ap->a_type == A_SYMBOL) | ||
2454 | canvas_rename(x, argv[3].a_w.w_symbol, 0); | ||
2455 | } | ||
2456 | canvas_pop(x, x->gl_willvis); | ||
2457 | |||
2458 | if (!(z = gensym("#X")->s_thing)) error("canvas_restore: out of context"); | ||
2459 | else if (*z != canvas_class) error("canvas_restore: wasn't a canvas"); | ||
2460 | else | ||
2461 | { | ||
2462 | t_canvas *x2 = (t_canvas *)z; | ||
2463 | x->gl_owner = x2; | ||
2464 | canvas_objfor(x2, &x->gl_obj, argc, argv); | ||
2465 | } | ||
2466 | } | ||
2467 | |||
2468 | static void canvas_loadbangabstractions(t_canvas *x) | ||
2469 | { | ||
2470 | t_gobj *y; | ||
2471 | t_symbol *s = gensym("loadbang"); | ||
2472 | for (y = x->gl_list; y; y = y->g_next) | ||
2473 | if (pd_class(&y->g_pd) == canvas_class) | ||
2474 | { | ||
2475 | if (canvas_isabstraction((t_canvas *)y)) | ||
2476 | canvas_loadbang((t_canvas *)y); | ||
2477 | else | ||
2478 | canvas_loadbangabstractions((t_canvas *)y); | ||
2479 | } | ||
2480 | } | ||
2481 | |||
2482 | void canvas_loadbangsubpatches(t_canvas *x) | ||
2483 | { | ||
2484 | t_gobj *y; | ||
2485 | t_symbol *s = gensym("loadbang"); | ||
2486 | for (y = x->gl_list; y; y = y->g_next) | ||
2487 | if (pd_class(&y->g_pd) == canvas_class) | ||
2488 | { | ||
2489 | if (!canvas_isabstraction((t_canvas *)y)) | ||
2490 | canvas_loadbangsubpatches((t_canvas *)y); | ||
2491 | } | ||
2492 | for (y = x->gl_list; y; y = y->g_next) | ||
2493 | if ((pd_class(&y->g_pd) != canvas_class) && | ||
2494 | zgetfn(&y->g_pd, s)) | ||
2495 | pd_vmess(&y->g_pd, s, ""); | ||
2496 | } | ||
2497 | |||
2498 | void canvas_loadbang(t_canvas *x) | ||
2499 | { | ||
2500 | t_gobj *y; | ||
2501 | canvas_loadbangabstractions(x); | ||
2502 | canvas_loadbangsubpatches(x); | ||
2503 | } | ||
2504 | |||
2505 | /* When you ask a canvas its size the result is 2 pixels more than what | ||
2506 | you gave it to open it; perhaps there's a 1-pixel border all around it | ||
2507 | or something. Anyway, we just add the 2 pixels back here; seems we | ||
2508 | have to do this for linux but not MSW; not sure about MacOS. */ | ||
2509 | |||
2510 | #ifdef MSW | ||
2511 | #define HORIZBORDER 0 | ||
2512 | #define VERTBORDER 0 | ||
2513 | #else | ||
2514 | #define HORIZBORDER 2 | ||
2515 | #define VERTBORDER 2 | ||
2516 | #endif | ||
2517 | |||
2518 | static void canvas_relocate(t_canvas *x, t_symbol *canvasgeom, | ||
2519 | t_symbol *topgeom) | ||
2520 | { | ||
2521 | int cxpix, cypix, cw, ch, txpix, typix, tw, th; | ||
2522 | if (sscanf(canvasgeom->s_name, "%dx%d+%d+%d", &cw, &ch, &cxpix, &cypix) | ||
2523 | < 4 || | ||
2524 | sscanf(topgeom->s_name, "%dx%d+%d+%d", &tw, &th, &txpix, &typix) < 4) | ||
2525 | bug("canvas_relocate"); | ||
2526 | /* for some reason this is initially called with cw=ch=1 so | ||
2527 | we just suppress that here. */ | ||
2528 | if (cw > 5 && ch > 5) | ||
2529 | canvas_setbounds(x, txpix, typix, | ||
2530 | txpix + cw - HORIZBORDER, typix + ch - VERTBORDER); | ||
2531 | } | ||
2532 | |||
2533 | void canvas_popabstraction(t_canvas *x) | ||
2534 | { | ||
2535 | newest = &x->gl_pd; | ||
2536 | pd_popsym(&x->gl_pd); | ||
2537 | x->gl_loading = 0; | ||
2538 | canvas_resortinlets(x); | ||
2539 | canvas_resortoutlets(x); | ||
2540 | } | ||
2541 | |||
2542 | void canvas_logerror(t_object *y) | ||
2543 | { | ||
2544 | #ifdef LATER | ||
2545 | canvas_vis(x, 1); | ||
2546 | if (!glist_isselected(x, &y->ob_g)) | ||
2547 | glist_select(x, &y->ob_g); | ||
2548 | #endif | ||
2549 | } | ||
2550 | |||
2551 | /* -------------------------- subcanvases ---------------------- */ | ||
2552 | |||
2553 | static void *subcanvas_new(t_symbol *s) | ||
2554 | { | ||
2555 | t_atom a[6]; | ||
2556 | t_canvas *x, *z = canvas_getcurrent(); | ||
2557 | if (!*s->s_name) s = gensym("/SUBPATCH/"); | ||
2558 | SETFLOAT(a, 0); | ||
2559 | SETFLOAT(a+1, GLIST_DEFCANVASYLOC); | ||
2560 | SETFLOAT(a+2, GLIST_DEFCANVASWIDTH); | ||
2561 | SETFLOAT(a+3, GLIST_DEFCANVASHEIGHT); | ||
2562 | SETSYMBOL(a+4, s); | ||
2563 | SETFLOAT(a+5, 1); | ||
2564 | x = canvas_new(0, 0, 6, a); | ||
2565 | x->gl_owner = z; | ||
2566 | canvas_pop(x, 1); | ||
2567 | return (x); | ||
2568 | } | ||
2569 | |||
2570 | static void canvas_click(t_canvas *x, | ||
2571 | t_floatarg xpos, t_floatarg ypos, | ||
2572 | t_floatarg shift, t_floatarg ctrl, t_floatarg alt) | ||
2573 | { | ||
2574 | canvas_vis(x, 1); | ||
2575 | } | ||
2576 | |||
2577 | |||
2578 | /* find out from subcanvas contents how much to fatten the box */ | ||
2579 | void canvas_fattensub(t_canvas *x, | ||
2580 | int *xp1, int *yp1, int *xp2, int *yp2) | ||
2581 | { | ||
2582 | t_gobj *y; | ||
2583 | *xp2 += 50; /* fake for now */ | ||
2584 | *yp2 += 50; | ||
2585 | } | ||
2586 | |||
2587 | static void canvas_rename_method(t_canvas *x, t_symbol *s, int ac, t_atom *av) | ||
2588 | { | ||
2589 | if (ac && av->a_type == A_SYMBOL) | ||
2590 | canvas_rename(x, av->a_w.w_symbol, 0); | ||
2591 | else canvas_rename(x, gensym("Pd"), 0); | ||
2592 | } | ||
2593 | |||
2594 | /* ------------------ table ---------------------------*/ | ||
2595 | |||
2596 | static int tabcount = 0; | ||
2597 | |||
2598 | static void *table_new(t_symbol *s, t_floatarg f) | ||
2599 | { | ||
2600 | t_atom a[9]; | ||
2601 | t_glist *gl; | ||
2602 | t_canvas *x, *z = canvas_getcurrent(); | ||
2603 | if (s == &s_) | ||
2604 | { | ||
2605 | char tabname[255]; | ||
2606 | t_symbol *t = gensym("table"); | ||
2607 | sprintf(tabname, "%s%d", t->s_name, tabcount++); | ||
2608 | s = gensym(tabname); | ||
2609 | } | ||
2610 | if (f <= 1) | ||
2611 | f = 100; | ||
2612 | SETFLOAT(a, 0); | ||
2613 | SETFLOAT(a+1, GLIST_DEFCANVASYLOC); | ||
2614 | SETFLOAT(a+2, 600); | ||
2615 | SETFLOAT(a+3, 400); | ||
2616 | SETSYMBOL(a+4, s); | ||
2617 | SETFLOAT(a+5, 0); | ||
2618 | x = canvas_new(0, 0, 6, a); | ||
2619 | |||
2620 | x->gl_owner = z; | ||
2621 | |||
2622 | /* create a graph for the table */ | ||
2623 | gl = glist_addglist((t_glist*)x, &s_, 0, -1, (f > 1 ? f-1 : 1), 1, | ||
2624 | 50, 350, 550, 50); | ||
2625 | |||
2626 | graph_array(gl, s, &s_float, f, 0); | ||
2627 | |||
2628 | canvas_pop(x, 0); | ||
2629 | |||
2630 | return (x); | ||
2631 | } | ||
2632 | |||
2633 | /* return true if the "canvas" object is an abstraction (so we don't | ||
2634 | save its contents, fogr example.) */ | ||
2635 | int canvas_isabstraction(t_canvas *x) | ||
2636 | { | ||
2637 | return (x->gl_env != 0); | ||
2638 | } | ||
2639 | |||
2640 | /* return true if the "canvas" object is a "table". */ | ||
2641 | int canvas_istable(t_canvas *x) | ||
2642 | { | ||
2643 | t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0); | ||
2644 | int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0); | ||
2645 | int istable = (argc && argv[0].a_type == A_SYMBOL && | ||
2646 | argv[0].a_w.w_symbol == gensym("table")); | ||
2647 | return (istable); | ||
2648 | } | ||
2649 | |||
2650 | /* return true if the "canvas" object should be treated as a text | ||
2651 | object. This is true for abstractions but also for "table"s... */ | ||
2652 | int canvas_showtext(t_canvas *x) | ||
2653 | { | ||
2654 | t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0); | ||
2655 | int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0); | ||
2656 | int isarray = (argc && argv[0].a_type == A_SYMBOL && | ||
2657 | argv[0].a_w.w_symbol == gensym("graph")); | ||
2658 | return (!isarray); | ||
2659 | } | ||
2660 | |||
2661 | static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp); | ||
2662 | static void canvas_dsp(t_canvas *x, t_signal **sp) | ||
2663 | { | ||
2664 | canvas_dodsp(x, 0, sp); | ||
2665 | } | ||
2666 | |||
2667 | /* get the document containing this canvas */ | ||
2668 | t_canvas *canvas_getrootfor(t_canvas *x) | ||
2669 | { | ||
2670 | if ((!x->gl_owner) || canvas_isabstraction(x)) | ||
2671 | return (x); | ||
2672 | else return (canvas_getrootfor(x->gl_owner)); | ||
2673 | } | ||
2674 | |||
2675 | /* ------------------------- DSP chain handling ------------------------- */ | ||
2676 | |||
2677 | EXTERN_STRUCT _dspcontext; | ||
2678 | #define t_dspcontext struct _dspcontext | ||
2679 | |||
2680 | void ugen_start(void); | ||
2681 | void ugen_stop(void); | ||
2682 | |||
2683 | t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp, | ||
2684 | int ninlets, int noutlets); | ||
2685 | void ugen_add(t_dspcontext *dc, t_object *x); | ||
2686 | void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, | ||
2687 | t_object *x2, int inno); | ||
2688 | void ugen_done_graph(t_dspcontext *dc); | ||
2689 | |||
2690 | /* schedule one canvas for DSP. This is called below for all "root" | ||
2691 | canvases, but is also called from the "dsp" method for sub- | ||
2692 | canvases, which are treated almost like any other tilde object. */ | ||
2693 | |||
2694 | static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp) | ||
2695 | { | ||
2696 | t_linetraverser t; | ||
2697 | t_outconnect *oc; | ||
2698 | t_gobj *y; | ||
2699 | t_object *ob; | ||
2700 | t_symbol *dspsym = gensym("dsp"); | ||
2701 | t_dspcontext *dc; | ||
2702 | |||
2703 | /* create a new "DSP graph" object to use in sorting this canvas. | ||
2704 | If we aren't toplevel, there are already other dspcontexts around. */ | ||
2705 | |||
2706 | dc = ugen_start_graph(toplevel, sp, | ||
2707 | obj_nsiginlets(&x->gl_obj), | ||
2708 | obj_nsigoutlets(&x->gl_obj)); | ||
2709 | |||
2710 | /* find all the "dsp" boxes and add them to the graph */ | ||
2711 | |||
2712 | for (y = x->gl_list; y; y = y->g_next) | ||
2713 | if ((ob = pd_checkobject(&y->g_pd)) && zgetfn(&y->g_pd, dspsym)) | ||
2714 | ugen_add(dc, ob); | ||
2715 | |||
2716 | /* ... and all dsp interconnections */ | ||
2717 | linetraverser_start(&t, x); | ||
2718 | while (oc = linetraverser_next(&t)) | ||
2719 | if (obj_issignaloutlet(t.tr_ob, t.tr_outno)) | ||
2720 | ugen_connect(dc, t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno); | ||
2721 | |||
2722 | /* finally, sort them and add them to the DSP chain */ | ||
2723 | ugen_done_graph(dc); | ||
2724 | } | ||
2725 | |||
2726 | /* this routine starts DSP for all root canvases. */ | ||
2727 | static void canvas_start_dsp(void) | ||
2728 | { | ||
2729 | t_canvas *x; | ||
2730 | if (canvas_dspstate) ugen_stop(); | ||
2731 | else sys_gui("pdtk_pd_dsp ON\n"); | ||
2732 | ugen_start(); | ||
2733 | |||
2734 | for (x = canvas_list; x; x = x->gl_next) | ||
2735 | canvas_dodsp(x, 1, 0); | ||
2736 | |||
2737 | canvas_dspstate = 1; | ||
2738 | } | ||
2739 | |||
2740 | static void canvas_stop_dsp(void) | ||
2741 | { | ||
2742 | if (canvas_dspstate) | ||
2743 | { | ||
2744 | ugen_stop(); | ||
2745 | sys_gui("pdtk_pd_dsp OFF\n"); | ||
2746 | canvas_dspstate = 0; | ||
2747 | } | ||
2748 | } | ||
2749 | |||
2750 | /* DSP can be suspended before, and resumed after, operations which | ||
2751 | might affect the DSP chain. For example, we suspend before loading and | ||
2752 | resume afterward, so that DSP doesn't get resorted for every DSP object | ||
2753 | int the patch. */ | ||
2754 | |||
2755 | int canvas_suspend_dsp(void) | ||
2756 | { | ||
2757 | int rval = canvas_dspstate; | ||
2758 | if (rval) canvas_stop_dsp(); | ||
2759 | return (rval); | ||
2760 | } | ||
2761 | |||
2762 | void canvas_resume_dsp(int oldstate) | ||
2763 | { | ||
2764 | if (oldstate) canvas_start_dsp(); | ||
2765 | } | ||
2766 | |||
2767 | /* this is equivalent to suspending and resuming in one step. */ | ||
2768 | void canvas_update_dsp(void) | ||
2769 | { | ||
2770 | if (canvas_dspstate) canvas_start_dsp(); | ||
2771 | } | ||
2772 | |||
2773 | void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv) | ||
2774 | { | ||
2775 | int newstate; | ||
2776 | if (argc) | ||
2777 | { | ||
2778 | newstate = atom_getintarg(0, argc, argv); | ||
2779 | if (newstate && !canvas_dspstate) | ||
2780 | { | ||
2781 | sys_set_audio_state(1); | ||
2782 | canvas_start_dsp(); | ||
2783 | } | ||
2784 | else if (!newstate && canvas_dspstate) | ||
2785 | { | ||
2786 | canvas_stop_dsp(); | ||
2787 | sys_set_audio_state(0); | ||
2788 | } | ||
2789 | } | ||
2790 | else post("dsp state %d", canvas_dspstate); | ||
2791 | } | ||
2792 | |||
2793 | /* LATER replace this with a queueing scheme */ | ||
2794 | void glist_redrawitem(t_glist *owner, t_gobj *gobj) | ||
2795 | { | ||
2796 | if (glist_isvisible(owner)) | ||
2797 | { | ||
2798 | gobj_vis(gobj, owner, 0); | ||
2799 | gobj_vis(gobj, owner, 1); | ||
2800 | } | ||
2801 | } | ||
2802 | |||
2803 | /* redraw all "scalars" (do this if a drawing command is changed.) | ||
2804 | LATER we'll use the "template" information to select which ones we | ||
2805 | redraw. */ | ||
2806 | static void glist_redrawall(t_glist *gl) | ||
2807 | { | ||
2808 | t_gobj *g; | ||
2809 | int vis = glist_isvisible(gl); | ||
2810 | for (g = gl->gl_list; g; g = g->g_next) | ||
2811 | { | ||
2812 | t_class *cl; | ||
2813 | if (vis && g->g_pd == scalar_class) | ||
2814 | glist_redrawitem(gl, g); | ||
2815 | else if (g->g_pd == canvas_class) | ||
2816 | glist_redrawall((t_glist *)g); | ||
2817 | } | ||
2818 | } | ||
2819 | |||
2820 | /* public interface for above */ | ||
2821 | void canvas_redrawallfortemplate(t_canvas *templatecanvas) | ||
2822 | { | ||
2823 | t_canvas *x; | ||
2824 | /* find all root canvases */ | ||
2825 | for (x = canvas_list; x; x = x->gl_next) | ||
2826 | glist_redrawall(x); | ||
2827 | } | ||
2828 | |||
2829 | /* ------------------------------- setup routine ------------------------ */ | ||
2830 | |||
2831 | /* why are some of these "glist" and others "canvas"? */ | ||
2832 | extern void glist_text(t_glist *x, t_symbol *s, int argc, t_atom *argv); | ||
2833 | extern void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2834 | extern void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2835 | extern void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2836 | extern void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2837 | extern void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2838 | extern void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2839 | /* old version... */ | ||
2840 | extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2841 | extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2842 | /* new version: */ | ||
2843 | extern void canvas_hradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2844 | extern void canvas_vradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2845 | extern void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2846 | extern void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2847 | extern void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2848 | extern void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2849 | extern void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2850 | extern void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv); | ||
2851 | extern void glist_scalar(t_glist *canvas, t_symbol *s, int argc, t_atom *argv); | ||
2852 | |||
2853 | void g_graph_setup(void); | ||
2854 | void g_editor_setup(void); | ||
2855 | void g_readwrite_setup(void); | ||
2856 | extern void graph_properties(t_gobj *z, t_glist *owner); | ||
2857 | |||
2858 | void g_canvas_setup(void) | ||
2859 | { | ||
2860 | /* we prevent the user from typing "canvas" in an object box | ||
2861 | by sending 0 for a creator function. */ | ||
2862 | canvas_class = class_new(gensym("canvas"), 0, | ||
2863 | (t_method)canvas_free, sizeof(t_canvas), CLASS_NOINLET, 0); | ||
2864 | /* here is the real creator function, invoked in patch files | ||
2865 | by sending the "canvas" message to #N, which is bound | ||
2866 | to pd_camvasmaker. */ | ||
2867 | class_addmethod(pd_canvasmaker, (t_method)canvas_new, gensym("canvas"), | ||
2868 | A_GIMME, 0); | ||
2869 | class_addmethod(canvas_class, (t_method)canvas_restore, | ||
2870 | gensym("restore"), A_GIMME, 0); | ||
2871 | class_addmethod(canvas_class, (t_method)canvas_coords, | ||
2872 | gensym("coords"), A_GIMME, 0); | ||
2873 | |||
2874 | /* -------------------------- objects ----------------------------- */ | ||
2875 | class_addmethod(canvas_class, (t_method)canvas_obj, | ||
2876 | gensym("obj"), A_GIMME, A_NULL); | ||
2877 | class_addmethod(canvas_class, (t_method)canvas_msg, | ||
2878 | gensym("msg"), A_GIMME, A_NULL); | ||
2879 | class_addmethod(canvas_class, (t_method)canvas_floatatom, | ||
2880 | gensym("floatatom"), A_GIMME, A_NULL); | ||
2881 | class_addmethod(canvas_class, (t_method)canvas_symbolatom, | ||
2882 | gensym("symbolatom"), A_GIMME, A_NULL); | ||
2883 | class_addmethod(canvas_class, (t_method)glist_text, | ||
2884 | gensym("text"), A_GIMME, A_NULL); | ||
2885 | class_addmethod(canvas_class, (t_method)glist_glist, gensym("graph"), | ||
2886 | A_GIMME, A_NULL); | ||
2887 | class_addmethod(canvas_class, (t_method)glist_scalar, | ||
2888 | gensym("scalar"), A_GIMME, A_NULL); | ||
2889 | |||
2890 | /* -------------- Thomas Musil's GUI objects ------------ */ | ||
2891 | class_addmethod(canvas_class, (t_method)canvas_bng, gensym("bng"), | ||
2892 | A_GIMME, A_NULL); | ||
2893 | class_addmethod(canvas_class, (t_method)canvas_toggle, gensym("toggle"), | ||
2894 | A_GIMME, A_NULL); | ||
2895 | class_addmethod(canvas_class, (t_method)canvas_vslider, gensym("vslider"), | ||
2896 | A_GIMME, A_NULL); | ||
2897 | class_addmethod(canvas_class, (t_method)canvas_hslider, gensym("hslider"), | ||
2898 | A_GIMME, A_NULL); | ||
2899 | class_addmethod(canvas_class, (t_method)canvas_hdial, gensym("hdial"), | ||
2900 | A_GIMME, A_NULL); | ||
2901 | class_addmethod(canvas_class, (t_method)canvas_vdial, gensym("vdial"), | ||
2902 | A_GIMME, A_NULL); | ||
2903 | class_addmethod(canvas_class, (t_method)canvas_hradio, gensym("hradio"), | ||
2904 | A_GIMME, A_NULL); | ||
2905 | class_addmethod(canvas_class, (t_method)canvas_vradio, gensym("vradio"), | ||
2906 | A_GIMME, A_NULL); | ||
2907 | class_addmethod(canvas_class, (t_method)canvas_vumeter, gensym("vumeter"), | ||
2908 | A_GIMME, A_NULL); | ||
2909 | class_addmethod(canvas_class, (t_method)canvas_mycnv, gensym("mycnv"), | ||
2910 | A_GIMME, A_NULL); | ||
2911 | class_addmethod(canvas_class, (t_method)canvas_numbox, gensym("numbox"), | ||
2912 | A_GIMME, A_NULL); | ||
2913 | |||
2914 | /* ------------------------ gui stuff --------------------------- */ | ||
2915 | class_addmethod(canvas_class, (t_method)canvas_pop, gensym("pop"), | ||
2916 | A_DEFFLOAT, A_NULL); | ||
2917 | class_addmethod(canvas_class, (t_method)canvas_loadbang, | ||
2918 | gensym("loadbang"), A_NULL); | ||
2919 | class_addmethod(canvas_class, (t_method)canvas_relocate, | ||
2920 | gensym("relocate"), A_SYMBOL, A_SYMBOL, A_NULL); | ||
2921 | class_addmethod(canvas_class, (t_method)canvas_vis, | ||
2922 | gensym("vis"), A_FLOAT, A_NULL); | ||
2923 | class_addmethod(canvas_class, (t_method)glist_menu_open, | ||
2924 | gensym("menu-open"), A_NULL); | ||
2925 | class_addmethod(canvas_class, (t_method)canvas_map, | ||
2926 | gensym("map"), A_FLOAT, A_NULL); | ||
2927 | class_setpropertiesfn(canvas_class, graph_properties); | ||
2928 | |||
2929 | /* ---------------------- list handling ------------------------ */ | ||
2930 | class_addmethod(canvas_class, (t_method)glist_clear, gensym("clear"), | ||
2931 | A_NULL); | ||
2932 | |||
2933 | /* ----- subcanvases, which you get by typing "pd" in a box ---- */ | ||
2934 | class_addcreator((t_newmethod)subcanvas_new, gensym("pd"), A_DEFSYMBOL, 0); | ||
2935 | class_addcreator((t_newmethod)subcanvas_new, gensym("page"), A_DEFSYMBOL, 0); | ||
2936 | |||
2937 | class_addmethod(canvas_class, (t_method)canvas_click, | ||
2938 | gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); | ||
2939 | class_addmethod(canvas_class, (t_method)canvas_dsp, gensym("dsp"), 0); | ||
2940 | class_addmethod(canvas_class, (t_method)canvas_rename_method, | ||
2941 | gensym("rename"), A_GIMME, 0); | ||
2942 | |||
2943 | /*---------------------------- tables -- GG ------------------- */ | ||
2944 | |||
2945 | class_addcreator((t_newmethod)table_new, gensym("table"), | ||
2946 | A_DEFSYM, A_DEFFLOAT, 0); | ||
2947 | |||
2948 | /* -------------- setups from other files for canvas_class ---------------- */ | ||
2949 | g_graph_setup(); | ||
2950 | g_editor_setup(); | ||
2951 | g_readwrite_setup(); | ||
2952 | } | ||