summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/src/g_template.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/g_template.c')
-rw-r--r--apps/plugins/pdbox/PDa/src/g_template.c1678
1 files changed, 0 insertions, 1678 deletions
diff --git a/apps/plugins/pdbox/PDa/src/g_template.c b/apps/plugins/pdbox/PDa/src/g_template.c
index c65613a0d6..9e62c0f1d2 100644
--- a/apps/plugins/pdbox/PDa/src/g_template.c
+++ b/apps/plugins/pdbox/PDa/src/g_template.c
@@ -1677,1682 +1677,4 @@ void g_template_setup(void)
1677 drawnumber_setup(); 1677 drawnumber_setup();
1678} 1678}
1679 1679
1680/* Copyright (c) 1997-1999 Miller Puckette.
1681* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1682* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1683
1684#include <stdlib.h>
1685#include <string.h>
1686#include <stdio.h>
1687
1688#include "m_pd.h"
1689#include "s_stuff.h" /* for sys_hostfontsize */
1690#include "g_canvas.h"
1691
1692/*
1693This file contains text objects you would put in a canvas to define a
1694template. Templates describe objects of type "array" (g_array.c) and
1695"scalar" (g_scalar.c).
1696*/
1697
1698/* T.Grill - changed the _template.t_pd member to t_pdobj to avoid name clashes
1699with the t_pd type */
1700
1701 /* the structure of a "struct" object (also the obsolete "gtemplate"
1702 you get when using the name "template" in a box.) */
1703
1704struct _gtemplate
1705{
1706 t_object x_obj;
1707 t_template *x_template;
1708 t_canvas *x_owner;
1709 t_symbol *x_sym;
1710 struct _gtemplate *x_next;
1711 int x_argc;
1712 t_atom *x_argv;
1713};
1714
1715/* ---------------- forward definitions ---------------- */
1716
1717static void template_conformarray(t_template *tfrom, t_template *tto,
1718 int *conformaction, t_array *a);
1719static void template_conformglist(t_template *tfrom, t_template *tto,
1720 t_glist *glist, int *conformaction);
1721
1722/* ---------------------- storage ------------------------- */
1723
1724static t_class *gtemplate_class;
1725static t_class *template_class;
1726
1727/* there's a pre-defined "float" template. LATER should we bind this
1728to a symbol such as "pd-float"??? */
1729
1730static t_dataslot template_float_vec =
1731{
1732 DT_FLOAT,
1733 &s_y,
1734 &s_
1735};
1736
1737static t_template template_float =
1738{
1739 0, /* class -- fill in in setup routine */
1740 0, /* list of "struct"/t_gtemplate objects */
1741 &s_float, /* name */
1742 1, /* number of items */
1743 &template_float_vec
1744};
1745
1746 /* return true if two dataslot definitions match */
1747static int dataslot_matches(t_dataslot *ds1, t_dataslot *ds2,
1748 int nametoo)
1749{
1750 return ((!nametoo || ds1->ds_name == ds2->ds_name) &&
1751 ds1->ds_type == ds2->ds_type &&
1752 (ds1->ds_type != DT_ARRAY ||
1753 ds1->ds_arraytemplate == ds2->ds_arraytemplate));
1754}
1755
1756/* -- templates, the active ingredient in gtemplates defined below. ------- */
1757
1758t_template *template_new(t_symbol *templatesym, int argc, t_atom *argv)
1759{
1760 t_template *x = (t_template *)pd_new(template_class);
1761 x->t_n = 0;
1762 x->t_vec = (t_dataslot *)t_getbytes(0);
1763 while (argc > 0)
1764 {
1765 int newtype, oldn, newn;
1766 t_symbol *newname, *newarraytemplate = &s_, *newtypesym;
1767 if (argc < 2 || argv[0].a_type != A_SYMBOL ||
1768 argv[1].a_type != A_SYMBOL)
1769 goto bad;
1770 newtypesym = argv[0].a_w.w_symbol;
1771 newname = argv[1].a_w.w_symbol;
1772 if (newtypesym == &s_float)
1773 newtype = DT_FLOAT;
1774 else if (newtypesym == &s_symbol)
1775 newtype = DT_SYMBOL;
1776 else if (newtypesym == &s_list)
1777 newtype = DT_LIST;
1778 else if (newtypesym == gensym("array"))
1779 {
1780 if (argc < 3 || argv[2].a_type != A_SYMBOL)
1781 {
1782 pd_error(x, "array lacks element template or name");
1783 goto bad;
1784 }
1785 newarraytemplate = canvas_makebindsym(argv[2].a_w.w_symbol);
1786 newtype = DT_ARRAY;
1787 argc--;
1788 argv++;
1789 }
1790 else
1791 {
1792 pd_error(x, "%s: no such type", newtypesym->s_name);
1793 return (0);
1794 }
1795 newn = (oldn = x->t_n) + 1;
1796 x->t_vec = (t_dataslot *)t_resizebytes(x->t_vec,
1797 oldn * sizeof(*x->t_vec), newn * sizeof(*x->t_vec));
1798 x->t_n = newn;
1799 x->t_vec[oldn].ds_type = newtype;
1800 x->t_vec[oldn].ds_name = newname;
1801 x->t_vec[oldn].ds_arraytemplate = newarraytemplate;
1802 bad:
1803 argc -= 2; argv += 2;
1804 }
1805 if (templatesym->s_name)
1806 {
1807 x->t_sym = templatesym;
1808 pd_bind(&x->t_pdobj, x->t_sym);
1809 }
1810 else x->t_sym = templatesym;
1811 return (x);
1812}
1813
1814int template_size(t_template *x)
1815{
1816 return (x->t_n * sizeof(t_word));
1817}
1818
1819int template_find_field(t_template *x, t_symbol *name, int *p_onset,
1820 int *p_type, t_symbol **p_arraytype)
1821{
1822 t_template *t;
1823 int i, n;
1824 if (!x)
1825 {
1826 bug("template_find_field");
1827 return (0);
1828 }
1829 n = x->t_n;
1830 for (i = 0; i < n; i++)
1831 if (x->t_vec[i].ds_name == name)
1832 {
1833 *p_onset = i * sizeof(t_word);
1834 *p_type = x->t_vec[i].ds_type;
1835 *p_arraytype = x->t_vec[i].ds_arraytemplate;
1836 return (1);
1837 }
1838 return (0);
1839}
1840
1841t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp,
1842 int loud)
1843{
1844 int onset, type;
1845 t_symbol *arraytype;
1846 t_sample val = 0;
1847 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
1848 {
1849 if (type == DT_FLOAT)
1850 val = *(t_sample *)(((char *)wp) + onset);
1851 else if (loud) error("%s.%s: not a number",
1852 x->t_sym->s_name, fieldname->s_name);
1853 }
1854 else if (loud) error("%s.%s: no such field",
1855 x->t_sym->s_name, fieldname->s_name);
1856 return (fixtof(val));
1857}
1858
1859void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp,
1860 t_float f, int loud)
1861{
1862 int onset, type;
1863 t_symbol *arraytype;
1864 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
1865 {
1866 if (type == DT_FLOAT)
1867 *(t_sample *)(((char *)wp) + onset) = ftofix(f);
1868 else if (loud) error("%s.%s: not a number",
1869 x->t_sym->s_name, fieldname->s_name);
1870 }
1871 else if (loud) error("%s.%s: no such field",
1872 x->t_sym->s_name, fieldname->s_name);
1873}
1874
1875t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp,
1876 int loud)
1877{
1878 int onset, type;
1879 t_symbol *arraytype;
1880 t_symbol *val = &s_;
1881 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
1882 {
1883 if (type == DT_SYMBOL)
1884 val = *(t_symbol **)(((char *)wp) + onset);
1885 else if (loud) error("%s.%s: not a symbol",
1886 x->t_sym->s_name, fieldname->s_name);
1887 }
1888 else if (loud) error("%s.%s: no such field",
1889 x->t_sym->s_name, fieldname->s_name);
1890 return (val);
1891}
1892
1893void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp,
1894 t_symbol *s, int loud)
1895{
1896 int onset, type;
1897 t_symbol *arraytype;
1898 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
1899 {
1900 if (type == DT_SYMBOL)
1901 *(t_symbol **)(((char *)wp) + onset) = s;
1902 else if (loud) error("%s.%s: not a symbol",
1903 x->t_sym->s_name, fieldname->s_name);
1904 }
1905 else if (loud) error("%s.%s: no such field",
1906 x->t_sym->s_name, fieldname->s_name);
1907}
1908
1909 /* stringent check to see if a "saved" template, x2, matches the current
1910 one (x1). It's OK if x1 has additional scalar elements but not (yet)
1911 arrays or lists. This is used for reading in "data files". */
1912int template_match(t_template *x1, t_template *x2)
1913{
1914 int i;
1915 if (x1->t_n < x2->t_n)
1916 return (0);
1917 for (i = x2->t_n; i < x1->t_n; i++)
1918 {
1919 if (x1->t_vec[i].ds_type == DT_ARRAY ||
1920 x1->t_vec[i].ds_type == DT_LIST)
1921 return (0);
1922 }
1923 if (x2->t_n > x1->t_n)
1924 post("add elements...");
1925 for (i = 0; i < x2->t_n; i++)
1926 if (!dataslot_matches(&x1->t_vec[i], &x2->t_vec[i], 1))
1927 return (0);
1928 return (1);
1929}
1930
1931/* --------------- CONFORMING TO CHANGES IN A TEMPLATE ------------ */
1932
1933/* the following routines handle updating scalars to agree with changes
1934in their template. The old template is assumed to be the "installed" one
1935so we can delete old items; but making new ones we have to avoid scalar_new
1936which would make an old one whereas we will want a new one (but whose array
1937elements might still be old ones.
1938 LATER deal with graphics updates too... */
1939
1940 /* conform the word vector of a scalar to the new template */
1941static void template_conformwords(t_template *tfrom, t_template *tto,
1942 int *conformaction, t_word *wfrom, t_word *wto)
1943{
1944 int nfrom = tfrom->t_n, nto = tto->t_n, i;
1945 for (i = 0; i < nto; i++)
1946 {
1947 if (conformaction[i] >= 0)
1948 {
1949 /* we swap the two, in case it's an array or list, so that
1950 when "wfrom" is deleted the old one gets cleaned up. */
1951 t_word wwas = wto[i];
1952 wto[i] = wfrom[conformaction[i]];
1953 wfrom[conformaction[i]] = wwas;
1954 }
1955 }
1956}
1957
1958 /* conform a scalar, recursively conforming sublists and arrays */
1959static t_scalar *template_conformscalar(t_template *tfrom, t_template *tto,
1960 int *conformaction, t_glist *glist, t_scalar *scfrom)
1961{
1962 t_scalar *x;
1963 t_gpointer gp;
1964 int nto = tto->t_n, nfrom = tfrom->t_n, i;
1965 t_template *scalartemplate;
1966 /* post("conform scalar"); */
1967 /* possibly replace the scalar */
1968 if (scfrom->sc_template == tfrom->t_sym)
1969 {
1970 /* see scalar_new() for comment about the gpointer. */
1971 gpointer_init(&gp);
1972 x = (t_scalar *)getbytes(sizeof(t_scalar) +
1973 (tto->t_n - 1) * sizeof(*x->sc_vec));
1974 x->sc_gobj.g_pd = scalar_class;
1975 x->sc_template = tfrom->t_sym;
1976 gpointer_setglist(&gp, glist, x);
1977 /* Here we initialize to the new template, but array and list
1978 elements will still belong to old template. */
1979 word_init(x->sc_vec, tto, &gp);
1980
1981 template_conformwords(tfrom, tto, conformaction,
1982 scfrom->sc_vec, x->sc_vec);
1983
1984 /* replace the old one with the new one in the list */
1985 if (glist->gl_list == &scfrom->sc_gobj)
1986 {
1987 glist->gl_list = &x->sc_gobj;
1988 x->sc_gobj.g_next = scfrom->sc_gobj.g_next;
1989 }
1990 else
1991 {
1992 t_gobj *y, *y2;
1993 for (y = glist->gl_list; y2 = y->g_next; y = y2)
1994 if (y2 == &scfrom->sc_gobj)
1995 {
1996 x->sc_gobj.g_next = y2->g_next;
1997 y->g_next = &x->sc_gobj;
1998 goto nobug;
1999 }
2000 bug("template_conformscalar");
2001 nobug: ;
2002 }
2003 /* burn the old one */
2004 pd_free(&scfrom->sc_gobj.g_pd);
2005 }
2006 else x = scfrom;
2007 scalartemplate = template_findbyname(x->sc_template);
2008 /* convert all array elements and sublists */
2009 for (i = 0; i < scalartemplate->t_n; i++)
2010 {
2011 t_dataslot *ds = scalartemplate->t_vec + i;
2012 if (ds->ds_type == DT_LIST)
2013 {
2014 t_glist *gl2 = x->sc_vec[i].w_list;
2015 template_conformglist(tfrom, tto, gl2, conformaction);
2016 }
2017 else if (ds->ds_type == DT_ARRAY)
2018 {
2019 template_conformarray(tfrom, tto, conformaction,
2020 x->sc_vec[i].w_array);
2021 }
2022 }
2023 return (x);
2024}
2025
2026 /* conform an array, recursively conforming sublists and arrays */
2027static void template_conformarray(t_template *tfrom, t_template *tto,
2028 int *conformaction, t_array *a)
2029{
2030 int i;
2031 if (a->a_templatesym == tfrom->t_sym)
2032 {
2033 /* the array elements must all be conformed */
2034 int oldelemsize = sizeof(t_word) * tfrom->t_n,
2035 newelemsize = sizeof(t_word) * tto->t_n;
2036 char *newarray = getbytes(sizeof(t_word) * tto->t_n * a->a_n);
2037 char *oldarray = a->a_vec;
2038 if (a->a_elemsize != oldelemsize)
2039 bug("template_conformarray");
2040 for (i = 0; i < a->a_n; i++)
2041 {
2042 t_word *wp = (t_word *)(newarray + newelemsize * i);
2043 word_init(wp, tto, &a->a_gp);
2044 template_conformwords(tfrom, tto, conformaction,
2045 (t_word *)(oldarray + oldelemsize * i), wp);
2046 }
2047 }
2048 bug("template_conformarray: this part not written");
2049 /* go through item by item conforming subarrays and sublists... */
2050}
2051
2052 /* this routine searches for every scalar in the glist that belongs
2053 to the "from" template and makes it belong to the "to" template. Descend
2054 glists recursively.
2055 We don't handle redrawing here; this is to be filled in LATER... */
2056
2057static void template_conformglist(t_template *tfrom, t_template *tto,
2058 t_glist *glist, int *conformaction)
2059{
2060 t_gobj *g;
2061 /* post("conform glist %s", glist->gl_name->s_name); */
2062 for (g = glist->gl_list; g; g = g->g_next)
2063 {
2064 if (pd_class(&g->g_pd) == scalar_class)
2065 g = &template_conformscalar(tfrom, tto, conformaction,
2066 glist, (t_scalar *)g)->sc_gobj;
2067 else if (pd_class(&g->g_pd) == canvas_class)
2068 template_conformglist(tfrom, tto, (t_glist *)g, conformaction);
2069 }
2070}
2071
2072 /* globally conform all scalars from one template to another */
2073void template_conform(t_template *tfrom, t_template *tto)
2074{
2075 int nto = tto->t_n, nfrom = tfrom->t_n, i, j,
2076 *conformaction = (int *)getbytes(sizeof(int) * nto),
2077 *conformedfrom = (int *)getbytes(sizeof(int) * nfrom), doit = 0;
2078 for (i = 0; i < nto; i++)
2079 conformaction[i] = -1;
2080 for (i = 0; i < nfrom; i++)
2081 conformedfrom[i] = 0;
2082 for (i = 0; i < nto; i++)
2083 {
2084 t_dataslot *dataslot = &tto->t_vec[i];
2085 for (j = 0; j < nfrom; j++)
2086 {
2087 t_dataslot *dataslot2 = &tfrom->t_vec[j];
2088 if (dataslot_matches(dataslot, dataslot2, 1))
2089 {
2090 conformaction[i] = j;
2091 conformedfrom[j] = 1;
2092 }
2093 }
2094 }
2095 for (i = 0; i < nto; i++)
2096 if (conformaction[i] < 0)
2097 {
2098 t_dataslot *dataslot = &tto->t_vec[i];
2099 for (j = 0; j < nfrom; j++)
2100 if (!conformedfrom[j] &&
2101 dataslot_matches(dataslot, &tfrom->t_vec[j], 1))
2102 {
2103 conformaction[i] = j;
2104 conformedfrom[j] = 1;
2105 }
2106 }
2107 if (nto != nfrom)
2108 doit = 1;
2109 else for (i = 0; i < nto; i++)
2110 if (conformaction[i] != i)
2111 doit = 1;
2112
2113 if (doit)
2114 {
2115 t_glist *gl;
2116 /* post("conforming template '%s' to new structure",
2117 tfrom->t_sym->s_name);
2118 for (i = 0; i < nto; i++)
2119 post("... %d", conformaction[i]); */
2120 for (gl = canvas_list; gl; gl = gl->gl_next)
2121 template_conformglist(tfrom, tto, gl, conformaction);
2122 }
2123 freebytes(conformaction, sizeof(int) * nto);
2124 freebytes(conformedfrom, sizeof(int) * nfrom);
2125}
2126
2127t_template *template_findbyname(t_symbol *s)
2128{
2129 int i;
2130 if (s == &s_float)
2131 return (&template_float);
2132 else return ((t_template *)pd_findbyclass(s, template_class));
2133}
2134
2135t_canvas *template_findcanvas(t_template *template)
2136{
2137 t_gtemplate *gt;
2138 if (!template)
2139 bug("template_findcanvas");
2140 if (!(gt = template->t_list))
2141 return (0);
2142 return (gt->x_owner);
2143 /* return ((t_canvas *)pd_findbyclass(template->t_sym, canvas_class)); */
2144}
2145
2146 /* call this when reading a patch from a file to declare what templates
2147 we'll need. If there's already a template, check if it matches.
2148 If it doesn't it's still OK as long as there are no "struct" (gtemplate)
2149 objects hanging from it; we just conform everyone to the new template.
2150 If there are still struct objects belonging to the other template, we're
2151 in trouble. LATER we'll figure out how to conform the new patch's objects
2152 to the pre-existing struct. */
2153static void *template_usetemplate(void *dummy, t_symbol *s,
2154 int argc, t_atom *argv)
2155{
2156 t_template *x;
2157 t_symbol *templatesym =
2158 canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
2159 if (!argc)
2160 return (0);
2161 argc--; argv++;
2162 /* check if there's already a template by this name. */
2163 if ((x = (t_template *)pd_findbyclass(templatesym, template_class)))
2164 {
2165 t_template *y = template_new(&s_, argc, argv);
2166 /* If the new template is the same as the old one,
2167 there's nothing to do. */
2168 if (!template_match(x, y))
2169 {
2170 /* Are there "struct" objects upholding this template? */
2171 if (x->t_list)
2172 {
2173 /* don't know what to do here! */
2174 error("%s: template mismatch",
2175 templatesym->s_name);
2176 }
2177 else
2178 {
2179 /* conform everyone to the new template */
2180 template_conform(x, y);
2181 pd_free(&x->t_pdobj);
2182 template_new(templatesym, argc, argv);
2183 }
2184 }
2185 pd_free(&y->t_pdobj);
2186 }
2187 /* otherwise, just make one. */
2188 else template_new(templatesym, argc, argv);
2189 return (0);
2190}
2191
2192 /* here we assume someone has already cleaned up all instances of this. */
2193void template_free(t_template *x)
2194{
2195 if (*x->t_sym->s_name)
2196 pd_unbind(&x->t_pdobj, x->t_sym);
2197 t_freebytes(x->t_vec, x->t_n * sizeof(*x->t_vec));
2198}
2199
2200static void template_setup(void)
2201{
2202 template_class = class_new(gensym("template"), 0, (t_method)template_free,
2203 sizeof(t_template), CLASS_PD, 0);
2204 class_addmethod(pd_canvasmaker, (t_method)template_usetemplate,
2205 gensym("struct"), A_GIMME, 0);
2206
2207}
2208
2209/* ---------------- gtemplates. One per canvas. ----------- */
2210
2211/* this is a "text" object that searches for, and if necessary creates,
2212a "template" (above). Other objects in the canvas then can give drawing
2213instructions for the template. The template doesn't go away when the
2214gtemplate is deleted, so that you can replace it with
2215another one to add new fields, for example. */
2216
2217static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv)
2218{
2219 t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
2220 t_template *t = template_findbyname(sym);
2221 int i;
2222 t_symbol *sx = gensym("x");
2223 x->x_owner = canvas_getcurrent();
2224 x->x_next = 0;
2225 x->x_sym = sym;
2226 x->x_argc = argc;
2227 x->x_argv = (t_atom *)getbytes(argc * sizeof(t_atom));
2228 for (i = 0; i < argc; i++)
2229 x->x_argv[i] = argv[i];
2230
2231 /* already have a template by this name? */
2232 if (t)
2233 {
2234 x->x_template = t;
2235 /* if it's already got a "struct" or "gtemplate" object we
2236 just tack this one to the end of the list and leave it
2237 there. */
2238 if (t->t_list)
2239 {
2240 t_gtemplate *x2, *x3;
2241 for (x2 = x->x_template->t_list; x3 = x2->x_next; x2 = x3)
2242 ;
2243 x2->x_next = x;
2244 post("template %s: warning: already exists.", sym->s_name);
2245 }
2246 else
2247 {
2248 /* if there's none, we just replace the template with
2249 our own and conform it. */
2250 t_template *y = template_new(&s_, argc, argv);
2251 /* Unless the new template is different from the old one,
2252 there's nothing to do. */
2253 if (!template_match(t, y))
2254 {
2255 /* conform everyone to the new template */
2256 template_conform(t, y);
2257 pd_free(&t->t_pdobj);
2258 t = template_new(sym, argc, argv);
2259 }
2260 pd_free(&y->t_pdobj);
2261 t->t_list = x;
2262 }
2263 }
2264 else
2265 {
2266 /* otherwise make a new one and we're the only struct on it. */
2267 x->x_template = t = template_new(sym, argc, argv);
2268 t->t_list = x;
2269 }
2270 return (x);
2271}
2272
2273static void *gtemplate_new(t_symbol *s, int argc, t_atom *argv)
2274{
2275 t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
2276 t_symbol *sym = atom_getsymbolarg(0, argc, argv);
2277 if (argc >= 1)
2278 argc--; argv++;
2279 return (gtemplate_donew(canvas_makebindsym(sym), argc, argv));
2280}
2281
2282 /* old version (0.34) -- delete 2003 or so */
2283static void *gtemplate_new_old(t_symbol *s, int argc, t_atom *argv)
2284{
2285 t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
2286 t_symbol *sym = canvas_makebindsym(canvas_getcurrent()->gl_name);
2287 static int warned;
2288 if (!warned)
2289 {
2290 post("warning -- 'template' (%s) is obsolete; replace with 'struct'",
2291 sym->s_name);
2292 warned = 1;
2293 }
2294 return (gtemplate_donew(sym, argc, argv));
2295}
2296
2297t_template *gtemplate_get(t_gtemplate *x)
2298{
2299 return (x->x_template);
2300}
2301
2302static void gtemplate_free(t_gtemplate *x)
2303{
2304 /* get off the template's list */
2305 t_template *t = x->x_template;
2306 if (x == t->t_list)
2307 {
2308 if (x->x_next)
2309 {
2310 /* if we were first on the list, and there are others on
2311 the list, make a new template corresponding to the new
2312 first-on-list and replace teh existing template with it. */
2313 t_template *z = template_new(&s_, x->x_argc, x->x_argv);
2314 template_conform(t, z);
2315 pd_free(&t->t_pdobj);
2316 pd_free(&z->t_pdobj);
2317 z = template_new(x->x_sym, x->x_argc, x->x_argv);
2318 z->t_list = x->x_next;
2319 }
2320 else t->t_list = 0;
2321 }
2322 else
2323 {
2324 t_gtemplate *x2, *x3;
2325 for (x2 = t->t_list; x3 = x2->x_next; x2 = x3)
2326 {
2327 if (x == x3)
2328 {
2329 x2->x_next = x3->x_next;
2330 break;
2331 }
2332 }
2333 }
2334 freebytes(x->x_argv, sizeof(t_atom) * x->x_argc);
2335}
2336
2337static void gtemplate_setup(void)
2338{
2339 gtemplate_class = class_new(gensym("struct"),
2340 (t_newmethod)gtemplate_new, (t_method)gtemplate_free,
2341 sizeof(t_gtemplate), CLASS_NOINLET, A_GIMME, 0);
2342 class_addcreator((t_newmethod)gtemplate_new_old, gensym("template"),
2343 A_GIMME, 0);
2344}
2345
2346/* --------------- FIELD DESCRIPTORS ---------------------- */
2347
2348/* a field descriptor can hold a constant or a variable; if a variable,
2349it's the name of a field in the template we belong to. LATER, we might
2350want to cache the offset of the field so we don't have to search for it
2351every single time we draw the object.
2352*/
2353
2354typedef struct _fielddesc
2355{
2356 char fd_type; /* LATER consider removing this? */
2357 char fd_var;
2358 union
2359 {
2360 t_float fd_float; /* the field is a constant float */
2361 t_symbol *fd_symbol; /* the field is a constant symbol */
2362 t_symbol *fd_varsym; /* the field is variable and this is the name */
2363 } fd_un;
2364} t_fielddesc;
2365
2366#define FIELDDESC_SETFLOAT(x, f) \
2367 ((x)->fd_type = A_FLOAT, (x)->fd_var = 0, (x)->fd_un.fd_float = (f))
2368#define FIELDDESC_SETSYMBOL(x, s) \
2369 ((x)->fd_type = A_SYMBOL, (x)->fd_var = 0, (x)->fd_un.fd_symbol = (s))
2370#define FIELDDESC_SETVAR(x, s, type) \
2371 ((x)->fd_type = type, (x)->fd_var = 1, (x)->fd_un.fd_varsym = (s))
2372
2373#define CLOSED 1
2374#define BEZ 2
2375#define A_ARRAY 55 /* LATER decide whether to enshrine this in m_pd.h */
2376
2377static void fielddesc_setfloatarg(t_fielddesc *fd, int argc, t_atom *argv)
2378{
2379 if (argc <= 0) FIELDDESC_SETFLOAT(fd, 0);
2380 else if (argv->a_type == A_SYMBOL)
2381 FIELDDESC_SETVAR(fd, argv->a_w.w_symbol, A_FLOAT);
2382 else FIELDDESC_SETFLOAT(fd, argv->a_w.w_float);
2383}
2384
2385static void fielddesc_setarrayarg(t_fielddesc *fd, int argc, t_atom *argv)
2386{
2387 if (argc <= 0) FIELDDESC_SETFLOAT(fd, 0);
2388 else if (argv->a_type == A_SYMBOL)
2389 FIELDDESC_SETVAR(fd, argv->a_w.w_symbol, A_ARRAY);
2390 else FIELDDESC_SETFLOAT(fd, argv->a_w.w_float);
2391}
2392
2393static t_float fielddesc_getfloat(t_fielddesc *f, t_template *template,
2394 t_word *wp, int loud)
2395{
2396 if (f->fd_type == A_FLOAT)
2397 {
2398 if (f->fd_var)
2399 return (template_getfloat(template, f->fd_un.fd_varsym, wp, loud));
2400 else return (f->fd_un.fd_float);
2401 }
2402 else
2403 {
2404 if (loud)
2405 error("symbolic data field used as number");
2406 return (0);
2407 }
2408}
2409
2410static t_symbol *fielddesc_getsymbol(t_fielddesc *f, t_template *template,
2411 t_word *wp, int loud)
2412{
2413 if (f->fd_type == A_SYMBOL)
2414 {
2415 if (f->fd_var)
2416 return(template_getsymbol(template, f->fd_un.fd_varsym, wp, loud));
2417 else return (f->fd_un.fd_symbol);
2418 }
2419 else
2420 {
2421 if (loud)
2422 error("numeric data field used as symbol");
2423 return (&s_);
2424 }
2425}
2426
2427/* ---------------- curves and polygons (joined segments) ---------------- */
2428
2429/*
2430curves belong to templates and describe how the data in the template are to
2431be drawn. The coordinates of the curve (and other display features) can
2432be attached to fields in the template.
2433*/
2434
2435t_class *curve_class;
2436
2437typedef struct _curve
2438{
2439 t_object x_obj;
2440 int x_flags; /* CLOSED and/or BEZ */
2441 t_fielddesc x_fillcolor;
2442 t_fielddesc x_outlinecolor;
2443 t_fielddesc x_width;
2444 int x_npoints;
2445 t_fielddesc *x_vec;
2446} t_curve;
2447
2448static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv)
2449{
2450 t_curve *x = (t_curve *)pd_new(curve_class);
2451 char *classname = classsym->s_name;
2452 int flags = 0;
2453 int nxy, i;
2454 t_fielddesc *fd;
2455 if (classname[0] == 'f')
2456 {
2457 classname += 6;
2458 flags |= CLOSED;
2459 if (argc) fielddesc_setfloatarg(&x->x_fillcolor, argc--, argv++);
2460 else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
2461 }
2462 else classname += 4;
2463 if (classname[0] == 'c') flags |= BEZ;
2464 x->x_flags = flags;
2465 if (argc) fielddesc_setfloatarg(&x->x_outlinecolor, argc--, argv++);
2466 else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
2467 if (argc) fielddesc_setfloatarg(&x->x_width, argc--, argv++);
2468 else FIELDDESC_SETFLOAT(&x->x_width, 1);
2469 if (argc < 0) argc = 0;
2470 nxy = (argc + (argc & 1));
2471 x->x_npoints = (nxy>>1);
2472 x->x_vec = (t_fielddesc *)t_getbytes(nxy * sizeof(t_fielddesc));
2473 for (i = 0, fd = x->x_vec; i < argc; i++, fd++, argv++)
2474 fielddesc_setfloatarg(fd, 1, argv);
2475 if (argc & 1) FIELDDESC_SETFLOAT(fd, 0);
2476
2477 return (x);
2478}
2479
2480/* -------------------- widget behavior for curve ------------ */
2481
2482static void curve_getrect(t_gobj *z, t_glist *glist,
2483 t_word *data, t_template *template, float basex, float basey,
2484 int *xp1, int *yp1, int *xp2, int *yp2)
2485{
2486 t_curve *x = (t_curve *)z;
2487 int i, n = x->x_npoints;
2488 t_fielddesc *f = x->x_vec;
2489 int x1 = 0x7fffffff, x2 = -0x7fffffff, y1 = 0x7fffffff, y2 = -0x7fffffff;
2490 for (i = 0, f = x->x_vec; i < n; i++, f += 2)
2491 {
2492 int xloc = glist_xtopixels(glist,
2493 basex + fielddesc_getfloat(f, template, data, 0));
2494 int yloc = glist_ytopixels(glist,
2495 basey + fielddesc_getfloat(f+1, template, data, 0));
2496 if (xloc < x1) x1 = xloc;
2497 if (xloc > x2) x2 = xloc;
2498 if (yloc < y1) y1 = yloc;
2499 if (yloc > y2) y2 = yloc;
2500 }
2501 *xp1 = x1;
2502 *yp1 = y1;
2503 *xp2 = x2;
2504 *yp2 = y2;
2505}
2506
2507static void curve_displace(t_gobj *z, t_glist *glist,
2508 t_word *data, t_template *template, float basex, float basey,
2509 int dx, int dy)
2510{
2511 /* refuse */
2512}
2513
2514static void curve_select(t_gobj *z, t_glist *glist,
2515 t_word *data, t_template *template, float basex, float basey,
2516 int state)
2517{
2518 /* fill in later */
2519}
2520
2521static void curve_activate(t_gobj *z, t_glist *glist,
2522 t_word *data, t_template *template, float basex, float basey,
2523 int state)
2524{
2525 /* fill in later */
2526}
2527
2528static int rangecolor(int n) /* 0 to 9 in 5 steps */
2529{
2530 int n2 = n/2; /* 0 to 4 */
2531 int ret = (n2 << 6); /* 0 to 256 in 5 steps */
2532 if (ret > 255) ret = 255;
2533 return (ret);
2534}
2535
2536static void numbertocolor(int n, char *s)
2537{
2538 int red, blue, green;
2539 if (n < 0) n = 0;
2540 red = n / 100;
2541 blue = ((n / 10) % 10);
2542 green = n % 10;
2543 sprintf(s, "#%2.2x%2.2x%2.2x", rangecolor(red), rangecolor(blue),
2544 rangecolor(green));
2545}
2546
2547static void curve_vis(t_gobj *z, t_glist *glist,
2548 t_word *data, t_template *template, float basex, float basey,
2549 int vis)
2550{
2551 t_curve *x = (t_curve *)z;
2552 int i, n = x->x_npoints;
2553 t_fielddesc *f = x->x_vec;
2554
2555 if (vis)
2556 {
2557 if (n > 1)
2558 {
2559 int flags = x->x_flags, closed = (flags & CLOSED);
2560 float width = fielddesc_getfloat(&x->x_width, template, data, 1);
2561 char outline[20], fill[20];
2562 if (width < 1) width = 1;
2563 numbertocolor(
2564 fielddesc_getfloat(&x->x_outlinecolor, template, data, 1),
2565 outline);
2566 if (flags & CLOSED)
2567 {
2568 numbertocolor(
2569 fielddesc_getfloat(&x->x_fillcolor, template, data, 1),
2570 fill);
2571 sys_vgui(".x%x.c create polygon\\\n",
2572 glist_getcanvas(glist));
2573 }
2574 else sys_vgui(".x%x.c create line\\\n",
2575 glist_getcanvas(glist));
2576 for (i = 0, f = x->x_vec; i < n; i++, f += 2)
2577 {
2578 float xloc = glist_xtopixels(glist,
2579 basex + fielddesc_getfloat(f, template, data, 1));
2580 float yloc = glist_ytopixels(glist,
2581 basey + fielddesc_getfloat(f+1, template, data, 1));
2582 sys_vgui("%d %d\\\n", (int)xloc, (int)yloc);
2583 }
2584 sys_vgui("-width %f\\\n",
2585 fielddesc_getfloat(&x->x_width, template, data, 1));
2586 if (flags & CLOSED) sys_vgui("-fill %s -outline %s\\\n",
2587 fill, outline);
2588 else sys_vgui("-fill %s\\\n", outline);
2589 if (flags & BEZ) sys_vgui("-smooth 1\\\n");
2590 sys_vgui("-tags curve%x\n", data);
2591 }
2592 else post("warning: curves need at least two points to be graphed");
2593 }
2594 else
2595 {
2596 if (n > 1) sys_vgui(".x%x.c delete curve%x\n",
2597 glist_getcanvas(glist), data);
2598 }
2599}
2600
2601static int curve_motion_field;
2602static float curve_motion_xcumulative;
2603static float curve_motion_xbase;
2604static float curve_motion_xper;
2605static float curve_motion_ycumulative;
2606static float curve_motion_ybase;
2607static float curve_motion_yper;
2608static t_glist *curve_motion_glist;
2609static t_gobj *curve_motion_gobj;
2610static t_word *curve_motion_wp;
2611static t_template *curve_motion_template;
2612
2613 /* LATER protect against the template changing or the scalar disappearing
2614 probably by attaching a gpointer here ... */
2615
2616static void curve_motion(void *z, t_floatarg dx, t_floatarg dy)
2617{
2618 t_curve *x = (t_curve *)z;
2619 t_fielddesc *f = x->x_vec + curve_motion_field;
2620 curve_motion_xcumulative += dx;
2621 curve_motion_ycumulative += dy;
2622 if (f->fd_var)
2623 {
2624 template_setfloat(curve_motion_template,
2625 f->fd_un.fd_varsym,
2626 curve_motion_wp,
2627 curve_motion_xbase + curve_motion_xcumulative * curve_motion_xper,
2628 1);
2629 }
2630 if ((f+1)->fd_var)
2631 {
2632 template_setfloat(curve_motion_template,
2633 (f+1)->fd_un.fd_varsym,
2634 curve_motion_wp,
2635 curve_motion_ybase + curve_motion_ycumulative * curve_motion_yper,
2636 1);
2637 }
2638 glist_redrawitem(curve_motion_glist, curve_motion_gobj);
2639}
2640
2641static int curve_click(t_gobj *z, t_glist *glist,
2642 t_scalar *sc, t_template *template, float basex, float basey,
2643 int xpix, int ypix, int shift, int alt, int dbl, int doit)
2644{
2645 t_curve *x = (t_curve *)z;
2646 int i, n = x->x_npoints;
2647 int bestn = -1;
2648 int besterror = 0x7fffffff;
2649 t_fielddesc *f = x->x_vec;
2650 t_word *data = sc->sc_vec;
2651 for (i = 0, f = x->x_vec; i < n; i++, f += 2)
2652 {
2653 int xloc = glist_xtopixels(glist,
2654 basex + fielddesc_getfloat(f, template, data, 0));
2655 int yloc = glist_ytopixels(glist,
2656 basey + fielddesc_getfloat(f+1, template, data, 0));
2657 int xerr = xloc - xpix, yerr = yloc - ypix;
2658 if (!f->fd_var && !(f+1)->fd_var)
2659 continue;
2660 if (xerr < 0)
2661 xerr = -xerr;
2662 if (yerr < 0)
2663 yerr = -yerr;
2664 if (yerr > xerr)
2665 xerr = yerr;
2666 if (xerr < besterror)
2667 {
2668 besterror = xerr;
2669 bestn = i;
2670 curve_motion_xbase = fielddesc_getfloat(f, template, data, 0);
2671 curve_motion_ybase = fielddesc_getfloat(f+1, template, data, 0);
2672 }
2673 }
2674 if (besterror > 10)
2675 return (0);
2676 if (doit)
2677 {
2678 curve_motion_xper = glist_pixelstox(glist, 1)
2679 - glist_pixelstox(glist, 0);
2680 curve_motion_yper = glist_pixelstoy(glist, 1)
2681 - glist_pixelstoy(glist, 0);
2682 curve_motion_xcumulative = curve_motion_ycumulative = 0;
2683 curve_motion_glist = glist;
2684 curve_motion_gobj = &sc->sc_gobj;
2685 curve_motion_wp = data;
2686 curve_motion_field = 2*bestn;
2687 curve_motion_template = template;
2688 glist_grab(glist, z, curve_motion, 0, xpix, ypix);
2689 }
2690 return (1);
2691}
2692
2693t_parentwidgetbehavior curve_widgetbehavior =
2694{
2695 curve_getrect,
2696 curve_displace,
2697 curve_select,
2698 curve_activate,
2699 curve_vis,
2700 curve_click,
2701};
2702
2703static void curve_free(t_curve *x)
2704{
2705 t_freebytes(x->x_vec, 2 * x->x_npoints * sizeof(*x->x_vec));
2706}
2707
2708static void curve_setup(void)
2709{
2710 curve_class = class_new(gensym("drawpolygon"), (t_newmethod)curve_new,
2711 (t_method)curve_free, sizeof(t_curve), CLASS_NOINLET, A_GIMME, 0);
2712 class_setdrawcommand(curve_class);
2713 class_addcreator((t_newmethod)curve_new, gensym("drawcurve"),
2714 A_GIMME, 0);
2715 class_addcreator((t_newmethod)curve_new, gensym("filledpolygon"),
2716 A_GIMME, 0);
2717 class_addcreator((t_newmethod)curve_new, gensym("filledcurve"),
2718 A_GIMME, 0);
2719 class_setparentwidget(curve_class, &curve_widgetbehavior);
2720}
2721
2722/* --------- plots for showing arrays --------------- */
2723
2724t_class *plot_class;
2725
2726typedef struct _plot
2727{
2728 t_object x_obj;
2729 int x_flags;
2730 t_fielddesc x_outlinecolor;
2731 t_fielddesc x_width;
2732 t_fielddesc x_xloc;
2733 t_fielddesc x_yloc;
2734 t_fielddesc x_xinc;
2735 t_fielddesc x_data;
2736} t_plot;
2737
2738static void *plot_new(t_symbol *classsym, t_int argc, t_atom *argv)
2739{
2740 t_plot *x = (t_plot *)pd_new(plot_class);
2741 int flags = 0;
2742 int nxy, i;
2743 t_fielddesc *fd;
2744 t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
2745 if (!strcmp(firstarg->s_name, "curve"))
2746 {
2747 flags |= BEZ;
2748 argc--, argv++;
2749 }
2750 if (argc) fielddesc_setarrayarg(&x->x_data, argc--, argv++);
2751 else FIELDDESC_SETFLOAT(&x->x_data, 1);
2752 if (argc) fielddesc_setfloatarg(&x->x_outlinecolor, argc--, argv++);
2753 else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
2754 if (argc) fielddesc_setfloatarg(&x->x_width, argc--, argv++);
2755 else FIELDDESC_SETFLOAT(&x->x_width, 1);
2756 if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
2757 else FIELDDESC_SETFLOAT(&x->x_xloc, 1);
2758 if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
2759 else FIELDDESC_SETFLOAT(&x->x_yloc, 1);
2760 if (argc) fielddesc_setfloatarg(&x->x_xinc, argc--, argv++);
2761 else FIELDDESC_SETFLOAT(&x->x_xinc, 1);
2762 x->x_flags = flags;
2763 return (x);
2764}
2765
2766/* -------------------- widget behavior for plot ------------ */
2767
2768
2769 /* get everything we'll need from the owner template of the array being
2770 plotted. Not used for garrays, but see below */
2771static int plot_readownertemplate(t_plot *x,
2772 t_word *data, t_template *ownertemplate,
2773 t_symbol **elemtemplatesymp, t_array **arrayp,
2774 float *linewidthp, float *xlocp, float *xincp, float *ylocp)
2775{
2776 int arrayonset, type;
2777 t_symbol *elemtemplatesym;
2778 t_array *array;
2779
2780 /* find the data and verify it's an array */
2781 if (x->x_data.fd_type != A_ARRAY || !x->x_data.fd_var)
2782 {
2783 error("plot: needs an array field");
2784 return (-1);
2785 }
2786 if (!template_find_field(ownertemplate, x->x_data.fd_un.fd_varsym,
2787 &arrayonset, &type, &elemtemplatesym))
2788 {
2789 error("plot: %s: no such field", x->x_data.fd_un.fd_varsym->s_name);
2790 return (-1);
2791 }
2792 if (type != DT_ARRAY)
2793 {
2794 error("plot: %s: not an array", x->x_data.fd_un.fd_varsym->s_name);
2795 return (-1);
2796 }
2797 array = *(t_array **)(((char *)data) + arrayonset);
2798 *linewidthp = fielddesc_getfloat(&x->x_width, ownertemplate, data, 1);
2799 *xlocp = fielddesc_getfloat(&x->x_xloc, ownertemplate, data, 1);
2800 *xincp = fielddesc_getfloat(&x->x_xinc, ownertemplate, data, 1);
2801 *ylocp = fielddesc_getfloat(&x->x_yloc, ownertemplate, data, 1);
2802 *elemtemplatesymp = elemtemplatesym;
2803 *arrayp = array;
2804 return (0);
2805}
2806
2807 /* get everything else you could possibly need about a plot,
2808 either for plot's own purposes or for plotting a "garray" */
2809int array_getfields(t_symbol *elemtemplatesym,
2810 t_canvas **elemtemplatecanvasp,
2811 t_template **elemtemplatep, int *elemsizep,
2812 int *xonsetp, int *yonsetp, int *wonsetp)
2813{
2814 int arrayonset, elemsize, yonset, wonset, xonset, type;
2815 t_template *elemtemplate;
2816 t_symbol *dummy;
2817 t_canvas *elemtemplatecanvas = 0;
2818
2819 /* the "float" template is special in not having to have a canvas;
2820 template_findbyname is hardwired to return a predefined
2821 template. */
2822
2823 if (!(elemtemplate = template_findbyname(elemtemplatesym)))
2824 {
2825 error("plot: %s: no such template", elemtemplatesym->s_name);
2826 return (-1);
2827 }
2828 if (!((elemtemplatesym == &s_float) ||
2829 (elemtemplatecanvas = template_findcanvas(elemtemplate))))
2830 {
2831 error("plot: %s: no canvas for this template", elemtemplatesym->s_name);
2832 return (-1);
2833 }
2834 elemsize = elemtemplate->t_n * sizeof(t_word);
2835 if (!template_find_field(elemtemplate, gensym("y"), &yonset, &type, &dummy)
2836 || type != DT_FLOAT)
2837 yonset = -1;
2838 if (!template_find_field(elemtemplate, gensym("x"), &xonset, &type, &dummy)
2839 || type != DT_FLOAT)
2840 xonset = -1;
2841 if (!template_find_field(elemtemplate, gensym("w"), &wonset, &type, &dummy)
2842 || type != DT_FLOAT)
2843 wonset = -1;
2844
2845 /* fill in slots for return values */
2846 *elemtemplatecanvasp = elemtemplatecanvas;
2847 *elemtemplatep = elemtemplate;
2848 *elemsizep = elemsize;
2849 *xonsetp = xonset;
2850 *yonsetp = yonset;
2851 *wonsetp = wonset;
2852 return (0);
2853}
2854
2855static void plot_getrect(t_gobj *z, t_glist *glist,
2856 t_word *data, t_template *template, float basex, float basey,
2857 int *xp1, int *yp1, int *xp2, int *yp2)
2858{
2859 t_plot *x = (t_plot *)z;
2860 int elemsize, yonset, wonset, xonset;
2861 t_canvas *elemtemplatecanvas;
2862 t_template *elemtemplate;
2863 t_symbol *elemtemplatesym;
2864 float linewidth, xloc, xinc, yloc;
2865 t_array *array;
2866 float x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
2867 int i;
2868 float xpix, ypix, wpix;
2869
2870 if (!plot_readownertemplate(x, data, template,
2871 &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc) &&
2872 !array_getfields(elemtemplatesym, &elemtemplatecanvas,
2873 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
2874 {
2875 for (i = 0; i < array->a_n; i++)
2876 {
2877 array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
2878 xonset, yonset, wonset, i, basex + xloc, basey + yloc, xinc,
2879 &xpix, &ypix, &wpix);
2880 if (xpix < x1)
2881 x1 = xpix;
2882 if (xpix > x2)
2883 x2 = xpix;
2884 if (ypix - wpix < y1)
2885 y1 = ypix - wpix;
2886 if (ypix + wpix > y2)
2887 y2 = ypix + wpix;
2888 }
2889 }
2890
2891 *xp1 = x1;
2892 *yp1 = y1;
2893 *xp2 = x2;
2894 *yp2 = y2;
2895}
2896
2897static void plot_displace(t_gobj *z, t_glist *glist,
2898 t_word *data, t_template *template, float basex, float basey,
2899 int dx, int dy)
2900{
2901 /* not yet */
2902}
2903
2904static void plot_select(t_gobj *z, t_glist *glist,
2905 t_word *data, t_template *template, float basex, float basey,
2906 int state)
2907{
2908 /* not yet */
2909}
2910
2911static void plot_activate(t_gobj *z, t_glist *glist,
2912 t_word *data, t_template *template, float basex, float basey,
2913 int state)
2914{
2915 /* not yet */
2916}
2917
2918static void plot_vis(t_gobj *z, t_glist *glist,
2919 t_word *data, t_template *template, float basex, float basey,
2920 int vis)
2921{
2922 t_plot *x = (t_plot *)z;
2923 int elemsize, yonset, wonset, xonset;
2924 t_canvas *elemtemplatecanvas;
2925 t_template *elemtemplate;
2926 t_symbol *elemtemplatesym;
2927 float linewidth, xloc, xinc, yloc;
2928 t_array *array;
2929 int nelem;
2930 char *elem;
2931 if (plot_readownertemplate(x, data, template,
2932 &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc) ||
2933 array_getfields(elemtemplatesym, &elemtemplatecanvas,
2934 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
2935 return;
2936 nelem = array->a_n;
2937 elem = (char *)array->a_vec;
2938 if (vis)
2939 {
2940 char outline[20];
2941 int lastpixel = -1, ndrawn = 0;
2942 float xsum, yval = 0, wval = 0, xpix;
2943 int ixpix = 0, i;
2944
2945 /* draw the trace */
2946 numbertocolor(fielddesc_getfloat(&x->x_outlinecolor, template, data, 1),
2947 outline);
2948 if (wonset >= 0)
2949 {
2950 /* found "w" field which controls linewidth. The trace is
2951 a filled polygon with 2n points. */
2952 sys_vgui(".x%x.c create polygon \\\n",
2953 glist_getcanvas(glist));
2954
2955 for (i = 0, xsum = xloc; i < nelem; i++)
2956 {
2957 float usexloc;
2958 if (xonset >= 0)
2959 usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
2960 else usexloc = xsum, xsum += xinc;
2961 if (yonset >= 0)
2962 yval = *(float *)((elem + elemsize * i) + yonset);
2963 else yval = 0;
2964 wval = *(float *)((elem + elemsize * i) + wonset);
2965 xpix = glist_xtopixels(glist, basex + usexloc);
2966 ixpix = xpix + 0.5;
2967 if (xonset >= 0 || ixpix != lastpixel)
2968 {
2969 sys_vgui("%d %f \\\n", ixpix,
2970 glist_ytopixels(glist,
2971 basey + yloc + yval - wval));
2972 ndrawn++;
2973 }
2974 lastpixel = ixpix;
2975 if (ndrawn >= 1000) goto ouch;
2976 }
2977 lastpixel = -1;
2978 for (i = nelem-1; i >= 0; i--)
2979 {
2980 float usexloc;
2981 if (xonset >= 0)
2982 usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
2983 else xsum -= xinc, usexloc = xsum;
2984 if (yonset >= 0)
2985 yval = *(float *)((elem + elemsize * i) + yonset);
2986 else yval = 0;
2987 wval = *(float *)((elem + elemsize * i) + wonset);
2988 xpix = glist_xtopixels(glist, basex + usexloc);
2989 ixpix = xpix + 0.5;
2990 if (xonset >= 0 || ixpix != lastpixel)
2991 {
2992 sys_vgui("%d %f \\\n", ixpix, glist_ytopixels(glist,
2993 basey + yloc + yval + wval));
2994 ndrawn++;
2995 }
2996 lastpixel = ixpix;
2997 if (ndrawn >= 1000) goto ouch;
2998 }
2999 /* TK will complain if there aren't at least 3 points. There
3000 should be at least two already. */
3001 if (ndrawn < 4)
3002 {
3003 sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
3004 basey + yloc + yval + wval));
3005 sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
3006 basey + yloc + yval - wval));
3007 }
3008 ouch:
3009 sys_vgui(" -width 1 -fill %s -outline %s\\\n", outline, outline);
3010 if (x->x_flags & BEZ) sys_vgui("-smooth 1\\\n");
3011
3012 sys_vgui("-tags plot%x\n", data);
3013 }
3014 else if (linewidth > 0)
3015 {
3016 /* no "w" field. If the linewidth is positive, draw a
3017 segmented line with the requested width; otherwise don't
3018 draw the trace at all. */
3019 sys_vgui(".x%x.c create line \\\n", glist_getcanvas(glist));
3020
3021 for (xsum = xloc, i = 0; i < nelem; i++)
3022 {
3023 float usexloc;
3024 if (xonset >= 0)
3025 usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
3026 else usexloc = xsum, xsum += xinc;
3027 if (yonset >= 0)
3028 yval = *(float *)((elem + elemsize * i) + yonset);
3029 else yval = 0;
3030 xpix = glist_xtopixels(glist, basex + usexloc);
3031 ixpix = xpix + 0.5;
3032 if (xonset >= 0 || ixpix != lastpixel)
3033 {
3034 sys_vgui("%d %f \\\n", ixpix,
3035 glist_ytopixels(glist, basey + yloc + yval));
3036 ndrawn++;
3037 }
3038 lastpixel = ixpix;
3039 if (ndrawn >= 1000) break;
3040 }
3041 /* TK will complain if there aren't at least 2 points... */
3042 if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n");
3043 else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix + 10,
3044 glist_ytopixels(glist, basey + yloc + yval));
3045
3046 sys_vgui("-width %f\\\n", linewidth);
3047 sys_vgui("-fill %s\\\n", outline);
3048 if (x->x_flags & BEZ) sys_vgui("-smooth 1\\\n");
3049
3050 sys_vgui("-tags plot%x\n", data);
3051 }
3052 /* We're done with the outline; now draw all the points.
3053 This code is inefficient since the template has to be
3054 searched for drawing instructions for every last point. */
3055
3056 for (xsum = xloc, i = 0; i < nelem; i++)
3057 {
3058 float usexloc, useyloc;
3059 t_gobj *y;
3060 if (xonset >= 0)
3061 usexloc = basex + xloc +
3062 *(float *)((elem + elemsize * i) + xonset);
3063 else usexloc = basex + xsum, xsum += xinc;
3064 if (yonset >= 0)
3065 yval = *(float *)((elem + elemsize * i) + yonset);
3066 else yval = 0;
3067 useyloc = basey + yloc + yval;
3068 for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
3069 {
3070 t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
3071 if (!wb) continue;
3072 (*wb->w_parentvisfn)(y, glist,
3073 (t_word *)(elem + elemsize * i),
3074 elemtemplate, usexloc, useyloc, vis);
3075 }
3076 }
3077 }
3078 else
3079 {
3080 /* un-draw the individual points */
3081 int i;
3082 for (i = 0; i < nelem; i++)
3083 {
3084 t_gobj *y;
3085 for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
3086 {
3087 t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
3088 if (!wb) continue;
3089 (*wb->w_parentvisfn)(y, glist,
3090 (t_word *)(elem + elemsize * i), elemtemplate,
3091 0, 0, 0);
3092 }
3093 }
3094 /* and then the trace */
3095 sys_vgui(".x%x.c delete plot%x\n",
3096 glist_getcanvas(glist), data);
3097 }
3098}
3099
3100
3101static int plot_click(t_gobj *z, t_glist *glist,
3102 t_scalar *sc, t_template *template, float basex, float basey,
3103 int xpix, int ypix, int shift, int alt, int dbl, int doit)
3104{
3105 t_plot *x = (t_plot *)z;
3106 t_symbol *elemtemplatesym;
3107 float linewidth, xloc, xinc, yloc;
3108 t_array *array;
3109 t_word *data = sc->sc_vec;
3110
3111 if (!plot_readownertemplate(x, data, template,
3112 &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc))
3113 {
3114 return (array_doclick(array, glist, &sc->sc_gobj,
3115 elemtemplatesym,
3116 linewidth, basex + xloc, xinc, basey + yloc,
3117 xpix, ypix, shift, alt, dbl, doit));
3118 }
3119 else return (0);
3120}
3121
3122t_parentwidgetbehavior plot_widgetbehavior =
3123{
3124 plot_getrect,
3125 plot_displace,
3126 plot_select,
3127 plot_activate,
3128 plot_vis,
3129 plot_click,
3130};
3131
3132static void plot_setup(void)
3133{
3134 plot_class = class_new(gensym("plot"), (t_newmethod)plot_new, 0,
3135 sizeof(t_plot), CLASS_NOINLET, A_GIMME, 0);
3136 class_setdrawcommand(plot_class);
3137 class_setparentwidget(plot_class, &plot_widgetbehavior);
3138}
3139
3140/* ---------------- drawnumber: draw a number ---------------- */
3141
3142/*
3143 drawnumbers draw numeric fields at controllable locations, with
3144 controllable color and label .
3145 invocation: (drawnumber|drawsymbol) variable x y color label
3146*/
3147
3148t_class *drawnumber_class;
3149
3150#define DRAW_SYMBOL 1
3151
3152typedef struct _drawnumber
3153{
3154 t_object x_obj;
3155 t_fielddesc x_value;
3156 t_fielddesc x_xloc;
3157 t_fielddesc x_yloc;
3158 t_fielddesc x_color;
3159 t_symbol *x_label;
3160 int x_flags;
3161} t_drawnumber;
3162
3163static void *drawnumber_new(t_symbol *classsym, t_int argc, t_atom *argv)
3164{
3165 t_drawnumber *x = (t_drawnumber *)pd_new(drawnumber_class);
3166 char *classname = classsym->s_name;
3167 int flags = 0;
3168 if (classname[4] == 's')
3169 flags |= DRAW_SYMBOL;
3170 x->x_flags = flags;
3171 if (argc) fielddesc_setfloatarg(&x->x_value, argc--, argv++);
3172 else FIELDDESC_SETFLOAT(&x->x_value, 0);
3173 if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
3174 else FIELDDESC_SETFLOAT(&x->x_xloc, 0);
3175 if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
3176 else FIELDDESC_SETFLOAT(&x->x_yloc, 0);
3177 if (argc) fielddesc_setfloatarg(&x->x_color, argc--, argv++);
3178 else FIELDDESC_SETFLOAT(&x->x_color, 1);
3179 if (argc)
3180 x->x_label = atom_getsymbolarg(0, argc, argv);
3181 else x->x_label = &s_;
3182
3183 return (x);
3184}
3185
3186/* -------------------- widget behavior for drawnumber ------------ */
3187
3188#define DRAWNUMBER_BUFSIZE 80
3189static void drawnumber_sprintf(t_drawnumber *x, char *buf, t_atom *ap)
3190{
3191 int nchars;
3192 strncpy(buf, x->x_label->s_name, DRAWNUMBER_BUFSIZE);
3193 buf[DRAWNUMBER_BUFSIZE - 1] = 0;
3194 nchars = strlen(buf);
3195 atom_string(ap, buf + nchars, DRAWNUMBER_BUFSIZE - nchars);
3196}
3197
3198static void drawnumber_getrect(t_gobj *z, t_glist *glist,
3199 t_word *data, t_template *template, float basex, float basey,
3200 int *xp1, int *yp1, int *xp2, int *yp2)
3201{
3202 t_drawnumber *x = (t_drawnumber *)z;
3203 t_atom at;
3204 int xloc = glist_xtopixels(glist,
3205 basex + fielddesc_getfloat(&x->x_xloc, template, data, 0));
3206 int yloc = glist_ytopixels(glist,
3207 basey + fielddesc_getfloat(&x->x_yloc, template, data, 0));
3208 int font = glist_getfont(glist);
3209 int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
3210 char buf[DRAWNUMBER_BUFSIZE];
3211 if (x->x_flags & DRAW_SYMBOL)
3212 SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
3213 else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
3214 drawnumber_sprintf(x, buf, &at);
3215 *xp1 = xloc;
3216 *yp1 = yloc;
3217 *xp2 = xloc + fontwidth * strlen(buf);
3218 *yp2 = yloc + fontheight;
3219}
3220
3221static void drawnumber_displace(t_gobj *z, t_glist *glist,
3222 t_word *data, t_template *template, float basex, float basey,
3223 int dx, int dy)
3224{
3225 /* refuse */
3226}
3227
3228static void drawnumber_select(t_gobj *z, t_glist *glist,
3229 t_word *data, t_template *template, float basex, float basey,
3230 int state)
3231{
3232 post("drawnumber_select %d", state);
3233 /* fill in later */
3234}
3235
3236static void drawnumber_activate(t_gobj *z, t_glist *glist,
3237 t_word *data, t_template *template, float basex, float basey,
3238 int state)
3239{
3240 post("drawnumber_activate %d", state);
3241}
3242
3243static void drawnumber_vis(t_gobj *z, t_glist *glist,
3244 t_word *data, t_template *template, float basex, float basey,
3245 int vis)
3246{
3247 t_drawnumber *x = (t_drawnumber *)z;
3248
3249 if (vis)
3250 {
3251 t_atom at;
3252 int xloc = glist_xtopixels(glist,
3253 basex + fielddesc_getfloat(&x->x_xloc, template, data, 0));
3254 int yloc = glist_ytopixels(glist,
3255 basey + fielddesc_getfloat(&x->x_yloc, template, data, 0));
3256 char colorstring[20], buf[DRAWNUMBER_BUFSIZE];
3257 numbertocolor(fielddesc_getfloat(&x->x_color, template, data, 1),
3258 colorstring);
3259 if (x->x_flags & DRAW_SYMBOL)
3260 SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
3261 else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
3262 drawnumber_sprintf(x, buf, &at);
3263 sys_vgui(".x%x.c create text %d %d -anchor nw -fill %s -text {%s}",
3264 glist_getcanvas(glist), xloc, yloc, colorstring, buf);
3265 sys_vgui(" -font -*-courier-bold--normal--%d-*",
3266 sys_hostfontsize(glist_getfont(glist)));
3267 sys_vgui(" -tags drawnumber%x\n", data);
3268 }
3269 else sys_vgui(".x%x.c delete drawnumber%x\n", glist_getcanvas(glist), data);
3270}
3271
3272static float drawnumber_motion_ycumulative;
3273static t_glist *drawnumber_motion_glist;
3274static t_gobj *drawnumber_motion_gobj;
3275static t_word *drawnumber_motion_wp;
3276static t_template *drawnumber_motion_template;
3277
3278 /* LATER protect against the template changing or the scalar disappearing
3279 probably by attaching a gpointer here ... */
3280
3281static void drawnumber_motion(void *z, t_floatarg dx, t_floatarg dy)
3282{
3283 t_drawnumber *x = (t_drawnumber *)z;
3284 t_fielddesc *f = &x->x_value;
3285 drawnumber_motion_ycumulative -= dy;
3286 template_setfloat(drawnumber_motion_template,
3287 f->fd_un.fd_varsym,
3288 drawnumber_motion_wp,
3289 drawnumber_motion_ycumulative,
3290 1);
3291 glist_redrawitem(drawnumber_motion_glist, drawnumber_motion_gobj);
3292}
3293
3294static int drawnumber_click(t_gobj *z, t_glist *glist,
3295 t_scalar *sc, t_template *template, float basex, float basey,
3296 int xpix, int ypix, int shift, int alt, int dbl, int doit)
3297{
3298 t_drawnumber *x = (t_drawnumber *)z;
3299 int x1, y1, x2, y2;
3300 t_word *data = sc->sc_vec;
3301 drawnumber_getrect(z, glist,
3302 sc->sc_vec, template, basex, basey,
3303 &x1, &y1, &x2, &y2);
3304 if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2
3305 && x->x_value.fd_var)
3306 {
3307 if (doit)
3308 {
3309 drawnumber_motion_glist = glist;
3310 drawnumber_motion_gobj = &sc->sc_gobj;
3311 drawnumber_motion_wp = data;
3312 drawnumber_motion_template = template;
3313 drawnumber_motion_ycumulative =
3314 fielddesc_getfloat(&x->x_value, template, data, 0);
3315 glist_grab(glist, z, drawnumber_motion, 0, xpix, ypix);
3316 }
3317 return (1);
3318 }
3319 else return (0);
3320}
3321
3322t_parentwidgetbehavior drawnumber_widgetbehavior =
3323{
3324 drawnumber_getrect,
3325 drawnumber_displace,
3326 drawnumber_select,
3327 drawnumber_activate,
3328 drawnumber_vis,
3329 drawnumber_click,
3330};
3331
3332static void drawnumber_free(t_drawnumber *x)
3333{
3334}
3335
3336static void drawnumber_setup(void)
3337{
3338 drawnumber_class = class_new(gensym("drawnumber"),
3339 (t_newmethod)drawnumber_new, (t_method)drawnumber_free,
3340 sizeof(t_drawnumber), CLASS_NOINLET, A_GIMME, 0);
3341 class_setdrawcommand(drawnumber_class);
3342 class_addcreator((t_newmethod)drawnumber_new, gensym("drawsymbol"),
3343 A_GIMME, 0);
3344 class_setparentwidget(drawnumber_class, &drawnumber_widgetbehavior);
3345}
3346
3347/* ---------------------- setup function ---------------------------- */
3348
3349void g_template_setup(void)
3350{
3351 template_setup();
3352 gtemplate_setup();
3353 template_float.t_pdobj = template_class;
3354 curve_setup();
3355 plot_setup();
3356 drawnumber_setup();
3357}
3358 1680