diff options
author | Peter D'Hoye <peter.dhoye@gmail.com> | 2009-05-24 21:28:16 +0000 |
---|---|---|
committer | Peter D'Hoye <peter.dhoye@gmail.com> | 2009-05-24 21:28:16 +0000 |
commit | 526b5580dabbfed7cfe5439dc3a90ec727f563c2 (patch) | |
tree | 22b1af92348785daad16714ee5e2b633017e0e48 /apps/plugins/pdbox/PDa/src/g_template.c | |
parent | 4f2dfcc01b260d946044ef2b6af5fe36cb772c8d (diff) | |
download | rockbox-526b5580dabbfed7cfe5439dc3a90ec727f563c2.tar.gz rockbox-526b5580dabbfed7cfe5439dc3a90ec727f563c2.zip |
Cut the files in half and it might work better (note to self: check your tree is really clean before patching)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21070 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/g_template.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/g_template.c | 1678 |
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 | /* | ||
1693 | This file contains text objects you would put in a canvas to define a | ||
1694 | template. 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 | ||
1699 | with 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 | |||
1704 | struct _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 | |||
1717 | static void template_conformarray(t_template *tfrom, t_template *tto, | ||
1718 | int *conformaction, t_array *a); | ||
1719 | static void template_conformglist(t_template *tfrom, t_template *tto, | ||
1720 | t_glist *glist, int *conformaction); | ||
1721 | |||
1722 | /* ---------------------- storage ------------------------- */ | ||
1723 | |||
1724 | static t_class *gtemplate_class; | ||
1725 | static t_class *template_class; | ||
1726 | |||
1727 | /* there's a pre-defined "float" template. LATER should we bind this | ||
1728 | to a symbol such as "pd-float"??? */ | ||
1729 | |||
1730 | static t_dataslot template_float_vec = | ||
1731 | { | ||
1732 | DT_FLOAT, | ||
1733 | &s_y, | ||
1734 | &s_ | ||
1735 | }; | ||
1736 | |||
1737 | static 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 */ | ||
1747 | static 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 | |||
1758 | t_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 | |||
1814 | int template_size(t_template *x) | ||
1815 | { | ||
1816 | return (x->t_n * sizeof(t_word)); | ||
1817 | } | ||
1818 | |||
1819 | int 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 | |||
1841 | t_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 | |||
1859 | void 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 | |||
1875 | t_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 | |||
1893 | void 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". */ | ||
1912 | int 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 | ||
1934 | in their template. The old template is assumed to be the "installed" one | ||
1935 | so we can delete old items; but making new ones we have to avoid scalar_new | ||
1936 | which would make an old one whereas we will want a new one (but whose array | ||
1937 | elements 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 */ | ||
1941 | static 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 */ | ||
1959 | static 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 */ | ||
2027 | static 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 | |||
2057 | static 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 */ | ||
2073 | void 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 | |||
2127 | t_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 | |||
2135 | t_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. */ | ||
2153 | static 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. */ | ||
2193 | void 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 | |||
2200 | static 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, | ||
2212 | a "template" (above). Other objects in the canvas then can give drawing | ||
2213 | instructions for the template. The template doesn't go away when the | ||
2214 | gtemplate is deleted, so that you can replace it with | ||
2215 | another one to add new fields, for example. */ | ||
2216 | |||
2217 | static 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 | |||
2273 | static 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 */ | ||
2283 | static 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 | |||
2297 | t_template *gtemplate_get(t_gtemplate *x) | ||
2298 | { | ||
2299 | return (x->x_template); | ||
2300 | } | ||
2301 | |||
2302 | static 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 | |||
2337 | static 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, | ||
2349 | it's the name of a field in the template we belong to. LATER, we might | ||
2350 | want to cache the offset of the field so we don't have to search for it | ||
2351 | every single time we draw the object. | ||
2352 | */ | ||
2353 | |||
2354 | typedef 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 | |||
2377 | static 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 | |||
2385 | static 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 | |||
2393 | static 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 | |||
2410 | static 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 | /* | ||
2430 | curves belong to templates and describe how the data in the template are to | ||
2431 | be drawn. The coordinates of the curve (and other display features) can | ||
2432 | be attached to fields in the template. | ||
2433 | */ | ||
2434 | |||
2435 | t_class *curve_class; | ||
2436 | |||
2437 | typedef 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 | |||
2448 | static 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 | |||
2482 | static 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 | |||
2507 | static 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 | |||
2514 | static 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 | |||
2521 | static 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 | |||
2528 | static 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 | |||
2536 | static 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 | |||
2547 | static 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 | |||
2601 | static int curve_motion_field; | ||
2602 | static float curve_motion_xcumulative; | ||
2603 | static float curve_motion_xbase; | ||
2604 | static float curve_motion_xper; | ||
2605 | static float curve_motion_ycumulative; | ||
2606 | static float curve_motion_ybase; | ||
2607 | static float curve_motion_yper; | ||
2608 | static t_glist *curve_motion_glist; | ||
2609 | static t_gobj *curve_motion_gobj; | ||
2610 | static t_word *curve_motion_wp; | ||
2611 | static 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 | |||
2616 | static 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 | |||
2641 | static 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 | |||
2693 | t_parentwidgetbehavior curve_widgetbehavior = | ||
2694 | { | ||
2695 | curve_getrect, | ||
2696 | curve_displace, | ||
2697 | curve_select, | ||
2698 | curve_activate, | ||
2699 | curve_vis, | ||
2700 | curve_click, | ||
2701 | }; | ||
2702 | |||
2703 | static void curve_free(t_curve *x) | ||
2704 | { | ||
2705 | t_freebytes(x->x_vec, 2 * x->x_npoints * sizeof(*x->x_vec)); | ||
2706 | } | ||
2707 | |||
2708 | static 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 | |||
2724 | t_class *plot_class; | ||
2725 | |||
2726 | typedef 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 | |||
2738 | static 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 */ | ||
2771 | static 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" */ | ||
2809 | int 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 | |||
2855 | static 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 | |||
2897 | static 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 | |||
2904 | static 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 | |||
2911 | static 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 | |||
2918 | static 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 | |||
3101 | static 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 | |||
3122 | t_parentwidgetbehavior plot_widgetbehavior = | ||
3123 | { | ||
3124 | plot_getrect, | ||
3125 | plot_displace, | ||
3126 | plot_select, | ||
3127 | plot_activate, | ||
3128 | plot_vis, | ||
3129 | plot_click, | ||
3130 | }; | ||
3131 | |||
3132 | static 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 | |||
3148 | t_class *drawnumber_class; | ||
3149 | |||
3150 | #define DRAW_SYMBOL 1 | ||
3151 | |||
3152 | typedef 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 | |||
3163 | static 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 | ||
3189 | static 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 | |||
3198 | static 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 | |||
3221 | static 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 | |||
3228 | static 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 | |||
3236 | static 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 | |||
3243 | static 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 | |||
3272 | static float drawnumber_motion_ycumulative; | ||
3273 | static t_glist *drawnumber_motion_glist; | ||
3274 | static t_gobj *drawnumber_motion_gobj; | ||
3275 | static t_word *drawnumber_motion_wp; | ||
3276 | static 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 | |||
3281 | static 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 | |||
3294 | static 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 | |||
3322 | t_parentwidgetbehavior drawnumber_widgetbehavior = | ||
3323 | { | ||
3324 | drawnumber_getrect, | ||
3325 | drawnumber_displace, | ||
3326 | drawnumber_select, | ||
3327 | drawnumber_activate, | ||
3328 | drawnumber_vis, | ||
3329 | drawnumber_click, | ||
3330 | }; | ||
3331 | |||
3332 | static void drawnumber_free(t_drawnumber *x) | ||
3333 | { | ||
3334 | } | ||
3335 | |||
3336 | static 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 | |||
3349 | void 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 | ||