aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shared/Makefile.dirs2
-rw-r--r--shared/common/props.c518
-rw-r--r--shared/common/props.h26
-rw-r--r--shared/toxy/Makefile4
-rw-r--r--shared/toxy/Makefile.objects0
-rw-r--r--shared/toxy/Makefile.sources2
-rw-r--r--shared/toxy/scriptlet.c666
-rw-r--r--shared/toxy/scriptlet.h42
-rw-r--r--test/toxy/button-test.pd37
-rw-r--r--test/toxy/default.wid108
-rw-r--r--test/toxy/defaults-test.pd25
-rw-r--r--test/toxy/kb-test.pd17
-rw-r--r--test/toxy/listbox-test.pd18
-rw-r--r--test/toxy/pop1.wid10
-rw-r--r--test/toxy/pop2.wid8
-rw-r--r--test/toxy/popup-test.pd39
-rw-r--r--test/toxy/radio-test.pd50
-rw-r--r--test/toxy/scale-test.pd44
-rw-r--r--test/toxy/test1.tot301
-rw-r--r--test/toxy/tot-bulk.pd67
-rw-r--r--test/toxy/tot-cover.pd87
-rw-r--r--test/toxy/tot-files.pd29
-rw-r--r--test/toxy/tot-head.pd17
-rw-r--r--test/toxy/tot-monkey.pd50
-rw-r--r--test/toxy/tot-nomenu.pd12
-rw-r--r--test/toxy/tot-qlist.pd59
-rw-r--r--test/toxy/tot-query.pd62
-rw-r--r--test/toxy/tot-rstring.pd15
-rw-r--r--test/toxy/tot.ql186
-rw-r--r--test/toxy/tow-test.pd65
-rw-r--r--toxy/Makefile2
-rw-r--r--toxy/Makefile.objects22
-rw-r--r--toxy/Makefile.sources5
-rw-r--r--toxy/build_counter3
-rw-r--r--toxy/tot.c530
-rw-r--r--toxy/tow.c26
-rw-r--r--toxy/toxy-all.exclude8
-rw-r--r--toxy/toxy-shared.include19
-rw-r--r--toxy/toxy-test.exclude5
-rw-r--r--toxy/toxy-vicious.exclude3
-rw-r--r--toxy/widget.c1146
-rw-r--r--toxy/widgettype.c300
-rw-r--r--toxy/widgettype.h30
43 files changed, 4664 insertions, 1 deletions
diff --git a/shared/Makefile.dirs b/shared/Makefile.dirs
index d9be5aa..5764f41 100644
--- a/shared/Makefile.dirs
+++ b/shared/Makefile.dirs
@@ -1 +1 @@
-MIXED_DIRS = common hammer sickle toys unstable
+MIXED_DIRS = common hammer sickle toxy unstable
diff --git a/shared/common/props.c b/shared/common/props.c
new file mode 100644
index 0000000..6b6181a
--- /dev/null
+++ b/shared/common/props.c
@@ -0,0 +1,518 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+#include "common/props.h"
+
+//#define PROPS_DEBUG
+
+#define PROPS_INISIZE 32 /* LATER rethink */
+#define PROPS_MAXOTHERS 32
+
+enum { PROPS_NONE = 0, PROPS_THIS, PROPS_OTHER };
+
+typedef struct _propelem
+{
+ char *e_key;
+ char *e_value;
+ struct _propelem *e_next;
+} t_propelem;
+
+struct _props
+{
+ char p_thisescape;
+ char *p_thisinitial;
+ char *p_name;
+ int p_size; /* as allocated */
+ int p_natoms; /* as used */
+ t_atom *p_buffer;
+ t_atom p_bufini[PROPS_INISIZE];
+ t_pd *p_owner;
+ t_propsresolver p_resolver;
+ t_propelem *p_dict;
+ t_propelem *p_nextelem;
+ int p_badupdate;
+ char p_otherescapes[PROPS_MAXOTHERS];
+ t_props *p_otherprops; /* props list's head */
+ t_props *p_next;
+};
+
+/* Dictionary of properties, p_dict, meant to be nothing more, but an
+ optimalization detail, is handled implicitly, through its owning t_props.
+ This optimalization has to be enabled by passing a nonzero 'resolver'
+ argument to props_new().
+ Since p_dict stores resolved strings, it is a secondary, `shallow' storage,
+ which has to be synced to its master, p_buffer of atoms.
+ Currently, p_dict is implemented as an unsorted linked list, which should
+ be fine in most cases (but might need revisiting LATER). */
+
+static t_propelem *propelem_new(char *key, char *value)
+{
+ t_propelem *ep = (t_propelem *)getbytes(sizeof(*ep));
+ ep->e_key = getbytes(strlen(key) + 1);
+ strcpy(ep->e_key, key);
+ ep->e_value = getbytes(strlen(value) + 1);
+ strcpy(ep->e_value, value);
+ ep->e_next = 0;
+ return (ep);
+}
+
+static void propelem_free(t_propelem *ep)
+{
+ if (ep->e_key) freebytes(ep->e_key, strlen(ep->e_key) + 1);
+ if (ep->e_value) freebytes(ep->e_value, strlen(ep->e_value) + 1);
+ freebytes(ep, sizeof(*ep));
+}
+
+/* Returns zero if the key was found (and value replaced),
+ nonzero if a new element was added. */
+static t_propelem *propelem_add(t_propelem *ep, char *key, char *value)
+{
+ while (ep)
+ {
+ if (strcmp(ep->e_key, key))
+ ep = ep->e_next;
+ else
+ break;
+ }
+ if (ep)
+ {
+ if (strcmp(ep->e_value, value))
+ {
+ if (ep->e_value)
+ ep->e_value = resizebytes(ep->e_value, strlen(ep->e_value) + 1,
+ strlen(value) + 1);
+ else
+ ep->e_value = getbytes(strlen(value) + 1);
+ strcpy(ep->e_value, value);
+ }
+ return (0);
+ }
+ else return (propelem_new(key, value));
+}
+
+static void props_dictadd(t_props *pp, t_symbol *s, int ac, t_atom *av)
+{
+ if (s && *s->s_name && s->s_name[1] && ac)
+ {
+ t_propelem *ep;
+ char *value = pp->p_resolver(pp->p_owner, ac, av);
+ if (value &&
+ (ep = propelem_add(pp->p_dict, s->s_name + 1, value)))
+ {
+ ep->e_next = pp->p_dict;
+ pp->p_dict = ep;
+ }
+ }
+}
+
+static int props_atstart(t_props *pp, char *buf)
+{
+ if (*buf == pp->p_thisescape)
+ {
+ char c = buf[1];
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
+ || (pp->p_thisinitial && strchr(pp->p_thisinitial, c)))
+ return (PROPS_THIS);
+ }
+ return (PROPS_NONE);
+}
+
+static char *props_otherinitial(t_props *pp, char c)
+{
+ t_props *pp1 = pp->p_otherprops;
+ while (pp1)
+ {
+ if (pp1 != pp && pp1->p_thisescape == c)
+ return (pp1->p_thisinitial);
+ pp1 = pp1->p_next;
+ }
+ bug("props_otherinitial");
+ post("(%c \"%s\")", c, pp->p_otherescapes);
+ return (0);
+}
+
+static int props_atnext(t_props *pp, char *buf)
+{
+ char *otherinitial;
+ if (*buf == pp->p_thisescape)
+ {
+ char c = buf[1];
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
+ || (pp->p_thisinitial && strchr(pp->p_thisinitial, c)))
+ return (PROPS_THIS);
+ }
+ else if (*pp->p_otherescapes && strchr(pp->p_otherescapes, *buf))
+ {
+ char c = buf[1];
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
+ || ((otherinitial = props_otherinitial(pp, *buf))
+ && *otherinitial && strchr(otherinitial, c)))
+ return (PROPS_OTHER);
+ }
+ return (PROPS_NONE);
+}
+
+/* Search for a property, replace its value if found, otherwise add.
+ Assuming s is valid. Returning nafter - nbefore. */
+static int props_update(t_props *pp, t_symbol *s, int ac, t_atom *av, int doit)
+{
+ int nadd, ndiff, ibeg, iend = 0;
+ t_atom *ap;
+ for (nadd = 0, ap = av; nadd < ac; nadd++, ap++)
+ if (ap->a_type == A_SYMBOL
+ && props_atnext(pp, ap->a_w.w_symbol->s_name))
+ break;
+ if (!nadd)
+ {
+ pp->p_badupdate = 1;
+ return (0);
+ }
+ pp->p_badupdate = 0;
+ nadd++;
+ for (ibeg = 0, ap = pp->p_buffer; ibeg < pp->p_natoms; ibeg++, ap++)
+ {
+ if (ap->a_type == A_SYMBOL && ap->a_w.w_symbol == s)
+ {
+ for (iend = ibeg + 1, ap++; iend < pp->p_natoms; iend++, ap++)
+ if (ap->a_type == A_SYMBOL
+ && props_atnext(pp, ap->a_w.w_symbol->s_name))
+ break;
+ break;
+ }
+ }
+ ndiff = (iend > ibeg ? nadd - (iend - ibeg) : nadd);
+ if (doit)
+ {
+ int i, newnatoms = pp->p_natoms + ndiff;
+ if (newnatoms > pp->p_size)
+ {
+ bug("props_update");
+ return (0);
+ }
+#ifdef PROPS_DEBUG
+ post("%s %s, [%d..%d), ndiff %d",
+ (iend > ibeg ? "replacing" : "adding"), s->s_name,
+ ibeg, iend, ndiff);
+#endif
+ if (iend > ibeg)
+ {
+ if (ndiff > 0)
+ {
+ t_atom *ap2 = pp->p_buffer + newnatoms;
+ t_atom *ap1 = ap2 - ndiff;
+ for (i = iend; i < pp->p_natoms; i++) *--ap2 = *--ap1;
+ }
+ else if (ndiff < 0)
+ {
+ t_atom *ap2 = pp->p_buffer + iend;
+ t_atom *ap1 = ap2 + ndiff;
+ for (i = iend; i < pp->p_natoms; i++) *ap1++ = *ap2++;
+ }
+ ap = pp->p_buffer + ibeg;
+ }
+ else
+ {
+ ap = pp->p_buffer + pp->p_natoms;
+ SETSYMBOL(ap, s);
+ }
+ ap++;
+ nadd--;
+ if (pp->p_resolver) props_dictadd(pp, s, nadd, av);
+ for (i = 0; i < nadd; i++) *ap++ = *av++;
+ pp->p_natoms = newnatoms;
+ }
+ return (ndiff);
+}
+
+/* If there is an empty property, do not parse beyond.
+ Return the offending switch, if any. */
+t_symbol *props_add(t_props *pp, t_symbol *s, int ac, t_atom *av)
+{
+ t_symbol *empty = 0;
+ t_atom *av1, *ap;
+ int ac1, i, ngrown = 0;
+ if (s && props_atstart(pp, s->s_name))
+ ngrown += props_update(pp, s, ac, av, 0);
+ if (pp->p_badupdate)
+ empty = s;
+ else for (i = 0, ap = av; i < ac; i++, ap++)
+ {
+ if (ap->a_type == A_SYMBOL
+ && props_atstart(pp, ap->a_w.w_symbol->s_name))
+ {
+ ngrown += props_update(pp, ap->a_w.w_symbol, ac - i - 1, ap + 1, 0);
+ if (pp->p_badupdate)
+ {
+ empty = ap->a_w.w_symbol;
+ break;
+ }
+ }
+ }
+ ngrown += pp->p_natoms;
+ if (ngrown > pp->p_size)
+ {
+ int nrequested = ngrown;
+ pp->p_buffer = grow_withdata(&nrequested, &pp->p_natoms,
+ &pp->p_size, pp->p_buffer,
+ PROPS_INISIZE, pp->p_bufini,
+ sizeof(*pp->p_buffer));
+ if (nrequested != ngrown)
+ goto done;
+ }
+ ac1 = (s ? ac + 1 : ac);
+ if (!(av1 = getbytes(ac1 * sizeof(*av1))))
+ goto done;
+ ap = av1;
+ if (s)
+ {
+ SETSYMBOL(ap, s);
+ ap++;
+ }
+ while (ac--) *ap++ = *av++;
+ ac = ac1;
+ av = av1;
+ for (i = 0, ap = av; i < ac; i++, ap++)
+ {
+ if (ap->a_type == A_SYMBOL
+ && props_atstart(pp, ap->a_w.w_symbol->s_name))
+ {
+ props_update(pp, ap->a_w.w_symbol, ac - i - 1, ap + 1, 1);
+ if (pp->p_badupdate)
+ {
+ empty = ap->a_w.w_symbol;
+ break;
+ }
+ }
+ }
+ freebytes(av1, ac1 * sizeof(*av1));
+done:
+ return (empty);
+}
+
+/* FIXME remove from p_dict */
+int props_remove(t_props *pp, t_symbol *s)
+{
+ int ac;
+ t_atom *av = props_getone(pp, s, &ac);
+ if (av)
+ {
+ int i;
+ t_atom *ap = av + ac;
+ t_atom *guard = pp->p_buffer + pp->p_natoms;
+ while (ap < guard) *av++ = *ap++;
+ pp->p_natoms -= ac;
+ return (1);
+ }
+ else return (0);
+}
+
+/* LATER think about 'deep' cloning, i.e. propagating source atoms into
+ the destination buffer. Since cloning, unless requested by the user,
+ should never be persistent (source atoms should not stick to the
+ destination object in a .pd file), deep cloning requires introducing
+ a two-buffer scheme. There is no reason for deep cloning of arguments,
+ or handlers, but options could benefit. */
+
+void props_clone(t_props *to, t_props *from)
+{
+ if (to->p_resolver)
+ {
+ /* LATER make this into a generic traversing method */
+ int ibeg = 0, iend = 0;
+ t_atom *abeg = from->p_buffer;
+ t_atom *ap = abeg;
+ while (ibeg < from->p_natoms)
+ {
+ if (ap->a_type == A_SYMBOL &&
+ props_atstart(from, ap->a_w.w_symbol->s_name))
+ {
+ for (iend = ibeg + 1, ap++; iend < from->p_natoms; iend++, ap++)
+ if (ap->a_type == A_SYMBOL
+ && props_atnext(from, ap->a_w.w_symbol->s_name))
+ break;
+ props_dictadd(to, abeg->a_w.w_symbol,
+ iend - ibeg - 1, abeg + 1);
+ if (iend < from->p_natoms)
+ {
+ ibeg = iend;
+ abeg = ap;
+ }
+ else break;
+ }
+ else
+ {
+ ibeg++;
+ ap++;
+ }
+ }
+ }
+ else
+ {
+ /* LATER */
+ }
+}
+
+/* only dictionary-enabled properties handle props_...value() calls */
+
+char *props_getvalue(t_props *pp, char *key)
+{
+ if (pp->p_resolver)
+ {
+ t_propelem *ep = pp->p_dict;
+ while (ep)
+ {
+ if (strcmp(ep->e_key, key))
+ ep = ep->e_next;
+ else
+ return (ep->e_value);
+ }
+ }
+ return (0);
+}
+
+char *props_nextvalue(t_props *pp, char **keyp)
+{
+ if (pp->p_nextelem)
+ {
+ char *value = pp->p_nextelem->e_value;
+ *keyp = pp->p_nextelem->e_key;
+ pp->p_nextelem = pp->p_nextelem->e_next;
+ return (value);
+ }
+ return (0);
+}
+
+char *props_firstvalue(t_props *pp, char **keyp)
+{
+ if (pp->p_resolver)
+ pp->p_nextelem = pp->p_dict;
+ return (props_nextvalue(pp, keyp));
+}
+
+t_atom *props_getone(t_props *pp, t_symbol *s, int *npp)
+{
+ int ibeg, iend = 0;
+ t_atom *ap;
+ if (!(s && props_atstart(pp, s->s_name)))
+ return (0);
+ for (ibeg = 0, ap = pp->p_buffer; ibeg < pp->p_natoms; ibeg++, ap++)
+ {
+ if (ap->a_type == A_SYMBOL && ap->a_w.w_symbol == s)
+ {
+ for (iend = ibeg + 1, ap++; iend < pp->p_natoms; iend++, ap++)
+ if (ap->a_type == A_SYMBOL
+ && props_atnext(pp, ap->a_w.w_symbol->s_name))
+ break;
+ break;
+ }
+ }
+ if (iend > ibeg)
+ {
+ *npp = iend - ibeg;
+ return (pp->p_buffer + ibeg);
+ }
+ else return (0);
+}
+
+t_atom *props_getall(t_props *pp, int *npp)
+{
+ *npp = pp->p_natoms;
+ return (pp->p_buffer);
+}
+
+char *props_getname(t_props *pp)
+{
+ return (pp ? pp->p_name : "property");
+}
+
+static void props_freeone(t_props *pp)
+{
+ if (pp->p_buffer != pp->p_bufini)
+ freebytes(pp->p_buffer, pp->p_size * sizeof(*pp->p_buffer));
+ while (pp->p_dict)
+ {
+ t_propelem *ep = pp->p_dict->e_next;
+ propelem_free(pp->p_dict);
+ pp->p_dict = ep;
+ }
+ freebytes(pp, sizeof(*pp));
+}
+
+void props_freeall(t_props *pp)
+{
+ if (pp && (pp = pp->p_otherprops))
+ {
+ while (pp)
+ {
+ t_props *pp1 = pp->p_next;
+ props_freeone(pp);
+ pp = pp1;
+ }
+ }
+ else bug("props_freeall");
+}
+
+void props_setupothers(t_props *pp, t_props *otherprops)
+{
+ t_props *pp1;
+ pp->p_next = (otherprops ? otherprops->p_otherprops : 0);
+ for (pp1 = pp; pp1; pp1 = pp1->p_next)
+ {
+ t_props *pp2;
+ char *bp = pp1->p_otherescapes;
+ int i;
+ pp1->p_otherprops = pp;
+ for (pp2 = pp, i = 1; pp2 && i < PROPS_MAXOTHERS;
+ pp2 = pp2->p_next, i++)
+ if (pp2 != pp1)
+ *bp++ = pp2->p_thisescape;
+ *bp = 0;
+#ifdef PROPS_DEBUG
+ startpost("%c \"%s\" ", pp1->p_thisescape, pp1->p_otherescapes);
+#endif
+ }
+#ifdef PROPS_DEBUG
+ endpost();
+#endif
+}
+
+/* nonzero resolver requires the owner to be nonzero */
+t_props *props_new(t_pd *owner, char *name, char *thisdelim,
+ t_props *otherprops, t_propsresolver resolver)
+{
+ t_props *pp = getbytes(sizeof(*pp));
+ if (pp)
+ {
+ pp->p_name = name;
+ if (thisdelim && *thisdelim)
+ {
+ pp->p_thisescape = *thisdelim++;
+ pp->p_thisinitial = (*thisdelim ? thisdelim : 0);
+ }
+ else
+ {
+ bug("props_new (no escape)");
+ pp->p_thisescape = '-';
+ pp->p_thisinitial = 0;
+ }
+ props_setupothers(pp, otherprops);
+ pp->p_size = PROPS_INISIZE;
+ pp->p_natoms = 0;
+ pp->p_buffer = pp->p_bufini;
+ if (pp->p_owner = owner)
+ pp->p_resolver = resolver;
+ else
+ {
+ if (resolver)
+ bug("props_new (no owner)");
+ pp->p_resolver = 0;
+ }
+ pp->p_dict = 0;
+ pp->p_nextelem = 0;
+ }
+ return (pp);
+}
diff --git a/shared/common/props.h b/shared/common/props.h
new file mode 100644
index 0000000..0eef345
--- /dev/null
+++ b/shared/common/props.h
@@ -0,0 +1,26 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __PROPS_H__
+#define __PROPS_H__
+
+EXTERN_STRUCT _props;
+#define t_props struct _props
+
+typedef char *(*t_propsresolver)(t_pd *, int, t_atom *);
+
+t_symbol *props_add(t_props *pp, t_symbol *s, int ac, t_atom *av);
+int props_remove(t_props *pp, t_symbol *s);
+void props_clone(t_props *to, t_props *from);
+char *props_getvalue(t_props *pp, char *key);
+char *props_firstvalue(t_props *pp, char **keyp);
+char *props_nextvalue(t_props *pp, char **keyp);
+t_atom *props_getone(t_props *pp, t_symbol *s, int *npp);
+t_atom *props_getall(t_props *pp, int *npp);
+char *props_getname(t_props *pp);
+void props_freeall(t_props *pp);
+t_props *props_new(t_pd *owner, char *name, char *thisdelim,
+ t_props *otherprops, t_propsresolver resolver);
+
+#endif
diff --git a/shared/toxy/Makefile b/shared/toxy/Makefile
new file mode 100644
index 0000000..5dcb2c8
--- /dev/null
+++ b/shared/toxy/Makefile
@@ -0,0 +1,4 @@
+ROOT_DIR = ../..
+include $(ROOT_DIR)/Makefile.common
+
+all: $(OBJECTS)
diff --git a/shared/toxy/Makefile.objects b/shared/toxy/Makefile.objects
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/shared/toxy/Makefile.objects
diff --git a/shared/toxy/Makefile.sources b/shared/toxy/Makefile.sources
new file mode 100644
index 0000000..5f34f42
--- /dev/null
+++ b/shared/toxy/Makefile.sources
@@ -0,0 +1,2 @@
+OTHER_SOURCES = \
+scriptlet.c
diff --git a/shared/toxy/scriptlet.c b/shared/toxy/scriptlet.c
new file mode 100644
index 0000000..2592cee
--- /dev/null
+++ b/shared/toxy/scriptlet.c
@@ -0,0 +1,666 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#ifdef NT
+#include <io.h>
+#endif
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "common/loud.h"
+#include "common/grow.h"
+#include "common/props.h"
+#include "scriptlet.h"
+
+//#define SCRIPTLET_DEBUG
+
+#define SCRIPTLET_INISIZE 1024
+#define SCRIPTLET_MARGIN 64
+#define SCRIPTLET_MAXARGS 9 /* do not increase (parser's constraint) */
+#define SCRIPTLET_MAXPUSH 20000 /* Tcl limit? LATER investigate */
+
+enum { SCRIPTLET_CVOK, SCRIPTLET_CVUNKNOWN, SCRIPTLET_CVMISSING };
+
+struct _scriptlet
+{
+ t_pd *s_owner;
+ t_glist *s_glist; /* containing glist (possibly null) */
+ t_symbol *s_rptarget; /* reply target */
+ t_symbol *s_cbtarget; /* callback target */
+ t_symbol *s_item;
+ t_scriptlet_cvfn s_cvfn;
+ t_canvas *s_cv;
+ int s_cvstate;
+ int s_size;
+ char *s_buffer;
+ char s_bufini[SCRIPTLET_INISIZE];
+ char *s_head; /* ptr to the command part of a scriptlet */
+ char *s_tail;
+ char s_separator; /* current separator, set before a new token */
+ int s_ac; /* the actual count */
+ t_atom s_av[SCRIPTLET_MAXARGS]; /* always padded with zeros (if used) */
+};
+
+static t_canvas *scriptlet_canvasvalidate(t_scriptlet *sp, int visedonly)
+{
+ t_canvas *cv;
+ if (sp->s_cvstate == SCRIPTLET_CVUNKNOWN)
+ {
+ if (sp->s_cvfn)
+ cv = sp->s_cv = sp->s_cvfn(sp->s_owner);
+ else
+ {
+ bug("scriptlet_canvasvalidate");
+ return (0);
+ }
+ if (cv && (!visedonly || glist_isvisible(cv)))
+ sp->s_cvstate = SCRIPTLET_CVOK;
+ else
+ sp->s_cvstate = SCRIPTLET_CVMISSING;
+ }
+ else cv = sp->s_cv;
+ return (sp->s_cvstate == SCRIPTLET_CVOK ? cv : 0);
+}
+
+static int scriptlet_ready(t_scriptlet *sp)
+{
+ int len = sp->s_tail - sp->s_head;
+ if (len > 0 && *sp->s_head && sp->s_cvstate != SCRIPTLET_CVMISSING)
+ {
+ if (len < SCRIPTLET_MAXPUSH)
+ return (1);
+ else
+ loud_error(sp->s_owner,
+ "scriptlet too long to be pushed (%d bytes)", len);
+ }
+ return (0);
+}
+
+static int scriptlet_doappend(t_scriptlet *sp, char *buf)
+{
+ if (buf)
+ {
+ int nprefix = sp->s_head - sp->s_buffer;
+ int nused = sp->s_tail - sp->s_buffer;
+ int newsize = nused + strlen(buf) + SCRIPTLET_MARGIN;
+ if (newsize > sp->s_size)
+ {
+ int nrequested = newsize;
+ sp->s_buffer = grow_withdata(&nrequested, &nused,
+ &sp->s_size, sp->s_buffer,
+ SCRIPTLET_INISIZE, sp->s_bufini,
+ sizeof(*sp->s_buffer));
+ if (nrequested != newsize)
+ {
+ scriptlet_reset(sp);
+ return (0);
+ }
+ sp->s_head = sp->s_buffer + nprefix;
+ sp->s_tail = sp->s_buffer + nused;
+ }
+ if (sp->s_separator && sp->s_tail > sp->s_head)
+ *sp->s_tail++ = sp->s_separator;
+ *sp->s_tail = 0;
+ strcpy(sp->s_tail, buf);
+ sp->s_tail += strlen(sp->s_tail);
+ }
+ sp->s_separator = 0;
+ return (1);
+}
+
+static char *scriptlet_dedot(t_scriptlet *sp, char *ibuf, char *obuf,
+ int resolveall, int visedonly,
+ int ac, t_atom *av, t_props *argprops)
+{
+ int len = 0;
+ switch (*ibuf)
+ {
+ case '#':
+ /* ac is ignored -- assuming av is padded to SCRIPTLET_MAXARGS atoms */
+ if (resolveall)
+ {
+ int which = ibuf[1] - '1';
+ if (which >= 0 && which < SCRIPTLET_MAXARGS)
+ {
+ if (av)
+ {
+ if (av[which].a_type == A_FLOAT)
+ {
+ sprintf(obuf, "%g", av[which].a_w.w_float);
+ len = 2;
+ }
+ else if (av[which].a_type == A_SYMBOL)
+ {
+ strcpy(obuf, av[which].a_w.w_symbol->s_name);
+ len = 2;
+ }
+ }
+ }
+ else if (argprops)
+ {
+ char *ptr;
+ int cnt;
+ for (ptr = ibuf + 1, cnt = 1; *ptr; ptr++, cnt++)
+ {
+ char c = *ptr;
+ if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z'))
+ {
+ cnt = 0;
+ break;
+ }
+ }
+ if (cnt && (ptr = props_getvalue(argprops, ibuf + 1)))
+ {
+ strcpy(obuf, ptr);
+ len = cnt;
+ }
+ }
+ }
+ break;
+ case '-':
+ if (resolveall && sp->s_item)
+ {
+ t_canvas *cv;
+ if (cv = scriptlet_canvasvalidate(sp, visedonly))
+ {
+ sprintf(obuf, ".x%x.c.%s%x", (int)cv, sp->s_item->s_name,
+ (int)sp->s_owner);
+ len = 1;
+ }
+ }
+ break;
+ case '^':
+ if (resolveall)
+ {
+ t_canvas *cv;
+ if (cv = scriptlet_canvasvalidate(sp, visedonly))
+ {
+ sprintf(obuf, ".x%x", (int)cv);
+ len = 1;
+ }
+ }
+ break;
+ case '|':
+ if (resolveall)
+ {
+ strcpy(obuf, sp->s_cbtarget->s_name);
+ len = 1;
+ }
+ break;
+ case '~':
+ if (resolveall)
+ {
+ t_canvas *cv;
+ if (cv = scriptlet_canvasvalidate(sp, visedonly))
+ {
+ /* FIXME */
+ if (!strcmp(&ibuf[1], "x1"))
+ {
+ sprintf(obuf, "%d", cv->gl_screenx1);
+ len = 3;
+ }
+ else if (!strcmp(&ibuf[1], "x2"))
+ {
+ sprintf(obuf, "%d", cv->gl_screenx2);
+ len = 3;
+ }
+ else if (!strcmp(&ibuf[1], "y1"))
+ {
+ sprintf(obuf, "%d", cv->gl_screeny1);
+ len = 3;
+ }
+ else if (!strcmp(&ibuf[1], "y2"))
+ {
+ sprintf(obuf, "%d", cv->gl_screeny2);
+ len = 3;
+ }
+ else if (!strcmp(&ibuf[1], "edit"))
+ {
+ sprintf(obuf, "%d", cv->gl_edit);
+ len = 5;
+ }
+ else loud_error(sp->s_owner, "bad field '%s'", &ibuf[1]);
+ }
+ }
+ break;
+ case '`':
+ sprintf(obuf, "\\");
+ len = 1;
+ break;
+ case ':':
+ sprintf(obuf, ";");
+ len = 1;
+ break;
+ case '(':
+ sprintf(obuf, "{");
+ len = 1;
+ break;
+ case ')':
+ sprintf(obuf, "}");
+ len = 1;
+ break;
+ case '<':
+ if (resolveall)
+ {
+ if (ibuf[1] == ':')
+ {
+ sprintf(obuf, "{::toxy::callback ");
+ len = 2;
+ }
+ else if (ibuf[1] == '|')
+ {
+ sprintf(obuf, "{::toxy::callback %s ",
+ sp->s_rptarget->s_name);
+ len = 2;
+ }
+ else
+ {
+ sprintf(obuf, "{::toxy::callback %s _cb ",
+ sp->s_cbtarget->s_name);
+ len = 1;
+ }
+ }
+ break;
+ case '>':
+ if (resolveall)
+ {
+ sprintf(obuf, "}");
+ len = 1;
+ }
+ break;
+ }
+ return (len ? ibuf + len : 0);
+}
+
+void scriptlet_reset(t_scriptlet *sp)
+{
+ sp->s_cvstate = SCRIPTLET_CVUNKNOWN;
+ sp->s_separator = 0;
+ strcpy(sp->s_buffer, "namespace eval ::toxy {\
+ proc query {} {set ::toxy::reply [\n");
+ sp->s_head = sp->s_tail = sp->s_buffer + strlen(sp->s_buffer);
+}
+
+void scriptlet_prealloc(t_scriptlet *sp, int sz, int mayshrink)
+{
+ if (sz < SCRIPTLET_INISIZE)
+ sz = SCRIPTLET_INISIZE;
+ if (sz < sp->s_size && mayshrink)
+ {
+ if (sp->s_buffer != sp->s_bufini)
+ freebytes(sp->s_buffer, sp->s_size * sizeof(*sp->s_buffer));
+ else
+ bug("scriptlet_prealloc");
+ sp->s_size = SCRIPTLET_INISIZE;
+ sp->s_buffer = sp->s_bufini;
+ }
+ if (sz > sp->s_size)
+ sp->s_buffer = grow_nodata(&sz, &sp->s_size, sp->s_buffer,
+ SCRIPTLET_INISIZE, sp->s_bufini,
+ sizeof(*sp->s_buffer));
+ scriptlet_reset(sp);
+}
+
+int scriptlet_addstring(t_scriptlet *sp, char *ibuf,
+ int resolveall, int visedonly,
+ int ac, t_atom *av, t_props *argprops)
+{
+ int result = 1;
+ char *bp = ibuf, *ep = ibuf, *ep1;
+ char dotbuf[64]; /* LATER reestimation */
+ if (!sp->s_separator)
+ sp->s_separator = ' ';
+ while (*ep)
+ {
+ if (*ep == '.'
+ && (ep1 = scriptlet_dedot(sp, ep + 1, dotbuf,
+ resolveall, visedonly, ac, av, argprops)))
+ {
+ *ep = 0;
+ if (!(result = scriptlet_doappend(sp, bp)))
+ break;
+ *ep = '.';
+ if (!(result = scriptlet_doappend(sp, dotbuf)))
+ break;
+ bp = ep = ep1;
+ }
+ else ep++;
+ }
+ if (result)
+ result = scriptlet_doappend(sp, bp);
+ sp->s_separator = 0;
+ return (result);
+}
+
+int scriptlet_addfloat(t_scriptlet *sp, t_float f)
+{
+ char buf[64];
+ if (!sp->s_separator)
+ sp->s_separator = ' ';
+ sprintf(buf, "%g ", f);
+ return (scriptlet_doappend(sp, buf));
+}
+
+int scriptlet_add(t_scriptlet *sp,
+ int resolveall, int visedonly, int ac, t_atom *av)
+{
+ while (ac--)
+ {
+ int result = 1;
+ if (av->a_type == A_SYMBOL)
+ result = scriptlet_addstring(sp, av->a_w.w_symbol->s_name,
+ resolveall, visedonly, 0, 0, 0);
+ else if (av->a_type == A_FLOAT)
+ result = scriptlet_addfloat(sp, av->a_w.w_float);
+ if (!result)
+ return (0);
+ av++;
+ }
+ return (1);
+}
+
+void scriptlet_setseparator(t_scriptlet *sp, char c)
+{
+ sp->s_separator = c;
+}
+
+void scriptlet_push(t_scriptlet *sp)
+{
+ if (scriptlet_ready(sp))
+ {
+ char *tail = sp->s_tail;
+ strcpy(tail, "\n");
+ sys_gui(sp->s_head);
+ *tail = 0;
+ }
+}
+
+void scriptlet_qpush(t_scriptlet *sp)
+{
+ if (scriptlet_ready(sp))
+ {
+ char buf[MAXPDSTRING];
+ char *tail = sp->s_tail;
+ strcpy(tail, "]}}\n");
+ sys_gui(sp->s_buffer);
+ *tail = 0;
+ sprintf(buf, "after 0 {::toxy::query}\nvwait ::toxy::reply\n\
+ pd [concat %s _rp $::toxy::reply \\;]\n", sp->s_rptarget->s_name);
+ sys_gui(buf);
+ }
+}
+
+int scriptlet_evaluate(t_scriptlet *insp, t_scriptlet *outsp,
+ int visedonly, int ac, t_atom *av, t_props *argprops)
+{
+ if (scriptlet_ready(insp))
+ {
+ t_atom *ap;
+ int i;
+ char *bp;
+ char separator = 0;
+ insp->s_ac = ac;
+ for (i = 0, ap = insp->s_av; i < SCRIPTLET_MAXARGS; i++, ap++)
+ {
+ if (ac)
+ {
+ if (av->a_type == A_FLOAT ||
+ (av->a_type == A_SYMBOL && av->a_w.w_symbol))
+ *ap = *av;
+ else
+ SETFLOAT(ap, 0);
+ ac--; av++;
+ }
+ else SETFLOAT(ap, 0);
+ }
+ /* FIXME pregrowing of the transient scriptlet */
+ scriptlet_reset(outsp);
+ /* LATER abstract this into scriptlet_parse() */
+ bp = insp->s_head;
+ while (*bp)
+ {
+ if (*bp == '\n')
+ separator = '\n';
+ else if (*bp == ' ' || *bp == '\t')
+ {
+ if (!separator) separator = ' ';
+ }
+ else
+ {
+ int done = 1;
+ char *ep = bp;
+ char c = ' ';
+ while (*++ep)
+ {
+ if (*ep == ' ' || *bp == '\t' || *ep == '\n')
+ {
+ done = 0;
+ c = *ep;
+ *ep = 0;
+ break;
+ }
+ }
+ outsp->s_separator = separator;
+ scriptlet_addstring(outsp, bp, 1, visedonly,
+ ac, insp->s_av, argprops);
+ if (done)
+ break;
+ *ep = c;
+ bp = ep;
+ separator = (c == '\t' ? ' ' : c);
+ }
+ bp++;
+ }
+ return (outsp->s_cvstate != SCRIPTLET_CVMISSING);
+ }
+ else return (0);
+}
+
+/* utility function to be used in a comment-parsing callback */
+char *scriptlet_nextword(char *buf)
+{
+ while (*++buf)
+ {
+ if (*buf == ' ' || *buf == '\t')
+ {
+ char *ptr = buf + 1;
+ while (*ptr == ' ' || *ptr == '\t') ptr++;
+ *buf = 0;
+ return (*ptr ? ptr : 0);
+ }
+ }
+ return (0);
+}
+
+static int scriptlet_doread(t_scriptlet *sp, FILE *fp, char *rc,
+ t_scriptlet_cmntfn cmntfn)
+{
+ t_scriptlet *outsp = sp, *newsp;
+ char buf[MAXPDSTRING];
+ scriptlet_reset(outsp);
+ while (!feof(fp))
+ {
+ if (fgets(buf, MAXPDSTRING - 1, fp))
+ {
+ char *ptr = buf;
+ while (*ptr == ' ' || *ptr == '\t') ptr++;
+ if (*ptr == '#')
+ {
+ if (cmntfn)
+ {
+ char sel = *++ptr;
+ if (sel && sel != '\n')
+ {
+ ptr++;
+ while (*ptr == ' ' || *ptr == '\t') ptr++;
+ if (*ptr == '\n')
+ *ptr = 0;
+ if (*ptr)
+ {
+ char *ep = ptr + strlen(ptr) - 1;
+ while (*ep == ' ' || *ep == '\t' || *ep == '\n')
+ ep--;
+ ep[1] = 0;
+ }
+ newsp = cmntfn(sp->s_owner, rc, sel, ptr);
+ if (newsp && newsp != outsp)
+ scriptlet_reset(outsp = newsp);
+ }
+ }
+ }
+ else if (*ptr && *ptr != '\n')
+ scriptlet_doappend(outsp, buf);
+ }
+ else break;
+ }
+ return (SCRIPTLET_OK);
+}
+
+int scriptlet_rcload(t_scriptlet *sp, char *rc, char *ext,
+ t_scriptlet_cmntfn cmntfn)
+{
+ char filename[MAXPDSTRING], buf[MAXPDSTRING], *nameptr, *dir;
+ int fd;
+ if (sp->s_glist)
+ dir = canvas_getdir(sp->s_glist)->s_name;
+ else
+ dir = "";
+ if ((fd = open_via_path(dir, rc, ext, buf, &nameptr, MAXPDSTRING, 0)) < 0)
+ {
+ return (SCRIPTLET_NOFILE);
+ }
+ else
+ {
+ FILE *fp;
+ close(fd);
+ strcpy(filename, buf);
+ strcat(filename, "/");
+ strcat(filename, nameptr);
+ sys_bashfilename(filename, filename);
+ if (fp = fopen(filename, "r"))
+ {
+ int result = scriptlet_doread(sp, fp, rc, cmntfn);
+ fclose(fp);
+ return (result);
+ }
+ else
+ {
+ bug("scriptlet_rcload");
+ return (SCRIPTLET_NOFILE);
+ }
+ }
+}
+
+int scriptlet_read(t_scriptlet *sp, t_symbol *fn)
+{
+ FILE *fp;
+ char buf[MAXPDSTRING];
+ post("loading scriptlet file \"%s\"", fn->s_name);
+ if (sp->s_glist)
+ canvas_makefilename(sp->s_glist, fn->s_name, buf, MAXPDSTRING);
+ else
+ strncpy(buf, fn->s_name, MAXPDSTRING);
+ sys_bashfilename(buf, buf);
+ if (fp = fopen(buf, "r"))
+ {
+ int result = scriptlet_doread(sp, fp, 0, 0);
+ fclose(fp);
+ return (result);
+ }
+ else
+ {
+ loud_error(sp->s_owner, "error while loading file \"%s\"", fn->s_name);
+ return (SCRIPTLET_NOFILE);
+ }
+}
+
+int scriptlet_write(t_scriptlet *sp, t_symbol *fn)
+{
+ int size = sp->s_tail - sp->s_head;
+ if (size > 0 && *sp->s_head)
+ {
+ FILE *fp;
+ char buf[MAXPDSTRING];
+ post("saving scriptlet file \"%s\"", fn->s_name);
+ if (sp->s_glist)
+ canvas_makefilename(sp->s_glist, fn->s_name, buf, MAXPDSTRING);
+ else
+ strncpy(buf, fn->s_name, MAXPDSTRING);
+ sys_bashfilename(buf, buf);
+ if (fp = fopen(buf, "w"))
+ {
+ int result = fwrite(sp->s_head, 1, size, fp);
+ fclose(fp);
+ if (result == size)
+ return (SCRIPTLET_OK);
+ }
+ loud_error(sp->s_owner, "error while saving file \"%s\"", fn->s_name);
+ return (fp ? SCRIPTLET_BADFILE : SCRIPTLET_NOFILE);
+ }
+ else
+ {
+ loud_warning(sp->s_owner, "empty scriptlet not written");
+ return (SCRIPTLET_IGNORED);
+ }
+}
+
+char *scriptlet_getcontents(t_scriptlet *sp, int *lenp)
+{
+ *lenp = sp->s_tail - sp->s_head;
+ return (sp->s_head);
+}
+
+char *scriptlet_getbuffer(t_scriptlet *sp, int *sizep)
+{
+ *sizep = sp->s_size;
+ return (sp->s_buffer);
+}
+
+void scriptlet_clone(t_scriptlet *to, t_scriptlet *from)
+{
+ scriptlet_reset(to);
+ to->s_separator = ' ';
+ /* LATER use from's buffer with refcount */
+ scriptlet_doappend(to, from->s_head);
+}
+
+void scriptlet_free(t_scriptlet *sp)
+{
+ if (sp)
+ {
+ if (sp->s_buffer != sp->s_bufini)
+ freebytes(sp->s_buffer, sp->s_size * sizeof(*sp->s_buffer));
+ freebytes(sp, sizeof(*sp));
+ }
+}
+
+t_scriptlet *scriptlet_new(t_pd *owner, t_symbol *rptarget, t_symbol *cbtarget,
+ t_symbol *item, t_scriptlet_cvfn cvfn)
+{
+ t_scriptlet *sp = getbytes(sizeof(*sp));
+ if (sp)
+ {
+ static int configured = 0;
+ if (!configured)
+ {
+ sys_gui("namespace eval ::toxy {\
+ proc callback {args} {pd $args \\;}}\n");
+ sys_gui("image create bitmap ::toxy::img::empty -data {}\n");
+ }
+ sp->s_owner = owner;
+ sp->s_glist = canvas_getcurrent();
+ sp->s_rptarget = rptarget;
+ sp->s_cbtarget = cbtarget;
+ sp->s_item = item;
+ sp->s_cvfn = cvfn;
+ sp->s_size = SCRIPTLET_INISIZE;
+ sp->s_buffer = sp->s_bufini;
+ scriptlet_reset(sp);
+ }
+ return (sp);
+}
diff --git a/shared/toxy/scriptlet.h b/shared/toxy/scriptlet.h
new file mode 100644
index 0000000..4b057b9
--- /dev/null
+++ b/shared/toxy/scriptlet.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __SCRIPTLET_H__
+#define __SCRIPTLET_H__
+
+enum { SCRIPTLET_OK = 0, SCRIPTLET_NOFILE, SCRIPTLET_BADFILE,
+ SCRIPTLET_IGNORED };
+
+EXTERN_STRUCT _scriptlet;
+#define t_scriptlet struct _scriptlet
+
+typedef t_canvas *(*t_scriptlet_cvfn)(t_pd *);
+typedef t_scriptlet *(*t_scriptlet_cmntfn)(t_pd *, char *, char, char *);
+
+void scriptlet_reset(t_scriptlet *sp);
+void scriptlet_prealloc(t_scriptlet *sp, int sz, int mayshrink);
+int scriptlet_add(t_scriptlet *sp,
+ int resolveall, int visedonly, int ac, t_atom *av);
+int scriptlet_addstring(t_scriptlet *sp, char *ibuf,
+ int resolveall, int visedonly,
+ int ac, t_atom *av, t_props *argprops);
+int scriptlet_addfloat(t_scriptlet *sp, t_float f);
+void scriptlet_setseparator(t_scriptlet *sp, char c);
+void scriptlet_push(t_scriptlet *sp);
+void scriptlet_qpush(t_scriptlet *sp);
+int scriptlet_evaluate(t_scriptlet *insp, t_scriptlet *outsp,
+ int visedonly, int ac, t_atom *av, t_props *argprops);
+char *scriptlet_nextword(char *buf);
+int scriptlet_rcload(t_scriptlet *sp, char *rc, char *ext,
+ t_scriptlet_cmntfn cmntfn);
+int scriptlet_read(t_scriptlet *sp, t_symbol *fn);
+int scriptlet_write(t_scriptlet *sp, t_symbol *fn);
+char *scriptlet_getcontents(t_scriptlet *sp, int *lenp);
+char *scriptlet_getbuffer(t_scriptlet *sp, int *sizep);
+void scriptlet_clone(t_scriptlet *to, t_scriptlet *from);
+void scriptlet_free(t_scriptlet *sp);
+t_scriptlet *scriptlet_new(t_pd *owner, t_symbol *rptarget, t_symbol *cbtarget,
+ t_symbol *item, t_scriptlet_cvfn cvfn);
+
+#endif
diff --git a/test/toxy/button-test.pd b/test/toxy/button-test.pd
new file mode 100644
index 0000000..1f553dd
--- /dev/null
+++ b/test/toxy/button-test.pd
@@ -0,0 +1,37 @@
+#N canvas 106 44 636 366 12;
+#X obj 21 259 widget button b -bg red -activebackground yellow -text
+red -command .<.>;
+#X msg 130 162 -command .<.>;
+#X msg 48 295 debug;
+#X obj 21 324 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 193 268 r t1;
+#X obj 193 324 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 45 74 -bg pink -text pink;
+#X msg 21 21 -bg red -text red;
+#X msg 34 47 -bg green -text green;
+#X msg 56 101 -bg gray -text "";
+#X msg 62 132 -activebackground \$1;
+#X msg 250 74 query tk_chooseColor;
+#X obj 250 101 tot .;
+#X msg 166 187 -command .<:t1 bang.>;
+#X msg 90 213 -command .(set c [tk_chooseColor] .: eval .<| "-bg" $c
+"-text" $c.>.);
+#X msg 68 186 -width \$1;
+#X floatatom 68 162 5 0 0 0 - - -;
+#X connect 0 0 3 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 4 0 5 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
+#X connect 11 0 12 0;
+#X connect 12 0 10 0;
+#X connect 13 0 0 0;
+#X connect 14 0 0 0;
+#X connect 15 0 0 0;
+#X connect 16 0 15 0;
diff --git a/test/toxy/default.wid b/test/toxy/default.wid
new file mode 100644
index 0000000..e9a20a1
--- /dev/null
+++ b/test/toxy/default.wid
@@ -0,0 +1,108 @@
+# first the setup stuff (is this the right place for it?)
+
+# LATER ask for adding something of the sort to pd.tk:
+bind Canvas <1> {+focus %W}
+
+proc ::toxy::popup {path target remote entries args} {
+ eval {menu $path.pop} $args
+ set i 1
+ foreach e $entries {
+ $path.pop add command -label [lindex $e 0] \
+ -command [concat ::toxy::callback $target \
+ -text [lindex $e [expr {[llength $e] > 1}]] \; \
+ ::toxy::callback $remote $i]
+ incr i
+ }
+}
+
+proc ::toxy::kb {path target remote noctaves size} {
+ set lft [expr {round(5 * $size)}]
+ set top [expr {5 * $size}]
+ set bot [expr {100 * $size}]
+ set dx [expr {round(17 * $size)}]
+ set wid [expr {$dx - $size * .5}]
+ set blbot [expr {$bot * .65}]
+
+ $path config -height [expr {$bot + $top}] \
+ -width [expr {$dx * ($noctaves * 7 + 1) + $lft * 2 - 1}]
+
+ for {set octave 0} {$octave <= $noctaves} {incr octave} {
+ set prevkey 0
+ foreach key {0 2 4 5 7 9 11} {
+ set ndx [expr $octave * 12 + $key]
+ set id [$path create rect $lft $top \
+ [expr {$lft + $wid}] $bot -fill white -tags $path.$ndx]
+ $path bind $id <1> [concat ::toxy::kbset \
+ $path $target $remote $ndx]
+ if {$key - $prevkey > 1} {
+ incr ndx -1
+ set x [expr {$lft - $wid * .22}]
+ set id [$path create rect $x $top [expr {$x + $wid * .44}] \
+ $blbot -fill black -tags $path.$ndx]
+ $path bind $id <1> [concat ::toxy::kbset \
+ $path $target $remote $ndx]
+ }
+ set prevkey $key
+ incr lft $dx
+ if {$octave == $noctaves && $key == 0} break
+ }
+ }
+ set ::toxy::kbval($target) 0
+ set ::toxy::kbcol($target) white
+ $path itemconfig $path.0 -fill grey
+}
+
+proc ::toxy::kbout {path target remote} {
+ ::toxy::callback $target _cb $::toxy::kbval($target)
+ if {$remote != "."} {::toxy::callback $remote $::toxy::kbval($target)}
+}
+
+proc ::toxy::kbset {path target remote value} {
+ $path itemconfig $path.$::toxy::kbval($target) \
+ -fill $::toxy::kbcol($target)
+ set ::toxy::kbval($target) $value
+ set ::toxy::kbcol($target) [lindex [$path itemconfig $path.$value -fill] 4]
+ $path itemconfig $path.$value -fill grey
+ ::toxy::kbout $path $target $remote
+}
+
+# the default initializer
+#> default
+
+# pdtk_canvas_mouseup is a hack, which we must call anyway
+bind .- <ButtonRelease> {
+ eval .<|_inout 1.>
+ pdtk_canvas_mouseup .^.c [expr %x + [winfo x %W]] [expr %y + [winfo y %W]] %b
+}
+
+bind .- <1> .<|_click %x %y %b 0.>
+bind .- <3> .<|_click %x %y %b 8.>
+bind .- <Motion> .<|_motion %x %y.>
+bind .- <Enter> .<|_inout 1.>
+bind .- <Leave> .<|_inout 0.>
+
+#> bang button
+#. -image ::toxy::img::empty -command .<.>
+#. -bg pink -activebackground red -width 50 -height 50
+#. @bang .- flash .: .- invoke
+
+#> float scale
+#. -command .<.> -bg pink -activebackground red -length 200
+#. @float .- set .#1
+
+#> symbol entry
+#. -bg pink -font .(helvetica 24.) -width 16
+#. @symbol .- delete 0 end .: .- insert 0 .#1
+
+bind .- <Return> {eval .<[.- get].>; focus .^.c}
+
+#> kb canvas
+#. -bg yellow -cursor hand1
+#. #oct 4 #size .75
+#. @bang ::toxy::kbout .- .| .
+#. @float ::toxy::kbset .- .| . .#1
+
+::toxy::kb .- .| . .#oct .#size
+
+# undo the "bind Canvas <1> {+focus %W}" in the setup part above
+bind .- <FocusIn> {focus .^.c}
diff --git a/test/toxy/defaults-test.pd b/test/toxy/defaults-test.pd
new file mode 100644
index 0000000..c0c5aaf
--- /dev/null
+++ b/test/toxy/defaults-test.pd
@@ -0,0 +1,25 @@
+#N canvas 281 172 504 371 12;
+#X obj 247 89 widget bang b;
+#X obj 33 89 widget float f;
+#X obj 124 247 widget symbol s;
+#X floatatom 33 325 5 0 0 0 - - -;
+#X obj 247 175 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 124 325 print;
+#X msg 33 20 debug;
+#X msg 247 20 bang;
+#X msg 307 55 remove @bang;
+#X msg 307 20 @bang .- invoke;
+#X floatatom 121 20 5 0 0 0 - - -;
+#X msg 124 206 symbol test;
+#X connect 0 0 4 0;
+#X connect 1 0 3 0;
+#X connect 2 0 5 0;
+#X connect 6 0 0 0;
+#X connect 6 0 1 0;
+#X connect 6 0 2 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 1 0;
+#X connect 11 0 2 0;
diff --git a/test/toxy/kb-test.pd b/test/toxy/kb-test.pd
new file mode 100644
index 0000000..2978dce
--- /dev/null
+++ b/test/toxy/kb-test.pd
@@ -0,0 +1,17 @@
+#N canvas 354 116 645 486 12;
+#X obj 37 61 widget kb k1;
+#X floatatom 37 160 5 0 0 0 - - -;
+#X obj 37 310 widget kb k2 #oct 8 #size 0.35 -bg red;
+#X floatatom 37 369 5 0 0 0 - - -;
+#X msg 120 271 #oct \$1 \, refresh;
+#X floatatom 120 237 5 0 0 0 - - -;
+#X floatatom 37 24 5 0 0 0 - - -;
+#X msg 114 24 bang;
+#X floatatom 37 237 5 0 0 0 - - -;
+#X connect 0 0 1 0;
+#X connect 2 0 3 0;
+#X connect 4 0 2 0;
+#X connect 5 0 4 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 2 0;
diff --git a/test/toxy/listbox-test.pd b/test/toxy/listbox-test.pd
new file mode 100644
index 0000000..cd1fa46
--- /dev/null
+++ b/test/toxy/listbox-test.pd
@@ -0,0 +1,18 @@
+#N canvas 154 52 626 383 12;
+#X obj 281 144 widget listbox lb -width 32 -height 12 -bg black -fg
+white;
+#X obj 20 282 tow . listbox lb;
+#X obj 20 21 loadbang;
+#X msg 20 52 ini foreach fn [lsort [glob *]] .(.- insert end $fn.)
+;
+#X obj 236 143 widget button b -text ok -height 14 -bg black -fg white
+-command .<.>;
+#X obj 112 21 tow . button b;
+#X msg 36 83 tot if .([.- curselection] != "".) .(eval .<set [.- get
+[.- curselection]].>.);
+#X msg 20 324;
+#X connect 1 0 7 0;
+#X connect 2 0 3 0;
+#X connect 3 0 1 0;
+#X connect 5 0 6 0;
+#X connect 6 0 1 0;
diff --git a/test/toxy/pop1.wid b/test/toxy/pop1.wid
new file mode 100644
index 0000000..88b6595
--- /dev/null
+++ b/test/toxy/pop1.wid
@@ -0,0 +1,10 @@
+#> pop1 menubutton
+#. -menu .-.pop
+#. -bg purple -fg white -activebackground magenta -width 8 -text jeden
+#. @float if .(.#1 >= 1.) .(.-.pop invoke .#1.)
+
+::toxy::popup .- .| rpop1 \
+ [list {one jeden} {two dwa} {three trzy} \
+ {four cztery} {five piêæ} {six sze¶æ} {seven siedem} \
+ {eight osiem} {nine dziewiêæ} {ten dziesiêæ}] \
+ -bg purple -fg white -activebackground magenta
diff --git a/test/toxy/pop2.wid b/test/toxy/pop2.wid
new file mode 100644
index 0000000..8f7ccf5
--- /dev/null
+++ b/test/toxy/pop2.wid
@@ -0,0 +1,8 @@
+#> pop2 menubutton
+#. -menu .-.pop
+#. -bg purple -fg white -activebackground magenta -width 6 -text kura
+#. @float if .(.#1 >= 1.) .(.-.pop invoke .#1.)
+
+::toxy::popup .- .| rpop2 \
+ [list {hen kura} {duck kaczka} {cat kot} {cow krowa} {horse koñ}] \
+ -bg purple -fg white -activebackground magenta
diff --git a/test/toxy/popup-test.pd b/test/toxy/popup-test.pd
new file mode 100644
index 0000000..7f49162
--- /dev/null
+++ b/test/toxy/popup-test.pd
@@ -0,0 +1,39 @@
+#N canvas 356 9 338 241 12;
+#X obj 38 104 r rpop;
+#X floatatom 38 142 5 0 0 0 - - -;
+#X floatatom 120 142 5 0 0 0 - - -;
+#X obj 120 104 r rpop1;
+#X floatatom 210 142 5 0 0 0 - - -;
+#X obj 210 104 r rpop2;
+#N canvas 12 11 293 279 blackpanel 1;
+#X obj 23 111 widget menubutton mb -menu .-.pop -bg green -activebackground
+yellow -width 5 -text one @float if .(.#1 >= 1.) .(.-.pop invoke .#1.)
+;
+#X obj 23 12 loadbang;
+#X obj 96 110 widget pop1 p1;
+#X obj 188 110 widget pop2 p2;
+#X msg 23 41 ini ::toxy::popup .- .| rpop [list one two three four five]
+-bg green -activebackground yellow .: destroy .^.m .: .^.scrollvert
+configure -width 0 .: .^.scrollhort configure -width 0 .: .^.c configure
+-bg black;
+#X obj 23 150 r topop;
+#X obj 96 150 r topop1;
+#X obj 188 150 r topop2;
+#X connect 1 0 4 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 2 0;
+#X connect 7 0 3 0;
+#X restore 95 198 pd blackpanel;
+#X floatatom 38 24 5 0 0 0 - - -;
+#X floatatom 120 24 5 0 0 0 - - -;
+#X floatatom 210 24 5 0 0 0 - - -;
+#X obj 38 58 s topop;
+#X obj 120 58 s topop1;
+#X obj 210 58 s topop2;
+#X connect 0 0 1 0;
+#X connect 3 0 2 0;
+#X connect 5 0 4 0;
+#X connect 7 0 10 0;
+#X connect 8 0 11 0;
+#X connect 9 0 12 0;
diff --git a/test/toxy/radio-test.pd b/test/toxy/radio-test.pd
new file mode 100644
index 0000000..24e1a3b
--- /dev/null
+++ b/test/toxy/radio-test.pd
@@ -0,0 +1,50 @@
+#N canvas 179 90 559 300 12;
+#X obj 20 158 widget radiobutton r -variable ::toxy::r -value 0 -command
+.<:common $::toxy::r.> -bg orange -activebackground magenta -width
+44 -height 44 -indicatoron off -image ::toxy::img::empty;
+#X obj 70 158 widget radiobutton r -variable ::toxy::r -value 1 -command
+.<:common $::toxy::r.> -bg orange -activebackground magenta -width
+44 -height 44 -indicatoron off -image ::toxy::img::empty;
+#X obj 120 158 widget radiobutton r -variable ::toxy::r -value 2 -command
+.<:common $::toxy::r.> -bg orange -activebackground magenta -width
+44 -height 44 -indicatoron off -image ::toxy::img::empty;
+#X obj 170 158 widget radiobutton r -variable ::toxy::r -value 3 -command
+.<:common $::toxy::r.> -bg orange -activebackground magenta -width
+44 -height 44 -indicatoron off -image ::toxy::img::empty;
+#X obj 20 221 r t0;
+#X obj 70 221 r t1;
+#X obj 120 221 r t2;
+#X obj 170 221 r t3;
+#X obj 261 260 hradio 15 1 0 4 empty empty empty 0 -6 0 8 -262144 -1
+-1 0;
+#X obj 20 127 t a;
+#X obj 20 260 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 70 260 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 120 260 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 170 260 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 261 222 r common;
+#X msg 20 15 -command .<:common $::toxy::r.>;
+#X msg 31 46 -command .<:[join [list t $::toxy::r] ""] $::toxy::r.>
+;
+#X obj 366 260 hradio 15 1 0 4 empty empty empty 0 -6 0 8 -262144 -1
+-1 0;
+#X connect 4 0 10 0;
+#X connect 4 0 8 0;
+#X connect 5 0 11 0;
+#X connect 5 0 8 0;
+#X connect 6 0 12 0;
+#X connect 6 0 8 0;
+#X connect 7 0 13 0;
+#X connect 7 0 8 0;
+#X connect 9 0 0 0;
+#X connect 9 0 1 0;
+#X connect 9 0 2 0;
+#X connect 9 0 3 0;
+#X connect 14 0 8 0;
+#X connect 14 0 17 0;
+#X connect 15 0 9 0;
+#X connect 16 0 9 0;
diff --git a/test/toxy/scale-test.pd b/test/toxy/scale-test.pd
new file mode 100644
index 0000000..e35a4a2
--- /dev/null
+++ b/test/toxy/scale-test.pd
@@ -0,0 +1,44 @@
+#N canvas 79 51 599 397 12;
+#X obj 22 197 widget scale s -command .<.> -variable ::toxy::simplescale
+-label "Simple Scale" -orient h -length 300 -width 50 -font "Helvetica
+12" -from -16 -to 16 -showvalue 0 @float .- set .#1;
+#X floatatom 22 336 5 0 0 0 - - -;
+#X floatatom 191 128 5 0 0 0 - - -;
+#X msg 191 159 -from \$1;
+#X floatatom 287 128 5 0 0 0 - - -;
+#X msg 287 159 -to \$1;
+#X msg 44 159 -showvalue \$1;
+#X obj 44 133 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 214 336 5 0 0 0 - - -;
+#X msg 36 102 -command .<.>;
+#X obj 214 306 r \$0-scale;
+#X msg 22 70 -command .<: \$1-scale .>;
+#X obj 22 10 loadbang;
+#X obj 22 40 int \$0;
+#X msg 113 10 bang;
+#X msg 269 67 @float .- set .#1;
+#X msg 269 102 remove @float;
+#X floatatom 269 40 5 0 0 0 - - -;
+#N canvas 0 0 450 420 linked 0;
+#X obj 54 49 widget scale s -command .<.> -variable ::toxy::simplescale
+-orient v -length 300 -width 50 -font "Helvetica 12" -from -16 -to
+16 -showvalue 0 @float .- set .#1;
+#X coords 0 0 1 1 80 360 1;
+#X restore 472 20 pd linked;
+#X connect 0 0 1 0;
+#X connect 2 0 3 0;
+#X connect 3 0 0 0;
+#X connect 4 0 5 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 6 0;
+#X connect 9 0 0 0;
+#X connect 10 0 8 0;
+#X connect 11 0 0 0;
+#X connect 12 0 13 0;
+#X connect 13 0 11 0;
+#X connect 14 0 13 0;
+#X connect 15 0 0 0;
+#X connect 16 0 0 0;
+#X connect 17 0 0 0;
diff --git a/test/toxy/test1.tot b/test/toxy/test1.tot
new file mode 100644
index 0000000..3faf74e
--- /dev/null
+++ b/test/toxy/test1.tot
@@ -0,0 +1,301 @@
+puts [concat .#0 .#1 .#9 .#: .^.c]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9]
+puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8 .#9] \ No newline at end of file
diff --git a/test/toxy/tot-bulk.pd b/test/toxy/tot-bulk.pd
new file mode 100644
index 0000000..cefb622
--- /dev/null
+++ b/test/toxy/tot-bulk.pd
@@ -0,0 +1,67 @@
+#N canvas 309 244 595 546 12;
+#X obj 62 449 pack;
+#X obj 62 387 t b b;
+#X obj 62 356 until;
+#X obj 33 250 makefilename #%x;
+#X obj 33 219 + 256;
+#X obj 33 188 random 3840;
+#X obj 62 418 random 500;
+#X obj 175 418 random 500;
+#X obj 33 126 + 3;
+#X obj 83 6 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1;
+#X obj 33 33 metro 500;
+#X obj 157 95 random 10;
+#X obj 157 126 sel 7;
+#X obj 33 64 t b b;
+#X obj 175 449 + 20;
+#X obj 33 6 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 -1
+;
+#X msg 130 33 tot .^.c delete bulk;
+#X msg 98 544 tot .^.c configure -bg pink;
+#X msg 62 480 add [expr \$1 + .#1] [expr \$2 + .#2];
+#X msg 62 511 debug;
+#X obj 33 285 pack s 0 0;
+#X obj 33 157 t b b b 0 b;
+#X msg 33 320 add -tags bulk -fill \$1 -smooth true \, push \$2 \$3
+;
+#X msg 157 188 reset \, add .^.c create polygon;
+#X obj 261 250 random 150;
+#X obj 201 219 random 100;
+#X obj 201 250 + 10;
+#X obj 33 95 random 700;
+#X obj 33 544 tot .;
+#X connect 0 0 18 0;
+#X connect 1 0 6 0;
+#X connect 1 1 7 0;
+#X connect 2 0 1 0;
+#X connect 3 0 20 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 0;
+#X connect 6 0 0 0;
+#X connect 7 0 14 0;
+#X connect 8 0 21 0;
+#X connect 9 0 10 0;
+#X connect 10 0 13 0;
+#X connect 11 0 12 0;
+#X connect 12 0 16 0;
+#X connect 13 0 27 0;
+#X connect 13 1 11 0;
+#X connect 14 0 0 1;
+#X connect 15 0 13 0;
+#X connect 16 0 28 0;
+#X connect 17 0 28 0;
+#X connect 18 0 28 0;
+#X connect 19 0 28 0;
+#X connect 20 0 22 0;
+#X connect 21 0 5 0;
+#X connect 21 1 25 0;
+#X connect 21 2 24 0;
+#X connect 21 3 2 0;
+#X connect 21 4 23 0;
+#X connect 22 0 28 0;
+#X connect 23 0 28 0;
+#X connect 24 0 20 2;
+#X connect 25 0 26 0;
+#X connect 26 0 20 1;
+#X connect 27 0 8 0;
+#X connect 28 3 17 0;
diff --git a/test/toxy/tot-cover.pd b/test/toxy/tot-cover.pd
new file mode 100644
index 0000000..267c22d
--- /dev/null
+++ b/test/toxy/tot-cover.pd
@@ -0,0 +1,87 @@
+#N canvas 392 177 590 367 12;
+#X msg 58 239 cover;
+#X msg 125 239 uncover;
+#N canvas 354 120 500 400 cv 1;
+#X restore 16 12 pd cv;
+#X obj 16 305 tot cv;
+#X obj 258 225 snapshot~;
+#X obj 481 225 snapshot~;
+#X obj 258 283 pack;
+#X obj 393 195 metro 50;
+#X obj 393 170 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 481 254 * 5;
+#X obj 258 254 * 5;
+#X msg 308 12 0 \; pd dsp 0;
+#X msg 199 12 1 \; pd dsp 1;
+#X obj 363 193 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 363 225 metro 500;
+#X obj 363 254 random 20;
+#X obj 258 170 osc~ 3;
+#X obj 481 170 osc~ 7;
+#X obj 199 62 pipe 3000;
+#X msg 122 58 stop;
+#X msg 122 29 bang;
+#X obj 16 62 delay 5000;
+#N canvas 80 35 613 356 commands 0;
+#X obj 25 13 inlet;
+#X obj 25 198 route cover uncover;
+#X obj 25 306 outlet;
+#X obj 48 46 loadbang;
+#X msg 25 226 tot tot_cover .^.c [ expr .~x2 - .~x1 ] [ expr .~y2 -
+.~y1 ];
+#X msg 42 259 tot if .( [winfo exists .^.c.cover] .) .( destroy .^.c.cover
+.);
+#X obj 48 145 tot .;
+#X msg 48 78 tot proc tot_cover .( cv wd ht .) .( if .( [expr ![winfo
+exists $cv.cover]] .) .( canvas $cv.cover -width $wd -height $ht -bg
+red -bd 0 .: pack $cv.cover .) .);
+#X connect 0 0 1 0;
+#X connect 1 0 4 0;
+#X connect 1 1 5 0;
+#X connect 3 0 7 0;
+#X connect 4 0 2 0;
+#X connect 5 0 2 0;
+#X connect 7 0 6 0;
+#X restore 58 268 pd commands;
+#X msg 16 91 tot .^.c create polygon 50 50 170 130 400 70 50 50 -fill
+#abcdef -tags t1 \, tot .^.c create text 200 90 -text "hide me" -font
+"times 24" -fill #fedcba -tags t1;
+#X msg 34 170 tot .^.c delete t1;
+#X msg 43 202 tot .^.c move t1 \$1 \$2;
+#X msg 65 336 tot .^.c configure -bg red;
+#X connect 0 0 22 0;
+#X connect 1 0 22 0;
+#X connect 3 3 26 0;
+#X connect 4 0 10 0;
+#X connect 5 0 9 0;
+#X connect 6 0 25 0;
+#X connect 7 0 4 0;
+#X connect 7 0 5 0;
+#X connect 8 0 7 0;
+#X connect 9 0 6 1;
+#X connect 10 0 6 0;
+#X connect 11 0 8 0;
+#X connect 11 0 24 0;
+#X connect 11 0 13 0;
+#X connect 11 0 19 0;
+#X connect 12 0 23 0;
+#X connect 12 0 18 0;
+#X connect 13 0 14 0;
+#X connect 14 0 15 0;
+#X connect 15 0 10 1;
+#X connect 15 0 9 1;
+#X connect 16 0 4 0;
+#X connect 17 0 5 0;
+#X connect 18 0 13 0;
+#X connect 18 0 8 0;
+#X connect 19 0 21 0;
+#X connect 20 0 21 0;
+#X connect 21 0 23 0;
+#X connect 22 0 3 0;
+#X connect 23 0 3 0;
+#X connect 23 0 20 0;
+#X connect 24 0 3 0;
+#X connect 25 0 3 0;
+#X connect 26 0 3 0;
diff --git a/test/toxy/tot-files.pd b/test/toxy/tot-files.pd
new file mode 100644
index 0000000..b21fd41
--- /dev/null
+++ b/test/toxy/tot-files.pd
@@ -0,0 +1,29 @@
+#N canvas 331 164 627 378 12;
+#X msg 33 336 debug;
+#X msg 83 178 tot puts [concat .#0 .#1 .#9 .#: .^.c ];
+#X msg 62 143 reset \, add puts [concat .#0 .#1 .#9 .#: .^.c];
+#X msg 276 306 push a b c;
+#X msg 276 335 push;
+#X msg 276 277 push a b c d e f g h i j k l m n;
+#X msg 100 216 write;
+#X msg 113 245 read;
+#X msg 171 245 read test1.tot;
+#X msg 171 216 write test1.tot;
+#X obj 37 51 until;
+#X msg 37 22 300;
+#X msg 37 86 addnext puts [concat .#0 .#1 .#2 .#3 .#4 .#5 .#6 .#7 .#8
+.#9];
+#X obj 96 336 tot . test1.tot;
+#X connect 0 0 13 0;
+#X connect 1 0 13 0;
+#X connect 2 0 13 0;
+#X connect 3 0 13 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 13 0;
+#X connect 7 0 13 0;
+#X connect 8 0 13 0;
+#X connect 9 0 13 0;
+#X connect 10 0 12 0;
+#X connect 11 0 10 0;
+#X connect 12 0 13 0;
diff --git a/test/toxy/tot-head.pd b/test/toxy/tot-head.pd
new file mode 100644
index 0000000..d5e5ec6
--- /dev/null
+++ b/test/toxy/tot-head.pd
@@ -0,0 +1,17 @@
+#N canvas 7 0 606 345 12;
+#X obj 38 156 -;
+#X floatatom 36 83 5 0 0 0 - - -;
+#X obj 36 122 t 0 0;
+#X msg 38 191 tot .^.c move head \$1 0;
+#X msg 54 224 tot .^.c delete head;
+#X msg 21 18 tot global margin .: set margin 3 .: .^.c create line
+300 $margin 300 [expr .~y2 - .~y1 - 2 * $margin ] -tags head;
+#X obj 21 264 tot .;
+#X connect 0 0 3 0;
+#X connect 1 0 2 0;
+#X connect 2 0 0 1;
+#X connect 2 1 0 0;
+#X connect 3 0 6 0;
+#X connect 4 0 6 0;
+#X connect 5 0 6 0;
+#X connect 6 3 5 0;
diff --git a/test/toxy/tot-monkey.pd b/test/toxy/tot-monkey.pd
new file mode 100644
index 0000000..2128ae8
--- /dev/null
+++ b/test/toxy/tot-monkey.pd
@@ -0,0 +1,50 @@
+#N canvas 199 254 540 290 12;
+#X obj 198 62 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X msg 41 62 capture \$1;
+#X obj 99 171 unpack 0 0 0;
+#X floatatom 99 212 5 0 0 0 - - -;
+#X floatatom 150 212 5 0 0 0 - - -;
+#X floatatom 202 212 5 0 0 0 - - -;
+#X obj 99 136 route motion mouseup mouse key;
+#X msg 260 171 \$1;
+#X obj 260 212 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X obj 297 208 route float;
+#X msg 297 171 \$2;
+#X floatatom 297 242 5 0 0 0 - - -;
+#X obj 364 171 print other;
+#N canvas 10 26 352 252 dux 1;
+#X obj 30 20 vsl 15 128 0 127 0 0 empty empty empty 0 -8 0 8 -262144
+-1 -1 0 1;
+#X obj 84 19 hsl 128 15 0 127 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X text 29 222 do some editing here \, too;
+#X restore 248 32 pd dux;
+#N canvas 408 26 352 252 comes 1;
+#X obj 30 20 vsl 15 128 0 127 0 0 empty empty empty 0 -8 0 8 -262144
+-1 -1 0 1;
+#X obj 84 19 hsl 128 15 0 127 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X restore 326 32 pd comes;
+#X obj 41 97 tot dux;
+#X obj 79 242 s pd-comes;
+#X msg 121 97 1;
+#X connect 0 0 1 0;
+#X connect 1 0 15 0;
+#X connect 2 0 3 0;
+#X connect 2 1 4 0;
+#X connect 2 2 5 0;
+#X connect 6 0 2 0;
+#X connect 6 1 2 0;
+#X connect 6 2 2 0;
+#X connect 6 3 7 0;
+#X connect 6 3 10 0;
+#X connect 6 4 12 0;
+#X connect 7 0 8 0;
+#X connect 9 0 11 0;
+#X connect 10 0 9 0;
+#X connect 15 2 16 0;
+#X connect 15 2 6 0;
+#X connect 15 3 17 0;
+#X connect 17 0 0 0;
diff --git a/test/toxy/tot-nomenu.pd b/test/toxy/tot-nomenu.pd
new file mode 100644
index 0000000..f2becca
--- /dev/null
+++ b/test/toxy/tot-nomenu.pd
@@ -0,0 +1,12 @@
+#N canvas 128 254 589 218 12;
+#X obj 13 175 tot nomenu;
+#N canvas 329 49 450 300 nomenu 1;
+#X restore 12 16 pd nomenu;
+#X msg 54 142 debug;
+#X msg 13 57 tot destroy .^.m \, tot bind .^.c <Control-Key> "";
+#X msg 41 92 tot global sz .: set sz [wm maxsize .^] .: wm geometry
+.^ [expr [lindex $sz 0] - 20]x[expr [lindex $sz 1] - 20]+20+20;
+#X connect 0 3 3 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
diff --git a/test/toxy/tot-qlist.pd b/test/toxy/tot-qlist.pd
new file mode 100644
index 0000000..24f7ba6
--- /dev/null
+++ b/test/toxy/tot-qlist.pd
@@ -0,0 +1,59 @@
+#N canvas 250 295 422 249 12;
+#X obj 75 126 qlist;
+#N canvas 59 33 296 202 src 1;
+#X restore 15 186 pd src;
+#N canvas 407 33 296 202 dst 1;
+#X restore 15 216 pd dst;
+#X obj 37 24 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X msg 16 126 print;
+#X obj 37 89 tot src;
+#X msg 139 89 rewind;
+#X msg 37 54 capture \$1 pd-dst;
+#X msg 271 54 read tot.ql;
+#X msg 270 89 write tot.ql;
+#X obj 271 20 loadbang;
+#X obj 139 156 tot dst;
+#X obj 209 54 t b b;
+#X msg 249 126 detach;
+#X msg 139 126 attach;
+#X obj 332 126 r pd-dst;
+#X obj 332 156 s pd-src;
+#X obj 249 156 tot src;
+#X obj 148 216 spigot;
+#X obj 258 216 spigot;
+#X obj 209 24 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 216 216 0;
+#X msg 197 186 1;
+#X msg 307 186 1;
+#X connect 0 1 14 0;
+#X connect 3 0 7 0;
+#X connect 4 0 0 0;
+#X connect 5 2 0 0;
+#X connect 6 0 0 0;
+#X connect 6 0 14 0;
+#X connect 7 0 5 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 8 0;
+#X connect 11 3 22 0;
+#X connect 11 3 19 0;
+#X connect 12 0 0 0;
+#X connect 12 1 13 0;
+#X connect 13 0 11 0;
+#X connect 13 0 17 0;
+#X connect 14 0 11 0;
+#X connect 14 0 17 0;
+#X connect 15 0 16 0;
+#X connect 17 3 23 0;
+#X connect 17 3 18 0;
+#X connect 18 0 12 0;
+#X connect 18 0 21 0;
+#X connect 19 0 12 0;
+#X connect 19 0 21 0;
+#X connect 20 0 12 0;
+#X connect 21 0 18 1;
+#X connect 21 0 19 1;
+#X connect 22 0 18 1;
+#X connect 23 0 19 1;
diff --git a/test/toxy/tot-query.pd b/test/toxy/tot-query.pd
new file mode 100644
index 0000000..d646f78
--- /dev/null
+++ b/test/toxy/tot-query.pd
@@ -0,0 +1,62 @@
+#N canvas 421 109 778 551 12;
+#X msg 21 8 symbol pinecone;
+#X obj 455 142 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 186 8 symbol conehead;
+#X obj 67 174 sel 1;
+#X obj 128 238 sel 0;
+#X obj 128 339 print error;
+#X obj 199 238 metro 150;
+#X msg 128 311 open it first...;
+#X msg 54 124 tot global ch .: set ch [open ~/PureData/miXed/test/toxy/tot-query.pd
+r];
+#X msg 75 435 query concat set [lsort -decreasing [glob *]];
+#X msg 37 90 reset \, addnext set x -1 .: concat set [expr acos($x)]
+\, qpush;
+#X msg 21 44 tot global ans .: regsub cone \$1 apple ans \, query global
+ans .: concat set $ans;
+#X msg 60 369 tot global ch .: set ch [open ~/.pdrc] \, query global
+ch .: concat set [read $ch] \, tot global ch .: close $ch .: unset
+ch;
+#X msg 199 266 tot global txt ch .: set txt [gets $ch] \, query global
+txt .: concat set $txt;
+#N canvas 0 0 578 346 more 0;
+#X msg 35 73 query .^.c bbox foo;
+#X obj 19 280 print reply;
+#X msg 84 152 query winfo id .^.c;
+#X msg 84 231 query winfo pathname \$1;
+#X msg 19 26 tot .^.c create text 400 100 -width 80 -font "times 24"
+-anchor nw -text "abcd efgh ijkl mnop" -tags foo;
+#X msg 48 104 tot .^.c delete foo;
+#X obj 19 231 tot .;
+#X obj 84 191 tot .;
+#X connect 0 0 6 0;
+#X connect 2 0 7 0;
+#X connect 3 0 6 0;
+#X connect 4 0 6 0;
+#X connect 5 0 6 0;
+#X connect 6 0 1 0;
+#X connect 7 0 3 0;
+#X restore 576 174 pd more;
+#X obj 21 468 tot .;
+#X obj 67 238 tot .;
+#X msg 67 202 tot eval .< [global ch .: info exists ch] .>;
+#X msg 21 502;
+#X connect 0 0 11 0;
+#X connect 1 0 3 0;
+#X connect 2 0 11 0;
+#X connect 3 0 17 0;
+#X connect 3 1 6 0;
+#X connect 4 0 7 0;
+#X connect 4 1 6 0;
+#X connect 6 0 13 0;
+#X connect 7 0 5 0;
+#X connect 8 0 15 0;
+#X connect 9 0 15 0;
+#X connect 10 0 15 0;
+#X connect 11 0 15 0;
+#X connect 12 0 15 0;
+#X connect 13 0 15 0;
+#X connect 15 0 18 0;
+#X connect 16 1 4 0;
+#X connect 17 0 16 0;
diff --git a/test/toxy/tot-rstring.pd b/test/toxy/tot-rstring.pd
new file mode 100644
index 0000000..24d1e1c
--- /dev/null
+++ b/test/toxy/tot-rstring.pd
@@ -0,0 +1,15 @@
+#N canvas 254 48 671 300 12;
+#X obj 21 179 tot .;
+#X obj 164 77 tosymbol;
+#X msg 50 77 123456;
+#X msg 21 124 query set lst [list] .: foreach el [split " \$1 " ""]
+.(set lst [linsert $lst 0 $el].) .: concat set [join $lst ""];
+#X msg 164 40 One Two Three;
+#X msg 21 40 symbol abcdef;
+#X msg 21 221;
+#X connect 0 0 6 0;
+#X connect 1 0 3 0;
+#X connect 2 0 3 0;
+#X connect 3 0 0 0;
+#X connect 4 0 1 0;
+#X connect 5 0 3 0;
diff --git a/test/toxy/tot.ql b/test/toxy/tot.ql
new file mode 100644
index 0000000..fa2b22e
--- /dev/null
+++ b/test/toxy/tot.ql
@@ -0,0 +1,186 @@
+590.4762 pd-dst motion 70 11 0;
+64.58 pd-dst text 0;
+0 pd-dst motion 117 114 0;
+1.45125 pd-dst motion 115 114 0;
+68.2086 pd-dst motion 103 110 0;
+23.22 pd-dst motion 87 106 0;
+17.415 pd-dst motion 65 98 0;
+23.22 pd-dst motion 53 92 0;
+29.0249 pd-dst motion 47 90 0;
+58.0499 pd-dst motion 47 89 0;
+29.0249 pd-dst motion 47 88 0;
+23.22 pd-dst motion 47 87 0;
+68.345 pd-dst motion 48 87 0;
+29.0249 pd-dst motion 50 87 0;
+23.22 pd-dst motion 53 87 0;
+17.415 pd-dst motion 59 85 0;
+23.22 pd-dst motion 63 79 0;
+17.415 pd-dst motion 63 78 0;
+69.6599 pd-dst motion 62 78 0;
+29.0249 pd-dst motion 61 76 0;
+23.22 pd-dst motion 55 70 0;
+17.415 pd-dst motion 49 66 0;
+23.22 pd-dst motion 45 62 0;
+29.0249 pd-dst motion 43 61 0;
+50 pd-dst key 1 32 0;
+50 pd-dst key 0 32 0;
+59.773 pd-dst mouse 43 61 1 0;
+76.9161 pd-dst mouseup 43 61 1;
+0 pd-dst relocate 298x204+0+0 319x225+99+33;
+63.8549 pd-dst motion 44 61 0;
+17.415 pd-dst motion 47 61 0;
+21.7687 pd-dst motion 55 63 0;
+18.8662 pd-dst motion 63 65 0;
+29.0249 pd-dst motion 66 65 0;
+23.22 pd-dst motion 67 65 0;
+451.25 pd-dst key 1 116 0;
+75.4649 pd-dst key 1 101 0;
+74.0136 pd-dst key 0 116 0;
+47.8912 pd-dst key 1 115 0;
+29.0249 pd-dst key 0 101 0;
+46.4399 pd-dst key 0 115 0;
+95.283 pd-dst key 1 116 0;
+69.6599 pd-dst key 0 116 0;
+23.22 pd-dst key 1 105 0;
+75.4649 pd-dst key 1 110 0;
+46.4399 pd-dst key 0 105 0;
+69.6599 pd-dst key 0 110 0;
+77.551 pd-dst key 1 103 0;
+50.7937 pd-dst key 0 103 0;
+88.934 pd-dst key 1 32 0;
+75.4649 pd-dst key 0 32 0;
+36.689 pd-dst key 1 116 0;
+75.4649 pd-dst key 0 116 0;
+69.6599 pd-dst key 1 111 0;
+76.9161 pd-dst key 0 111 0;
+21.7687 pd-dst key 1 116 0;
+29.0249 pd-dst key 0 116 0;
+48.844 pd-dst key 1 39 0;
+46.4399 pd-dst key 1 115 0;
+29.0249 pd-dst key 0 39 0;
+52.2449 pd-dst key 0 115 0;
+57.823 pd-dst key 1 32 0;
+75.4649 pd-dst key 0 32 0;
+88.934 pd-dst key 1 113 0;
+75.4649 pd-dst key 0 113 0;
+81.2698 pd-dst key 1 108 0;
+75.4649 pd-dst key 1 105 0;
+29.0249 pd-dst key 0 108 0;
+69.6599 pd-dst key 0 105 0;
+23.22 pd-dst key 1 115 0;
+52.2449 pd-dst key 0 115 0;
+69.6599 pd-dst key 1 116 0;
+75.4649 pd-dst key 0 116 0;
+70.204 pd-dst key 1 32 0;
+63.8549 pd-dst key 0 32 0;
+58.594 pd-dst key 1 102 0;
+21.905 pd-dst key 0 102 0;
+17.415 pd-dst key 1 97 0;
+29.0249 pd-dst key 0 97 0;
+267.029 pd-dst key 1 99 0;
+52.2449 pd-dst key 0 99 0;
+69.6599 pd-dst key 1 105 0;
+69.6599 pd-dst key 0 105 0;
+36.689 pd-dst key 1 108 0;
+92.8798 pd-dst key 1 105 0;
+26.1224 pd-dst key 0 108 0;
+49.3424 pd-dst key 0 105 0;
+75.4649 pd-dst key 1 116 0;
+52.2449 pd-dst key 0 116 0;
+92.8798 pd-dst key 1 121 0;
+46.4399 pd-dst key 0 121 0;
+399.773 pd-dst motion 67 66 0;
+17.415 pd-dst motion 85 86 0;
+23.22 pd-dst motion 105 102 0;
+17.415 pd-dst motion 115 104 0;
+69.6599 pd-dst motion 116 104 0;
+21.905 pd-dst mouse 116 104 1 0;
+69.6599 pd-dst mouseup 116 104 1;
+280.86 pd-dst motion 117 104 0;
+20.3175 pd-dst motion 129 94 0;
+17.415 pd-dst motion 143 82 0;
+23.22 pd-dst motion 157 72 0;
+17.415 pd-dst motion 169 66 0;
+29.0249 pd-dst motion 171 65 0;
+72.063 pd-dst mouse 171 65 1 0;
+52.2449 pd-dst motion 170 65 0;
+29.0249 pd-dst motion 156 65 0;
+17.415 pd-dst motion 138 65 0;
+23.22 pd-dst motion 126 67 0;
+17.415 pd-dst motion 116 69 0;
+23.22 pd-dst motion 112 73 0;
+29.0249 pd-dst motion 111 74 0;
+17.415 pd-dst motion 110 76 0;
+23.22 pd-dst motion 110 84 0;
+17.415 pd-dst motion 110 94 0;
+29.0249 pd-dst motion 112 102 0;
+23.22 pd-dst motion 116 108 0;
+17.415 pd-dst motion 124 112 0;
+23.22 pd-dst motion 136 116 0;
+29.0249 pd-dst motion 152 116 0;
+17.415 pd-dst motion 170 116 0;
+23.22 pd-dst motion 178 110 0;
+17.415 pd-dst motion 182 100 0;
+23.22 pd-dst motion 182 97 0;
+29.0249 pd-dst motion 180 91 0;
+17.415 pd-dst motion 177 91 0;
+23.22 pd-dst motion 174 91 0;
+17.415 pd-dst motion 172 90 0;
+29.0249 pd-dst motion 166 88 0;
+23.22 pd-dst motion 156 84 0;
+17.415 pd-dst motion 148 82 0;
+23.22 pd-dst motion 146 81 0;
+29.0249 pd-dst motion 145 80 0;
+52.2449 pd-dst motion 145 79 0;
+17.415 pd-dst motion 145 65 0;
+23.22 pd-dst motion 147 41 0;
+17.415 pd-dst motion 147 15 0;
+17.415 pd-dst motion 147 7 0;
+81.2698 pd-dst motion 147 8 0;
+23.22 pd-dst motion 149 14 0;
+17.415 pd-dst motion 157 22 0;
+29.0249 pd-dst motion 167 28 0;
+23.22 pd-dst motion 175 44 0;
+17.415 pd-dst motion 183 64 0;
+23.22 pd-dst motion 183 80 0;
+17.415 pd-dst motion 181 92 0;
+29.0249 pd-dst motion 173 104 0;
+23.22 pd-dst motion 163 114 0;
+17.415 pd-dst motion 157 118 0;
+23.22 pd-dst motion 154 118 0;
+29.0249 pd-dst motion 148 120 0;
+17.415 pd-dst motion 145 120 0;
+23.22 pd-dst motion 139 118 0;
+17.415 pd-dst motion 133 110 0;
+29.0249 pd-dst motion 133 100 0;
+23.22 pd-dst motion 133 86 0;
+17.415 pd-dst motion 133 72 0;
+23.22 pd-dst motion 133 64 0;
+17.415 pd-dst motion 137 58 0;
+29.0249 pd-dst motion 139 57 0;
+23.22 pd-dst motion 141 56 0;
+17.415 pd-dst motion 143 56 0;
+23.22 pd-dst motion 151 62 0;
+29.0249 pd-dst motion 157 72 0;
+17.415 pd-dst motion 159 80 0;
+23.22 pd-dst motion 159 88 0;
+17.415 pd-dst motion 159 90 0;
+29.0249 pd-dst motion 157 91 0;
+23.22 pd-dst motion 156 91 0;
+17.415 pd-dst motion 155 91 0;
+23.22 pd-dst motion 155 89 0;
+29.0249 pd-dst motion 155 88 0;
+36.689 pd-dst mouseup 155 88 1;
+52.2449 pd-dst motion 155 89 0;
+17.415 pd-dst motion 167 101 0;
+23.22 pd-dst motion 177 111 0;
+29.0249 pd-dst motion 185 127 0;
+17.415 pd-dst motion 187 133 0;
+59.138 pd-dst mouse 187 133 1 0;
+69.6599 pd-dst mouseup 187 133 1;
+23.22 pd-dst motion 188 133 0;
+46.4399 pd-dst motion 189 133 0;
+74.15 pd-dst motion 189 134 0;
+29.0249 pd-dst motion 188 136 0;
+17.415 pd-dst motion 184 154 0;
+23.22 pd-dst motion 178 194 0;
diff --git a/test/toxy/tow-test.pd b/test/toxy/tow-test.pd
new file mode 100644
index 0000000..d0a8c95
--- /dev/null
+++ b/test/toxy/tow-test.pd
@@ -0,0 +1,65 @@
+#N canvas 275 304 262 189 12;
+#N canvas 23 43 450 305 panel 1;
+#X obj 37 49 widget float f -bg orange;
+#X floatatom 37 273 5 0 0 0 - - -;
+#X floatatom 37 15 5 0 0 0 - - -;
+#X obj 269 49 widget bang b1;
+#X msg 269 15 bang;
+#X obj 269 126 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 104 49 widget float f -bg orange;
+#X floatatom 104 273 5 0 0 0 - - -;
+#X floatatom 104 15 5 0 0 0 - - -;
+#X obj 267 195 widget bang b2 -bg violet;
+#X obj 267 273 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 267 160 bang;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 3 0 5 0;
+#X connect 4 0 3 0;
+#X connect 6 0 7 0;
+#X connect 8 0 6 0;
+#X connect 9 0 10 0;
+#X connect 11 0 9 0;
+#X restore 21 32 pd panel;
+#N canvas 329 98 450 310 guts 1;
+#X msg 253 123 bang;
+#X obj 253 279 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 72 56 bang;
+#X obj 136 123 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 136 88 tow panel bang b1;
+#X obj 253 245 tow panel bang b2;
+#X msg 280 215 debug;
+#X msg 280 183 -bg violet;
+#X msg 262 153 -bg white;
+#X obj 29 245 tow panel float f;
+#X floatatom 29 279 5 0 0 0 - - -;
+#X floatatom 29 123 5 0 0 0 - - -;
+#X msg 63 215 debug;
+#X msg 63 183 -bg orange;
+#X msg 50 153 -bg brown;
+#X obj 136 21 loadbang;
+#X msg 136 56 ini .^.c configure -bg darkgreen;
+#X connect 0 0 5 0;
+#X connect 2 0 4 0;
+#X connect 4 0 3 0;
+#X connect 5 0 1 0;
+#X connect 6 0 5 0;
+#X connect 7 0 5 0;
+#X connect 8 0 5 0;
+#X connect 9 0 10 0;
+#X connect 11 0 9 0;
+#X connect 12 0 9 0;
+#X connect 13 0 9 0;
+#X connect 14 0 9 0;
+#X connect 15 0 16 0;
+#X connect 16 0 4 0;
+#X restore 120 32 pd guts;
+#X obj 21 105 tow panel float f;
+#X floatatom 21 139 5 0 0 0 - - -;
+#X floatatom 21 72 5 0 0 0 - - -;
+#X connect 2 0 3 0;
+#X connect 4 0 2 0;
diff --git a/toxy/Makefile b/toxy/Makefile
new file mode 100644
index 0000000..fc022be
--- /dev/null
+++ b/toxy/Makefile
@@ -0,0 +1,2 @@
+ROOT_DIR = ..
+include $(ROOT_DIR)/Makefile.common
diff --git a/toxy/Makefile.objects b/toxy/Makefile.objects
new file mode 100644
index 0000000..d0e6476
--- /dev/null
+++ b/toxy/Makefile.objects
@@ -0,0 +1,22 @@
+TOT_OBJECTS = \
+common/loud.o \
+common/grow.o \
+hammer/file.o \
+hammer/gui.o \
+common/props.o \
+toxy/scriptlet.o
+
+TOW_OBJECTS = \
+common/loud.o \
+unstable/loader.o
+
+WIDGET_OBJECTS = \
+unstable/forky.o \
+common/loud.o \
+common/grow.o \
+common/dict.o \
+hammer/file.o \
+common/props.o \
+toxy/scriptlet.o
+
+WIDGET_PRIVATEOBJECTS = widgettype.o
diff --git a/toxy/Makefile.sources b/toxy/Makefile.sources
new file mode 100644
index 0000000..b0f3646
--- /dev/null
+++ b/toxy/Makefile.sources
@@ -0,0 +1,5 @@
+TYPES = TOT TOW WIDGET
+
+TOT_SOURCES = tot.c
+TOW_SOURCES = tow.c
+WIDGET_SOURCES = widget.c
diff --git a/toxy/build_counter b/toxy/build_counter
new file mode 100644
index 0000000..5774bf7
--- /dev/null
+++ b/toxy/build_counter
@@ -0,0 +1,3 @@
+#define TOXY_VERSION "0.1"
+#define TOXY_RELEASE "alpha"
+#define TOXY_BUILD 1
diff --git a/toxy/tot.c b/toxy/tot.c
new file mode 100644
index 0000000..eced2b2
--- /dev/null
+++ b/toxy/tot.c
@@ -0,0 +1,530 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* LATER handle stcriptlet's named arguments */
+
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "common/loud.h"
+#include "hammer/file.h"
+#include "hammer/gui.h"
+#include "common/props.h"
+#include "toxy/scriptlet.h"
+#include "build_counter"
+
+//#define TOT_DEBUG
+
+/* probably much more than needed for canvas messages from gui */
+#define TOTSPY_MAXSIZE 32
+
+typedef struct _tot
+{
+ t_object x_ob;
+ t_glist *x_glist; /* containing glist */
+ t_symbol *x_cvremote; /* null if containing glist is our destination */
+ t_symbol *x_cvname;
+ t_symbol *x_cvpathname; /* see tot_getpathname() */
+ t_symbol *x_visedpathname; /* see tot__vised() */
+ t_symbol *x_target;
+ int x_warned;
+ t_scriptlet *x_persistent;
+ t_scriptlet *x_transient;
+ t_outlet *x_out2;
+ t_outlet *x_out4;
+ t_symbol *x_defname; /* file name (if given as a creation arg) */
+ t_hammerfile *x_filehandle;
+ t_pd *x_guidetached;
+ t_pd *x_guisink;
+ struct _totspy *x_spy;
+} t_tot;
+
+typedef struct _totspy
+{
+ t_pd ts_pd;
+ int ts_on;
+ t_canvas *ts_cv;
+ t_symbol *ts_target;
+ t_symbol *ts_qsym;
+ double ts_lasttime;
+ t_symbol *ts_selector;
+ t_atom ts_outbuf[TOTSPY_MAXSIZE];
+ t_outlet *ts_out3;
+} t_totspy;
+
+static t_class *tot_class;
+static t_class *totspy_class;
+static t_class *totsink_class;
+static t_class *tot_guiconnect_class = 0;
+
+static t_symbol *tot_ps_qpush;
+static t_symbol *tot_ps_query;
+
+static t_canvas *tot_getcanvas(t_tot *x, int complain)
+{
+ t_canvas *cv = 0;
+ t_glist *glist =
+ (x->x_cvremote ?
+ (t_glist *)pd_findbyclass(x->x_cvremote, canvas_class) : x->x_glist);
+ if (glist)
+ cv = glist_getcanvas(glist);
+ else if (complain)
+ loud_error((t_pd *)x, "bad canvas name '%s'", x->x_cvname->s_name);
+ if (!x->x_warned && !x->x_cvremote)
+ {
+ x->x_warned = 1;
+ if (!cv) cv = x->x_glist; /* redundant */
+ loud_warning((t_pd *)x, "using containing canvas ('%s')",
+ cv->gl_name->s_name);
+ }
+ return (cv);
+}
+
+static t_canvas *tot_cvhook(t_pd *z)
+{
+ return (tot_getcanvas((t_tot *)z, 1));
+}
+
+static t_symbol *tot_dogetpathname(t_tot *x, int visedonly, int complain)
+{
+ t_canvas *cv = tot_getcanvas(x, complain);
+ if (cv)
+ {
+ if (visedonly && !glist_isvisible(cv))
+ return (0);
+ else if (cv == x->x_glist)
+ /* containing glist is our destination, and we are not in a gop */
+ return (x->x_cvpathname);
+ else
+ {
+ char buf[32];
+ sprintf(buf, ".x%x.c", (int)cv);
+ return (gensym(buf));
+ }
+ }
+ else return (0);
+}
+
+static t_symbol *tot_getpathname(t_tot *x, int complain)
+{
+ return (tot_dogetpathname(x, 0, complain));
+}
+
+static t_symbol *tot_getvisedpathname(t_tot *x, int complain)
+{
+ return (tot_dogetpathname(x, 1, complain));
+}
+
+static void tot_reset(t_tot *x)
+{
+ scriptlet_reset(x->x_persistent);
+}
+
+static void tot_prealloc(t_tot *x, t_floatarg f)
+{
+ int reqsize = (int)f;
+ scriptlet_prealloc(x->x_persistent, reqsize, 1);
+ scriptlet_prealloc(x->x_transient, reqsize, 1); /* LATER rethink */
+}
+
+static void tot_add(t_tot *x, t_symbol *s, int ac, t_atom *av)
+{
+ scriptlet_add(x->x_persistent, 0, 0, ac, av);
+}
+
+static void tot_addnext(t_tot *x, t_symbol *s, int ac, t_atom *av)
+{
+ scriptlet_setseparator(x->x_persistent, '\n');
+ scriptlet_add(x->x_persistent, 0, 0, ac, av);
+}
+
+static void tot_push(t_tot *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (scriptlet_evaluate(x->x_persistent, x->x_transient, 1, ac, av, 0))
+ {
+ if (s == tot_ps_qpush)
+ scriptlet_qpush(x->x_transient);
+ else
+ scriptlet_push(x->x_transient);
+ }
+}
+
+static void tot_tot(t_tot *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_scriptlet *sp = x->x_transient;
+ scriptlet_reset(sp);
+ scriptlet_add(sp, 1, 1, ac, av);
+ if (s == tot_ps_query)
+ scriptlet_qpush(sp);
+ else
+ scriptlet_push(sp);
+ }
+}
+
+static void tot_dooutput(t_tot *x, t_outlet *op,
+ t_symbol *s, int ac, t_atom *av)
+{
+ if (ac == 1)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_float(op, av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ outlet_symbol(op, av->a_w.w_symbol);
+ }
+ else if (ac)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_list(op, &s_list, ac, av);
+ else if (av->a_type == A_SYMBOL)
+ outlet_anything(op, av->a_w.w_symbol, ac - 1, av + 1);
+ }
+ else outlet_bang(op);
+}
+
+static void tot__reply(t_tot *x, t_symbol *s, int ac, t_atom *av)
+{
+ tot_dooutput(x, ((t_object *)x)->ob_outlet, s, ac, av);
+}
+
+static void tot__callback(t_tot *x, t_symbol *s, int ac, t_atom *av)
+{
+ tot_dooutput(x, x->x_out2, s, ac, av);
+}
+
+/* LATER use properties in widgetbehavior (if gop visibility rules change) */
+static void tot_click(t_tot *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ int nleft;
+ char *head = scriptlet_getcontents(x->x_persistent, &nleft);
+ char buf[MAXPDSTRING + 1];
+ buf[MAXPDSTRING] = 0;
+ hammereditor_open(x->x_filehandle, "scriptlet editor");
+ while (nleft > 0)
+ {
+ if (nleft > MAXPDSTRING)
+ {
+ strncpy(buf, head, MAXPDSTRING);
+ head += MAXPDSTRING;
+ nleft -= MAXPDSTRING;
+ }
+ else
+ {
+ strncpy(buf, head, nleft);
+ buf[nleft] = 0;
+ nleft = 0;
+ }
+ hammereditor_append(x->x_filehandle, buf);
+ }
+}
+
+/* This is called for all Map (f==1) and all Destroy (f==0) events,
+ comming from any canvas. If visedpathname is zero, we assume our
+ canvas does not exist. So we ignore everything, waiting for a Map
+ event that fits tot_getpathname(). Once we spot it, we set
+ visedpathname, and ignore everything, waiting for a Destroy event
+ that fits visedpathname. Then we clear visedpathname, etc... */
+static void tot__vised(t_tot *x, t_symbol *s, t_floatarg f)
+{
+ int flag = f != 0.;
+#ifdef TOT_DEBUG
+ t_symbol *pn = tot_getpathname(x, 0);
+ post("tot__vised %s %g (pathname %s) ", s->s_name, f,
+ (pn ? pn->s_name : "unknown"));
+#endif
+ if (!x->x_visedpathname)
+ {
+ if (flag && s == tot_getpathname(x, 0))
+ {
+ x->x_visedpathname = s;
+ outlet_bang(x->x_out4);
+ }
+ }
+ else if (!flag && s == x->x_visedpathname)
+ x->x_visedpathname = 0; /* LATER reconsider reporting this */
+}
+
+#ifdef TOT_DEBUG
+static void tot_debug(t_tot *x)
+{
+ t_symbol *pn = tot_getpathname(x, 0);
+ int sz;
+ char *bp;
+ post("containing glist: %x", x->x_glist);
+ post("destination: %s", x->x_cvname->s_name);
+ post("pathname%s %s", (pn ? ":" : ""), (pn ? pn->s_name : "unknown"));
+ bp = scriptlet_getbuffer(x->x_transient, &sz);
+ post("transient buffer (size %d):\n\"%s\"", sz, bp);
+ bp = scriptlet_getbuffer(x->x_persistent, &sz);
+ post("persistent buffer (size %d):\n\"%s\"", sz, bp);
+}
+#endif
+
+static void tot_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ scriptlet_read(((t_tot *)z)->x_persistent, fn);
+}
+
+static void tot_writehook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ scriptlet_write(((t_tot *)z)->x_persistent, fn);
+}
+
+static void tot_read(t_tot *x, t_symbol *s)
+{
+ if (s && s != &s_)
+ scriptlet_read(x->x_persistent, s);
+ else
+ hammerpanel_open(x->x_filehandle, 0);
+}
+
+static void tot_write(t_tot *x, t_symbol *s)
+{
+ if (s && s != &s_)
+ scriptlet_write(x->x_persistent, s);
+ else
+ hammerpanel_save(x->x_filehandle,
+ canvas_getdir(x->x_glist), x->x_defname);
+}
+
+static void tot_detach(t_tot *x)
+{
+ t_canvas *cv = tot_getcanvas(x, 1);
+ if (cv && glist_isvisible(cv))
+ {
+ t_pd *gc;
+ t_symbol *target;
+ char buf[64];
+ sprintf(buf, ".x%x", (int)cv);
+ target = gensym(buf);
+ if (!tot_guiconnect_class)
+ {
+ gc = (t_pd *)guiconnect_new(0, gensym("tot"));
+ tot_guiconnect_class = *gc;
+ typedmess(gc, gensym("signoff"), 0, 0);
+ }
+ if (gc = pd_findbyclass(target, tot_guiconnect_class))
+ {
+ x->x_guidetached = gc;
+ pd_unbind(gc, target);
+ pd_bind(x->x_guisink, target);
+ }
+ }
+}
+
+static void tot_attach(t_tot *x)
+{
+ t_canvas *cv = tot_getcanvas(x, 1);
+ if (cv && glist_isvisible(cv) && x->x_guidetached)
+ {
+ if (tot_guiconnect_class)
+ {
+ t_pd *gc;
+ t_symbol *target;
+ char buf[64];
+ sprintf(buf, ".x%x", (int)cv);
+ target = gensym(buf);
+ if (gc = pd_findbyclass(target, tot_guiconnect_class))
+ {
+ }
+ else
+ { /* assuming nobody else detached it in the meantime... */
+ pd_unbind(x->x_guisink, target);
+ pd_bind(x->x_guidetached, target);
+ x->x_guidetached = 0;
+ }
+ }
+ else bug("tot_attach");
+ }
+}
+
+static void tot_capture(t_tot *x, t_symbol *s, t_floatarg f)
+{
+ t_totspy *ts = x->x_spy;
+ if ((int)f)
+ {
+ t_canvas *cv = tot_getcanvas(x, 1);
+ ts->ts_qsym = (s == &s_ ? 0 : s);
+ if (cv != ts->ts_cv)
+ {
+ if (ts->ts_target)
+ {
+ pd_unbind((t_pd *)ts, ts->ts_target);
+ ts->ts_cv = 0;
+ ts->ts_target = 0;
+ }
+ if (cv)
+ {
+ char buf[64];
+ ts->ts_cv = cv;
+ sprintf(buf, ".x%x", (int)cv);
+ pd_bind((t_pd *)ts, ts->ts_target = gensym(buf));
+ }
+ }
+ ts->ts_on = (ts->ts_target != 0);
+ if (ts->ts_on && ts->ts_qsym)
+ {
+ ts->ts_lasttime = clock_getlogicaltime();
+ ts->ts_selector = gensym("add");
+ SETFLOAT(&ts->ts_outbuf[0], 0);
+ SETSYMBOL(&ts->ts_outbuf[1], ts->ts_qsym);
+ SETSYMBOL(&ts->ts_outbuf[2], &s_);
+ outlet_anything(ts->ts_out3, gensym("clear"), 0, 0);
+ }
+ }
+ else ts->ts_on = 0;
+}
+
+static void totspy_anything(t_totspy *ts, t_symbol *s, int ac, t_atom *av)
+{
+ if (ts->ts_on)
+ {
+ if (ts->ts_qsym)
+ {
+ int cnt = ac + 3;
+ if (cnt < TOTSPY_MAXSIZE)
+ {
+ t_atom *ap = ts->ts_outbuf;
+ ap++->a_w.w_float = (float)clock_gettimesince(ts->ts_lasttime);
+ ap++;
+ ap++->a_w.w_symbol = s;
+ while (ac--) *ap++ = *av++;
+ outlet_anything(ts->ts_out3,
+ ts->ts_selector, cnt, ts->ts_outbuf);
+ ts->ts_lasttime = clock_getlogicaltime();
+ }
+ else loud_warning((t_pd *)ts,
+ "unexpectedly long message (\"%s...\"), ignored",
+ s->s_name);
+ }
+ else outlet_anything(ts->ts_out3, s, ac, av);
+ }
+}
+
+static void totsink_anything(t_pd *x, t_symbol *s, int ac, t_atom *av)
+{
+ /* nop */
+}
+
+static void tot_free(t_tot *x)
+{
+ pd_unbind((t_pd *)x, x->x_target);
+ hammergui_unbindvised((t_pd *)x);
+ hammerfile_free(x->x_filehandle);
+ scriptlet_free(x->x_persistent);
+ scriptlet_free(x->x_transient);
+ if (x->x_spy->ts_target)
+ pd_unbind((t_pd *)x->x_spy, x->x_spy->ts_target);
+ pd_free((t_pd *)x->x_spy);
+ pd_free(x->x_guisink);
+}
+
+static void *tot_new(t_symbol *s1, t_symbol *s2)
+{
+ t_tot *x = (t_tot *)pd_new(tot_class);
+ char buf[64];
+ sprintf(buf, "tot%x", (int)x);
+ pd_bind((t_pd *)x, x->x_target = gensym(buf));
+ x->x_transient =
+ scriptlet_new((t_pd *)x, x->x_target, x->x_target, 0, tot_cvhook);
+ x->x_persistent =
+ scriptlet_new((t_pd *)x, x->x_target, x->x_target, 0, tot_cvhook);
+ x->x_glist = canvas_getcurrent();
+ if (s1 && s1 != &s_ && strcmp(s1->s_name, "."))
+ {
+ x->x_cvremote = canvas_makebindsym(x->x_cvname = s1);
+ x->x_cvpathname = 0;
+ }
+ else
+ {
+ x->x_warned = (s1 && *s1->s_name == '.'); /* do not warn if explicit */
+ x->x_cvremote = 0;
+ x->x_cvname = x->x_glist->gl_name;
+ sprintf(buf, ".x%x.c", (int)x->x_glist);
+ x->x_cvpathname = gensym(buf);
+ }
+ outlet_new((t_object *)x, &s_anything);
+ x->x_out2 = outlet_new((t_object *)x, &s_anything);
+ x->x_spy = (t_totspy *)pd_new(totspy_class);
+ x->x_spy->ts_on = 0;
+ x->x_spy->ts_cv = 0;
+ x->x_spy->ts_target = 0;
+ x->x_spy->ts_qsym = 0;
+ x->x_spy->ts_out3 = outlet_new((t_object *)x, &s_anything);
+ x->x_out4 = outlet_new((t_object *)x, &s_bang);
+ if (s2 && s2 != &s_)
+ {
+ x->x_defname = s2;
+ scriptlet_read(x->x_persistent, s2);
+ }
+ else x->x_defname = &s_;
+ x->x_filehandle = hammerfile_new((t_pd *)x, 0,
+ tot_readhook, tot_writehook, 0);
+ hammergui_bindvised((t_pd *)x);
+ x->x_visedpathname = tot_getvisedpathname(x, 0);
+ x->x_guidetached = 0;
+ x->x_guisink = pd_new(totsink_class);
+ return (x);
+}
+
+void tot_setup(void)
+{
+ post("beware! this is tot %s, %s %s build...",
+ TOXY_VERSION, loud_ordinal(TOXY_BUILD), TOXY_RELEASE);
+ tot_ps_qpush = gensym("qpush");
+ tot_ps_query = gensym("query");
+ tot_class = class_new(gensym("tot"),
+ (t_newmethod)tot_new,
+ (t_method)tot_free,
+ sizeof(t_tot), 0, A_DEFSYM, A_DEFSYM, 0);
+ class_addmethod(tot_class, (t_method)tot_prealloc,
+ gensym("prealloc"), A_FLOAT, 0);
+ class_addmethod(tot_class, (t_method)tot_read,
+ gensym("read"), A_DEFSYM, 0);
+ class_addmethod(tot_class, (t_method)tot_write,
+ gensym("write"), A_DEFSYM, 0);
+ class_addmethod(tot_class, (t_method)tot_reset,
+ gensym("reset"), 0);
+ class_addmethod(tot_class, (t_method)tot_push,
+ gensym("push"), A_GIMME, 0);
+ class_addmethod(tot_class, (t_method)tot_push,
+ gensym("qpush"), A_GIMME, 0);
+ class_addmethod(tot_class, (t_method)tot_add,
+ gensym("add"), A_GIMME, 0);
+ class_addmethod(tot_class, (t_method)tot_addnext,
+ gensym("addnext"), A_GIMME, 0);
+ class_addmethod(tot_class, (t_method)tot_tot,
+ gensym("tot"), A_GIMME, 0);
+ class_addmethod(tot_class, (t_method)tot_tot,
+ gensym("query"), A_GIMME, 0);
+ class_addmethod(tot_class, (t_method)tot_detach,
+ gensym("detach"), 0);
+ class_addmethod(tot_class, (t_method)tot_attach,
+ gensym("attach"), 0);
+ class_addmethod(tot_class, (t_method)tot_capture,
+ gensym("capture"), A_FLOAT, A_DEFSYM, 0);
+ class_addmethod(tot_class, (t_method)tot__reply,
+ gensym("_rp"), A_GIMME, 0);
+ class_addmethod(tot_class, (t_method)tot__callback,
+ gensym("_cb"), A_GIMME, 0);
+ class_addmethod(tot_class, (t_method)tot_click,
+ gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(tot_class, (t_method)tot__vised,
+ gensym("_vised"), A_SYMBOL, A_FLOAT, 0);
+#ifdef TOT_DEBUG
+ class_addmethod(tot_class, (t_method)tot_debug,
+ gensym("debug"), 0);
+#endif
+ hammerfile_setup(tot_class, 0);
+ totspy_class = class_new(gensym("tot spy"), 0, 0,
+ sizeof(t_totspy), CLASS_PD, 0);
+ class_addanything(totspy_class, totspy_anything);
+ totsink_class = class_new(gensym("tot sink"), 0, 0,
+ sizeof(t_pd), CLASS_PD, 0);
+ class_addanything(totsink_class, totsink_anything);
+}
diff --git a/toxy/tow.c b/toxy/tow.c
new file mode 100644
index 0000000..5e4f902
--- /dev/null
+++ b/toxy/tow.c
@@ -0,0 +1,26 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* The tow extern just loads the 'widget' library.
+ The tow class itself is defined in widget.c. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+#include "unstable/loader.h"
+
+void tow_setup(void)
+{
+ int result = LOADER_OK;
+ if (zgetfn(&pd_objectmaker, gensym("widget")))
+ loud_warning(0, "widget is already loaded");
+ else
+ result = unstable_load_lib("", "widget");
+ if (result == LOADER_NOFILE)
+ loud_error(0, "widget library is missing");
+ else if (!zgetfn(&pd_objectmaker, gensym("widget")))
+ {
+ loud_error(0, "version mismatch");
+ loud_errand(0, "use a more recent Pd release (or recompile toxy).");
+ }
+}
diff --git a/toxy/toxy-all.exclude b/toxy/toxy-all.exclude
new file mode 100644
index 0000000..d9e9df1
--- /dev/null
+++ b/toxy/toxy-all.exclude
@@ -0,0 +1,8 @@
+*~
+*.o
+*.gz
+*.html
+*.out
+ref
+ref/*
+dumpsetups
diff --git a/toxy/toxy-shared.include b/toxy/toxy-shared.include
new file mode 100644
index 0000000..e754469
--- /dev/null
+++ b/toxy/toxy-shared.include
@@ -0,0 +1,19 @@
+shared/common/loud.c
+shared/common/loud.h
+shared/common/grow.c
+shared/common/grow.h
+shared/common/dict.c
+shared/common/dict.h
+shared/hammer/file.c
+shared/hammer/file.h
+shared/hammer/gui.c
+shared/hammer/gui.h
+shared/unstable/forky.c
+shared/unstable/forky.h
+shared/unstable/loader.c
+shared/unstable/loader.h
+shared/unstable/pd_imp.h
+shared/common/props.c
+shared/common/props.h
+shared/toxy/scriptlet.c
+shared/toxy/scriptlet.h
diff --git a/toxy/toxy-test.exclude b/toxy/toxy-test.exclude
new file mode 100644
index 0000000..6b3cc43
--- /dev/null
+++ b/toxy/toxy-test.exclude
@@ -0,0 +1,5 @@
+*~
+import-result.pd
+import-debug.pd
+temporary
+temporary/*
diff --git a/toxy/toxy-vicious.exclude b/toxy/toxy-vicious.exclude
new file mode 100644
index 0000000..5e5a82e
--- /dev/null
+++ b/toxy/toxy-vicious.exclude
@@ -0,0 +1,3 @@
+*~
+old
+old/*
diff --git a/toxy/widget.c b/toxy/widget.c
new file mode 100644
index 0000000..aff5e32
--- /dev/null
+++ b/toxy/widget.c
@@ -0,0 +1,1146 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* LATER think about reloading method for .wid files */
+/* FIXME sink-binding */
+
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "common/loud.h"
+#include "common/grow.h"
+#include "unstable/forky.h"
+#include "hammer/file.h"
+#include "common/props.h"
+#include "toxy/scriptlet.h"
+#include "widgettype.h"
+#include "build_counter"
+
+/* our proxy of the text_class (not in the API), LATER do not cheat */
+static t_class *makeshift_class;
+
+//#define WIDGET_DEBUG
+//#define TOW_DEBUG
+
+enum { WIDGET_NOUPDATE = 0, WIDGET_RECONFIG, WIDGET_REVIS };
+
+typedef struct _towentry
+{
+ struct _tow *te_tow;
+ struct _towentry *te_next;
+} t_towentry;
+
+typedef struct _widgetentry
+{
+ struct _widget *we_widget;
+ struct _widgetentry *we_next;
+} t_widgetentry;
+
+typedef struct _widget
+{
+ t_object x_ob;
+ t_glist *x_glist; /* containing glist */
+ t_widgettype *x_typedef;
+ t_symbol *x_type; /* 1st creation arg: our type */
+ t_symbol *x_tkclass; /* Tk widget class */
+ t_symbol *x_name; /* 2nd creation arg: our name (common tag) */
+ t_symbol *x_cbtarget; /* same, mangled (a target, and a tag) */
+ t_symbol *x_rptarget; /* same, further mangled */
+ t_symbol *x_cvpathname; /* see widget_getcvpathname() */
+ t_props *x_options; /* instance options */
+ t_props *x_handlers; /* instance handlers */
+ t_props *x_arguments; /* instance arguments */
+ t_scriptlet *x_iniscript; /* instance initializer */
+ t_scriptlet *x_optscript; /* option scriptlet */
+ t_scriptlet *x_auxscript; /* auxiliary scriptlet */
+ t_scriptlet *x_transient; /* output buffer */
+ t_hammerfile *x_filehandle;
+ int x_width;
+ int x_height;
+ t_symbol *x_background;
+ int x_hasstate;
+ int x_update; /* see widget_update() */
+ int x_selected;
+ int x_disabled;
+ t_clock *x_transclock;
+ t_towentry *x_towlist;
+} t_widget;
+
+typedef struct _tow
+{
+ t_object x_ob;
+ t_glist *x_glist; /* containing glist */
+ t_symbol *x_cvremote; /* null if containing glist is our destination */
+ t_symbol *x_cvname;
+ t_symbol *x_type; /* 2nd creation arg: widget's type */
+ t_symbol *x_name; /* 3rd creation arg: widget's name */
+ t_widgettype *x_typedef;
+ t_widgetentry *x_widgetlist;
+ struct _tow *x_next; /* next in the global towlist */
+} t_tow;
+
+static t_class *widget_class;
+static t_class *tow_class;
+
+/* Global towlist, searched in widget_attach(). There is no global widgetlist,
+ because a destination glist is searched instead in tow_attach(). */
+static t_tow *towlist = 0;
+
+static char *widget_propsresolver(t_pd *z, int ac, t_atom *av)
+{
+ t_widget *x = (t_widget *)z;
+ int len;
+ scriptlet_reset(x->x_auxscript);
+ if (scriptlet_add(x->x_auxscript, 1, 0, ac, av))
+ return (scriptlet_getcontents(x->x_auxscript, &len));
+ else
+ return (0);
+}
+
+static t_canvas *widget_cvhook(t_pd *z)
+{
+ return (glist_getcanvas(((t_widget *)z)->x_glist));
+}
+
+/* LATER move to scriptlet.c, use the scriptlet interface (.^) */
+static t_symbol *widget_getcvpathname(t_widget *x, t_glist *glist)
+{
+ t_canvas *cv;
+ if (glist && glist != x->x_glist)
+ {
+ bug("widget_getcvpathname");
+ x->x_glist = glist;
+ }
+ cv = glist_getcanvas(x->x_glist);
+ if (cv == x->x_glist)
+ return (x->x_cvpathname); /* we are not in a gop */
+ else
+ {
+ char buf[32];
+ sprintf(buf, ".x%x.c", (int)cv);
+ return (gensym(buf));
+ }
+}
+
+/* LATER use the scriptlet interface (.-) */
+static t_symbol *widget_getmypathname(t_widget *x, t_glist *glist)
+{
+ char buf[64];
+ t_symbol *cvpathname = widget_getcvpathname(x, glist);
+ sprintf(buf, "%s.%s%x", cvpathname->s_name, x->x_name->s_name, (int)x);
+ return (gensym(buf));
+}
+
+static void widget_postatoms(char *msg, int ac, t_atom *av)
+{
+ startpost(msg);
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT)
+ postfloat(av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ poststring(av->a_w.w_symbol->s_name);
+ av++;
+ }
+ endpost();
+}
+
+static void widget_transtick(t_widget *x)
+{
+ glist_delete(x->x_glist, (t_gobj *)x);
+}
+
+/* called from widget__failure(), LATER also bind this to F4 or something */
+static void widget_transedit(t_widget *x)
+{
+ t_text *newt, *oldt = (t_text *)x;
+ t_binbuf *bb = binbuf_new();
+ int nopt, nbnd, narg;
+ t_atom *opt = props_getall(x->x_options, &nopt);
+ t_atom *bnd = props_getall(x->x_handlers, &nbnd);
+ t_atom *arg = props_getall(x->x_arguments, &narg);
+ binbuf_addv(bb, "sss", gensym("widget"), x->x_type, x->x_name);
+ if (narg) binbuf_add(bb, narg, arg);
+ if (nopt) binbuf_add(bb, nopt, opt);
+ if (nbnd) binbuf_add(bb, nbnd, bnd);
+ canvas_setcurrent(x->x_glist);
+ newt = (t_text *)pd_new(makeshift_class);
+ newt->te_width = 0;
+ newt->te_type = T_OBJECT;
+ newt->te_binbuf = bb;
+ newt->te_xpix = oldt->te_xpix;
+ newt->te_ypix = oldt->te_ypix;
+ glist_add(x->x_glist, &newt->te_g);
+ glist_noselect(x->x_glist);
+ glist_select(x->x_glist, &newt->te_g);
+ gobj_activate(&newt->te_g, x->x_glist, 1);
+ x->x_glist->gl_editor->e_textdirty = 1; /* force evaluation */
+ canvas_unsetcurrent(x->x_glist);
+ canvas_dirty(x->x_glist, 1);
+ clock_delay(x->x_transclock, 0); /* LATER rethink */
+}
+
+/* FIXME x_glist field validation against glist parameter (all handlers) */
+
+static void widget_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_widget *x = (t_widget *)z;
+ float x1, y1, x2, y2;
+ x1 = text_xpix((t_text *)x, glist);
+ y1 = text_ypix((t_text *)x, glist);
+ x2 = x1 + x->x_width;
+ y2 = y1 + x->x_height;
+ *xp1 = x1;
+ *yp1 = y1;
+ *xp2 = x2;
+ *yp2 = y2;
+}
+
+static void widget_displace(t_gobj *z, t_glist *glist, int dx, int dy)
+{
+ t_widget *x = (t_widget *)z;
+ t_text *t = (t_text *)z;
+ t->te_xpix += dx;
+ t->te_ypix += dy;
+ if (glist_isvisible(glist))
+ sys_vgui("%s move %s %d %d\n", widget_getcvpathname(x, glist)->s_name,
+ x->x_cbtarget->s_name, dx, dy);
+ canvas_fixlinesfor(glist_getcanvas(glist), t);
+}
+
+static void widget_select(t_gobj *z, t_glist *glist, int state)
+{
+ t_widget *x = (t_widget *)z;
+ char *mypathname = widget_getmypathname(x, glist)->s_name;
+ if (state)
+ {
+ sys_vgui("%s config -bg blue %s\n", mypathname,
+ (x->x_hasstate ? "-state disabled" : ""));
+ x->x_selected = 1;
+ }
+ else
+ {
+ if (x->x_disabled)
+ sys_vgui("%s config -bg %s\n", mypathname,
+ (x->x_background ? x->x_background->s_name : "gray"));
+ else
+ sys_vgui("%s config -bg %s\n", mypathname,
+ (x->x_background ? x->x_background->s_name : "gray"),
+ (x->x_hasstate ? "-state normal" : ""));
+ x->x_selected = 0;
+ }
+}
+
+static void widget_delete(t_gobj *z, t_glist *glist)
+{
+ canvas_deletelinesfor(glist, (t_text *)z);
+}
+
+static void widget_pushoptions(t_widget *x)
+{
+ char *mypathname = widget_getmypathname(x, x->x_glist)->s_name;
+ if (scriptlet_evaluate(x->x_optscript, x->x_transient, 0, 0, 0, 0))
+ {
+#ifdef WIDGET_DEBUG
+ int sz;
+ char *dp = scriptlet_getcontents(x->x_transient, &sz);
+ post("vis: \"%s\"", dp);
+#endif
+ sys_vgui("%s config ", mypathname);
+ scriptlet_push(x->x_transient);
+ }
+ else
+ {
+ /* LATER if scriptlet not empty: bug("widget_pushoptions"); */
+ }
+}
+
+static void widget_pushinits(t_widget *x)
+{
+ if (masterwidget_evaluate(x->x_transient, 0, 0, 0, x->x_arguments))
+ scriptlet_push(x->x_transient);
+ else
+ bug("widget_pushinits (master)");
+ if (widgettype_isdefined(x->x_typedef))
+ {
+ if (widgettype_evaluate(x->x_typedef, x->x_transient, 0,
+ 0, 0, x->x_arguments))
+ scriptlet_push(x->x_transient);
+ else
+ {
+ /* LATER if scriptlet not empty: bug("widget_pushinits (type)"); */
+ }
+ }
+ if (scriptlet_evaluate(x->x_iniscript, x->x_transient, 0,
+ 0, 0, x->x_arguments))
+ scriptlet_push(x->x_transient);
+ else
+ {
+ /* LATER if scriptlet not empty: bug("widget_pushinits (instance)"); */
+ }
+}
+
+static void widget_vis(t_gobj *z, t_glist *glist, int vis)
+{
+ t_widget *x = (t_widget *)z;
+ t_text *t = (t_text *)z;
+ char *cvpathname = widget_getcvpathname(x, glist)->s_name;
+ char *mypathname = widget_getmypathname(x, glist)->s_name;
+ x->x_update = WIDGET_NOUPDATE;
+ if (vis)
+ {
+ float px1 = text_xpix((t_text *)x, glist);
+ float py1 = text_ypix((t_text *)x, glist);
+#ifndef PD_MINOR_VERSION
+ rtext_new(glist, t, glist->gl_editor->e_rtext, 0);
+#endif
+ sys_vgui("set ::toxy::itempath %s; set ::toxy::itemtarget %s\n\
+ set ::toxy::itemfailure [catch {%s %s}]\n\
+ if {$::toxy::itemfailure} {pd %s _failure\\;}\n",
+ mypathname, x->x_rptarget->s_name,
+ x->x_tkclass->s_name, mypathname,
+ x->x_rptarget->s_name);
+ widget_pushoptions(x);
+ sys_vgui("if {$::toxy::itemfailure == 0}\
+ {%s create window %g %g\
+ -anchor nw -window %s -tags {toxy%s %s}}\n",
+ cvpathname, px1, py1, mypathname,
+ x->x_name->s_name, x->x_cbtarget->s_name);
+ widget_pushinits(x);
+ sys_vgui("if {$::toxy::itemfailure == 0}\
+ {pd %s _config %s [%s cget -bg]\
+ [winfo reqwidth %s] [winfo reqheight %s]\
+ [catch {%s config -state normal}]\\;}\n",
+ x->x_rptarget->s_name, x->x_rptarget->s_name,
+ mypathname, mypathname, mypathname, mypathname);
+ sys_gui("unset ::toxy::itempath; unset ::toxy::itemtarget\n");
+ }
+ else
+ {
+#ifndef PD_MINOR_VERSION
+ t_rtext *rt = glist_findrtext(glist, t);
+ if (rt) rtext_free(rt);
+#endif
+ sys_vgui("destroy %s\n", mypathname);
+ }
+}
+
+static void widget_save(t_gobj *z, t_binbuf *bb)
+{
+ t_widget *x = (t_widget *)z;
+ t_text *t = (t_text *)x;
+ int nopt, nbnd, narg;
+ t_atom *opt = props_getall(x->x_options, &nopt);
+ t_atom *bnd = props_getall(x->x_handlers, &nbnd);
+ t_atom *arg = props_getall(x->x_arguments, &narg);
+ binbuf_addv(bb, "ssiisss", gensym("#X"), gensym("obj"),
+ (int)t->te_xpix, (int)t->te_ypix, gensym("widget"),
+ x->x_type, x->x_name);
+ if (narg) binbuf_add(bb, narg, arg);
+ if (nopt) binbuf_add(bb, nopt, opt);
+ if (nbnd) binbuf_add(bb, nbnd, bnd);
+ binbuf_addsemi(bb);
+}
+
+/* FIXME */
+static void widget_properties(t_gobj *z, t_glist *glist)
+{
+ t_widget *x = (t_widget *)z;
+ t_atom *ap;
+ int ac, nleft;
+ char *head = scriptlet_getcontents(x->x_optscript, &nleft);
+ char buf[MAXPDSTRING + 1];
+ buf[MAXPDSTRING] = 0;
+ sprintf(buf, "%s %s", x->x_type->s_name, x->x_name->s_name);
+ hammereditor_open(x->x_filehandle, buf);
+ while (nleft > 0)
+ {
+ if (nleft > MAXPDSTRING)
+ {
+ strncpy(buf, head, MAXPDSTRING);
+ head += MAXPDSTRING;
+ nleft -= MAXPDSTRING;
+ }
+ else
+ {
+ strncpy(buf, head, nleft);
+ buf[nleft] = 0;
+ nleft = 0;
+ }
+ hammereditor_append(x->x_filehandle, buf);
+ }
+ scriptlet_reset(x->x_auxscript);
+ ap = props_getall(x->x_handlers, &ac);
+ if (ac) scriptlet_add(x->x_auxscript, 0, 0, ac, ap);
+ head = scriptlet_getcontents(x->x_auxscript, &nleft);
+ hammereditor_append(x->x_filehandle, "\n");
+ while (nleft > 0)
+ {
+ if (nleft > MAXPDSTRING)
+ {
+ strncpy(buf, head, MAXPDSTRING);
+ head += MAXPDSTRING;
+ nleft -= MAXPDSTRING;
+ }
+ else
+ {
+ strncpy(buf, head, nleft);
+ buf[nleft] = 0;
+ nleft = 0;
+ }
+ hammereditor_append(x->x_filehandle, buf);
+ }
+}
+
+static t_widgetbehavior widget_behavior =
+{
+ widget_getrect,
+ widget_displace,
+ widget_select,
+ 0,
+ widget_delete,
+ widget_vis,
+ 0,
+ FORKY_WIDGETPADDING
+};
+
+static void widget_update(t_widget *x)
+{
+ t_atom *ap;
+ int ac;
+ scriptlet_reset(x->x_optscript);
+ ap = props_getall(widgettype_getoptions(x->x_typedef), &ac);
+ if (ac) scriptlet_add(x->x_optscript, 0, 0, ac, ap);
+ ap = props_getall(x->x_options, &ac);
+ if (ac) scriptlet_add(x->x_optscript, 0, 0, ac, ap);
+ if (x->x_update &&
+ glist_isvisible(x->x_glist)) /* FIXME the condition */
+ {
+ if (x->x_update == WIDGET_REVIS)
+ {
+ widget_vis((t_gobj *)x, x->x_glist, 0);
+ widget_vis((t_gobj *)x, x->x_glist, 1);
+ }
+ else widget_pushoptions(x);
+ x->x_update = WIDGET_NOUPDATE;
+ }
+ /* LATER cache handlers */
+}
+
+static t_symbol *widget_addprops(t_widget *x, t_props *op,
+ t_symbol *s, int ac, t_atom *av)
+{
+ if (op)
+ {
+ t_symbol *empty;
+ empty = props_add(op, s, ac, av);
+ if (empty)
+ loud_error((t_pd *)x, "no value given for %s '%s'",
+ props_getname(op), empty->s_name);
+ widget_update(x);
+ return (empty);
+ }
+ else
+ {
+ bug("widget_addprops");
+ return (0);
+ }
+}
+
+static t_symbol *widget_addmessage(t_widget *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_symbol *empty;
+ if (!(empty = widget_addprops(x, x->x_options, s, ac, av)) &&
+ !(empty = widget_addprops(x, x->x_handlers, s, ac, av)))
+ empty = widget_addprops(x, x->x_arguments, s, ac, av);
+ return (empty);
+}
+
+static void widget_anything(t_widget *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (s && s != &s_)
+ {
+ if (*s->s_name == '-' || *s->s_name == '@' || *s->s_name == '#')
+ {
+ t_symbol *empty;
+ x->x_update = WIDGET_RECONFIG;
+ if (empty = widget_addmessage(x, s, ac, av))
+ loud_errand((t_pd *)x,
+ "(use 'remove %s' if that is what you want).",
+ empty->s_name);
+ }
+ else
+ {
+ /* LATER cache this */
+ int hlen;
+ t_atom *hp;
+ t_symbol *sel;
+ char buf[MAXPDSTRING];
+ buf[0] = '@';
+ strcpy(buf + 1, s->s_name);
+ sel = gensym(buf);
+ if (((hp = props_getone(x->x_handlers, sel, &hlen)) ||
+ (hp = props_getone(widgettype_gethandlers(x->x_typedef),
+ sel, &hlen)))
+ && hlen > 1)
+ {
+ scriptlet_reset(x->x_auxscript);
+ scriptlet_add(x->x_auxscript, 0, 0, hlen - 1, hp + 1);
+ if (scriptlet_evaluate(x->x_auxscript, x->x_transient,
+ 1, ac, av, 0))
+ scriptlet_push(x->x_transient);
+ }
+ else loud_nomethod((t_pd *)x, s);
+ }
+ }
+}
+
+/* LATER cache this */
+static void widget_bang(t_widget *x)
+{
+ int ac;
+ t_atom *av;
+ t_symbol *sel = gensym("@bang");
+ if ((av = props_getone(x->x_handlers, sel, &ac)) ||
+ (av = props_getone(widgettype_gethandlers(x->x_typedef), sel, &ac)))
+ {
+ if (ac > 1)
+ {
+ scriptlet_reset(x->x_transient);
+ scriptlet_add(x->x_transient, 1, 1, ac - 1, av + 1);
+ scriptlet_push(x->x_transient);
+ }
+ }
+}
+
+/* LATER cache this */
+static void widget_float(t_widget *x, t_float f)
+{
+ int ac;
+ t_atom *av;
+ t_symbol *sel = gensym("@float");
+ if ((av = props_getone(x->x_handlers, sel, &ac)) ||
+ (av = props_getone(widgettype_gethandlers(x->x_typedef), sel, &ac)))
+ {
+ if (ac > 1)
+ {
+ t_atom at;
+ SETFLOAT(&at, f);
+ scriptlet_reset(x->x_auxscript);
+ scriptlet_add(x->x_auxscript, 0, 0, ac - 1, av + 1);
+ if (scriptlet_evaluate(x->x_auxscript,
+ x->x_transient, 1, 1, &at, 0))
+ scriptlet_push(x->x_transient);
+ }
+ }
+}
+
+/* LATER cache this */
+static void widget_symbol(t_widget *x, t_symbol *s)
+{
+ int ac;
+ t_atom *av;
+ t_symbol *sel = gensym("@symbol");
+ if ((av = props_getone(x->x_handlers, sel, &ac)) ||
+ (av = props_getone(widgettype_gethandlers(x->x_typedef), sel, &ac)))
+ {
+ if (ac > 1)
+ {
+ t_atom at;
+ SETSYMBOL(&at, s);
+ scriptlet_reset(x->x_auxscript);
+ scriptlet_add(x->x_auxscript, 0, 0, ac - 1, av + 1);
+ if (scriptlet_evaluate(x->x_auxscript,
+ x->x_transient, 1, 1, &at, 0))
+ scriptlet_push(x->x_transient);
+ }
+ }
+}
+
+static void widget_remove(t_widget *x, t_symbol *s)
+{
+ if (s)
+ {
+ t_props *op;
+ if (*s->s_name == '-')
+ op = x->x_options;
+ else if (*s->s_name == '@')
+ op = x->x_handlers;
+ else if (*s->s_name == '#')
+ op = x->x_arguments;
+ else
+ op = 0;
+ if (op && props_remove(op, s))
+ {
+ x->x_update = WIDGET_REVIS;
+ widget_update(x);
+ }
+ else loud_warning((t_pd *)x, "%s %s has not been specified",
+ props_getname(op), s->s_name);
+ }
+}
+
+static void widget_ini(t_widget *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ scriptlet_reset(x->x_iniscript);
+ scriptlet_add(x->x_iniscript, 0, 0, ac, av);
+ }
+}
+static void widget_tot(t_widget *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_scriptlet *sp = x->x_transient;
+ scriptlet_reset(sp);
+ scriptlet_add(sp, 1, 1, ac, av);
+ scriptlet_push(sp);
+ }
+}
+
+static void widget_refresh(t_widget *x)
+{
+ x->x_update = WIDGET_REVIS;
+ widget_update(x);
+}
+
+static void widget__failure(t_widget *x)
+{
+ /* LATER pass error message from gui, and report here */
+ loud_error((t_pd *)x, "creation failure");
+ widget_transedit(x);
+}
+
+static void widget__config(t_widget *x, t_symbol *target, t_symbol *bg,
+ t_floatarg fw, t_floatarg fh, t_floatarg fst)
+{
+#ifdef WIDGET_DEBUG
+ post("config %d \"%s\" %g %g", bg->s_name, fw, fh);
+#endif
+ x->x_width = (int)fw;
+ x->x_height = (int)fh;
+ if (bg != &s_) x->x_background = bg;
+ x->x_hasstate = ((int)fst == 0);
+ canvas_fixlinesfor(glist_getcanvas(x->x_glist), (t_text *)x); /* FIXME */
+}
+
+static void widget__callback(t_widget *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac == 1)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_float(((t_object *)x)->ob_outlet, av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ outlet_symbol(((t_object *)x)->ob_outlet, av->a_w.w_symbol);
+ }
+ else if (ac)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else if (av->a_type == A_SYMBOL)
+ outlet_anything(((t_object *)x)->ob_outlet,
+ av->a_w.w_symbol, ac - 1, av + 1);
+ }
+ else outlet_bang(((t_object *)x)->ob_outlet);
+}
+
+/* FIXME this is a hack (see also widget_select) */
+/* FIXME why <Leave> is being issued on button press? */
+static void widget__inout(t_widget *x, t_floatarg f)
+{
+ if (x->x_disabled)
+ {
+ if (!x->x_glist->gl_edit)
+ {
+ if (!x->x_selected)
+ {
+ char *mypathname = widget_getmypathname(x, x->x_glist)->s_name;
+ if (x->x_hasstate)
+ sys_vgui("%s config -state normal\n", mypathname);
+ }
+ x->x_disabled = 0;
+ }
+ }
+ else if ((int)f && x->x_glist->gl_edit)
+ {
+ char *mypathname = widget_getmypathname(x, x->x_glist)->s_name;
+ if (x->x_hasstate)
+ sys_vgui("%s config -state disabled\n", mypathname);
+ x->x_disabled = 1;
+ }
+}
+
+static void widget__click(t_widget *x, t_floatarg fx, t_floatarg fy,
+ t_floatarg fb, t_floatarg fm)
+{
+ t_text *t = (t_text *)x;
+ t_atom at[4];
+ fx += t->te_xpix;
+ fy += t->te_ypix;
+ SETFLOAT(&at[0], fx);
+ SETFLOAT(&at[1], fy);
+ SETFLOAT(&at[2], fb);
+ SETFLOAT(&at[3], fm);
+ typedmess((t_pd *)x->x_glist, gensym("mouse"), 4, at);
+ widget__inout(x, 1.);
+}
+
+static void widget__motion(t_widget *x, t_floatarg fx, t_floatarg fy)
+{
+ t_text *t = (t_text *)x;
+ t_atom at[3];
+ fx += t->te_xpix;
+ fy += t->te_ypix;
+ SETFLOAT(&at[0], fx);
+ SETFLOAT(&at[1], fy);
+ SETFLOAT(&at[2], 0);
+ typedmess((t_pd *)x->x_glist, gensym("motion"), 3, at);
+}
+
+int widget_iswidget(t_gobj *g, t_symbol *type, t_symbol *name)
+{
+ if (*(t_pd *)g == widget_class)
+ {
+ t_widget *x = (t_widget *)g;
+ return ((!type || type == x->x_type) &&
+ (!name || name == x->x_name));
+ }
+ else return (0);
+}
+
+#ifdef WIDGET_DEBUG
+static void widget_debug(t_widget *x)
+{
+ t_symbol *pn = widget_getcvpathname(x, 0);
+ t_symbol *mn = widget_getmypathname(x, 0);
+ int sz, i, nopt;
+ t_atom *ap;
+ char *bp, *key;
+ post("containing glist: %x", x->x_glist);
+ post("cv pathname%s %s", (pn ? ":" : ""), (pn ? pn->s_name : "unknown"));
+ post("my pathname%s %s", (mn ? ":" : ""), (mn ? mn->s_name : "unknown"));
+ if (ap = props_getall(widgettype_getoptions(x->x_typedef), &nopt))
+ widget_postatoms("default options:", nopt, ap);
+ if (ap = props_getall(x->x_options, &nopt))
+ widget_postatoms("instance options:", nopt, ap);
+ if (ap = props_getall(widgettype_gethandlers(x->x_typedef), &nopt))
+ widget_postatoms("default handlers:", nopt, ap);
+ if (ap = props_getall(x->x_handlers, &nopt))
+ widget_postatoms("instance handlers:", nopt, ap);
+ if (ap = props_getall(widgettype_getarguments(x->x_typedef), &nopt))
+ widget_postatoms("default arguments:", nopt, ap);
+ if (ap = props_getall(x->x_arguments, &nopt))
+ widget_postatoms("instance arguments:", nopt, ap);
+ post("dictionary:");
+ bp = props_firstvalue(x->x_arguments, &key);
+ while (bp)
+ {
+ post("\t%s: \"%s\"", key, bp);
+ bp = props_nextvalue(x->x_arguments, &key);
+ }
+ bp = scriptlet_getcontents(x->x_transient, &sz);
+ post("transient buffer (size %d):\n\"%s\"", sz, bp);
+ bp = scriptlet_getcontents(x->x_optscript, &sz);
+ post("option buffer (size %d):\n\"%s\"", sz, bp);
+ bp = widgettype_getcontents(x->x_typedef, &sz);
+ post("type initializer (size %d):\n\"%s\"", sz, bp);
+ bp = scriptlet_getcontents(x->x_iniscript, &sz);
+ post("instance initializer (size %d):\n\"%s\"", sz, bp);
+}
+#endif
+
+static void widget_attach(t_widget *x);
+static void widget_detach(t_widget *x);
+
+static void widget_free(t_widget *x)
+{
+ pd_unbind((t_pd *)x, x->x_cbtarget);
+ pd_unbind((t_pd *)x, x->x_rptarget);
+ props_freeall(x->x_options);
+ scriptlet_free(x->x_iniscript);
+ scriptlet_free(x->x_optscript);
+ scriptlet_free(x->x_auxscript);
+ scriptlet_free(x->x_transient);
+ hammerfile_free(x->x_filehandle);
+ if (x->x_transclock) clock_free(x->x_transclock);
+ widget_detach(x);
+}
+
+static void *widget_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_widget *x = (t_widget *)pd_new(widget_class);
+ char buf[MAXPDSTRING];
+ masterwidget_initialize();
+ x->x_type = 0;
+ x->x_name = 0;
+ if (ac && av->a_type == A_SYMBOL)
+ {
+ x->x_type = av->a_w.w_symbol;
+ ac--; av++;
+ }
+ if (ac && av->a_type == A_SYMBOL)
+ {
+ x->x_name = av->a_w.w_symbol;
+ ac--; av++;
+ }
+ /* LATER think about anonymous widgets (single arg, or '.') */
+ if (!x->x_type || x->x_type == &s_ ||
+ !x->x_name || x->x_name == &s_)
+ {
+ loud_error((t_pd *)x, "bad arguments for a widget");
+ loud_errand((t_pd *)x,
+ "expecting \"widget <type> <name> [properties]\"");
+ return (0);
+ }
+ sprintf(buf, "%s%x", x->x_name->s_name, (int)x);
+ pd_bind((t_pd *)x, x->x_cbtarget = gensym(buf));
+ sprintf(buf, "%s%x.rp", x->x_name->s_name, (int)x);
+ pd_bind((t_pd *)x, x->x_rptarget = gensym(buf));
+
+ x->x_typedef = widgettype_get(x->x_type);
+ if (!(x->x_tkclass = widgettype_tkclass(x->x_typedef)))
+ x->x_tkclass = x->x_type;
+
+ x->x_iniscript = scriptlet_new((t_pd *)x, x->x_rptarget, x->x_cbtarget,
+ x->x_name, widget_cvhook);
+ x->x_optscript = scriptlet_new((t_pd *)x, x->x_rptarget, x->x_cbtarget,
+ x->x_name, widget_cvhook);
+ x->x_auxscript = scriptlet_new((t_pd *)x, x->x_rptarget, x->x_cbtarget,
+ x->x_name, widget_cvhook);
+ x->x_transient = scriptlet_new((t_pd *)x, x->x_rptarget, x->x_cbtarget,
+ x->x_name, widget_cvhook);
+
+ x->x_options = props_new((t_pd *)x, "option", "-", 0, 0);
+ x->x_handlers = props_new((t_pd *)x, "handler", "@", x->x_options, 0);
+ x->x_arguments = props_new((t_pd *)x, "argument", "#", x->x_options,
+ widget_propsresolver);
+
+ sprintf(buf, ".^.c.%s%x", x->x_name->s_name, (int)x);
+ x->x_glist = canvas_getcurrent();
+ sprintf(buf, ".x%x.c", (int)x->x_glist);
+ x->x_cvpathname = gensym(buf);
+ outlet_new((t_object *)x, &s_anything);
+ /* LATER consider estimating these, based on widget class and options */
+ x->x_width = 50;
+ x->x_height = 50;
+ props_clone(x->x_arguments, widgettype_getarguments(x->x_typedef));
+ widget_addmessage(x, 0, ac, av);
+ x->x_filehandle = hammerfile_new((t_pd *)x, 0, 0, 0, 0);
+ x->x_transclock = clock_new(x, (t_method)widget_transtick);
+ x->x_background = 0;
+ x->x_hasstate = 0;
+ x->x_update = WIDGET_NOUPDATE;
+ x->x_disabled = 0;
+ widget_attach(x);
+ return (x);
+}
+
+static t_glist *tow_getglist(t_tow *x, int complain)
+{
+ t_glist *glist =
+ (x->x_cvremote ?
+ (t_glist *)pd_findbyclass(x->x_cvremote, canvas_class) : x->x_glist);
+ if (!glist && complain)
+ loud_error((t_pd *)x, "bad canvas name '%s'", x->x_cvname->s_name);
+ return (glist);
+}
+
+static void tow_bang(t_tow *x)
+{
+ t_widgetentry *we;
+ for (we = x->x_widgetlist; we; we = we->we_next)
+ widget_bang(we->we_widget);
+}
+
+static void tow_float(t_tow *x, t_float f)
+{
+ t_widgetentry *we;
+ for (we = x->x_widgetlist; we; we = we->we_next)
+ widget_float(we->we_widget, f);
+}
+
+static void tow_symbol(t_tow *x, t_symbol *s)
+{
+ t_widgetentry *we;
+ for (we = x->x_widgetlist; we; we = we->we_next)
+ widget_symbol(we->we_widget, s);
+}
+
+static void tow_anything(t_tow *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_widgetentry *we;
+ for (we = x->x_widgetlist; we; we = we->we_next)
+ typedmess((t_pd *)we->we_widget, s, ac, av);
+}
+
+static void tow__callback(t_tow *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac == 1)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_float(((t_object *)x)->ob_outlet, av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ outlet_symbol(((t_object *)x)->ob_outlet, av->a_w.w_symbol);
+ }
+ else if (ac)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else if (av->a_type == A_SYMBOL)
+ outlet_anything(((t_object *)x)->ob_outlet,
+ av->a_w.w_symbol, ac - 1, av + 1);
+ }
+ else outlet_bang(((t_object *)x)->ob_outlet);
+}
+
+static void tow_widgetattach(t_tow *x, t_widget *w)
+{
+ t_towentry *te = getbytes(sizeof(*te));
+ t_widgetentry *we = getbytes(sizeof(*we));
+ te->te_tow = x;
+ te->te_next = w->x_towlist;
+ w->x_towlist = te;
+ we->we_widget = w;
+ we->we_next = x->x_widgetlist;
+ x->x_widgetlist = we;
+ pd_bind((t_pd *)x, w->x_cbtarget);
+#ifdef TOW_DEBUG
+ post("%s widget '%s' attached", w->x_type->s_name, w->x_cbtarget->s_name);
+#endif
+}
+
+static void tow_widgetdetach(t_tow *x, t_widget *w)
+{
+ t_widgetentry *we1, *we2;
+ for (we1 = 0, we2 = x->x_widgetlist; we2; we2 = we2->we_next)
+ {
+ if (we2->we_widget == w)
+ {
+#ifdef TOW_DEBUG
+ post("%s widget '%s' detached by widget's destructor",
+ w->x_type->s_name, w->x_cbtarget->s_name);
+#endif
+ pd_unbind((t_pd *)x, w->x_cbtarget);
+ if (we1)
+ we1->we_next = we2->we_next;
+ else
+ x->x_widgetlist = we2->we_next;
+ freebytes(we2, sizeof(*we2));
+ return;
+ }
+ we1 = we2;
+ }
+ bug("tow_widgetdetach");
+}
+
+static void widget_attach(t_widget *x)
+{
+ t_tow *t;
+ for (t = towlist; t; t = t->x_next)
+ if (x->x_glist == tow_getglist(t, 0) &&
+ t->x_type == x->x_type && t->x_name == x->x_name)
+ tow_widgetattach(t, x);
+}
+
+static void widget_detach(t_widget *x)
+{
+ t_towentry *te;
+ while (te = x->x_towlist)
+ {
+ x->x_towlist = te->te_next;
+ tow_widgetdetach(te->te_tow, x);
+ freebytes(te, sizeof(*te));
+ }
+}
+
+static void tow_attach(t_tow *x)
+{
+ t_glist *glist = tow_getglist(x, 0);
+ if (glist)
+ {
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ {
+ if (*(t_pd *)g == widget_class)
+ {
+ t_widget *w = (t_widget *)g;
+ if (w->x_type == x->x_type && w->x_name == x->x_name)
+ tow_widgetattach(x, w);
+ }
+ }
+#ifdef TOW_DEBUG
+ if (!x->x_widgetlist)
+ post("%s widget '%s' not found",
+ x->x_type->s_name, x->x_name->s_name);
+#endif
+ }
+#ifdef TOW_DEBUG
+ else post("glist '%s' not found", x->x_cvname->s_name);
+#endif
+}
+
+static void tow_detach(t_tow *x)
+{
+ t_widgetentry *we;
+ while (we = x->x_widgetlist)
+ {
+ t_widget *w = we->we_widget;
+ t_towentry *te1, *te2;
+ x->x_widgetlist = we->we_next;
+ pd_unbind((t_pd *)x, w->x_cbtarget);
+ freebytes(we, sizeof(*we));
+ for (te1 = 0, te2 = w->x_towlist; te2; te2 = te2->te_next)
+ {
+ if (te2->te_tow == x)
+ {
+#ifdef TOW_DEBUG
+ post("%s widget '%s' detached by tow's destructor",
+ w->x_type->s_name, w->x_cbtarget->s_name);
+#endif
+ if (te1)
+ te1->te_next = te2->te_next;
+ else
+ w->x_towlist = te2->te_next;
+ freebytes(te2, sizeof(*te2));
+ break;
+ }
+ te1 = te2;
+ }
+ if (!te2) bug("tow_detach");
+ }
+}
+
+#ifdef TOW_DEBUG
+static void tow_debug(t_tow *x)
+{
+ t_widgetentry *we;
+ post("attached widgets:");
+ for (we = x->x_widgetlist; we; we = we->we_next)
+ {
+ t_widget *w = we->we_widget;
+ t_towentry *te;
+ int other = 0, found = 0;
+ startpost("\t%s %s", w->x_type->s_name, w->x_cbtarget->s_name);
+ for (te = w->x_towlist; te; te = te->te_next)
+ if (te->te_tow == x)
+ found++;
+ else
+ other++;
+ post(" (%d other tow%s)", other, (other == 1 ? "" : "s"));
+ if (found != 1) post("BUG: listed %d times in widget's towlist", found);
+ }
+}
+#endif
+
+static void tow_free(t_tow *x)
+{
+ t_tow *t1, *t2;
+#ifdef TOW_DEBUG
+ startpost("updating towlist...");
+#endif
+ for (t1 = 0, t2 = towlist; t2; t2 = t2->x_next)
+ {
+ if (t2 == x)
+ {
+ if (t1)
+ t1->x_next = t2->x_next;
+ else
+ towlist = t2->x_next;
+#ifdef TOW_DEBUG
+ post("ok");
+#endif
+ break;
+ }
+ t1 = t2;
+ }
+ tow_detach(x);
+}
+
+static void *tow_new(t_symbol *s1, t_symbol *s2, t_symbol *s3)
+{
+ t_tow *x = (t_tow *)pd_new(tow_class);
+ char buf[64];
+ x->x_glist = canvas_getcurrent();
+ if (s1 && s1 != &s_ && strcmp(s1->s_name, "."))
+ x->x_cvremote = canvas_makebindsym(x->x_cvname = s1);
+ else
+ {
+ x->x_cvremote = 0;
+ x->x_cvname = x->x_glist->gl_name;
+ }
+ x->x_type = s2;
+ x->x_name = s3;
+ outlet_new((t_object *)x, &s_anything);
+ x->x_widgetlist = 0;
+ x->x_next = towlist;
+ towlist = x;
+ tow_attach(x);
+ return (x);
+}
+
+void widget_setup(void)
+{
+ post("beware! this is widget %s, %s %s build...",
+ TOXY_VERSION, loud_ordinal(TOXY_BUILD), TOXY_RELEASE);
+ widgettype_setup();
+ widget_class = class_new(gensym("widget"),
+ (t_newmethod)widget_new,
+ (t_method)widget_free,
+ sizeof(t_widget), 0, A_GIMME, 0);
+ class_setwidget(widget_class, &widget_behavior);
+ forky_setsavefn(widget_class, widget_save);
+ forky_setpropertiesfn(widget_class, widget_properties);
+ class_addbang(widget_class, widget_bang);
+ class_addfloat(widget_class, widget_float);
+ class_addsymbol(widget_class, widget_symbol);
+ class_addanything(widget_class, widget_anything);
+ class_addmethod(widget_class, (t_method)widget_remove,
+ gensym("remove"), A_SYMBOL, 0);
+ class_addmethod(widget_class, (t_method)widget_ini,
+ gensym("ini"), A_GIMME, 0);
+ class_addmethod(widget_class, (t_method)widget_tot,
+ gensym("tot"), A_GIMME, 0);
+ class_addmethod(widget_class, (t_method)widget_refresh,
+ gensym("refresh"), 0);
+ class_addmethod(widget_class, (t_method)widget__config,
+ gensym("_config"),
+ A_SYMBOL, A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(widget_class, (t_method)widget__failure,
+ gensym("_failure"), 0);
+ class_addmethod(widget_class, (t_method)widget__callback,
+ gensym("_cb"), A_GIMME, 0);
+ class_addmethod(widget_class, (t_method)widget__inout,
+ gensym("_inout"), A_FLOAT, 0);
+ class_addmethod(widget_class, (t_method)widget__click,
+ gensym("_click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(widget_class, (t_method)widget__motion,
+ gensym("_motion"), A_FLOAT, A_FLOAT, 0);
+#ifdef WIDGET_DEBUG
+ class_addmethod(widget_class, (t_method)widget_debug,
+ gensym("debug"), 0);
+#endif
+ hammerfile_setup(widget_class, 0);
+
+ makeshift_class = class_new(gensym("text"), 0, 0,
+ sizeof(t_text),
+ CLASS_NOINLET | CLASS_PATCHABLE, 0);
+
+ tow_class = class_new(gensym("tow"),
+ (t_newmethod)tow_new,
+ (t_method)tow_free,
+ sizeof(t_tow), 0, A_SYMBOL, A_SYMBOL, A_SYMBOL, 0);
+ class_addbang(tow_class, tow_bang);
+ class_addfloat(tow_class, tow_float);
+ class_addsymbol(tow_class, tow_symbol);
+ class_addanything(tow_class, tow_anything);
+ class_addmethod(tow_class, (t_method)tow__callback,
+ gensym("_cb"), A_GIMME, 0);
+#ifdef TOW_DEBUG
+ class_addmethod(tow_class, (t_method)tow_debug,
+ gensym("debug"), 0);
+#endif
+}
diff --git a/toxy/widgettype.c b/toxy/widgettype.c
new file mode 100644
index 0000000..6f26c27
--- /dev/null
+++ b/toxy/widgettype.c
@@ -0,0 +1,300 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/dict.h"
+#include "common/props.h"
+#include "toxy/scriptlet.h"
+#include "widgettype.h"
+
+#define WIDGETTYPE_VERBOSE
+//#define WIDGETTYPE_DEBUG
+
+struct _widgettype
+{
+ t_pd wt_pd;
+ t_symbol *wt_typekey; /* this is a typemap symbol */
+ t_symbol *wt_tkclass; /* also 'undefined' flag (gensym symbol) */
+ t_symbol *wt_tkpackage; /* gensym symbol */
+ t_props *wt_options;
+ t_props *wt_handlers;
+ t_props *wt_arguments;
+ t_scriptlet *wt_iniscript;
+};
+
+struct _masterwidget
+{
+ t_pd mw_pd;
+ t_symbol *mw_target;
+ t_scriptlet *mw_setupscript;
+ t_dict *mw_typemap;
+ t_widgettype *mw_defaulttype; /* contains master iniscript */
+ t_widgettype *mw_parsedtype; /* the type currently parsed, if loading */
+ t_binbuf *mw_bb; /* auxiliary, LATER remove */
+};
+
+static t_class *widgettype_class;
+static t_class *masterwidget_class;
+
+static t_masterwidget *masterwidget = 0;
+
+static t_canvas *widgettype_cvhook(t_pd *z)
+{
+ return (0);
+}
+
+static void widgettype_map(t_widgettype *wt, char *cls, char *pkg)
+{
+ wt->wt_tkclass = (cls ? gensym(cls) : 0);
+ wt->wt_tkpackage = (pkg ? gensym(pkg) : 0);
+}
+
+static t_widgettype *widgettype_new(t_masterwidget *mw,
+ char *typ, char *cls, char *pkg)
+{
+ t_widgettype *wt = (t_widgettype *)pd_new(widgettype_class);
+ wt->wt_typekey = dict_key(mw->mw_typemap, typ);
+ widgettype_map(wt, cls, pkg);
+ wt->wt_options = props_new(0, "option", "-", 0, 0);
+ wt->wt_handlers = props_new(0, "handler", "@", wt->wt_options, 0);
+ wt->wt_arguments = props_new(0, "argument", "#", wt->wt_options, 0);
+ wt->wt_iniscript = scriptlet_new((t_pd *)wt, mw->mw_target, mw->mw_target,
+ 0, widgettype_cvhook);
+ dict_bind(mw->mw_typemap, (t_pd *)wt, wt->wt_typekey);
+ return (wt);
+}
+
+static t_canvas *masterwidget_cvhook(t_pd *z)
+{
+ return (0);
+}
+
+static t_scriptlet *masterwidget_cmnthook(t_pd *z, char *rc,
+ char sel, char *buf)
+{
+ t_masterwidget *mw = masterwidget;
+ if (!*buf)
+ return (0);
+ if (sel == '>')
+ {
+ t_symbol *typekey;
+ t_widgettype *typeval;
+ char *cls = scriptlet_nextword(buf);
+ char *pkg = (cls ? scriptlet_nextword(cls) : 0);
+ mw->mw_parsedtype = 0;
+ if (!cls)
+ cls = buf;
+ typekey = dict_key(mw->mw_typemap, buf);
+ typeval = (t_widgettype *)dict_value(mw->mw_typemap, typekey);
+ if (z == (t_pd *)mw)
+ { /* default.wid */
+ if (typeval)
+ {
+ /* LATER rethink */
+ loud_warning((t_pd *)mw, "redefinition of '%s'\
+ in \"%s.wid\" file, ignored", buf, rc);
+ return (0);
+ }
+ }
+ else
+ { /* <type>.wid */
+ if (z != (t_pd *)typeval)
+ {
+ loud_warning((t_pd *)mw, "alien definition of '%s'\
+ in \"%s.wid\" file, ignored", buf, rc);
+ return (0);
+ }
+ }
+ if (pkg)
+ /* carve out a single word as pkg, LATER rethink */
+ scriptlet_nextword(pkg);
+ if (typeval)
+ widgettype_map(typeval, cls, pkg);
+ else
+ typeval = widgettype_new(mw, buf, cls, pkg);
+ mw->mw_parsedtype = typeval;
+#ifdef WIDGETTYPE_DEBUG
+ post("adding widget type '%s'", typeval->wt_typekey->s_name);
+#endif
+ return (typeval->wt_iniscript);
+ }
+ else if (sel == '.')
+ {
+ if (mw->mw_parsedtype
+ && (*buf == '-' || *buf == '@' || *buf == '#'))
+ {
+ t_symbol *empty;
+ int ac;
+ /* LATER get rid of the binbuf thing */
+ binbuf_text(mw->mw_bb, buf, strlen(buf));
+ if (ac = binbuf_getnatom(mw->mw_bb))
+ {
+ t_atom *av = binbuf_getvec(mw->mw_bb);
+ t_props *pp;
+ if (!(empty = props_add(pp = mw->mw_parsedtype->wt_options,
+ 0, ac, av)) &&
+ !(empty = props_add(pp = mw->mw_parsedtype->wt_handlers,
+ 0, ac, av)))
+ empty = props_add(pp = mw->mw_parsedtype->wt_arguments,
+ 0, ac, av);
+ if (empty)
+ loud_warning((t_pd *)mw,
+ "no value given for %s '%s'\
+ of a widget type '%s' in \"%s.wid\" file",
+ props_getname(pp), empty->s_name,
+ mw->mw_parsedtype->wt_typekey->s_name, rc);
+ }
+ }
+ }
+ return (0);
+}
+
+t_widgettype *widgettype_get(t_symbol *s)
+{
+ t_widgettype *wt;
+ /* default.wid defs are NOT overridden by <type>.wid --
+ feature stability comes first, LATER rethink */
+ if (wt = (t_widgettype *)dict_value(masterwidget->mw_typemap,
+ dict_key(masterwidget->mw_typemap,
+ s->s_name)))
+ masterwidget->mw_parsedtype = 0;
+ else
+ {
+ /* first instance of a type not defined in default.wid */
+ wt = widgettype_new(masterwidget, s->s_name, 0, 0);
+ masterwidget->mw_parsedtype = wt;
+ }
+ if (masterwidget->mw_parsedtype)
+ {
+ if (scriptlet_rcload(wt->wt_iniscript, s->s_name, ".wid",
+ masterwidget_cmnthook) == SCRIPTLET_OK)
+ {
+#ifdef WIDGETTYPE_VERBOSE
+ post("using %s's initializer", s->s_name);
+#endif
+ }
+ }
+ return (wt);
+}
+
+int widgettype_isdefined(t_widgettype *wt)
+{
+ return (wt->wt_tkclass != 0);
+}
+
+t_symbol *widgettype_tkclass(t_widgettype *wt)
+{
+ return (wt->wt_tkclass);
+}
+
+t_props *widgettype_getoptions(t_widgettype *wt)
+{
+ return (wt->wt_options);
+}
+
+t_props *widgettype_gethandlers(t_widgettype *wt)
+{
+ return (wt->wt_handlers);
+}
+
+t_props *widgettype_getarguments(t_widgettype *wt)
+{
+ return (wt->wt_arguments);
+}
+
+char *widgettype_getcontents(t_widgettype *wt, int *szp)
+{
+ return (scriptlet_getcontents(wt->wt_iniscript, szp));
+}
+
+int widgettype_evaluate(t_widgettype *wt, t_scriptlet *outsp,
+ int visedonly, int ac, t_atom *av, t_props *argprops)
+{
+ return (scriptlet_evaluate(wt->wt_iniscript, outsp,
+ visedonly, ac, av, argprops));
+}
+
+int masterwidget_evaluate(t_scriptlet *outsp, int visedonly,
+ int ac, t_atom *av, t_props *argprops)
+{
+ return (scriptlet_evaluate(masterwidget->mw_defaulttype->wt_iniscript,
+ outsp, visedonly, ac, av, argprops));
+}
+
+void widgettype_setup(void)
+{
+ static int done = 0;
+ if (!done)
+ {
+ widgettype_class = class_new(gensym("widget type"), 0, 0,
+ sizeof(t_widgettype), CLASS_PD, 0);
+ masterwidget_class = class_new(gensym("Widget"), 0, 0,
+ sizeof(t_masterwidget), CLASS_PD, 0);
+ done = 1;
+ }
+}
+
+void masterwidget_initialize(void)
+{
+ t_scriptlet *sp;
+ t_symbol *typekey;
+ t_widgettype *typeval;
+ char buf[MAXPDSTRING];
+ if (masterwidget)
+ return;
+ masterwidget = (t_masterwidget *)pd_new(masterwidget_class);
+ sprintf(buf, "mw%x", (int)masterwidget);
+ /* never unbound, LATER rethink */
+ pd_bind((t_pd *)masterwidget, masterwidget->mw_target = gensym(buf));
+
+ masterwidget->mw_typemap = dict_new(0);
+
+ sp = masterwidget->mw_setupscript =
+ scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target,
+ masterwidget->mw_target, 0, 0);
+ masterwidget->mw_parsedtype = 0;
+ masterwidget->mw_bb = binbuf_new();
+
+ if (scriptlet_rcload(sp, "default", ".wid",
+ masterwidget_cmnthook) == SCRIPTLET_OK)
+ {
+#ifdef WIDGETTYPE_VERBOSE
+ post("using file 'default.wid'");
+#endif
+ }
+ else
+ {
+ loud_warning((t_pd *)masterwidget, "missing file 'default.wid'");
+
+ /* no setup scriptlet, LATER use built-in default */
+#if 0
+ scriptlet_reset(sp);
+ scriptlet_addstring(sp, ...
+#endif
+ }
+ typekey = dict_key(masterwidget->mw_typemap, "default");
+ if (typeval = (t_widgettype *)dict_value(masterwidget->mw_typemap, typekey))
+ masterwidget->mw_defaulttype = typeval;
+ else
+ {
+ /* no master initializer, LATER use built-in default */
+ masterwidget->mw_defaulttype =
+ widgettype_new(masterwidget, "default", 0, 0);
+ sp = masterwidget->mw_defaulttype->wt_iniscript;
+#if 0
+ scriptlet_reset(sp);
+ scriptlet_addstring(sp, ...
+#endif
+ }
+ sp = scriptlet_new((t_pd *)masterwidget,
+ masterwidget->mw_target, masterwidget->mw_target, 0, 0);
+ if (scriptlet_evaluate(masterwidget->mw_setupscript, sp, 0, 0, 0, 0))
+ scriptlet_push(sp);
+ else
+ bug("masterwidget_initialize");
+ scriptlet_free(sp);
+}
diff --git a/toxy/widgettype.h b/toxy/widgettype.h
new file mode 100644
index 0000000..55c8e9d
--- /dev/null
+++ b/toxy/widgettype.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __WIDGETTYPE_H__
+#define __WIDGETTYPE_H__
+
+EXTERN_STRUCT _widgettype;
+#define t_widgettype struct _widgettype
+
+EXTERN_STRUCT _masterwidget;
+#define t_masterwidget struct _masterwidget
+
+t_widgettype *widgettype_get(t_symbol *s);
+int widgettype_isdefined(t_widgettype *wt);
+t_symbol *widgettype_tkclass(t_widgettype *wt);
+t_props *widgettype_getoptions(t_widgettype *wt);
+t_props *widgettype_gethandlers(t_widgettype *wt);
+t_props *widgettype_getarguments(t_widgettype *wt);
+char *widgettype_propname(t_symbol *s);
+char *widgettype_getcontents(t_widgettype *wt, int *szp);
+int widgettype_evaluate(t_widgettype *wt, t_scriptlet *outsp,
+ int visedonly, int ac, t_atom *av, t_props *argprops);
+int masterwidget_evaluate(t_scriptlet *outsp, int visedonly,
+ int ac, t_atom *av, t_props *argprops);
+void masterwidget_initialize(void);
+
+void widgettype_setup(void);
+
+#endif