1
/* Copyright (c) 1997-1999 Miller Puckette.
2
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
10
#include "s_stuff.h" /* for sys_hostfontsize */
13
void array_redraw(t_array *a, t_glist *glist);
16
This file contains text objects you would put in a canvas to define a
17
template. Templates describe objects of type "array" (g_array.c) and
18
"scalar" (g_scalar.c).
21
/* the structure of a "struct" object (also the obsolete "gtemplate"
22
you get when using the name "template" in a box.) */
27
t_template *x_template;
30
struct _gtemplate *x_next;
35
/* ---------------- forward definitions ---------------- */
37
static void template_conformarray(t_template *tfrom, t_template *tto,
38
int *conformaction, t_array *a);
39
static void template_conformglist(t_template *tfrom, t_template *tto,
40
t_glist *glist, int *conformaction);
42
/* ---------------------- storage ------------------------- */
44
static t_class *gtemplate_class;
45
static t_class *template_class;
47
/* there's a pre-defined "float" template. LATER should we bind this
48
to a symbol such as "pd-float"??? */
50
/* return true if two dataslot definitions match */
51
static int dataslot_matches(t_dataslot *ds1, t_dataslot *ds2,
54
return ((!nametoo || ds1->ds_name == ds2->ds_name) &&
55
ds1->ds_type == ds2->ds_type &&
56
(ds1->ds_type != DT_ARRAY ||
57
ds1->ds_arraytemplate == ds2->ds_arraytemplate));
60
/* -- templates, the active ingredient in gtemplates defined below. ------- */
62
t_template *template_new(t_symbol *templatesym, int argc, t_atom *argv)
64
t_template *x = (t_template *)pd_new(template_class);
66
x->t_vec = (t_dataslot *)t_getbytes(0);
69
int newtype, oldn, newn;
70
t_symbol *newname, *newarraytemplate = &s_, *newtypesym;
71
if (argc < 2 || argv[0].a_type != A_SYMBOL ||
72
argv[1].a_type != A_SYMBOL)
74
newtypesym = argv[0].a_w.w_symbol;
75
newname = argv[1].a_w.w_symbol;
76
if (newtypesym == &s_float)
78
else if (newtypesym == &s_symbol)
80
else if (newtypesym == &s_list)
82
else if (newtypesym == gensym("array"))
84
if (argc < 3 || argv[2].a_type != A_SYMBOL)
86
pd_error(x, "array lacks element template or name");
89
newarraytemplate = canvas_makebindsym(argv[2].a_w.w_symbol);
96
pd_error(x, "%s: no such type", newtypesym->s_name);
99
newn = (oldn = x->t_n) + 1;
100
x->t_vec = (t_dataslot *)t_resizebytes(x->t_vec,
101
oldn * sizeof(*x->t_vec), newn * sizeof(*x->t_vec));
103
x->t_vec[oldn].ds_type = newtype;
104
x->t_vec[oldn].ds_name = newname;
105
x->t_vec[oldn].ds_arraytemplate = newarraytemplate;
107
argc -= 2; argv += 2;
109
if (*templatesym->s_name)
111
x->t_sym = templatesym;
112
pd_bind(&x->t_pdobj, x->t_sym);
114
else x->t_sym = templatesym;
118
int template_size(t_template *x)
120
return (x->t_n * sizeof(t_word));
123
int template_find_field(t_template *x, t_symbol *name, int *p_onset,
124
int *p_type, t_symbol **p_arraytype)
130
bug("template_find_field");
134
for (i = 0; i < n; i++)
135
if (x->t_vec[i].ds_name == name)
137
*p_onset = i * sizeof(t_word);
138
*p_type = x->t_vec[i].ds_type;
139
*p_arraytype = x->t_vec[i].ds_arraytemplate;
145
t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp,
151
if (template_find_field(x, fieldname, &onset, &type, &arraytype))
153
if (type == DT_FLOAT)
154
val = *(t_float *)(((char *)wp) + onset);
155
else if (loud) error("%s.%s: not a number",
156
x->t_sym->s_name, fieldname->s_name);
158
else if (loud) error("%s.%s: no such field",
159
x->t_sym->s_name, fieldname->s_name);
163
void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp,
168
if (template_find_field(x, fieldname, &onset, &type, &arraytype))
170
if (type == DT_FLOAT)
171
*(t_float *)(((char *)wp) + onset) = f;
172
else if (loud) error("%s.%s: not a number",
173
x->t_sym->s_name, fieldname->s_name);
175
else if (loud) error("%s.%s: no such field",
176
x->t_sym->s_name, fieldname->s_name);
179
t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp,
185
if (template_find_field(x, fieldname, &onset, &type, &arraytype))
187
if (type == DT_SYMBOL)
188
val = *(t_symbol **)(((char *)wp) + onset);
189
else if (loud) error("%s.%s: not a symbol",
190
x->t_sym->s_name, fieldname->s_name);
192
else if (loud) error("%s.%s: no such field",
193
x->t_sym->s_name, fieldname->s_name);
197
void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp,
198
t_symbol *s, int loud)
202
if (template_find_field(x, fieldname, &onset, &type, &arraytype))
204
if (type == DT_SYMBOL)
205
*(t_symbol **)(((char *)wp) + onset) = s;
206
else if (loud) error("%s.%s: not a symbol",
207
x->t_sym->s_name, fieldname->s_name);
209
else if (loud) error("%s.%s: no such field",
210
x->t_sym->s_name, fieldname->s_name);
213
/* stringent check to see if a "saved" template, x2, matches the current
214
one (x1). It's OK if x1 has additional scalar elements but not (yet)
215
arrays or lists. This is used for reading in "data files". */
216
int template_match(t_template *x1, t_template *x2)
219
if (x1->t_n < x2->t_n)
221
for (i = x2->t_n; i < x1->t_n; i++)
223
if (x1->t_vec[i].ds_type == DT_ARRAY ||
224
x1->t_vec[i].ds_type == DT_LIST)
227
if (x2->t_n > x1->t_n)
228
post("add elements...");
229
for (i = 0; i < x2->t_n; i++)
230
if (!dataslot_matches(&x1->t_vec[i], &x2->t_vec[i], 1))
235
/* --------------- CONFORMING TO CHANGES IN A TEMPLATE ------------ */
237
/* the following routines handle updating scalars to agree with changes
238
in their template. The old template is assumed to be the "installed" one
239
so we can delete old items; but making new ones we have to avoid scalar_new
240
which would make an old one whereas we will want a new one (but whose array
241
elements might still be old ones.)
242
LATER deal with graphics updates too... */
244
/* conform the word vector of a scalar to the new template */
245
static void template_conformwords(t_template *tfrom, t_template *tto,
246
int *conformaction, t_word *wfrom, t_word *wto)
248
int nfrom = tfrom->t_n, nto = tto->t_n, i;
249
for (i = 0; i < nto; i++)
251
if (conformaction[i] >= 0)
253
/* we swap the two, in case it's an array or list, so that
254
when "wfrom" is deleted the old one gets cleaned up. */
255
t_word wwas = wto[i];
256
wto[i] = wfrom[conformaction[i]];
257
wfrom[conformaction[i]] = wwas;
262
/* conform a scalar, recursively conforming sublists and arrays */
263
static t_scalar *template_conformscalar(t_template *tfrom, t_template *tto,
264
int *conformaction, t_glist *glist, t_scalar *scfrom)
268
int nto = tto->t_n, nfrom = tfrom->t_n, i;
269
t_template *scalartemplate;
270
/* post("conform scalar"); */
271
/* possibly replace the scalar */
272
if (scfrom->sc_template == tfrom->t_sym)
274
/* see scalar_new() for comment about the gpointer. */
276
x = (t_scalar *)getbytes(sizeof(t_scalar) +
277
(tto->t_n - 1) * sizeof(*x->sc_vec));
278
x->sc_gobj.g_pd = scalar_class;
279
x->sc_template = tfrom->t_sym;
280
gpointer_setglist(&gp, glist, x);
281
/* Here we initialize to the new template, but array and list
282
elements will still belong to old template. */
283
word_init(x->sc_vec, tto, &gp);
285
template_conformwords(tfrom, tto, conformaction,
286
scfrom->sc_vec, x->sc_vec);
288
/* replace the old one with the new one in the list */
289
if (glist->gl_list == &scfrom->sc_gobj)
291
glist->gl_list = &x->sc_gobj;
292
x->sc_gobj.g_next = scfrom->sc_gobj.g_next;
297
for (y = glist->gl_list; y2 = y->g_next; y = y2)
298
if (y2 == &scfrom->sc_gobj)
300
x->sc_gobj.g_next = y2->g_next;
301
y->g_next = &x->sc_gobj;
304
bug("template_conformscalar");
307
/* burn the old one */
308
pd_free(&scfrom->sc_gobj.g_pd);
309
scalartemplate = tto;
314
scalartemplate = template_findbyname(x->sc_template);
316
/* convert all array elements and sublists */
317
for (i = 0; i < scalartemplate->t_n; i++)
319
t_dataslot *ds = scalartemplate->t_vec + i;
320
if (ds->ds_type == DT_LIST)
322
t_glist *gl2 = x->sc_vec[i].w_list;
323
template_conformglist(tfrom, tto, gl2, conformaction);
325
else if (ds->ds_type == DT_ARRAY)
327
template_conformarray(tfrom, tto, conformaction,
328
x->sc_vec[i].w_array);
334
/* conform an array, recursively conforming sublists and arrays */
335
static void template_conformarray(t_template *tfrom, t_template *tto,
336
int *conformaction, t_array *a)
339
t_template *scalartemplate = 0;
340
if (a->a_templatesym == tfrom->t_sym)
342
/* the array elements must all be conformed */
343
int oldelemsize = sizeof(t_word) * tfrom->t_n,
344
newelemsize = sizeof(t_word) * tto->t_n;
345
char *newarray = getbytes(newelemsize * a->a_n);
346
char *oldarray = a->a_vec;
347
if (a->a_elemsize != oldelemsize)
348
bug("template_conformarray");
349
for (i = 0; i < a->a_n; i++)
351
t_word *wp = (t_word *)(newarray + newelemsize * i);
352
word_init(wp, tto, &a->a_gp);
353
template_conformwords(tfrom, tto, conformaction,
354
(t_word *)(oldarray + oldelemsize * i), wp);
355
word_free((t_word *)(oldarray + oldelemsize * i), tfrom);
357
scalartemplate = tto;
359
freebytes(oldarray, oldelemsize * a->a_n);
361
else scalartemplate = template_findbyname(a->a_templatesym);
362
/* convert all arrays and sublist fields in each element of the array */
363
for (i = 0; i < a->a_n; i++)
365
t_word *wp = (t_word *)(a->a_vec + sizeof(t_word) * a->a_n * i);
366
for (j = 0; j < scalartemplate->t_n; j++)
368
t_dataslot *ds = scalartemplate->t_vec + j;
369
if (ds->ds_type == DT_LIST)
371
t_glist *gl2 = wp[j].w_list;
372
template_conformglist(tfrom, tto, gl2, conformaction);
374
else if (ds->ds_type == DT_ARRAY)
376
template_conformarray(tfrom, tto, conformaction,
383
/* this routine searches for every scalar in the glist that belongs
384
to the "from" template and makes it belong to the "to" template. Descend
386
We don't handle redrawing here; this is to be filled in LATER... */
388
t_array *garray_getarray(t_garray *x);
390
static void template_conformglist(t_template *tfrom, t_template *tto,
391
t_glist *glist, int *conformaction)
394
/* post("conform glist %s", glist->gl_name->s_name); */
395
for (g = glist->gl_list; g; g = g->g_next)
397
if (pd_class(&g->g_pd) == scalar_class)
398
g = &template_conformscalar(tfrom, tto, conformaction,
399
glist, (t_scalar *)g)->sc_gobj;
400
else if (pd_class(&g->g_pd) == canvas_class)
401
template_conformglist(tfrom, tto, (t_glist *)g, conformaction);
402
else if (pd_class(&g->g_pd) == garray_class)
403
template_conformarray(tfrom, tto, conformaction,
404
garray_getarray((t_garray *)g));
408
/* globally conform all scalars from one template to another */
409
void template_conform(t_template *tfrom, t_template *tto)
411
int nto = tto->t_n, nfrom = tfrom->t_n, i, j,
412
*conformaction = (int *)getbytes(sizeof(int) * nto),
413
*conformedfrom = (int *)getbytes(sizeof(int) * nfrom), doit = 0;
414
for (i = 0; i < nto; i++)
415
conformaction[i] = -1;
416
for (i = 0; i < nfrom; i++)
417
conformedfrom[i] = 0;
418
for (i = 0; i < nto; i++)
420
t_dataslot *dataslot = &tto->t_vec[i];
421
for (j = 0; j < nfrom; j++)
423
t_dataslot *dataslot2 = &tfrom->t_vec[j];
424
if (dataslot_matches(dataslot, dataslot2, 1))
426
conformaction[i] = j;
427
conformedfrom[j] = 1;
431
for (i = 0; i < nto; i++)
432
if (conformaction[i] < 0)
434
t_dataslot *dataslot = &tto->t_vec[i];
435
for (j = 0; j < nfrom; j++)
436
if (!conformedfrom[j] &&
437
dataslot_matches(dataslot, &tfrom->t_vec[j], 0))
439
conformaction[i] = j;
440
conformedfrom[j] = 1;
445
else for (i = 0; i < nto; i++)
446
if (conformaction[i] != i)
452
post("conforming template '%s' to new structure",
453
tfrom->t_sym->s_name);
454
for (i = 0; i < nto; i++)
455
post("... %d", conformaction[i]);
456
for (gl = canvas_list; gl; gl = gl->gl_next)
457
template_conformglist(tfrom, tto, gl, conformaction);
459
freebytes(conformaction, sizeof(int) * nto);
460
freebytes(conformedfrom, sizeof(int) * nfrom);
463
t_template *template_findbyname(t_symbol *s)
465
return ((t_template *)pd_findbyclass(s, template_class));
468
t_canvas *template_findcanvas(t_template *template)
472
bug("template_findcanvas");
473
if (!(gt = template->t_list))
475
return (gt->x_owner);
476
/* return ((t_canvas *)pd_findbyclass(template->t_sym, canvas_class)); */
479
void template_notify(t_template *template, t_symbol *s, int argc, t_atom *argv)
481
if (template->t_list)
482
outlet_anything(template->t_list->x_obj.ob_outlet, s, argc, argv);
485
/* bash the first of (argv) with a pointer to a scalar, and send on
486
to template as a notification message */
487
void template_notifyforscalar(t_template *template, t_glist *owner,
488
t_scalar *sc, t_symbol *s, int argc, t_atom *argv)
492
gpointer_setglist(&gp, owner, sc);
493
SETPOINTER(argv, &gp);
494
template_notify(template, s, argc, argv);
498
/* call this when reading a patch from a file to declare what templates
499
we'll need. If there's already a template, check if it matches.
500
If it doesn't it's still OK as long as there are no "struct" (gtemplate)
501
objects hanging from it; we just conform everyone to the new template.
502
If there are still struct objects belonging to the other template, we're
503
in trouble. LATER we'll figure out how to conform the new patch's objects
504
to the pre-existing struct. */
505
static void *template_usetemplate(void *dummy, t_symbol *s,
506
int argc, t_atom *argv)
509
t_symbol *templatesym =
510
canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
514
/* check if there's already a template by this name. */
515
if ((x = (t_template *)pd_findbyclass(templatesym, template_class)))
517
t_template *y = template_new(&s_, argc, argv), *y2;
518
/* If the new template is the same as the old one,
519
there's nothing to do. */
520
if (!template_match(x, y))
522
/* Are there "struct" objects upholding this template? */
525
/* don't know what to do here! */
526
error("%s: template mismatch",
527
templatesym->s_name);
531
/* conform everyone to the new template */
532
template_conform(x, y);
533
pd_free(&x->t_pdobj);
534
y2 = template_new(templatesym, argc, argv);
538
pd_free(&y->t_pdobj);
540
/* otherwise, just make one. */
541
else template_new(templatesym, argc, argv);
545
/* here we assume someone has already cleaned up all instances of this. */
546
void template_free(t_template *x)
548
if (*x->t_sym->s_name)
549
pd_unbind(&x->t_pdobj, x->t_sym);
550
t_freebytes(x->t_vec, x->t_n * sizeof(*x->t_vec));
553
static void template_setup(void)
555
template_class = class_new(gensym("template"), 0, (t_method)template_free,
556
sizeof(t_template), CLASS_PD, 0);
557
class_addmethod(pd_canvasmaker, (t_method)template_usetemplate,
558
gensym("struct"), A_GIMME, 0);
562
/* ---------------- gtemplates. One per canvas. ----------- */
564
/* "Struct": an object that searches for, and if necessary creates,
565
a template (above). Other objects in the canvas then can give drawing
566
instructions for the template. The template doesn't go away when the
567
"struct" is deleted, so that you can replace it with
568
another one to add new fields, for example. */
570
static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv)
572
t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
573
t_template *t = template_findbyname(sym);
575
t_symbol *sx = gensym("x");
576
x->x_owner = canvas_getcurrent();
580
x->x_argv = (t_atom *)getbytes(argc * sizeof(t_atom));
581
for (i = 0; i < argc; i++)
582
x->x_argv[i] = argv[i];
584
/* already have a template by this name? */
588
/* if it's already got a "struct" object we
589
just tack this one to the end of the list and leave it
593
t_gtemplate *x2, *x3;
594
for (x2 = x->x_template->t_list; x3 = x2->x_next; x2 = x3)
597
post("template %s: warning: already exists.", sym->s_name);
601
/* if there's none, we just replace the template with
602
our own and conform it. */
603
t_template *y = template_new(&s_, argc, argv);
604
canvas_redrawallfortemplate(t, 2);
605
/* Unless the new template is different from the old one,
606
there's nothing to do. */
607
if (!template_match(t, y))
609
/* conform everyone to the new template */
610
template_conform(t, y);
611
pd_free(&t->t_pdobj);
612
t = template_new(sym, argc, argv);
614
pd_free(&y->t_pdobj);
616
canvas_redrawallfortemplate(t, 1);
621
/* otherwise make a new one and we're the only struct on it. */
622
x->x_template = t = template_new(sym, argc, argv);
625
outlet_new(&x->x_obj, 0);
629
static void *gtemplate_new(t_symbol *s, int argc, t_atom *argv)
631
t_symbol *sym = atom_getsymbolarg(0, argc, argv);
634
return (gtemplate_donew(canvas_makebindsym(sym), argc, argv));
637
/* old version (0.34) -- delete 2003 or so */
638
static void *gtemplate_new_old(t_symbol *s, int argc, t_atom *argv)
640
t_symbol *sym = canvas_makebindsym(canvas_getcurrent()->gl_name);
644
post("warning -- 'template' (%s) is obsolete; replace with 'struct'",
648
return (gtemplate_donew(sym, argc, argv));
651
t_template *gtemplate_get(t_gtemplate *x)
653
return (x->x_template);
656
static void gtemplate_free(t_gtemplate *x)
658
/* get off the template's list */
659
t_template *t = x->x_template;
663
canvas_redrawallfortemplate(t, 2);
666
/* if we were first on the list, and there are others on
667
the list, make a new template corresponding to the new
668
first-on-list and replace the existing template with it. */
669
t_template *z = template_new(&s_,
670
x->x_next->x_argc, x->x_next->x_argv);
671
template_conform(t, z);
672
pd_free(&t->t_pdobj);
673
pd_free(&z->t_pdobj);
674
z = template_new(x->x_sym, x->x_next->x_argc, x->x_next->x_argv);
675
z->t_list = x->x_next;
676
for (y = z->t_list; y ; y = y->x_next)
680
canvas_redrawallfortemplate(t, 1);
684
t_gtemplate *x2, *x3;
685
for (x2 = t->t_list; x3 = x2->x_next; x2 = x3)
689
x2->x_next = x3->x_next;
694
freebytes(x->x_argv, sizeof(t_atom) * x->x_argc);
697
static void gtemplate_setup(void)
699
gtemplate_class = class_new(gensym("struct"),
700
(t_newmethod)gtemplate_new, (t_method)gtemplate_free,
701
sizeof(t_gtemplate), CLASS_NOINLET, A_GIMME, 0);
702
class_addcreator((t_newmethod)gtemplate_new_old, gensym("template"),
706
/* --------------- FIELD DESCRIPTORS ---------------------- */
708
/* a field descriptor can hold a constant or a variable; if a variable,
709
it's the name of a field in the template we belong to. LATER, we might
710
want to cache the offset of the field so we don't have to search for it
711
every single time we draw the object.
716
char fd_type; /* LATER consider removing this? */
720
t_float fd_float; /* the field is a constant float */
721
t_symbol *fd_symbol; /* the field is a constant symbol */
722
t_symbol *fd_varsym; /* the field is variable and this is the name */
724
float fd_v1; /* min and max values */
726
float fd_screen1; /* min and max screen values */
728
float fd_quantum; /* quantization in value */
731
static void fielddesc_setfloat_const(t_fielddesc *fd, t_float f)
733
fd->fd_type = A_FLOAT;
735
fd->fd_un.fd_float = f;
736
fd->fd_v1 = fd->fd_v2 = fd->fd_screen1 = fd->fd_screen2 =
740
static void fielddesc_setsymbol_const(t_fielddesc *fd, t_symbol *s)
742
fd->fd_type = A_SYMBOL;
744
fd->fd_un.fd_symbol = s;
745
fd->fd_v1 = fd->fd_v2 = fd->fd_screen1 = fd->fd_screen2 =
749
static void fielddesc_setfloat_var(t_fielddesc *fd, t_symbol *s)
751
char *s1, *s2, *s3, strbuf[MAXPDSTRING];
753
fd->fd_type = A_FLOAT;
755
if (!(s1 = strchr(s->s_name, '(')) || !(s2 = strchr(s->s_name, ')'))
758
fd->fd_un.fd_varsym = s;
759
fd->fd_v1 = fd->fd_v2 = fd->fd_screen1 = fd->fd_screen2 =
764
int cpy = s1 - s->s_name, got;
765
if (cpy > MAXPDSTRING-5)
767
strncpy(strbuf, s->s_name, cpy);
769
fd->fd_un.fd_varsym = gensym(strbuf);
770
got = sscanf(s1, "(%f:%f)(%f:%f)(%f)",
771
&fd->fd_v1, &fd->fd_v2, &fd->fd_screen1, &fd->fd_screen2,
775
if (got == 3 || (got < 4 && strchr(s2, '(')))
777
if (got < 5 && (s3 = strchr(s2, '(')) && strchr(s3+1, '('))
784
fd->fd_screen1 = fd->fd_v1;
785
fd->fd_screen2 = fd->fd_v2;
789
post("parse error: %s", s->s_name);
790
fd->fd_v1 = fd->fd_screen1 = fd->fd_v2 = fd->fd_screen2 =
798
#define A_ARRAY 55 /* LATER decide whether to enshrine this in m_pd.h */
800
static void fielddesc_setfloatarg(t_fielddesc *fd, int argc, t_atom *argv)
802
if (argc <= 0) fielddesc_setfloat_const(fd, 0);
803
else if (argv->a_type == A_SYMBOL)
804
fielddesc_setfloat_var(fd, argv->a_w.w_symbol);
805
else fielddesc_setfloat_const(fd, argv->a_w.w_float);
808
static void fielddesc_setsymbolarg(t_fielddesc *fd, int argc, t_atom *argv)
810
if (argc <= 0) fielddesc_setsymbol_const(fd, &s_);
811
else if (argv->a_type == A_SYMBOL)
813
fd->fd_type = A_SYMBOL;
815
fd->fd_un.fd_varsym = argv->a_w.w_symbol;
816
fd->fd_v1 = fd->fd_v2 = fd->fd_screen1 = fd->fd_screen2 =
819
else fielddesc_setsymbol_const(fd, &s_);
822
static void fielddesc_setarrayarg(t_fielddesc *fd, int argc, t_atom *argv)
824
if (argc <= 0) fielddesc_setfloat_const(fd, 0);
825
else if (argv->a_type == A_SYMBOL)
827
fd->fd_type = A_ARRAY;
829
fd->fd_un.fd_varsym = argv->a_w.w_symbol;
831
else fielddesc_setfloat_const(fd, argv->a_w.w_float);
834
/* getting and setting values via fielddescs -- note confusing names;
835
the above are setting up the fielddesc itself. */
836
static t_float fielddesc_getfloat(t_fielddesc *f, t_template *template,
837
t_word *wp, int loud)
839
if (f->fd_type == A_FLOAT)
842
return (template_getfloat(template, f->fd_un.fd_varsym, wp, loud));
843
else return (f->fd_un.fd_float);
848
error("symbolic data field used as number");
853
/* convert a variable's value to a screen coordinate via its fielddesc */
854
t_float fielddesc_cvttocoord(t_fielddesc *f, t_float val)
856
t_float coord, pix, extreme, div;
857
if (f->fd_v2 == f->fd_v1)
859
div = (f->fd_screen2 - f->fd_screen1)/(f->fd_v2 - f->fd_v1);
860
coord = f->fd_screen1 + (val - f->fd_v1) * div;
861
extreme = (f->fd_screen1 < f->fd_screen2 ?
862
f->fd_screen1 : f->fd_screen2);
865
extreme = (f->fd_screen1 > f->fd_screen2 ?
866
f->fd_screen1 : f->fd_screen2);
872
/* read a variable via fielddesc and convert to screen coordinate */
873
t_float fielddesc_getcoord(t_fielddesc *f, t_template *template,
874
t_word *wp, int loud)
876
if (f->fd_type == A_FLOAT)
880
t_float val = template_getfloat(template,
881
f->fd_un.fd_varsym, wp, loud);
882
return (fielddesc_cvttocoord(f, val));
884
else return (f->fd_un.fd_float);
889
error("symbolic data field used as number");
894
static t_symbol *fielddesc_getsymbol(t_fielddesc *f, t_template *template,
895
t_word *wp, int loud)
897
if (f->fd_type == A_SYMBOL)
900
return(template_getsymbol(template, f->fd_un.fd_varsym, wp, loud));
901
else return (f->fd_un.fd_symbol);
906
error("numeric data field used as symbol");
911
/* convert from a screen coordinate to a variable value */
912
t_float fielddesc_cvtfromcoord(t_fielddesc *f, t_float coord)
915
if (f->fd_screen2 == f->fd_screen1)
919
t_float div = (f->fd_v2 - f->fd_v1)/(f->fd_screen2 - f->fd_screen1);
921
val = f->fd_v1 + (coord - f->fd_screen1) * div;
922
if (f->fd_quantum != 0)
923
val = ((int)((val/f->fd_quantum) + 0.5)) * f->fd_quantum;
924
extreme = (f->fd_v1 < f->fd_v2 ?
925
f->fd_v1 : f->fd_v2);
926
if (val < extreme) val = extreme;
927
extreme = (f->fd_v1 > f->fd_v2 ?
928
f->fd_v1 : f->fd_v2);
929
if (val > extreme) val = extreme;
934
void fielddesc_setcoord(t_fielddesc *f, t_template *template,
935
t_word *wp, t_float coord, int loud)
937
if (f->fd_type == A_FLOAT && f->fd_var)
939
t_float val = fielddesc_cvtfromcoord(f, coord);
940
template_setfloat(template,
941
f->fd_un.fd_varsym, wp, val, loud);
946
error("attempt to set constant or symbolic data field to a number");
950
/* ---------------- curves and polygons (joined segments) ---------------- */
953
curves belong to templates and describe how the data in the template are to
954
be drawn. The coordinates of the curve (and other display features) can
955
be attached to fields in the template.
958
t_class *curve_class;
960
typedef struct _curve
963
int x_flags; /* CLOSED and/or BEZ and/or NOMOUSE */
964
t_fielddesc x_fillcolor;
965
t_fielddesc x_outlinecolor;
973
static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv)
975
t_curve *x = (t_curve *)pd_new(curve_class);
976
char *classname = classsym->s_name;
980
x->x_canvas = canvas_getcurrent();
981
if (classname[0] == 'f')
987
if (classname[0] == 'c') flags |= BEZ;
988
fielddesc_setfloat_const(&x->x_vis, 1);
991
t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
992
if (!strcmp(firstarg->s_name, "-v") && argc > 1)
994
fielddesc_setfloatarg(&x->x_vis, 1, argv+1);
995
argc -= 2; argv += 2;
997
else if (!strcmp(firstarg->s_name, "-x"))
1000
argc -= 1; argv += 1;
1005
if ((flags & CLOSED) && argc)
1006
fielddesc_setfloatarg(&x->x_fillcolor, argc--, argv++);
1007
else fielddesc_setfloat_const(&x->x_fillcolor, 0);
1008
if (argc) fielddesc_setfloatarg(&x->x_outlinecolor, argc--, argv++);
1009
else fielddesc_setfloat_const(&x->x_outlinecolor, 0);
1010
if (argc) fielddesc_setfloatarg(&x->x_width, argc--, argv++);
1011
else fielddesc_setfloat_const(&x->x_width, 1);
1012
if (argc < 0) argc = 0;
1013
nxy = (argc + (argc & 1));
1014
x->x_npoints = (nxy>>1);
1015
x->x_vec = (t_fielddesc *)t_getbytes(nxy * sizeof(t_fielddesc));
1016
for (i = 0, fd = x->x_vec; i < argc; i++, fd++, argv++)
1017
fielddesc_setfloatarg(fd, 1, argv);
1018
if (argc & 1) fielddesc_setfloat_const(fd, 0);
1023
void curve_float(t_curve *x, t_floatarg f)
1026
if (x->x_vis.fd_type != A_FLOAT || x->x_vis.fd_var)
1028
pd_error(x, "global vis/invis for a template with variable visibility");
1031
viswas = (x->x_vis.fd_un.fd_float != 0);
1033
if ((f != 0 && viswas) || (f == 0 && !viswas))
1035
canvas_redrawallfortemplatecanvas(x->x_canvas, 2);
1036
fielddesc_setfloat_const(&x->x_vis, (f != 0));
1037
canvas_redrawallfortemplatecanvas(x->x_canvas, 1);
1040
/* -------------------- widget behavior for curve ------------ */
1042
static void curve_getrect(t_gobj *z, t_glist *glist,
1043
t_word *data, t_template *template, t_float basex, t_float basey,
1044
int *xp1, int *yp1, int *xp2, int *yp2)
1046
t_curve *x = (t_curve *)z;
1047
int i, n = x->x_npoints;
1048
t_fielddesc *f = x->x_vec;
1049
int x1 = 0x7fffffff, x2 = -0x7fffffff, y1 = 0x7fffffff, y2 = -0x7fffffff;
1050
if (!fielddesc_getfloat(&x->x_vis, template, data, 0) ||
1051
(x->x_flags & NOMOUSE))
1053
*xp1 = *yp1 = 0x7fffffff;
1054
*xp2 = *yp2 = -0x7fffffff;
1057
for (i = 0, f = x->x_vec; i < n; i++, f += 2)
1059
int xloc = glist_xtopixels(glist,
1060
basex + fielddesc_getcoord(f, template, data, 0));
1061
int yloc = glist_ytopixels(glist,
1062
basey + fielddesc_getcoord(f+1, template, data, 0));
1063
if (xloc < x1) x1 = xloc;
1064
if (xloc > x2) x2 = xloc;
1065
if (yloc < y1) y1 = yloc;
1066
if (yloc > y2) y2 = yloc;
1074
static void curve_displace(t_gobj *z, t_glist *glist,
1075
t_word *data, t_template *template, t_float basex, t_float basey,
1081
static void curve_select(t_gobj *z, t_glist *glist,
1082
t_word *data, t_template *template, t_float basex, t_float basey,
1088
static void curve_activate(t_gobj *z, t_glist *glist,
1089
t_word *data, t_template *template, t_float basex, t_float basey,
1096
static int rangecolor(int n) /* 0 to 9 in 5 steps */
1098
int n2 = n/2; /* 0 to 4 */
1099
int ret = (n2 << 6); /* 0 to 256 in 5 steps */
1100
if (ret > 255) ret = 255;
1105
static int rangecolor(int n) /* 0 to 9 in 5 steps */
1107
int n2 = (n == 9 ? 8 : n); /* 0 to 8 */
1108
int ret = (n2 << 5); /* 0 to 256 in 9 steps */
1109
if (ret > 255) ret = 255;
1113
static void numbertocolor(int n, char *s)
1115
int red, blue, green;
1118
blue = ((n / 10) % 10);
1120
sprintf(s, "#%2.2x%2.2x%2.2x", rangecolor(red), rangecolor(blue),
1124
static void curve_vis(t_gobj *z, t_glist *glist,
1125
t_word *data, t_template *template, t_float basex, t_float basey,
1128
t_curve *x = (t_curve *)z;
1129
int i, n = x->x_npoints;
1130
t_fielddesc *f = x->x_vec;
1132
/* see comment in plot_vis() */
1133
if (vis && !fielddesc_getfloat(&x->x_vis, template, data, 0))
1139
int flags = x->x_flags, closed = (flags & CLOSED);
1140
t_float width = fielddesc_getfloat(&x->x_width, template, data, 1);
1141
char outline[20], fill[20];
1145
/* calculate the pixel values before we start printing
1146
out the TK message so that "error" printout won't be
1147
interspersed with it. Only show up to 100 points so we don't
1148
have to allocate memory here. */
1149
for (i = 0, f = x->x_vec; i < n; i++, f += 2)
1151
pix[2*i] = glist_xtopixels(glist,
1152
basex + fielddesc_getcoord(f, template, data, 1));
1153
pix[2*i+1] = glist_ytopixels(glist,
1154
basey + fielddesc_getcoord(f+1, template, data, 1));
1156
if (width < 1) width = 1;
1158
fielddesc_getfloat(&x->x_outlinecolor, template, data, 1),
1163
fielddesc_getfloat(&x->x_fillcolor, template, data, 1),
1165
sys_vgui(".x%lx.c create polygon\\\n",
1166
glist_getcanvas(glist));
1168
else sys_vgui(".x%lx.c create line\\\n", glist_getcanvas(glist));
1169
for (i = 0; i < n; i++)
1170
sys_vgui("%d %d\\\n", pix[2*i], pix[2*i+1]);
1171
sys_vgui("-width %f\\\n", width);
1172
if (flags & CLOSED) sys_vgui("-fill %s -outline %s\\\n",
1174
else sys_vgui("-fill %s\\\n", outline);
1175
if (flags & BEZ) sys_vgui("-smooth 1\\\n");
1176
sys_vgui("-tags curve%lx\n", data);
1178
else post("warning: curves need at least two points to be graphed");
1182
if (n > 1) sys_vgui(".x%lx.c delete curve%lx\n",
1183
glist_getcanvas(glist), data);
1187
static int curve_motion_field;
1188
static t_float curve_motion_xcumulative;
1189
static t_float curve_motion_xbase;
1190
static t_float curve_motion_xper;
1191
static t_float curve_motion_ycumulative;
1192
static t_float curve_motion_ybase;
1193
static t_float curve_motion_yper;
1194
static t_glist *curve_motion_glist;
1195
static t_scalar *curve_motion_scalar;
1196
static t_array *curve_motion_array;
1197
static t_word *curve_motion_wp;
1198
static t_template *curve_motion_template;
1199
static t_gpointer curve_motion_gpointer;
1201
/* LATER protect against the template changing or the scalar disappearing
1202
probably by attaching a gpointer here ... */
1204
static void curve_motion(void *z, t_floatarg dx, t_floatarg dy)
1206
t_curve *x = (t_curve *)z;
1207
t_fielddesc *f = x->x_vec + curve_motion_field;
1209
if (!gpointer_check(&curve_motion_gpointer, 0))
1211
post("curve_motion: scalar disappeared");
1214
curve_motion_xcumulative += dx;
1215
curve_motion_ycumulative += dy;
1216
if (f->fd_var && (dx != 0))
1218
fielddesc_setcoord(f, curve_motion_template, curve_motion_wp,
1219
curve_motion_xbase + curve_motion_xcumulative * curve_motion_xper,
1222
if ((f+1)->fd_var && (dy != 0))
1224
fielddesc_setcoord(f+1, curve_motion_template, curve_motion_wp,
1225
curve_motion_ybase + curve_motion_ycumulative * curve_motion_yper,
1228
/* LATER figure out what to do to notify for an array? */
1229
if (curve_motion_scalar)
1230
template_notifyforscalar(curve_motion_template, curve_motion_glist,
1231
curve_motion_scalar, gensym("change"), 1, &at);
1232
if (curve_motion_scalar)
1233
scalar_redraw(curve_motion_scalar, curve_motion_glist);
1234
if (curve_motion_array)
1235
array_redraw(curve_motion_array, curve_motion_glist);
1238
static int curve_click(t_gobj *z, t_glist *glist,
1239
t_word *data, t_template *template, t_scalar *sc, t_array *ap,
1240
t_float basex, t_float basey,
1241
int xpix, int ypix, int shift, int alt, int dbl, int doit)
1243
t_curve *x = (t_curve *)z;
1244
int i, n = x->x_npoints;
1246
int besterror = 0x7fffffff;
1248
if (!fielddesc_getfloat(&x->x_vis, template, data, 0))
1250
for (i = 0, f = x->x_vec; i < n; i++, f += 2)
1252
int xval = fielddesc_getcoord(f, template, data, 0),
1253
xloc = glist_xtopixels(glist, basex + xval);
1254
int yval = fielddesc_getcoord(f+1, template, data, 0),
1255
yloc = glist_ytopixels(glist, basey + yval);
1256
int xerr = xloc - xpix, yerr = yloc - ypix;
1257
if (!f->fd_var && !(f+1)->fd_var)
1265
if (xerr < besterror)
1267
curve_motion_xbase = xval;
1268
curve_motion_ybase = yval;
1277
curve_motion_xper = glist_pixelstox(glist, 1)
1278
- glist_pixelstox(glist, 0);
1279
curve_motion_yper = glist_pixelstoy(glist, 1)
1280
- glist_pixelstoy(glist, 0);
1281
curve_motion_xcumulative = 0;
1282
curve_motion_ycumulative = 0;
1283
curve_motion_glist = glist;
1284
curve_motion_scalar = sc;
1285
curve_motion_array = ap;
1286
curve_motion_wp = data;
1287
curve_motion_field = 2*bestn;
1288
curve_motion_template = template;
1289
if (curve_motion_scalar)
1290
gpointer_setglist(&curve_motion_gpointer, curve_motion_glist,
1291
curve_motion_scalar);
1292
else gpointer_setarray(&curve_motion_gpointer,
1293
curve_motion_array, curve_motion_wp);
1294
glist_grab(glist, z, curve_motion, 0, xpix, ypix);
1299
t_parentwidgetbehavior curve_widgetbehavior =
1309
static void curve_free(t_curve *x)
1311
t_freebytes(x->x_vec, 2 * x->x_npoints * sizeof(*x->x_vec));
1314
static void curve_setup(void)
1316
curve_class = class_new(gensym("drawpolygon"), (t_newmethod)curve_new,
1317
(t_method)curve_free, sizeof(t_curve), 0, A_GIMME, 0);
1318
class_setdrawcommand(curve_class);
1319
class_addcreator((t_newmethod)curve_new, gensym("drawcurve"),
1321
class_addcreator((t_newmethod)curve_new, gensym("filledpolygon"),
1323
class_addcreator((t_newmethod)curve_new, gensym("filledcurve"),
1325
class_setparentwidget(curve_class, &curve_widgetbehavior);
1326
class_addfloat(curve_class, curve_float);
1329
/* --------- plots for showing arrays --------------- */
1331
t_class *plot_class;
1333
typedef struct _plot
1337
t_fielddesc x_outlinecolor;
1338
t_fielddesc x_width;
1342
t_fielddesc x_style;
1344
t_fielddesc x_xpoints;
1345
t_fielddesc x_ypoints;
1346
t_fielddesc x_wpoints;
1347
t_fielddesc x_vis; /* visible */
1348
t_fielddesc x_scalarvis; /* true if drawing the scalar at each point */
1351
static void *plot_new(t_symbol *classsym, t_int argc, t_atom *argv)
1353
t_plot *x = (t_plot *)pd_new(plot_class);
1354
int defstyle = PLOTSTYLE_POLY;
1355
x->x_canvas = canvas_getcurrent();
1357
fielddesc_setfloat_var(&x->x_xpoints, gensym("x"));
1358
fielddesc_setfloat_var(&x->x_ypoints, gensym("y"));
1359
fielddesc_setfloat_var(&x->x_wpoints, gensym("w"));
1361
fielddesc_setfloat_const(&x->x_vis, 1);
1362
fielddesc_setfloat_const(&x->x_scalarvis, 1);
1365
t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
1366
if (!strcmp(firstarg->s_name, "curve") ||
1367
!strcmp(firstarg->s_name, "-c"))
1369
defstyle = PLOTSTYLE_BEZ;
1372
else if (!strcmp(firstarg->s_name, "-v") && argc > 1)
1374
fielddesc_setfloatarg(&x->x_vis, 1, argv+1);
1375
argc -= 2; argv += 2;
1377
else if (!strcmp(firstarg->s_name, "-vs") && argc > 1)
1379
fielddesc_setfloatarg(&x->x_scalarvis, 1, argv+1);
1380
argc -= 2; argv += 2;
1382
else if (!strcmp(firstarg->s_name, "-x") && argc > 1)
1384
fielddesc_setfloatarg(&x->x_xpoints, 1, argv+1);
1385
argc -= 2; argv += 2;
1387
else if (!strcmp(firstarg->s_name, "-y") && argc > 1)
1389
fielddesc_setfloatarg(&x->x_ypoints, 1, argv+1);
1390
argc -= 2; argv += 2;
1392
else if (!strcmp(firstarg->s_name, "-w") && argc > 1)
1394
fielddesc_setfloatarg(&x->x_wpoints, 1, argv+1);
1395
argc -= 2; argv += 2;
1399
if (argc) fielddesc_setarrayarg(&x->x_data, argc--, argv++);
1400
else fielddesc_setfloat_const(&x->x_data, 1);
1401
if (argc) fielddesc_setfloatarg(&x->x_outlinecolor, argc--, argv++);
1402
else fielddesc_setfloat_const(&x->x_outlinecolor, 0);
1403
if (argc) fielddesc_setfloatarg(&x->x_width, argc--, argv++);
1404
else fielddesc_setfloat_const(&x->x_width, 1);
1405
if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
1406
else fielddesc_setfloat_const(&x->x_xloc, 1);
1407
if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
1408
else fielddesc_setfloat_const(&x->x_yloc, 1);
1409
if (argc) fielddesc_setfloatarg(&x->x_xinc, argc--, argv++);
1410
else fielddesc_setfloat_const(&x->x_xinc, 1);
1411
if (argc) fielddesc_setfloatarg(&x->x_style, argc--, argv++);
1412
else fielddesc_setfloat_const(&x->x_style, defstyle);
1416
void plot_float(t_plot *x, t_floatarg f)
1419
if (x->x_vis.fd_type != A_FLOAT || x->x_vis.fd_var)
1421
pd_error(x, "global vis/invis for a template with variable visibility");
1424
viswas = (x->x_vis.fd_un.fd_float != 0);
1426
if ((f != 0 && viswas) || (f == 0 && !viswas))
1428
canvas_redrawallfortemplatecanvas(x->x_canvas, 2);
1429
fielddesc_setfloat_const(&x->x_vis, (f != 0));
1430
canvas_redrawallfortemplatecanvas(x->x_canvas, 1);
1433
/* -------------------- widget behavior for plot ------------ */
1436
/* get everything we'll need from the owner template of the array being
1437
plotted. Not used for garrays, but see below */
1438
static int plot_readownertemplate(t_plot *x,
1439
t_word *data, t_template *ownertemplate,
1440
t_symbol **elemtemplatesymp, t_array **arrayp,
1441
t_float *linewidthp, t_float *xlocp, t_float *xincp, t_float *ylocp, t_float *stylep,
1442
t_float *visp, t_float *scalarvisp,
1443
t_fielddesc **xfield, t_fielddesc **yfield, t_fielddesc **wfield)
1445
int arrayonset, type;
1446
t_symbol *elemtemplatesym;
1449
/* find the data and verify it's an array */
1450
if (x->x_data.fd_type != A_ARRAY || !x->x_data.fd_var)
1452
error("plot: needs an array field");
1455
if (!template_find_field(ownertemplate, x->x_data.fd_un.fd_varsym,
1456
&arrayonset, &type, &elemtemplatesym))
1458
error("plot: %s: no such field", x->x_data.fd_un.fd_varsym->s_name);
1461
if (type != DT_ARRAY)
1463
error("plot: %s: not an array", x->x_data.fd_un.fd_varsym->s_name);
1466
array = *(t_array **)(((char *)data) + arrayonset);
1467
*linewidthp = fielddesc_getfloat(&x->x_width, ownertemplate, data, 1);
1468
*xlocp = fielddesc_getfloat(&x->x_xloc, ownertemplate, data, 1);
1469
*xincp = fielddesc_getfloat(&x->x_xinc, ownertemplate, data, 1);
1470
*ylocp = fielddesc_getfloat(&x->x_yloc, ownertemplate, data, 1);
1471
*stylep = fielddesc_getfloat(&x->x_style, ownertemplate, data, 1);
1472
*visp = fielddesc_getfloat(&x->x_vis, ownertemplate, data, 1);
1473
*scalarvisp = fielddesc_getfloat(&x->x_scalarvis, ownertemplate, data, 1);
1474
*elemtemplatesymp = elemtemplatesym;
1476
*xfield = &x->x_xpoints;
1477
*yfield = &x->x_ypoints;
1478
*wfield = &x->x_wpoints;
1482
/* get everything else you could possibly need about a plot,
1483
either for plot's own purposes or for plotting a "garray" */
1484
int array_getfields(t_symbol *elemtemplatesym,
1485
t_canvas **elemtemplatecanvasp,
1486
t_template **elemtemplatep, int *elemsizep,
1487
t_fielddesc *xfielddesc, t_fielddesc *yfielddesc, t_fielddesc *wfielddesc,
1488
int *xonsetp, int *yonsetp, int *wonsetp)
1490
int arrayonset, elemsize, yonset, wonset, xonset, type;
1491
t_template *elemtemplate;
1492
t_symbol *dummy, *varname;
1493
t_canvas *elemtemplatecanvas = 0;
1495
/* the "float" template is special in not having to have a canvas;
1496
template_findbyname is hardwired to return a predefined
1499
if (!(elemtemplate = template_findbyname(elemtemplatesym)))
1501
error("plot: %s: no such template", elemtemplatesym->s_name);
1504
if (!((elemtemplatesym == &s_float) ||
1505
(elemtemplatecanvas = template_findcanvas(elemtemplate))))
1507
error("plot: %s: no canvas for this template", elemtemplatesym->s_name);
1510
elemsize = elemtemplate->t_n * sizeof(t_word);
1511
if (yfielddesc && yfielddesc->fd_var)
1512
varname = yfielddesc->fd_un.fd_varsym;
1513
else varname = gensym("y");
1514
if (!template_find_field(elemtemplate, varname, &yonset, &type, &dummy)
1515
|| type != DT_FLOAT)
1517
if (xfielddesc && xfielddesc->fd_var)
1518
varname = xfielddesc->fd_un.fd_varsym;
1519
else varname = gensym("x");
1520
if (!template_find_field(elemtemplate, varname, &xonset, &type, &dummy)
1521
|| type != DT_FLOAT)
1523
if (wfielddesc && wfielddesc->fd_var)
1524
varname = wfielddesc->fd_un.fd_varsym;
1525
else varname = gensym("w");
1526
if (!template_find_field(elemtemplate, varname, &wonset, &type, &dummy)
1527
|| type != DT_FLOAT)
1530
/* fill in slots for return values */
1531
*elemtemplatecanvasp = elemtemplatecanvas;
1532
*elemtemplatep = elemtemplate;
1533
*elemsizep = elemsize;
1540
static void plot_getrect(t_gobj *z, t_glist *glist,
1541
t_word *data, t_template *template, t_float basex, t_float basey,
1542
int *xp1, int *yp1, int *xp2, int *yp2)
1544
t_plot *x = (t_plot *)z;
1545
int elemsize, yonset, wonset, xonset;
1546
t_canvas *elemtemplatecanvas;
1547
t_template *elemtemplate;
1548
t_symbol *elemtemplatesym;
1549
t_float linewidth, xloc, xinc, yloc, style, xsum, yval, vis, scalarvis;
1551
int x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
1553
t_float xpix, ypix, wpix;
1554
t_fielddesc *xfielddesc, *yfielddesc, *wfielddesc;
1555
if (!plot_readownertemplate(x, data, template,
1556
&elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc, &style,
1557
&vis, &scalarvis, &xfielddesc, &yfielddesc, &wfielddesc) &&
1559
!array_getfields(elemtemplatesym, &elemtemplatecanvas,
1560
&elemtemplate, &elemsize,
1561
xfielddesc, yfielddesc, wfielddesc,
1562
&xonset, &yonset, &wonset))
1564
/* if it has more than 2000 points, just check 1000 of them. */
1565
int incr = (array->a_n <= 2000 ? 1 : array->a_n / 1000);
1566
for (i = 0, xsum = 0; i < array->a_n; i += incr)
1568
t_float usexloc, useyloc;
1570
/* get the coords of the point proper */
1571
array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
1572
xonset, yonset, wonset, i, basex + xloc, basey + yloc, xinc,
1573
xfielddesc, yfielddesc, wfielddesc, &xpix, &ypix, &wpix);
1578
if (ypix - wpix < y1)
1580
if (ypix + wpix > y2)
1585
/* check also the drawing instructions for the scalar */
1587
usexloc = basex + xloc + fielddesc_cvttocoord(xfielddesc,
1588
*(t_float *)(((char *)(array->a_vec) + elemsize * i)
1590
else usexloc = basex + xsum, xsum += xinc;
1592
yval = *(t_float *)(((char *)(array->a_vec) + elemsize * i)
1595
useyloc = basey + yloc + fielddesc_cvttocoord(yfielddesc, yval);
1596
for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
1598
int xx1, xx2, yy1, yy2;
1599
t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
1601
(*wb->w_parentgetrectfn)(y, glist,
1602
(t_word *)((char *)(array->a_vec) + elemsize * i),
1603
elemtemplate, usexloc, useyloc,
1604
&xx1, &yy1, &xx2, &yy2);
1624
static void plot_displace(t_gobj *z, t_glist *glist,
1625
t_word *data, t_template *template, t_float basex, t_float basey,
1631
static void plot_select(t_gobj *z, t_glist *glist,
1632
t_word *data, t_template *template, t_float basex, t_float basey,
1638
static void plot_activate(t_gobj *z, t_glist *glist,
1639
t_word *data, t_template *template, t_float basex, t_float basey,
1645
static void plot_vis(t_gobj *z, t_glist *glist,
1646
t_word *data, t_template *template, t_float basex, t_float basey,
1649
t_plot *x = (t_plot *)z;
1650
int elemsize, yonset, wonset, xonset, i;
1651
t_canvas *elemtemplatecanvas;
1652
t_template *elemtemplate;
1653
t_symbol *elemtemplatesym;
1654
t_float linewidth, xloc, xinc, yloc, style, usexloc, xsum, yval, vis,
1659
t_fielddesc *xfielddesc, *yfielddesc, *wfielddesc;
1660
/* even if the array is "invisible", if its visibility is
1661
set by an instance variable you have to explicitly erase it,
1662
because the flag could earlier have been on when we were getting
1663
drawn. Rather than look to try to find out whether we're
1664
visible we just do the erasure. At the TK level this should
1665
cause no action because the tag matches nobody. LATER we
1666
might want to optimize this somehow. Ditto the "vis()" routines
1667
for other drawing instructions. */
1669
if (plot_readownertemplate(x, data, template,
1670
&elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc, &style,
1671
&vis, &scalarvis, &xfielddesc, &yfielddesc, &wfielddesc) ||
1672
((vis == 0) && tovis) /* see above for 'tovis' */
1673
|| array_getfields(elemtemplatesym, &elemtemplatecanvas,
1674
&elemtemplate, &elemsize, xfielddesc, yfielddesc, wfielddesc,
1675
&xonset, &yonset, &wonset))
1678
elem = (char *)array->a_vec;
1682
if (style == PLOTSTYLE_POINTS)
1684
t_float minyval = 1e20, maxyval = -1e20;
1686
for (xsum = basex + xloc, i = 0; i < nelem; i++)
1688
t_float yval, xpix, ypix, nextxloc;
1693
usexloc = basex + xloc +
1694
*(t_float *)((elem + elemsize * i) + xonset);
1695
ixpix = glist_xtopixels(glist,
1696
fielddesc_cvttocoord(xfielddesc, usexloc));
1703
ixpix = glist_xtopixels(glist,
1704
fielddesc_cvttocoord(xfielddesc, usexloc));
1705
inextx = glist_xtopixels(glist,
1706
fielddesc_cvttocoord(xfielddesc, xsum));
1710
yval = yloc + *(t_float *)((elem + elemsize * i) + yonset);
1716
if (i == nelem-1 || inextx != ixpix)
1719
".x%lx.c create rectangle %d %d %d %d -fill black -width 0 -tags plot%lx\n",
1720
glist_getcanvas(glist),
1721
ixpix, (int)glist_ytopixels(glist,
1722
basey + fielddesc_cvttocoord(yfielddesc, minyval)),
1723
inextx, (int)(glist_ytopixels(glist,
1724
basey + fielddesc_cvttocoord(yfielddesc, maxyval))
1725
+ linewidth), data);
1730
if (ndrawn > 2000 || ixpix >= 3000) break;
1736
int lastpixel = -1, ndrawn = 0;
1737
t_float yval = 0, wval = 0, xpix;
1739
/* draw the trace */
1740
numbertocolor(fielddesc_getfloat(&x->x_outlinecolor, template,
1744
/* found "w" field which controls linewidth. The trace is
1745
a filled polygon with 2n points. */
1746
sys_vgui(".x%lx.c create polygon \\\n",
1747
glist_getcanvas(glist));
1749
for (i = 0, xsum = xloc; i < nelem; i++)
1752
usexloc = xloc + *(t_float *)((elem + elemsize * i)
1754
else usexloc = xsum, xsum += xinc;
1756
yval = *(t_float *)((elem + elemsize * i) + yonset);
1758
wval = *(t_float *)((elem + elemsize * i) + wonset);
1759
xpix = glist_xtopixels(glist,
1760
basex + fielddesc_cvttocoord(xfielddesc, usexloc));
1762
if (xonset >= 0 || ixpix != lastpixel)
1764
sys_vgui("%d %f \\\n", ixpix,
1765
glist_ytopixels(glist,
1766
basey + fielddesc_cvttocoord(yfielddesc,
1768
fielddesc_cvttocoord(wfielddesc,wval)));
1772
if (ndrawn >= 1000) goto ouch;
1775
for (i = nelem-1; i >= 0; i--)
1779
usexloc = xloc + *(t_float *)((elem + elemsize * i)
1781
else xsum -= xinc, usexloc = xsum;
1783
yval = *(t_float *)((elem + elemsize * i) + yonset);
1785
wval = *(t_float *)((elem + elemsize * i) + wonset);
1786
xpix = glist_xtopixels(glist,
1787
basex + fielddesc_cvttocoord(xfielddesc, usexloc));
1789
if (xonset >= 0 || ixpix != lastpixel)
1791
sys_vgui("%d %f \\\n", ixpix, glist_ytopixels(glist,
1792
basey + yloc + fielddesc_cvttocoord(yfielddesc,
1794
fielddesc_cvttocoord(wfielddesc, wval)));
1798
if (ndrawn >= 1000) goto ouch;
1800
/* TK will complain if there aren't at least 3 points.
1801
There should be at least two already. */
1804
sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
1805
basey + yloc + fielddesc_cvttocoord(yfielddesc,
1807
fielddesc_cvttocoord(wfielddesc, wval)));
1808
sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
1809
basey + yloc + fielddesc_cvttocoord(yfielddesc,
1811
fielddesc_cvttocoord(wfielddesc, wval)));
1814
sys_vgui(" -width 1 -fill %s -outline %s\\\n",
1816
if (style == PLOTSTYLE_BEZ) sys_vgui("-smooth 1\\\n");
1818
sys_vgui("-tags plot%lx\n", data);
1820
else if (linewidth > 0)
1822
/* no "w" field. If the linewidth is positive, draw a
1823
segmented line with the requested width; otherwise don't
1824
draw the trace at all. */
1825
sys_vgui(".x%lx.c create line \\\n", glist_getcanvas(glist));
1827
for (xsum = xloc, i = 0; i < nelem; i++)
1831
usexloc = xloc + *(t_float *)((elem + elemsize * i) +
1833
else usexloc = xsum, xsum += xinc;
1835
yval = *(t_float *)((elem + elemsize * i) + yonset);
1837
xpix = glist_xtopixels(glist,
1838
basex + fielddesc_cvttocoord(xfielddesc, usexloc));
1840
if (xonset >= 0 || ixpix != lastpixel)
1842
sys_vgui("%d %f \\\n", ixpix,
1843
glist_ytopixels(glist,
1844
basey + yloc + fielddesc_cvttocoord(yfielddesc,
1849
if (ndrawn >= 1000) break;
1851
/* TK will complain if there aren't at least 2 points... */
1852
if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n");
1853
else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix + 10,
1854
glist_ytopixels(glist, basey + yloc +
1855
fielddesc_cvttocoord(yfielddesc, yval)));
1857
sys_vgui("-width %f\\\n", linewidth);
1858
sys_vgui("-fill %s\\\n", outline);
1859
if (style == PLOTSTYLE_BEZ) sys_vgui("-smooth 1\\\n");
1861
sys_vgui("-tags plot%lx\n", data);
1864
/* We're done with the outline; now draw all the points.
1865
This code is inefficient since the template has to be
1866
searched for drawing instructions for every last point. */
1869
for (xsum = xloc, i = 0; i < nelem; i++)
1871
t_float usexloc, useyloc;
1874
usexloc = basex + xloc +
1875
*(t_float *)((elem + elemsize * i) + xonset);
1876
else usexloc = basex + xsum, xsum += xinc;
1878
yval = *(t_float *)((elem + elemsize * i) + yonset);
1880
useyloc = basey + yloc +
1881
fielddesc_cvttocoord(yfielddesc, yval);
1882
for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
1884
t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
1886
(*wb->w_parentvisfn)(y, glist,
1887
(t_word *)(elem + elemsize * i),
1888
elemtemplate, usexloc, useyloc, tovis);
1895
/* un-draw the individual points */
1899
for (i = 0; i < nelem; i++)
1902
for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
1904
t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
1906
(*wb->w_parentvisfn)(y, glist,
1907
(t_word *)(elem + elemsize * i), elemtemplate,
1912
/* and then the trace */
1913
sys_vgui(".x%lx.c delete plot%lx\n",
1914
glist_getcanvas(glist), data);
1918
static int plot_click(t_gobj *z, t_glist *glist,
1919
t_word *data, t_template *template, t_scalar *sc, t_array *ap,
1920
t_float basex, t_float basey,
1921
int xpix, int ypix, int shift, int alt, int dbl, int doit)
1923
t_plot *x = (t_plot *)z;
1924
t_symbol *elemtemplatesym;
1925
t_float linewidth, xloc, xinc, yloc, style, vis, scalarvis;
1927
t_fielddesc *xfielddesc, *yfielddesc, *wfielddesc;
1929
if (!plot_readownertemplate(x, data, template,
1930
&elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc, &style,
1932
&xfielddesc, &yfielddesc, &wfielddesc) && (vis != 0))
1934
return (array_doclick(array, glist, sc, ap,
1936
linewidth, basex + xloc, xinc, basey + yloc, scalarvis,
1937
xfielddesc, yfielddesc, wfielddesc,
1938
xpix, ypix, shift, alt, dbl, doit));
1943
t_parentwidgetbehavior plot_widgetbehavior =
1953
static void plot_setup(void)
1955
plot_class = class_new(gensym("plot"), (t_newmethod)plot_new, 0,
1956
sizeof(t_plot), 0, A_GIMME, 0);
1957
class_setdrawcommand(plot_class);
1958
class_addfloat(plot_class, plot_float);
1959
class_setparentwidget(plot_class, &plot_widgetbehavior);
1962
/* ---------------- drawnumber: draw a number (or symbol) ---------------- */
1965
drawnumbers draw numeric fields at controllable locations, with
1966
controllable color and label. invocation:
1967
(drawnumber|drawsymbol) [-v <visible>] variable x y color label
1970
t_class *drawnumber_class;
1972
#define DRAW_SYMBOL 1
1974
typedef struct _drawnumber
1977
t_fielddesc x_value;
1980
t_fielddesc x_color;
1987
static void *drawnumber_new(t_symbol *classsym, t_int argc, t_atom *argv)
1989
t_drawnumber *x = (t_drawnumber *)pd_new(drawnumber_class);
1990
char *classname = classsym->s_name;
1993
if (classname[4] == 's')
1994
flags |= DRAW_SYMBOL;
1996
fielddesc_setfloat_const(&x->x_vis, 1);
1997
x->x_canvas = canvas_getcurrent();
2000
t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
2001
if (!strcmp(firstarg->s_name, "-v") && argc > 1)
2003
fielddesc_setfloatarg(&x->x_vis, 1, argv+1);
2004
argc -= 2; argv += 2;
2008
if (flags & DRAW_SYMBOL)
2010
if (argc) fielddesc_setsymbolarg(&x->x_value, argc--, argv++);
2011
else fielddesc_setsymbol_const(&x->x_value, &s_);
2015
if (argc) fielddesc_setfloatarg(&x->x_value, argc--, argv++);
2016
else fielddesc_setfloat_const(&x->x_value, 0);
2018
if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
2019
else fielddesc_setfloat_const(&x->x_xloc, 0);
2020
if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
2021
else fielddesc_setfloat_const(&x->x_yloc, 0);
2022
if (argc) fielddesc_setfloatarg(&x->x_color, argc--, argv++);
2023
else fielddesc_setfloat_const(&x->x_color, 1);
2025
x->x_label = atom_getsymbolarg(0, argc, argv);
2026
else x->x_label = &s_;
2031
void drawnumber_float(t_drawnumber *x, t_floatarg f)
2034
if (x->x_vis.fd_type != A_FLOAT || x->x_vis.fd_var)
2036
pd_error(x, "global vis/invis for a template with variable visibility");
2039
viswas = (x->x_vis.fd_un.fd_float != 0);
2041
if ((f != 0 && viswas) || (f == 0 && !viswas))
2043
canvas_redrawallfortemplatecanvas(x->x_canvas, 2);
2044
fielddesc_setfloat_const(&x->x_vis, (f != 0));
2045
canvas_redrawallfortemplatecanvas(x->x_canvas, 1);
2048
/* -------------------- widget behavior for drawnumber ------------ */
2050
#define DRAWNUMBER_BUFSIZE 80
2051
static void drawnumber_sprintf(t_drawnumber *x, char *buf, t_atom *ap)
2054
strncpy(buf, x->x_label->s_name, DRAWNUMBER_BUFSIZE);
2055
buf[DRAWNUMBER_BUFSIZE - 1] = 0;
2056
nchars = strlen(buf);
2057
atom_string(ap, buf + nchars, DRAWNUMBER_BUFSIZE - nchars);
2060
static void drawnumber_getrect(t_gobj *z, t_glist *glist,
2061
t_word *data, t_template *template, t_float basex, t_float basey,
2062
int *xp1, int *yp1, int *xp2, int *yp2)
2064
t_drawnumber *x = (t_drawnumber *)z;
2066
int xloc, yloc, font, fontwidth, fontheight;
2067
char buf[DRAWNUMBER_BUFSIZE];
2069
if (!fielddesc_getfloat(&x->x_vis, template, data, 0))
2071
*xp1 = *yp1 = 0x7fffffff;
2072
*xp2 = *yp2 = -0x7fffffff;
2075
xloc = glist_xtopixels(glist,
2076
basex + fielddesc_getcoord(&x->x_xloc, template, data, 0));
2077
yloc = glist_ytopixels(glist,
2078
basey + fielddesc_getcoord(&x->x_yloc, template, data, 0));
2079
font = glist_getfont(glist);
2080
fontwidth = sys_fontwidth(font);
2081
fontheight = sys_fontheight(font);
2082
if (x->x_flags & DRAW_SYMBOL)
2083
SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
2084
else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
2085
drawnumber_sprintf(x, buf, &at);
2088
*xp2 = xloc + fontwidth * strlen(buf);
2089
*yp2 = yloc + fontheight;
2092
static void drawnumber_displace(t_gobj *z, t_glist *glist,
2093
t_word *data, t_template *template, t_float basex, t_float basey,
2099
static void drawnumber_select(t_gobj *z, t_glist *glist,
2100
t_word *data, t_template *template, t_float basex, t_float basey,
2103
post("drawnumber_select %d", state);
2107
static void drawnumber_activate(t_gobj *z, t_glist *glist,
2108
t_word *data, t_template *template, t_float basex, t_float basey,
2111
post("drawnumber_activate %d", state);
2114
static void drawnumber_vis(t_gobj *z, t_glist *glist,
2115
t_word *data, t_template *template, t_float basex, t_float basey,
2118
t_drawnumber *x = (t_drawnumber *)z;
2120
/* see comment in plot_vis() */
2121
if (vis && !fielddesc_getfloat(&x->x_vis, template, data, 0))
2126
int xloc = glist_xtopixels(glist,
2127
basex + fielddesc_getcoord(&x->x_xloc, template, data, 0));
2128
int yloc = glist_ytopixels(glist,
2129
basey + fielddesc_getcoord(&x->x_yloc, template, data, 0));
2130
char colorstring[20], buf[DRAWNUMBER_BUFSIZE];
2131
numbertocolor(fielddesc_getfloat(&x->x_color, template, data, 1),
2133
if (x->x_flags & DRAW_SYMBOL)
2134
SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
2135
else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
2136
drawnumber_sprintf(x, buf, &at);
2137
sys_vgui(".x%lx.c create text %d %d -anchor nw -fill %s -text {%s}",
2138
glist_getcanvas(glist), xloc, yloc, colorstring, buf);
2139
sys_vgui(" -font {{%s} -%d %s}", sys_font,
2140
sys_hostfontsize(glist_getfont(glist)), sys_fontweight);
2141
sys_vgui(" -tags drawnumber%lx\n", data);
2143
else sys_vgui(".x%lx.c delete drawnumber%lx\n", glist_getcanvas(glist), data);
2146
static t_float drawnumber_motion_ycumulative;
2147
static t_glist *drawnumber_motion_glist;
2148
static t_scalar *drawnumber_motion_scalar;
2149
static t_array *drawnumber_motion_array;
2150
static t_word *drawnumber_motion_wp;
2151
static t_template *drawnumber_motion_template;
2152
static t_gpointer drawnumber_motion_gpointer;
2153
static int drawnumber_motion_symbol;
2154
static int drawnumber_motion_firstkey;
2156
/* LATER protect against the template changing or the scalar disappearing
2157
probably by attaching a gpointer here ... */
2159
static void drawnumber_motion(void *z, t_floatarg dx, t_floatarg dy)
2161
t_drawnumber *x = (t_drawnumber *)z;
2162
t_fielddesc *f = &x->x_value;
2164
if (!gpointer_check(&drawnumber_motion_gpointer, 0))
2166
post("drawnumber_motion: scalar disappeared");
2169
if (drawnumber_motion_symbol)
2171
post("drawnumber_motion: symbol");
2174
drawnumber_motion_ycumulative -= dy;
2175
template_setfloat(drawnumber_motion_template,
2177
drawnumber_motion_wp,
2178
drawnumber_motion_ycumulative,
2180
if (drawnumber_motion_scalar)
2181
template_notifyforscalar(drawnumber_motion_template,
2182
drawnumber_motion_glist, drawnumber_motion_scalar,
2183
gensym("change"), 1, &at);
2185
if (drawnumber_motion_scalar)
2186
scalar_redraw(drawnumber_motion_scalar, drawnumber_motion_glist);
2187
if (drawnumber_motion_array)
2188
array_redraw(drawnumber_motion_array, drawnumber_motion_glist);
2191
static void drawnumber_key(void *z, t_floatarg fkey)
2193
t_drawnumber *x = (t_drawnumber *)z;
2194
t_fielddesc *f = &x->x_value;
2196
char sbuf[MAXPDSTRING];
2198
if (!gpointer_check(&drawnumber_motion_gpointer, 0))
2200
post("drawnumber_motion: scalar disappeared");
2205
if (drawnumber_motion_symbol)
2207
/* key entry for a symbol field */
2208
if (drawnumber_motion_firstkey)
2210
else strncpy(sbuf, template_getsymbol(drawnumber_motion_template,
2211
f->fd_un.fd_varsym, drawnumber_motion_wp, 1)->s_name,
2213
sbuf[MAXPDSTRING-1] = 0;
2217
sbuf[strlen(sbuf)-1] = 0;
2221
sbuf[strlen(sbuf)+1] = 0;
2222
sbuf[strlen(sbuf)] = key;
2227
/* key entry for a numeric field. This is just a stopgap. */
2229
if (drawnumber_motion_firstkey)
2231
else sprintf(sbuf, "%g", template_getfloat(drawnumber_motion_template,
2232
f->fd_un.fd_varsym, drawnumber_motion_wp, 1));
2233
drawnumber_motion_firstkey = (key == '\n');
2237
sbuf[strlen(sbuf)-1] = 0;
2241
sbuf[strlen(sbuf)+1] = 0;
2242
sbuf[strlen(sbuf)] = key;
2244
if (sscanf(sbuf, "%g", &newf) < 1)
2246
template_setfloat(drawnumber_motion_template,
2247
f->fd_un.fd_varsym, drawnumber_motion_wp, newf, 1);
2248
if (drawnumber_motion_scalar)
2249
template_notifyforscalar(drawnumber_motion_template,
2250
drawnumber_motion_glist, drawnumber_motion_scalar,
2251
gensym("change"), 1, &at);
2252
if (drawnumber_motion_scalar)
2253
scalar_redraw(drawnumber_motion_scalar, drawnumber_motion_glist);
2254
if (drawnumber_motion_array)
2255
array_redraw(drawnumber_motion_array, drawnumber_motion_glist);
2259
static int drawnumber_click(t_gobj *z, t_glist *glist,
2260
t_word *data, t_template *template, t_scalar *sc, t_array *ap,
2261
t_float basex, t_float basey,
2262
int xpix, int ypix, int shift, int alt, int dbl, int doit)
2264
t_drawnumber *x = (t_drawnumber *)z;
2266
drawnumber_getrect(z, glist,
2267
data, template, basex, basey,
2268
&x1, &y1, &x2, &y2);
2269
if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2
2270
&& x->x_value.fd_var &&
2271
fielddesc_getfloat(&x->x_vis, template, data, 0))
2275
drawnumber_motion_glist = glist;
2276
drawnumber_motion_wp = data;
2277
drawnumber_motion_template = template;
2278
drawnumber_motion_scalar = sc;
2279
drawnumber_motion_array = ap;
2280
drawnumber_motion_firstkey = 1;
2281
drawnumber_motion_ycumulative =
2282
fielddesc_getfloat(&x->x_value, template, data, 0);
2283
drawnumber_motion_symbol = ((x->x_flags & DRAW_SYMBOL) != 0);
2284
if (drawnumber_motion_scalar)
2285
gpointer_setglist(&drawnumber_motion_gpointer,
2286
drawnumber_motion_glist, drawnumber_motion_scalar);
2287
else gpointer_setarray(&drawnumber_motion_gpointer,
2288
drawnumber_motion_array, drawnumber_motion_wp);
2289
glist_grab(glist, z, drawnumber_motion, drawnumber_key,
2297
t_parentwidgetbehavior drawnumber_widgetbehavior =
2300
drawnumber_displace,
2302
drawnumber_activate,
2307
static void drawnumber_free(t_drawnumber *x)
2311
static void drawnumber_setup(void)
2313
drawnumber_class = class_new(gensym("drawnumber"),
2314
(t_newmethod)drawnumber_new, (t_method)drawnumber_free,
2315
sizeof(t_drawnumber), 0, A_GIMME, 0);
2316
class_setdrawcommand(drawnumber_class);
2317
class_addfloat(drawnumber_class, drawnumber_float);
2318
class_addcreator((t_newmethod)drawnumber_new, gensym("drawsymbol"),
2320
class_setparentwidget(drawnumber_class, &drawnumber_widgetbehavior);
2323
/* ---------------------- setup function ---------------------------- */
2325
void g_template_setup(void)