summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/src/g_canvas.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/g_canvas.c')
-rw-r--r--apps/plugins/pdbox/PDa/src/g_canvas.c1475
1 files changed, 0 insertions, 1475 deletions
diff --git a/apps/plugins/pdbox/PDa/src/g_canvas.c b/apps/plugins/pdbox/PDa/src/g_canvas.c
index f4ef8b14aa..f8b8dda0cf 100644
--- a/apps/plugins/pdbox/PDa/src/g_canvas.c
+++ b/apps/plugins/pdbox/PDa/src/g_canvas.c
@@ -1474,1479 +1474,4 @@ void g_canvas_setup(void)
1474 g_editor_setup(); 1474 g_editor_setup();
1475 g_readwrite_setup(); 1475 g_readwrite_setup();
1476} 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
1482to 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
1506struct _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
1525extern t_pd *newest;
1526t_class *canvas_class;
1527static int canvas_dspstate; /* whether DSP is on or off */
1528t_canvas *canvas_editing; /* last canvas to start text edting */
1529t_canvas *canvas_whichfind; /* last canvas we did a find in */
1530t_canvas *canvas_list; /* list of all root canvases */
1531
1532/* ------------------ forward function declarations --------------- */
1533static void canvas_start_dsp(void);
1534static void canvas_stop_dsp(void);
1535static void canvas_drawlines(t_canvas *x);
1536static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2);
1537static void canvas_reflecttitle(t_canvas *x);
1538static void canvas_addtolist(t_canvas *x);
1539static void canvas_takeofflist(t_canvas *x);
1540static void canvas_pop(t_canvas *x, t_floatarg fvis);
1541void canvas_create_editor(t_glist *x, int createit);
1542
1543/* --------- functions to handle the canvas environment ----------- */
1544
1545static t_symbol *canvas_newfilename = &s_;
1546static t_symbol *canvas_newdirectory = &s_;
1547static int canvas_newargc;
1548static t_atom *canvas_newargv;
1549
1550static 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 */
1576void 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.) */
1590static void canvas_addtolist(t_canvas *x)
1591{
1592 x->gl_next = canvas_list;
1593 canvas_list = x;
1594}
1595
1596static 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
1610void 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
1621void glob_setfilename(void *dummy, t_symbol *filesym, t_symbol *dirsym)
1622{
1623 canvas_newfilename = filesym;
1624 canvas_newdirectory = dirsym;
1625}
1626
1627t_canvas *canvas_getcurrent(void)
1628{
1629 return ((t_canvas *)pd_findbyclass(&s__X, canvas_class));
1630}
1631
1632void canvas_setcurrent(t_canvas *x)
1633{
1634 pd_pushsym(&x->gl_pd);
1635}
1636
1637void canvas_unsetcurrent(t_canvas *x)
1638{
1639 pd_popsym(&x->gl_pd);
1640}
1641
1642t_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
1651int 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
1660void 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
1667t_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
1683t_symbol *canvas_getcurrentdir(void)
1684{
1685 t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
1686 return (e->ce_dir);
1687}
1688
1689t_symbol *canvas_getdir(t_canvas *x)
1690{
1691 t_canvasenvironment *e = canvas_getenv(x);
1692 return (e->ce_dir);
1693}
1694
1695void 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
1716void 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
1734int 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
1743void 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
1751t_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
1807void linetraverser_skipobject(t_linetraverser *t)
1808{
1809 t->tr_nextoc = 0;
1810 t->tr_nextoutno = t->tr_nout;
1811}
1812
1813/* -------------------- the canvas object -------------------------- */
1814int glist_valid = 10000;
1815
1816void 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. */
1829t_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 1477
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
1899void canvas_setgraph(t_glist *x, int flag);
1900
1901static 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. */
1914t_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 */
1984void 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. */
2000int 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. */
2007static 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
2035t_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
2043void 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
2068void 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. */
2081void 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
2122void 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
2133static 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
2145static 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. */
2156void 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. */
2194void 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. */
2267void 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
2288int glist_isvisible(t_glist *x)
2289{
2290 return ((!x->gl_loading) && glist_getcanvas(x)->gl_mapped);
2291}
2292
2293int 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
2301int glist_getfont(t_glist *x)
2302{
2303 return (glist_getcanvas(x)->gl_font);
2304}
2305
2306void 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
2336static 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
2351void 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 */
2369void 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 */
2389void 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
2410static 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
2420void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv);
2421
2422
2423void 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
2468static 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
2482void 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
2498void 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
2518static 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
2533void 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
2542void 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
2553static 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
2570static 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 */
2579void 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
2587static 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
2596static int tabcount = 0;
2597
2598static 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.) */
2635int canvas_isabstraction(t_canvas *x)
2636{
2637 return (x->gl_env != 0);
2638}
2639
2640 /* return true if the "canvas" object is a "table". */
2641int 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... */
2652int 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
2661static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp);
2662static 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 */
2668t_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
2677EXTERN_STRUCT _dspcontext;
2678#define t_dspcontext struct _dspcontext
2679
2680void ugen_start(void);
2681void ugen_stop(void);
2682
2683t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp,
2684 int ninlets, int noutlets);
2685void ugen_add(t_dspcontext *dc, t_object *x);
2686void ugen_connect(t_dspcontext *dc, t_object *x1, int outno,
2687 t_object *x2, int inno);
2688void 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
2694static 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. */
2727static 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
2740static 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
2755int canvas_suspend_dsp(void)
2756{
2757 int rval = canvas_dspstate;
2758 if (rval) canvas_stop_dsp();
2759 return (rval);
2760}
2761
2762void 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. */
2768void canvas_update_dsp(void)
2769{
2770 if (canvas_dspstate) canvas_start_dsp();
2771}
2772
2773void 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 */
2794void 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. */
2806static 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 */
2821void 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"? */
2832extern void glist_text(t_glist *x, t_symbol *s, int argc, t_atom *argv);
2833extern void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2834extern void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2835extern void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2836extern void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2837extern void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2838extern void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2839 /* old version... */
2840extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2841extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2842 /* new version: */
2843extern void canvas_hradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2844extern void canvas_vradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2845extern void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2846extern void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2847extern void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2848extern void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2849extern void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2850extern void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2851extern void glist_scalar(t_glist *canvas, t_symbol *s, int argc, t_atom *argv);
2852
2853void g_graph_setup(void);
2854void g_editor_setup(void);
2855void g_readwrite_setup(void);
2856extern void graph_properties(t_gobj *z, t_glist *owner);
2857
2858void 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}