Fix some greedy sed changes in imported code. Also provide a sys/types.h for compatib...
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / g_canvas.c
bloba48a28e164b1c3150a9f5a8c3f75adef5531201c
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. */
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.) */
8 /* changes by Thomas Musil IEM KUG Graz Austria 2001 */
10 /* bug-fix: canvas_menuclose(): by Krzysztof Czaja */
11 /* bug-fix: table_new(): I reversed the y-bounds */
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
21 #ifdef ROCKBOX
22 #include "plugin.h"
23 #include "../../pdbox.h"
24 #include "m_pd.h"
25 #include "m_imp.h"
26 #include "s_stuff.h"
27 #include "g_canvas.h"
28 #include "g_all_guis.h"
29 #else /* ROCKBOX */
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include "m_pd.h"
33 #include "m_imp.h"
34 #include "s_stuff.h"
35 #include "g_canvas.h"
36 #include <string.h>
37 #include "g_all_guis.h"
38 #endif /* ROCKBOX */
40 struct _canvasenvironment
42 t_symbol *ce_dir; /* directory patch lives in */
43 int ce_argc; /* number of "$" arguments */
44 t_atom *ce_argv; /* array of "$" arguments */
45 int ce_dollarzero; /* value of "$0" */
48 #define GLIST_DEFCANVASWIDTH 240
49 #define GLIST_DEFCANVASHEIGHT 300
51 #ifdef MACOSX
52 #define GLIST_DEFCANVASYLOC 22
53 #else
54 #define GLIST_DEFCANVASYLOC 0
55 #endif
57 /* ---------------------- variables --------------------------- */
59 extern t_pd *newest;
60 t_class *canvas_class;
61 static int canvas_dspstate; /* whether DSP is on or off */
62 t_canvas *canvas_editing; /* last canvas to start text edting */
63 t_canvas *canvas_whichfind; /* last canvas we did a find in */
64 t_canvas *canvas_list; /* list of all root canvases */
66 /* ------------------ forward function declarations --------------- */
67 static void canvas_start_dsp(void);
68 static void canvas_stop_dsp(void);
69 static void canvas_drawlines(t_canvas *x);
70 static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2);
71 static void canvas_reflecttitle(t_canvas *x);
72 static void canvas_addtolist(t_canvas *x);
73 static void canvas_takeofflist(t_canvas *x);
74 static void canvas_pop(t_canvas *x, t_floatarg fvis);
75 void canvas_create_editor(t_glist *x, int createit);
77 /* --------- functions to handle the canvas environment ----------- */
79 static t_symbol *canvas_newfilename = &s_;
80 static t_symbol *canvas_newdirectory = &s_;
81 static int canvas_newargc;
82 static t_atom *canvas_newargv;
84 static void glist_doupdatewindowlist(t_glist *gl, char *sbuf)
86 t_gobj *g;
87 if (!gl->gl_owner)
89 /* this is a canvas; if we have a window, put on "windows" list */
90 t_canvas *canvas = (t_canvas *)gl;
91 if (canvas->gl_havewindow)
93 if (strlen(sbuf) + strlen(gl->gl_name->s_name) + 100 <= 1024)
95 char tbuf[1024];
96 #ifdef ROCKBOX
97 snprintf(tbuf, sizeof(tbuf),
98 "{%s .x%lx} ", gl->gl_name->s_name,
99 (unsigned long) (t_int) canvas);
100 #else /* ROCKBOX */
101 sprintf(tbuf, "{%s .x%x} ", gl->gl_name->s_name, (t_int)canvas);
102 #endif /* ROCKBOX */
103 strcat(sbuf, tbuf);
107 for (g = gl->gl_list; g; g = g->g_next)
109 if (pd_class(&g->g_pd) == canvas_class)
110 glist_doupdatewindowlist((t_glist *)g, sbuf);
112 return;
115 /* maintain the list of visible toplevels for the GUI's "windows" menu */
116 void canvas_updatewindowlist( void)
118 t_canvas *x;
119 char sbuf[1024];
120 strcpy(sbuf, "set menu_windowlist {");
121 /* find all root canvases */
122 for (x = canvas_list; x; x = x->gl_next)
123 glist_doupdatewindowlist(x, sbuf);
124 /* next line updates the window menu state before -postcommand tries it */
125 strcat(sbuf, "}\npdtk_fixwindowmenu\n");
126 #ifndef ROCKBOX
127 sys_gui(sbuf);
128 #endif
131 /* add a glist the list of "root" canvases (toplevels without parents.) */
132 static void canvas_addtolist(t_canvas *x)
134 x->gl_next = canvas_list;
135 canvas_list = x;
138 static void canvas_takeofflist(t_canvas *x)
140 /* take it off the window list */
141 if (x == canvas_list) canvas_list = x->gl_next;
142 else
144 t_canvas *z;
145 for (z = canvas_list; z->gl_next != x; z = z->gl_next)
147 z->gl_next = x->gl_next;
152 void canvas_setargs(int argc, t_atom *argv)
154 /* if there's an old one lying around free it here. This
155 happens if an abstraction is loaded but never gets as far
156 as calling canvas_new(). */
157 if (canvas_newargv)
158 freebytes(canvas_newargv, canvas_newargc * sizeof(t_atom));
159 canvas_newargc = argc;
160 canvas_newargv = copybytes(argv, argc * sizeof(t_atom));
163 void glob_setfilename(void *dummy, t_symbol *filesym, t_symbol *dirsym)
165 #ifdef ROCKBOX
166 (void) dummy;
167 #endif
168 canvas_newfilename = filesym;
169 canvas_newdirectory = dirsym;
172 t_canvas *canvas_getcurrent(void)
174 return ((t_canvas *)pd_findbyclass(&s__X, canvas_class));
177 void canvas_setcurrent(t_canvas *x)
179 pd_pushsym(&x->gl_pd);
182 void canvas_unsetcurrent(t_canvas *x)
184 pd_popsym(&x->gl_pd);
187 t_canvasenvironment *canvas_getenv(t_canvas *x)
189 if (!x) bug("canvas_getenv");
190 while (!x->gl_env)
191 if (!(x = x->gl_owner))
192 bug("t_canvasenvironment", x);
193 return (x->gl_env);
196 int canvas_getdollarzero( void)
198 t_canvas *x = canvas_getcurrent();
199 t_canvasenvironment *env = (x ? canvas_getenv(x) : 0);
200 if (env)
201 return (env->ce_dollarzero);
202 else return (0);
205 void canvas_getargs(int *argcp, t_atom **argvp)
207 t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
208 *argcp = e->ce_argc;
209 *argvp = e->ce_argv;
212 t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s)
214 t_symbol *ret;
215 char *name = s->s_name;
216 if (*name == '$' && name[1] >= '0' && name[1] <= '9')
218 t_canvasenvironment *env = canvas_getenv(x);
219 canvas_setcurrent(x);
220 ret = binbuf_realizedollsym(gensym(name+1),
221 env->ce_argc, env->ce_argv, 1);
222 canvas_unsetcurrent(x);
224 else ret = s;
225 return (ret);
228 t_symbol *canvas_getcurrentdir(void)
230 t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
231 return (e->ce_dir);
234 t_symbol *canvas_getdir(t_canvas *x)
236 t_canvasenvironment *e = canvas_getenv(x);
237 return (e->ce_dir);
240 void canvas_makefilename(t_canvas *x, char *file, char *result, int resultsize)
242 char *dir = canvas_getenv(x)->ce_dir->s_name;
243 if (file[0] == '/' || (file[0] && file[1] == ':') || !*dir)
245 strncpy(result, file, resultsize);
246 result[resultsize-1] = 0;
248 else
250 int nleft;
251 strncpy(result, dir, resultsize);
252 result[resultsize-1] = 0;
253 nleft = resultsize - strlen(result) - 1;
254 if (nleft <= 0) return;
255 strcat(result, "/");
256 strncat(result, file, nleft);
257 result[resultsize-1] = 0;
261 void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir)
263 if (strcmp(x->gl_name->s_name, "Pd"))
264 pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name));
265 x->gl_name = s;
266 if (strcmp(x->gl_name->s_name, "Pd"))
267 pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
268 if (glist_isvisible(x))
269 canvas_reflecttitle(x);
270 if (dir && dir != &s_)
272 t_canvasenvironment *e = canvas_getenv(x);
273 e->ce_dir = dir;
277 /* --------------- traversing the set of lines in a canvas ----------- */
279 int canvas_getindex(t_canvas *x, t_gobj *y)
281 t_gobj *y2;
282 int indexno;
283 for (indexno = 0, y2 = x->gl_list; y2 && y2 != y; y2 = y2->g_next)
284 indexno++;
285 return (indexno);
288 void linetraverser_start(t_linetraverser *t, t_canvas *x)
290 t->tr_ob = 0;
291 t->tr_x = x;
292 t->tr_nextoc = 0;
293 t->tr_nextoutno = t->tr_nout = 0;
296 t_outconnect *linetraverser_next(t_linetraverser *t)
298 t_outconnect *rval = t->tr_nextoc;
299 int outno;
300 while (!rval)
302 outno = t->tr_nextoutno;
303 while (outno == t->tr_nout)
305 t_gobj *y;
306 t_object *ob = 0;
307 if (!t->tr_ob) y = t->tr_x->gl_list;
308 else y = t->tr_ob->ob_g.g_next;
309 for (; y; y = y->g_next)
310 if((ob = pd_checkobject(&y->g_pd))) break;
311 if (!ob) return (0);
312 t->tr_ob = ob;
313 t->tr_nout = obj_noutlets(ob);
314 outno = 0;
315 if (glist_isvisible(t->tr_x))
316 gobj_getrect(y, t->tr_x,
317 &t->tr_x11, &t->tr_y11, &t->tr_x12, &t->tr_y12);
318 else t->tr_x11 = t->tr_y11 = t->tr_x12 = t->tr_y12 = 0;
320 t->tr_nextoutno = outno + 1;
321 rval = obj_starttraverseoutlet(t->tr_ob, &t->tr_outlet, outno);
322 t->tr_outno = outno;
324 t->tr_nextoc = obj_nexttraverseoutlet(rval, &t->tr_ob2,
325 &t->tr_inlet, &t->tr_inno);
326 t->tr_nin = obj_ninlets(t->tr_ob2);
327 if (!t->tr_nin) bug("drawline");
328 if (glist_isvisible(t->tr_x))
330 int inplus = (t->tr_nin == 1 ? 1 : t->tr_nin - 1);
331 int outplus = (t->tr_nout == 1 ? 1 : t->tr_nout - 1);
332 gobj_getrect(&t->tr_ob2->ob_g, t->tr_x,
333 &t->tr_x21, &t->tr_y21, &t->tr_x22, &t->tr_y22);
334 t->tr_lx1 = t->tr_x11 +
335 ((t->tr_x12 - t->tr_x11 - IOWIDTH) * t->tr_outno) /
336 outplus + IOMIDDLE;
337 t->tr_ly1 = t->tr_y12;
338 t->tr_lx2 = t->tr_x21 +
339 ((t->tr_x22 - t->tr_x21 - IOWIDTH) * t->tr_inno)/inplus +
340 IOMIDDLE;
341 t->tr_ly2 = t->tr_y21;
343 else
345 t->tr_x21 = t->tr_y21 = t->tr_x22 = t->tr_y22 = 0;
346 t->tr_lx1 = t->tr_ly1 = t->tr_lx2 = t->tr_ly2 = 0;
349 return (rval);
352 void linetraverser_skipobject(t_linetraverser *t)
354 t->tr_nextoc = 0;
355 t->tr_nextoutno = t->tr_nout;
358 /* -------------------- the canvas object -------------------------- */
359 int glist_valid = 10000;
361 void glist_init(t_glist *x)
363 /* zero out everyone except "pd" field */
364 memset(((char *)x) + sizeof(x->gl_pd), 0, sizeof(*x) - sizeof(x->gl_pd));
365 x->gl_stub = gstub_new(x, 0);
366 x->gl_valid = ++glist_valid;
367 x->gl_xlabel = (t_symbol **)t_getbytes(0);
368 x->gl_ylabel = (t_symbol **)t_getbytes(0);
371 /* make a new glist. It will either be a "root" canvas or else
372 its parent will be a "text" object in another window... we don't
373 know which yet. */
374 t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv)
376 t_canvas *x = (t_canvas *)pd_new(canvas_class);
377 t_canvas *owner = canvas_getcurrent();
378 t_symbol *s = &s_;
379 int vis = 0, width = GLIST_DEFCANVASWIDTH, height = GLIST_DEFCANVASHEIGHT;
380 int xloc = 0, yloc = GLIST_DEFCANVASYLOC;
381 #ifdef ROCKBOX
382 (void) dummy;
383 (void) sel;
384 int font = 10;
385 #else /* ROCKBOX */
386 int font = (owner ? owner->gl_font : sys_defaultfont);
387 #endif /* ROCKBOX */
388 glist_init(x);
389 x->gl_obj.te_type = T_OBJECT;
390 if (!owner)
391 canvas_addtolist(x);
392 /* post("canvas %x, owner %x", x, owner); */
394 if (argc == 5) /* toplevel: x, y, w, h, font */
396 xloc = atom_getintarg(0, argc, argv);
397 yloc = atom_getintarg(1, argc, argv);
398 width = atom_getintarg(2, argc, argv);
399 height = atom_getintarg(3, argc, argv);
400 font = atom_getintarg(4, argc, argv);
402 else if (argc == 6) /* subwindow: x, y, w, h, name, vis */
404 xloc = atom_getintarg(0, argc, argv);
405 yloc = atom_getintarg(1, argc, argv);
406 width = atom_getintarg(2, argc, argv);
407 height = atom_getintarg(3, argc, argv);
408 s = atom_getsymbolarg(4, argc, argv);
409 vis = atom_getintarg(5, argc, argv);
411 /* (otherwise assume we're being created from the menu.) */
413 if (canvas_newdirectory->s_name[0])
415 static int dollarzero = 1000;
416 t_canvasenvironment *env = x->gl_env =
417 (t_canvasenvironment *)getbytes(sizeof(*x->gl_env));
418 env->ce_dir = canvas_newdirectory;
419 env->ce_argc = canvas_newargc;
420 env->ce_argv = canvas_newargv;
421 env->ce_dollarzero = dollarzero++;
422 canvas_newdirectory = &s_;
423 canvas_newargc = 0;
424 canvas_newargv = 0;
426 else x->gl_env = 0;
428 if (yloc < GLIST_DEFCANVASYLOC)
429 yloc = GLIST_DEFCANVASYLOC;
430 if (xloc < 0)
431 xloc = 0;
432 x->gl_x1 = 0;
433 x->gl_y1 = 0;
434 x->gl_x2 = 1;
435 x->gl_y2 = 1;
436 canvas_setbounds(x, xloc, yloc, xloc + width, yloc + height);
437 x->gl_owner = owner;
438 x->gl_name = (*s->s_name ? s :
439 (canvas_newfilename ? canvas_newfilename : gensym("Pd")));
440 if (strcmp(x->gl_name->s_name, "Pd"))
441 pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
442 x->gl_loading = 1;
443 x->gl_willvis = vis;
444 x->gl_edit = !strncmp(x->gl_name->s_name, "Untitled", 8);
445 #ifdef ROCKBOX
446 x->gl_font = 10;
447 #else /* ROCKBOX */
448 x->gl_font = sys_nearestfontsize(font);
449 #endif /* ROCKBOX */
450 pd_pushsym(&x->gl_pd);
451 return(x);
454 void canvas_setgraph(t_glist *x, int flag);
456 static void canvas_coords(t_glist *x, t_symbol *s, int argc, t_atom *argv)
458 #ifdef ROCKBOX
459 (void) s;
460 #endif
461 x->gl_x1 = atom_getfloatarg(0, argc, argv);
462 x->gl_y1 = atom_getfloatarg(1, argc, argv);
463 x->gl_x2 = atom_getfloatarg(2, argc, argv);
464 x->gl_y2 = atom_getfloatarg(3, argc, argv);
465 x->gl_pixwidth = atom_getintarg(4, argc, argv);
466 x->gl_pixheight = atom_getintarg(5, argc, argv);
467 canvas_setgraph(x, atom_getintarg(6, argc, argv));
470 /* make a new glist and add it to this glist. It will appear as
471 a "graph", not a text object. */
472 t_glist *glist_addglist(t_glist *g, t_symbol *sym,
473 float x1, float y1, float x2, float y2,
474 float px1, float py1, float px2, float py2)
476 static int gcount = 0;
477 int zz;
478 int menu = 0;
479 char *str;
480 t_glist *x = (t_glist *)pd_new(canvas_class);
481 glist_init(x);
482 x->gl_obj.te_type = T_OBJECT;
483 if (!*sym->s_name)
485 char buf[40];
486 #ifdef ROCKBOX
487 snprintf(buf, sizeof(buf), "graph%d", ++gcount);
488 #else /* ROCKBOX */
489 sprintf(buf, "graph%d", ++gcount);
490 #endif /* ROCKBOX */
491 sym = gensym(buf);
492 menu = 1;
494 else if (!strncmp((str = sym->s_name), "graph", 5)
495 && (zz = atoi(str + 5)) > gcount)
496 gcount = zz;
497 /* in 0.34 and earlier, the pixel rectangle and the y bounds were
498 reversed; this would behave the same, except that the dialog window
499 would be confusing. The "correct" way is to have "py1" be the value
500 that is higher on the screen. */
501 if (py2 < py1)
503 float zz;
504 zz = y2;
505 y2 = y1;
506 y1 = zz;
507 zz = py2;
508 py2 = py1;
509 py1 = zz;
511 if (x1 == x2 || y1 == y2)
512 x1 = 0, x2 = 100, y1 = 1, y2 = -1;
513 if (px1 >= px2 || py1 >= py2)
514 px1 = 100, py1 = 20, px2 = 100 + GLIST_DEFGRAPHWIDTH,
515 py2 = 20 + GLIST_DEFGRAPHHEIGHT;
516 x->gl_name = sym;
517 x->gl_x1 = x1;
518 x->gl_x2 = x2;
519 x->gl_y1 = y1;
520 x->gl_y2 = y2;
521 x->gl_obj.te_xpix = px1;
522 x->gl_obj.te_ypix = py1;
523 x->gl_pixwidth = px2 - px1;
524 x->gl_pixheight = py2 - py1;
525 #ifdef ROCKBOX
526 x->gl_font = 10;
527 #else /* ROCKBOX */
528 x->gl_font = (canvas_getcurrent() ?
529 canvas_getcurrent()->gl_font : sys_defaultfont);
530 #endif /* ROCKBOX */
531 x->gl_screenx1 = x->gl_screeny1 = 0;
532 x->gl_screenx2 = 240;
533 x->gl_screeny2 = 300;
534 if (strcmp(x->gl_name->s_name, "Pd"))
535 pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
536 x->gl_owner = g;
537 x->gl_stretch = 1;
538 x->gl_isgraph = 1;
539 x->gl_obj.te_binbuf = binbuf_new();
540 binbuf_addv(x->gl_obj.te_binbuf, "s", gensym("graph"));
541 if (!menu)
542 pd_pushsym(&x->gl_pd);
543 glist_add(g, &x->gl_gobj);
544 if (glist_isvisible(g))
545 canvas_create_editor(x, 1);
546 return (x);
549 /* call glist_addglist from a Pd message */
550 void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv)
552 #ifdef ROCKBOX
553 (void) s;
554 #endif
555 t_symbol *sym = atom_getsymbolarg(0, argc, argv);
556 float x1 = atom_getfloatarg(1, argc, argv);
557 float y1 = atom_getfloatarg(2, argc, argv);
558 float x2 = atom_getfloatarg(3, argc, argv);
559 float y2 = atom_getfloatarg(4, argc, argv);
560 float px1 = atom_getfloatarg(5, argc, argv);
561 float py1 = atom_getfloatarg(6, argc, argv);
562 float px2 = atom_getfloatarg(7, argc, argv);
563 float py2 = atom_getfloatarg(8, argc, argv);
564 glist_addglist(g, sym, x1, y1, x2, y2, px1, py1, px2, py2);
567 /* return true if the glist should appear as a graph on parent;
568 otherwise it appears as a text box. */
569 int glist_isgraph(t_glist *x)
571 return (x->gl_isgraph);
574 /* This is sent from the GUI to inform a toplevel that its window has been
575 moved or resized. */
576 static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2)
578 int heightwas = y2 - y1;
579 int heightchange = y2 - y1 - (x->gl_screeny2 - x->gl_screeny1);
580 x->gl_screenx1 = x1;
581 x->gl_screeny1 = y1;
582 x->gl_screenx2 = x2;
583 x->gl_screeny2 = y2;
584 /* post("set bounds %d %d %d %d", x1, y1, x2, y2); */
585 if (!glist_isgraph(x) && (x->gl_y2 < x->gl_y1))
587 /* if it's flipped so that y grows upward,
588 fix so that zero is bottom edge and redraw. This is
589 only appropriate if we're a regular "text" object on the
590 parent. */
591 float diff = x->gl_y1 - x->gl_y2;
592 t_gobj *y;
593 x->gl_y1 = heightwas * diff;
594 x->gl_y2 = x->gl_y1 - diff;
595 /* and move text objects accordingly; they should stick
596 to the bottom, not the top. */
597 for (y = x->gl_list; y; y = y->g_next)
598 if (pd_checkobject(&y->g_pd))
599 gobj_displace(y, x, 0, heightchange);
600 canvas_redraw(x);
604 t_symbol *canvas_makebindsym(t_symbol *s)
606 char buf[MAXPDSTRING];
607 strcpy(buf, "pd-");
608 strcat(buf, s->s_name);
609 return (gensym(buf));
612 void canvas_reflecttitle(t_canvas *x)
614 char namebuf[MAXPDSTRING];
615 t_canvasenvironment *env = canvas_getenv(x);
616 if (env->ce_argc)
618 int i;
619 strcpy(namebuf, " (");
620 for (i = 0; i < env->ce_argc; i++)
622 if (strlen(namebuf) > MAXPDSTRING/2 - 5)
623 break;
624 if (i != 0)
625 strcat(namebuf, " ");
626 atom_string(&env->ce_argv[i], namebuf + strlen(namebuf),
627 MAXPDSTRING/2);
629 strcat(namebuf, ")");
631 else namebuf[0] = 0;
632 #ifndef ROCKBOX
633 sys_vgui("wm title .x%x {%s%c%s - %s}\n",
634 x, x->gl_name->s_name, (x->gl_dirty? '*' : ' '), namebuf,
635 canvas_getdir(x)->s_name);
636 #endif
639 void canvas_dirty(t_canvas *x, t_int n)
641 t_canvas *x2 = canvas_getrootfor(x);
642 if ((unsigned)n != x2->gl_dirty)
644 x2->gl_dirty = n;
645 canvas_reflecttitle(x2);
649 /* the window becomes "mapped" (visible and not miniaturized) or
650 "unmapped" (either miniaturized or just plain gone.) This should be
651 called from the GUI after the fact to "notify" us that we're mapped. */
652 void canvas_map(t_canvas *x, t_floatarg f)
654 int flag = (f != 0);
655 t_gobj *y;
656 if (flag)
658 if (!glist_isvisible(x))
660 t_selection *sel;
661 if (!x->gl_havewindow)
663 bug("canvas_map");
664 canvas_vis(x, 1);
666 for (y = x->gl_list; y; y = y->g_next)
667 gobj_vis(y, x, 1);
668 for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
669 gobj_select(sel->sel_what, x, 1);
670 x->gl_mapped = 1;
671 canvas_drawlines(x);
672 /* simulate a mouse up so u_main will calculate scrollbars...
673 ugly! */
674 #ifndef ROCKBOX
675 sys_vgui("pdtk_canvas_mouseup .x%x.c 0 0 0\n", x);
676 #endif
679 else
681 if (glist_isvisible(x))
683 /* just clear out the whole canvas... */
684 #ifndef ROCKBOX
685 sys_vgui(".x%x.c delete all\n", x);
686 #endif
687 /* alternatively, we could have erased them one by one...
688 for (y = x->gl_list; y; y = y->g_next)
689 gobj_vis(y, x, 0);
690 ... but we should go through and erase the lines as well
691 if we do it that way. */
692 x->gl_mapped = 0;
697 void canvas_redraw(t_canvas *x)
699 if (glist_isvisible(x))
701 canvas_map(x, 0);
702 canvas_map(x, 1);
706 /* ---- editors -- perhaps this and "vis" should go to g_editor.c ------- */
708 static t_editor *editor_new(t_glist *owner)
710 char buf[40];
711 t_editor *x = (t_editor *)getbytes(sizeof(*x));
712 x->e_connectbuf = binbuf_new();
713 x->e_deleted = binbuf_new();
714 x->e_glist = owner;
715 #ifdef ROCKBOX
716 snprintf(buf, sizeof(buf), ".x%lx", (unsigned long) (t_int) owner);
717 #else /* ROCKBOX */
718 sprintf(buf, ".x%x", (t_int)owner);
719 #endif /* ROCKBOX */
720 x->e_guiconnect = guiconnect_new(&owner->gl_pd, gensym(buf));
721 return (x);
724 static void editor_free(t_editor *x, t_glist *y)
726 glist_noselect(y);
727 guiconnect_notarget(x->e_guiconnect, 1000);
728 binbuf_free(x->e_connectbuf);
729 binbuf_free(x->e_deleted);
730 freebytes((void *)x, sizeof(*x));
733 /* recursively create or destroy all editors of a glist and its
734 sub-glists, as long as they aren't toplevels. */
735 void canvas_create_editor(t_glist *x, int createit)
737 t_gobj *y;
738 t_object *ob;
739 if (createit)
741 if (x->gl_editor)
742 bug("canvas_create_editor");
743 else
745 x->gl_editor = editor_new(x);
746 for (y = x->gl_list; y; y = y->g_next)
747 if((ob = pd_checkobject(&y->g_pd)))
748 rtext_new(x, ob);
751 else
753 if (!x->gl_editor)
754 bug("canvas_create_editor");
755 else
757 for (y = x->gl_list; y; y = y->g_next)
758 if((ob = pd_checkobject(&y->g_pd)))
759 rtext_free(glist_findrtext(x, ob));
760 editor_free(x->gl_editor, x);
761 x->gl_editor = 0;
764 for (y = x->gl_list; y; y = y->g_next)
765 if (pd_class(&y->g_pd) == canvas_class &&
766 ((t_canvas *)y)->gl_isgraph)
767 canvas_create_editor((t_canvas *)y, createit);
770 /* we call this when we want the window to become visible, mapped, and
771 in front of all windows; or with "f" zero, when we want to get rid of
772 the window. */
773 void canvas_vis(t_canvas *x, t_floatarg f)
775 #ifndef ROCKBOX
776 char buf[30];
777 #endif
778 int flag = (f != 0);
779 if (flag)
781 /* test if we're already visible and toplevel */
782 if (glist_isvisible(x) && !x->gl_isgraph)
783 { /* just put us in front */
784 #ifdef MSW
785 canvas_vis(x, 0);
786 canvas_vis(x, 1);
787 #else
788 #ifndef ROCKBOX
789 sys_vgui("raise .x%x\n", x);
790 sys_vgui("focus .x%x.c\n", x);
791 sys_vgui("wm deiconify .x%x\n", x);
792 #endif /* ROCKBOX */
793 #endif
795 else
797 canvas_create_editor(x, 1);
798 #ifndef ROCKBOX
799 sys_vgui("pdtk_canvas_new .x%x %d %d +%d+%d %d\n", x,
800 (int)(x->gl_screenx2 - x->gl_screenx1),
801 (int)(x->gl_screeny2 - x->gl_screeny1),
802 (int)(x->gl_screenx1), (int)(x->gl_screeny1),
803 x->gl_edit);
804 #endif /* ROCKBOX */
805 canvas_reflecttitle(x);
806 x->gl_havewindow = 1;
807 canvas_updatewindowlist();
810 else /* make invisible */
812 int i;
813 t_canvas *x2;
814 if (!x->gl_havewindow)
816 /* bug workaround -- a graph in a visible patch gets "invised"
817 when the patch is closed, and must lose the editor here. It's
818 probably not the natural place to do this. Other cases like
819 subpatches fall here too but don'd need the editor freed, so
820 we check if it exists. */
821 if (x->gl_editor)
822 canvas_create_editor(x, 0);
823 return;
825 glist_noselect(x);
826 if (glist_isvisible(x))
827 canvas_map(x, 0);
828 canvas_create_editor(x, 0);
829 #ifndef ROCKBOX
830 sys_vgui("destroy .x%x\n", x);
831 #endif
832 for (i = 1, x2 = x; x2; x2 = x2->gl_next, i++)
834 #ifndef ROCKBOX
835 sys_vgui(".mbar.find delete %d\n", i);
836 #endif
837 /* if we're a graph on our parent, and if the parent exists
838 and is visible, show ourselves on parent. */
839 if (glist_isgraph(x) && x->gl_owner)
841 t_glist *gl2 = x->gl_owner;
842 canvas_create_editor(x, 1);
843 if (glist_isvisible(gl2))
844 gobj_vis(&x->gl_gobj, gl2, 0);
845 x->gl_havewindow = 0;
846 if (glist_isvisible(gl2))
847 gobj_vis(&x->gl_gobj, gl2, 1);
849 else x->gl_havewindow = 0;
850 canvas_updatewindowlist();
854 /* we call this on a non-toplevel glist to "open" it into its
855 own window. */
856 void glist_menu_open(t_glist *x)
858 if (glist_isvisible(x) && !glist_istoplevel(x))
860 t_glist *gl2 = x->gl_owner;
861 if (!gl2)
862 bug("canvas_vis"); /* shouldn't happen but don't get too upset. */
863 else
865 /* erase ourself in parent window */
866 gobj_vis(&x->gl_gobj, gl2, 0);
867 /* get rid of our editor (and subeditors) */
868 canvas_create_editor(x, 0);
869 x->gl_havewindow = 1;
870 /* redraw ourself in parent window (blanked out this time) */
871 gobj_vis(&x->gl_gobj, gl2, 1);
874 canvas_vis(x, 1);
877 int glist_isvisible(t_glist *x)
879 return ((!x->gl_loading) && glist_getcanvas(x)->gl_mapped);
882 int glist_istoplevel(t_glist *x)
884 /* we consider a graph "toplevel" if it has its own window
885 or if it appears as a box in its parent window so that we
886 don't draw the actual contents there. */
887 return (x->gl_havewindow || !x->gl_isgraph);
890 int glist_getfont(t_glist *x)
892 return (glist_getcanvas(x)->gl_font);
895 void canvas_free(t_canvas *x)
897 t_gobj *y;
898 int dspstate = canvas_suspend_dsp();
899 canvas_noundo(x);
900 if (canvas_editing == x)
901 canvas_editing = 0;
902 if (canvas_whichfind == x)
903 canvas_whichfind = 0;
904 glist_noselect(x);
905 while((y = x->gl_list))
906 glist_delete(x, y);
907 canvas_vis(x, 0);
909 if (strcmp(x->gl_name->s_name, "Pd"))
910 pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name));
911 if (x->gl_env)
913 freebytes(x->gl_env->ce_argv, x->gl_env->ce_argc * sizeof(t_atom));
914 freebytes(x->gl_env, sizeof(*x->gl_env));
916 canvas_resume_dsp(dspstate);
917 glist_cleanup(x);
918 #ifndef ROCKBOX
919 gfxstub_deleteforkey(x); /* probably unnecessary */
920 #endif
921 if (!x->gl_owner)
922 canvas_takeofflist(x);
925 /* ----------------- lines ---------- */
927 static void canvas_drawlines(t_canvas *x)
929 t_linetraverser t;
930 t_outconnect *oc;
932 linetraverser_start(&t, x);
933 while((oc = linetraverser_next(&t)))
934 #ifdef ROCKBOX
936 #else /* ROCKBOX */
937 sys_vgui(".x%x.c create line %d %d %d %d -width %d -tags l%x\n",
938 glist_getcanvas(x),
939 t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2,
940 (outlet_getsymbol(t.tr_outlet) == &s_signal ? 2:1),
941 oc);
942 #endif /* ROCKBOX */
946 void canvas_fixlinesfor(t_canvas *x, t_text *text)
948 t_linetraverser t;
949 t_outconnect *oc;
951 linetraverser_start(&t, x);
952 while((oc = linetraverser_next(&t)))
954 if (t.tr_ob == text || t.tr_ob2 == text)
956 #ifndef ROCKBOX
957 sys_vgui(".x%x.c coords l%x %d %d %d %d\n",
958 glist_getcanvas(x), oc,
959 t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2);
960 #endif
965 /* kill all lines for the object */
966 void canvas_deletelinesfor(t_canvas *x, t_text *text)
968 t_linetraverser t;
969 t_outconnect *oc;
970 linetraverser_start(&t, x);
971 while((oc = linetraverser_next(&t)))
973 if (t.tr_ob == text || t.tr_ob2 == text)
975 if (x->gl_editor)
977 #ifndef ROCKBOX
978 sys_vgui(".x%x.c delete l%x\n",
979 glist_getcanvas(x), oc);
980 #endif
982 obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
987 /* kill all lines for one inlet or outlet */
988 void canvas_deletelinesforio(t_canvas *x, t_text *text,
989 t_inlet *inp, t_outlet *outp)
991 t_linetraverser t;
992 t_outconnect *oc;
993 linetraverser_start(&t, x);
994 while((oc = linetraverser_next(&t)))
996 if ((t.tr_ob == text && t.tr_outlet == outp) ||
997 (t.tr_ob2 == text && t.tr_inlet == inp))
999 if (x->gl_editor)
1001 #ifndef ROCKBOX
1002 sys_vgui(".x%x.c delete l%x\n",
1003 glist_getcanvas(x), oc);
1004 #endif
1006 obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
1011 static void canvas_pop(t_canvas *x, t_floatarg fvis)
1013 if (fvis != 0)
1014 canvas_vis(x, 1);
1015 pd_popsym(&x->gl_pd);
1016 canvas_resortinlets(x);
1017 canvas_resortoutlets(x);
1018 x->gl_loading = 0;
1021 void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv);
1024 void canvas_restore(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
1025 { /* IOhannes */
1026 t_pd *z;
1027 #ifdef ROCKBOX
1028 (void) s;
1029 #endif
1030 /* this should be unnecessary, but sometimes the canvas's name gets
1031 out of sync with the owning box's argument; this fixes that */
1032 if (argc > 3)
1034 t_atom *ap=argv+3;
1035 if (ap->a_type == A_SYMBOL)
1037 char *buf=ap->a_w.w_symbol->s_name, *bufp;
1038 if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9')
1040 for (bufp = buf+2; *bufp; bufp++)
1041 if (*bufp < '0' || *bufp > '9')
1043 SETDOLLSYM(ap, gensym(buf+1));
1044 goto didit;
1046 SETDOLLAR(ap, atoi(buf+1));
1047 didit: ;
1051 if (ap->a_type == A_DOLLSYM)
1053 t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
1054 canvas_rename(x, binbuf_realizedollsym(ap->a_w.w_symbol,
1055 e->ce_argc, e->ce_argv, 1), 0);
1057 else if (ap->a_type == A_SYMBOL)
1058 canvas_rename(x, argv[3].a_w.w_symbol, 0);
1060 canvas_pop(x, x->gl_willvis);
1062 if (!(z = gensym("#X")->s_thing)) error("canvas_restore: out of context");
1063 else if (*z != canvas_class) error("canvas_restore: wasn't a canvas");
1064 else
1066 t_canvas *x2 = (t_canvas *)z;
1067 x->gl_owner = x2;
1068 canvas_objfor(x2, &x->gl_obj, argc, argv);
1072 static void canvas_loadbangabstractions(t_canvas *x)
1074 t_gobj *y;
1075 #ifdef ROCKBOX
1076 gensym("loadbang");
1077 #else
1078 t_symbol *s = gensym("loadbang");
1079 #endif
1080 for (y = x->gl_list; y; y = y->g_next)
1081 if (pd_class(&y->g_pd) == canvas_class)
1083 if (canvas_isabstraction((t_canvas *)y))
1084 canvas_loadbang((t_canvas *)y);
1085 else
1086 canvas_loadbangabstractions((t_canvas *)y);
1090 void canvas_loadbangsubpatches(t_canvas *x)
1092 t_gobj *y;
1093 t_symbol *s = gensym("loadbang");
1094 for (y = x->gl_list; y; y = y->g_next)
1095 if (pd_class(&y->g_pd) == canvas_class)
1097 if (!canvas_isabstraction((t_canvas *)y))
1098 canvas_loadbangsubpatches((t_canvas *)y);
1100 for (y = x->gl_list; y; y = y->g_next)
1101 if ((pd_class(&y->g_pd) != canvas_class) &&
1102 zgetfn(&y->g_pd, s))
1103 pd_vmess(&y->g_pd, s, "");
1106 void canvas_loadbang(t_canvas *x)
1108 #ifndef ROCKBOX
1109 t_gobj *y;
1110 #endif
1111 canvas_loadbangabstractions(x);
1112 canvas_loadbangsubpatches(x);
1115 /* When you ask a canvas its size the result is 2 pixels more than what
1116 you gave it to open it; perhaps there's a 1-pixel border all around it
1117 or something. Anyway, we just add the 2 pixels back here; seems we
1118 have to do this for linux but not MSW; not sure about MacOS.\x11 */
1120 #ifdef MSW
1121 #define HORIZBORDER 0
1122 #define VERTBORDER 0
1123 #else
1124 #define HORIZBORDER 2
1125 #define VERTBORDER 2
1126 #endif
1128 static void canvas_relocate(t_canvas *x, t_symbol *canvasgeom,
1129 t_symbol *topgeom)
1131 #ifdef ROCKBOX
1132 (void) x;
1133 (void) canvasgeom;
1134 (void) topgeom;
1135 #else /* ROCKBOX */
1136 int cxpix, cypix, cw, ch, txpix, typix, tw, th;
1137 if (sscanf(canvasgeom->s_name, "%dx%d+%d+%d", &cw, &ch, &cxpix, &cypix)
1138 < 4 ||
1139 sscanf(topgeom->s_name, "%dx%d+%d+%d", &tw, &th, &txpix, &typix) < 4)
1140 bug("canvas_relocate");
1141 /* for some reason this is initially called with cw=ch=1 so
1142 we just suppress that here. */
1143 if (cw > 5 && ch > 5)
1144 canvas_setbounds(x, txpix, typix,
1145 txpix + cw - HORIZBORDER, typix + ch - VERTBORDER);
1146 #endif /* ROCKBOX */
1149 void canvas_popabstraction(t_canvas *x)
1151 newest = &x->gl_pd;
1152 pd_popsym(&x->gl_pd);
1153 x->gl_loading = 0;
1154 canvas_resortinlets(x);
1155 canvas_resortoutlets(x);
1158 void canvas_logerror(t_object *y)
1160 #ifdef ROCKBOX
1161 (void) y;
1162 #endif
1163 #ifdef LATER
1164 canvas_vis(x, 1);
1165 if (!glist_isselected(x, &y->ob_g))
1166 glist_select(x, &y->ob_g);
1167 #endif
1170 /* -------------------------- subcanvases ---------------------- */
1172 static void *subcanvas_new(t_symbol *s)
1174 t_atom a[6];
1175 t_canvas *x, *z = canvas_getcurrent();
1176 if (!*s->s_name) s = gensym("/SUBPATCH/");
1177 SETFLOAT(a, 0);
1178 SETFLOAT(a+1, GLIST_DEFCANVASYLOC);
1179 SETFLOAT(a+2, GLIST_DEFCANVASWIDTH);
1180 SETFLOAT(a+3, GLIST_DEFCANVASHEIGHT);
1181 SETSYMBOL(a+4, s);
1182 SETFLOAT(a+5, 1);
1183 x = canvas_new(0, 0, 6, a);
1184 x->gl_owner = z;
1185 canvas_pop(x, 1);
1186 return (x);
1189 static void canvas_click(t_canvas *x,
1190 t_floatarg xpos, t_floatarg ypos,
1191 t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
1193 #ifdef ROCKBOX
1194 (void) xpos;
1195 (void) ypos;
1196 (void) shift;
1197 (void) ctrl;
1198 (void) alt;
1199 #endif
1200 canvas_vis(x, 1);
1204 /* find out from subcanvas contents how much to fatten the box */
1205 void canvas_fattensub(t_canvas *x,
1206 int *xp1, int *yp1, int *xp2, int *yp2)
1208 #ifdef ROCKBOX
1209 (void) x;
1210 (void) xp1;
1211 (void) yp1;
1212 #else /* ROCKBOX */
1213 t_gobj *y;
1214 #endif /* ROCKBOX */
1215 *xp2 += 50; /* fake for now */
1216 *yp2 += 50;
1219 static void canvas_rename_method(t_canvas *x, t_symbol *s, int ac, t_atom *av)
1221 #ifdef ROCKBOX
1222 (void) s;
1223 #endif
1224 if (ac && av->a_type == A_SYMBOL)
1225 canvas_rename(x, av->a_w.w_symbol, 0);
1226 else canvas_rename(x, gensym("Pd"), 0);
1229 /* ------------------ table ---------------------------*/
1231 static int tabcount = 0;
1233 static void *table_new(t_symbol *s, t_floatarg f)
1235 t_atom a[9];
1236 t_glist *gl;
1237 t_canvas *x, *z = canvas_getcurrent();
1238 if (s == &s_)
1240 char tabname[255];
1241 t_symbol *t = gensym("table");
1242 #ifdef ROCKBOX
1243 snprintf(tabname, sizeof(tabname), "%s%d", t->s_name, tabcount++);
1244 #else /* ROCKBOX */
1245 sprintf(tabname, "%s%d", t->s_name, tabcount++);
1246 #endif /* ROCKBOX */
1247 s = gensym(tabname);
1249 if (f <= 1)
1250 f = 100;
1251 SETFLOAT(a, 0);
1252 SETFLOAT(a+1, GLIST_DEFCANVASYLOC);
1253 SETFLOAT(a+2, 600);
1254 SETFLOAT(a+3, 400);
1255 SETSYMBOL(a+4, s);
1256 SETFLOAT(a+5, 0);
1257 x = canvas_new(0, 0, 6, a);
1259 x->gl_owner = z;
1261 /* create a graph for the table */
1262 gl = glist_addglist((t_glist*)x, &s_, 0, -1, (f > 1 ? f-1 : 1), 1,
1263 50, 350, 550, 50);
1265 graph_array(gl, s, &s_float, f, 0);
1267 canvas_pop(x, 0);
1269 return (x);
1272 /* return true if the "canvas" object is an abstraction (so we don't
1273 save its contents, fogr example.) */
1274 int canvas_isabstraction(t_canvas *x)
1276 return (x->gl_env != 0);
1279 /* return true if the "canvas" object is a "table". */
1280 int canvas_istable(t_canvas *x)
1282 t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0);
1283 int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0);
1284 int istable = (argc && argv[0].a_type == A_SYMBOL &&
1285 argv[0].a_w.w_symbol == gensym("table"));
1286 return (istable);
1289 /* return true if the "canvas" object should be treated as a text
1290 object. This is true for abstractions but also for "table"s... */
1291 int canvas_showtext(t_canvas *x)
1293 t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0);
1294 int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0);
1295 int isarray = (argc && argv[0].a_type == A_SYMBOL &&
1296 argv[0].a_w.w_symbol == gensym("graph"));
1297 return (!isarray);
1300 static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp);
1301 static void canvas_dsp(t_canvas *x, t_signal **sp)
1303 canvas_dodsp(x, 0, sp);
1306 /* get the document containing this canvas */
1307 t_canvas *canvas_getrootfor(t_canvas *x)
1309 if ((!x->gl_owner) || canvas_isabstraction(x))
1310 return (x);
1311 else return (canvas_getrootfor(x->gl_owner));
1314 /* ------------------------- DSP chain handling ------------------------- */
1316 EXTERN_STRUCT _dspcontext;
1317 #define t_dspcontext struct _dspcontext
1319 void ugen_start(void);
1320 void ugen_stop(void);
1322 t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp,
1323 int ninlets, int noutlets);
1324 void ugen_add(t_dspcontext *dc, t_object *x);
1325 void ugen_connect(t_dspcontext *dc, t_object *x1, int outno,
1326 t_object *x2, int inno);
1327 void ugen_done_graph(t_dspcontext *dc);
1329 /* schedule one canvas for DSP. This is called below for all "root"
1330 canvases, but is also called from the "dsp" method for sub-
1331 canvases, which are treated almost like any other tilde object. */
1333 static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp)
1335 t_linetraverser t;
1336 t_outconnect *oc;
1337 t_gobj *y;
1338 t_object *ob;
1339 t_symbol *dspsym = gensym("dsp");
1340 t_dspcontext *dc;
1342 /* create a new "DSP graph" object to use in sorting this canvas.
1343 If we aren't toplevel, there are already other dspcontexts around. */
1345 dc = ugen_start_graph(toplevel, sp,
1346 obj_nsiginlets(&x->gl_obj),
1347 obj_nsigoutlets(&x->gl_obj));
1349 /* find all the "dsp" boxes and add them to the graph */
1351 for (y = x->gl_list; y; y = y->g_next)
1352 if ((ob = pd_checkobject(&y->g_pd)) && zgetfn(&y->g_pd, dspsym))
1353 ugen_add(dc, ob);
1355 /* ... and all dsp interconnections */
1356 linetraverser_start(&t, x);
1357 while((oc = linetraverser_next(&t)))
1358 if (obj_issignaloutlet(t.tr_ob, t.tr_outno))
1359 ugen_connect(dc, t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
1361 /* finally, sort them and add them to the DSP chain */
1362 ugen_done_graph(dc);
1365 /* this routine starts DSP for all root canvases. */
1366 static void canvas_start_dsp(void)
1368 t_canvas *x;
1369 if (canvas_dspstate) ugen_stop();
1370 #ifndef ROCKBOX
1371 else sys_gui("pdtk_pd_dsp ON\n");
1372 #endif
1373 ugen_start();
1375 for (x = canvas_list; x; x = x->gl_next)
1376 canvas_dodsp(x, 1, 0);
1378 canvas_dspstate = 1;
1381 static void canvas_stop_dsp(void)
1383 if (canvas_dspstate)
1385 ugen_stop();
1386 #ifndef ROCKBOX
1387 sys_gui("pdtk_pd_dsp OFF\n");
1388 #endif
1389 canvas_dspstate = 0;
1393 /* DSP can be suspended before, and resumed after, operations which
1394 might affect the DSP chain. For example, we suspend before loading and
1395 resume afterward, so that DSP doesn't get resorted for every DSP object
1396 int the patch. */
1398 int canvas_suspend_dsp(void)
1400 int rval = canvas_dspstate;
1401 if (rval) canvas_stop_dsp();
1402 return (rval);
1405 void canvas_resume_dsp(int oldstate)
1407 if (oldstate) canvas_start_dsp();
1410 /* this is equivalent to suspending and resuming in one step. */
1411 void canvas_update_dsp(void)
1413 if (canvas_dspstate) canvas_start_dsp();
1416 void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv)
1418 int newstate;
1419 #ifdef ROCKBOX
1420 (void) dummy;
1421 (void) s;
1422 #endif
1423 if (argc)
1425 newstate = atom_getintarg(0, argc, argv);
1426 if (newstate && !canvas_dspstate)
1428 sys_set_audio_state(1);
1429 canvas_start_dsp();
1431 else if (!newstate && canvas_dspstate)
1433 canvas_stop_dsp();
1434 sys_set_audio_state(0);
1437 else post("dsp state %d", canvas_dspstate);
1440 /* LATER replace this with a queueing scheme */
1441 void glist_redrawitem(t_glist *owner, t_gobj *gobj)
1443 if (glist_isvisible(owner))
1445 gobj_vis(gobj, owner, 0);
1446 gobj_vis(gobj, owner, 1);
1450 /* redraw all "scalars" (do this if a drawing command is changed.)
1451 LATER we'll use the "template" information to select which ones we
1452 redraw. */
1453 static void glist_redrawall(t_glist *gl)
1455 t_gobj *g;
1456 int vis = glist_isvisible(gl);
1457 for (g = gl->gl_list; g; g = g->g_next)
1459 #ifndef ROCKBOX
1460 t_class *cl;
1461 #endif
1462 if (vis && g->g_pd == scalar_class)
1463 glist_redrawitem(gl, g);
1464 else if (g->g_pd == canvas_class)
1465 glist_redrawall((t_glist *)g);
1469 /* public interface for above */
1470 void canvas_redrawallfortemplate(t_canvas *templatecanvas)
1472 t_canvas *x;
1473 #ifdef ROCKBOX
1474 (void) templatecanvas;
1475 #endif
1476 /* find all root canvases */
1477 for (x = canvas_list; x; x = x->gl_next)
1478 glist_redrawall(x);
1481 /* ------------------------------- setup routine ------------------------ */
1483 /* why are some of these "glist" and others "canvas"? */
1484 extern void glist_text(t_glist *x, t_symbol *s, int argc, t_atom *argv);
1485 extern void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1486 extern void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1487 extern void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1488 extern void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1489 extern void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1490 extern void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1491 /* old version... */
1492 extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1493 extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1494 /* new version: */
1495 extern void canvas_hradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1496 extern void canvas_vradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1497 extern void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1498 extern void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1499 extern void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1500 extern void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1501 extern void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1502 extern void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1503 extern void glist_scalar(t_glist *canvas, t_symbol *s, int argc, t_atom *argv);
1505 void g_graph_setup(void);
1506 void g_editor_setup(void);
1507 void g_readwrite_setup(void);
1508 extern void graph_properties(t_gobj *z, t_glist *owner);
1510 void g_canvas_setup(void)
1512 /* we prevent the user from typing "canvas" in an object box
1513 by sending 0 for a creator function. */
1514 canvas_class = class_new(gensym("canvas"), 0,
1515 (t_method)canvas_free, sizeof(t_canvas), CLASS_NOINLET, 0);
1516 /* here is the real creator function, invoked in patch files
1517 by sending the "canvas" message to #N, which is bound
1518 to pd_camvasmaker. */
1519 class_addmethod(pd_canvasmaker, (t_method)canvas_new, gensym("canvas"),
1520 A_GIMME, 0);
1521 class_addmethod(canvas_class, (t_method)canvas_restore,
1522 gensym("restore"), A_GIMME, 0);
1523 class_addmethod(canvas_class, (t_method)canvas_coords,
1524 gensym("coords"), A_GIMME, 0);
1526 /* -------------------------- objects ----------------------------- */
1527 class_addmethod(canvas_class, (t_method)canvas_obj,
1528 gensym("obj"), A_GIMME, A_NULL);
1529 class_addmethod(canvas_class, (t_method)canvas_msg,
1530 gensym("msg"), A_GIMME, A_NULL);
1531 class_addmethod(canvas_class, (t_method)canvas_floatatom,
1532 gensym("floatatom"), A_GIMME, A_NULL);
1533 class_addmethod(canvas_class, (t_method)canvas_symbolatom,
1534 gensym("symbolatom"), A_GIMME, A_NULL);
1535 class_addmethod(canvas_class, (t_method)glist_text,
1536 gensym("text"), A_GIMME, A_NULL);
1537 class_addmethod(canvas_class, (t_method)glist_glist, gensym("graph"),
1538 A_GIMME, A_NULL);
1539 class_addmethod(canvas_class, (t_method)glist_scalar,
1540 gensym("scalar"), A_GIMME, A_NULL);
1542 /* -------------- Thomas Musil's GUI objects ------------ */
1543 class_addmethod(canvas_class, (t_method)canvas_bng, gensym("bng"),
1544 A_GIMME, A_NULL);
1545 class_addmethod(canvas_class, (t_method)canvas_toggle, gensym("toggle"),
1546 A_GIMME, A_NULL);
1547 class_addmethod(canvas_class, (t_method)canvas_vslider, gensym("vslider"),
1548 A_GIMME, A_NULL);
1549 class_addmethod(canvas_class, (t_method)canvas_hslider, gensym("hslider"),
1550 A_GIMME, A_NULL);
1551 class_addmethod(canvas_class, (t_method)canvas_hdial, gensym("hdial"),
1552 A_GIMME, A_NULL);
1553 class_addmethod(canvas_class, (t_method)canvas_vdial, gensym("vdial"),
1554 A_GIMME, A_NULL);
1555 class_addmethod(canvas_class, (t_method)canvas_hradio, gensym("hradio"),
1556 A_GIMME, A_NULL);
1557 class_addmethod(canvas_class, (t_method)canvas_vradio, gensym("vradio"),
1558 A_GIMME, A_NULL);
1559 class_addmethod(canvas_class, (t_method)canvas_vumeter, gensym("vumeter"),
1560 A_GIMME, A_NULL);
1561 class_addmethod(canvas_class, (t_method)canvas_mycnv, gensym("mycnv"),
1562 A_GIMME, A_NULL);
1563 class_addmethod(canvas_class, (t_method)canvas_numbox, gensym("numbox"),
1564 A_GIMME, A_NULL);
1566 /* ------------------------ gui stuff --------------------------- */
1567 class_addmethod(canvas_class, (t_method)canvas_pop, gensym("pop"),
1568 A_DEFFLOAT, A_NULL);
1569 class_addmethod(canvas_class, (t_method)canvas_loadbang,
1570 gensym("loadbang"), A_NULL);
1571 class_addmethod(canvas_class, (t_method)canvas_relocate,
1572 gensym("relocate"), A_SYMBOL, A_SYMBOL, A_NULL);
1573 class_addmethod(canvas_class, (t_method)canvas_vis,
1574 gensym("vis"), A_FLOAT, A_NULL);
1575 class_addmethod(canvas_class, (t_method)glist_menu_open,
1576 gensym("menu-open"), A_NULL);
1577 class_addmethod(canvas_class, (t_method)canvas_map,
1578 gensym("map"), A_FLOAT, A_NULL);
1579 class_setpropertiesfn(canvas_class, graph_properties);
1581 /* ---------------------- list handling ------------------------ */
1582 class_addmethod(canvas_class, (t_method)glist_clear, gensym("clear"),
1583 A_NULL);
1585 /* ----- subcanvases, which you get by typing "pd" in a box ---- */
1586 class_addcreator((t_newmethod)subcanvas_new, gensym("pd"), A_DEFSYMBOL, 0);
1587 class_addcreator((t_newmethod)subcanvas_new, gensym("page"), A_DEFSYMBOL, 0);
1589 class_addmethod(canvas_class, (t_method)canvas_click,
1590 gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1591 class_addmethod(canvas_class, (t_method)canvas_dsp, gensym("dsp"), 0);
1592 class_addmethod(canvas_class, (t_method)canvas_rename_method,
1593 gensym("rename"), A_GIMME, 0);
1595 /*---------------------------- tables -- GG ------------------- */
1597 class_addcreator((t_newmethod)table_new, gensym("table"),
1598 A_DEFSYM, A_DEFFLOAT, 0);
1600 /* -------------- setups from other files for canvas_class ---------------- */
1601 g_graph_setup();
1602 g_editor_setup();
1603 g_readwrite_setup();