~ubuntu-branches/ubuntu/precise/puredata/precise

« back to all changes in this revision

Viewing changes to src/g_template.c

  • Committer: Bazaar Package Importer
  • Author(s): Paul Brossier
  • Date: 2009-12-22 21:29:31 UTC
  • mfrom: (1.2.6 upstream) (4.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091222212931-nhwkzapjwsmjao1l
Tags: 0.42.5-3
* debian/control:
  - add community site to homepage field
  - improve long description
  - remove Replaces and Conflicts fields
  - add Suggests on pd-csound, pd-pdp, pd-zexy, pd-aubio
* debian/rules: add per-arch configuration flags
* debian/patches/02_kfreebsd.diff:
  - also define pd_tilde_dllextent on FreeBSD
  - fix typo (really closing #414414 this time)
  - also add hurd glue
* debian/patches/04_hurd.diff:
  - add hurd glue and s_midi_dummy.c

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.  */
 
4
 
 
5
#include <stdlib.h>
 
6
#include <string.h>
 
7
#include <stdio.h>
 
8
 
 
9
#include "m_pd.h"
 
10
#include "s_stuff.h"    /* for sys_hostfontsize */
 
11
#include "g_canvas.h"
 
12
 
 
13
void array_redraw(t_array *a, t_glist *glist);
 
14
 
 
15
/*
 
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).
 
19
*/
 
20
 
 
21
    /* the structure of a "struct" object (also the obsolete "gtemplate"
 
22
    you get when using the name "template" in a box.) */
 
23
 
 
24
struct _gtemplate
 
25
{
 
26
    t_object x_obj;
 
27
    t_template *x_template;
 
28
    t_canvas *x_owner;
 
29
    t_symbol *x_sym;
 
30
    struct _gtemplate *x_next;
 
31
    int x_argc;
 
32
    t_atom *x_argv;
 
33
};
 
34
 
 
35
/* ---------------- forward definitions ---------------- */
 
36
 
 
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);
 
41
 
 
42
/* ---------------------- storage ------------------------- */
 
43
 
 
44
static t_class *gtemplate_class;
 
45
static t_class *template_class;
 
46
 
 
47
/* there's a pre-defined "float" template.  LATER should we bind this
 
48
to a symbol such as "pd-float"??? */
 
49
 
 
50
    /* return true if two dataslot definitions match */
 
51
static int dataslot_matches(t_dataslot *ds1, t_dataslot *ds2,
 
52
    int nametoo)
 
53
{
 
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));
 
58
}
 
59
 
 
60
/* -- templates, the active ingredient in gtemplates defined below. ------- */
 
61
 
 
62
t_template *template_new(t_symbol *templatesym, int argc, t_atom *argv)
 
63
{
 
64
    t_template *x = (t_template *)pd_new(template_class);
 
65
    x->t_n = 0;
 
66
    x->t_vec = (t_dataslot *)t_getbytes(0);
 
67
    while (argc > 0)
 
68
    {
 
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)
 
73
                goto bad;
 
74
        newtypesym = argv[0].a_w.w_symbol;
 
75
        newname = argv[1].a_w.w_symbol;
 
76
        if (newtypesym == &s_float)
 
77
            newtype = DT_FLOAT;
 
78
        else if (newtypesym == &s_symbol)
 
79
            newtype = DT_SYMBOL;
 
80
        else if (newtypesym == &s_list)
 
81
            newtype = DT_LIST;
 
82
        else if (newtypesym == gensym("array"))
 
83
        {
 
84
            if (argc < 3 || argv[2].a_type != A_SYMBOL)
 
85
            {
 
86
                pd_error(x, "array lacks element template or name");
 
87
                goto bad;
 
88
            }
 
89
            newarraytemplate = canvas_makebindsym(argv[2].a_w.w_symbol);
 
90
            newtype = DT_ARRAY;
 
91
            argc--;
 
92
            argv++;
 
93
        }
 
94
        else
 
95
        {
 
96
            pd_error(x, "%s: no such type", newtypesym->s_name);
 
97
            goto bad;
 
98
        }
 
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));
 
102
        x->t_n = newn;
 
103
        x->t_vec[oldn].ds_type = newtype;
 
104
        x->t_vec[oldn].ds_name = newname;
 
105
        x->t_vec[oldn].ds_arraytemplate = newarraytemplate;
 
106
    bad: 
 
107
        argc -= 2; argv += 2;
 
108
    }
 
109
    if (*templatesym->s_name)
 
110
    {
 
111
        x->t_sym = templatesym;
 
112
        pd_bind(&x->t_pdobj, x->t_sym);
 
113
    }
 
114
    else x->t_sym = templatesym;
 
115
    return (x);
 
116
}
 
117
 
 
118
int template_size(t_template *x)
 
119
{
 
120
    return (x->t_n * sizeof(t_word));
 
121
}
 
122
 
 
123
int template_find_field(t_template *x, t_symbol *name, int *p_onset,
 
124
    int *p_type, t_symbol **p_arraytype)
 
125
{
 
126
    t_template *t;
 
127
    int i, n;
 
128
    if (!x)
 
129
    {
 
130
        bug("template_find_field");
 
131
        return (0);
 
132
    }
 
133
    n = x->t_n;
 
134
    for (i = 0; i < n; i++)
 
135
        if (x->t_vec[i].ds_name == name)
 
136
    {
 
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;
 
140
        return (1);
 
141
    }
 
142
    return (0);
 
143
}
 
144
 
 
145
t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp,
 
146
    int loud)
 
147
{
 
148
    int onset, type;
 
149
    t_symbol *arraytype;
 
150
    t_float val = 0;
 
151
    if (template_find_field(x, fieldname, &onset, &type, &arraytype))
 
152
    {
 
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);
 
157
    }
 
158
    else if (loud) error("%s.%s: no such field",
 
159
        x->t_sym->s_name, fieldname->s_name);
 
160
    return (val);
 
161
}
 
162
 
 
163
void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp, 
 
164
    t_float f, int loud)
 
165
{
 
166
    int onset, type;
 
167
    t_symbol *arraytype;
 
168
    if (template_find_field(x, fieldname, &onset, &type, &arraytype))
 
169
     {
 
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);
 
174
    }
 
175
    else if (loud) error("%s.%s: no such field",
 
176
        x->t_sym->s_name, fieldname->s_name);
 
177
}
 
178
 
 
179
t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp,
 
180
    int loud)
 
181
{
 
182
    int onset, type;
 
183
    t_symbol *arraytype;
 
184
    t_symbol *val = &s_;
 
185
    if (template_find_field(x, fieldname, &onset, &type, &arraytype))
 
186
    {
 
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);
 
191
    }
 
192
    else if (loud) error("%s.%s: no such field",
 
193
        x->t_sym->s_name, fieldname->s_name);
 
194
    return (val);
 
195
}
 
196
 
 
197
void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp, 
 
198
    t_symbol *s, int loud)
 
199
{
 
200
    int onset, type;
 
201
    t_symbol *arraytype;
 
202
    if (template_find_field(x, fieldname, &onset, &type, &arraytype))
 
203
     {
 
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);
 
208
    }
 
209
    else if (loud) error("%s.%s: no such field",
 
210
        x->t_sym->s_name, fieldname->s_name);
 
211
}
 
212
 
 
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)
 
217
{
 
218
    int i;
 
219
    if (x1->t_n < x2->t_n)
 
220
        return (0);
 
221
    for (i = x2->t_n; i < x1->t_n; i++)
 
222
    {
 
223
        if (x1->t_vec[i].ds_type == DT_ARRAY || 
 
224
            x1->t_vec[i].ds_type == DT_LIST)
 
225
                return (0);
 
226
    }
 
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))
 
231
            return (0);
 
232
    return (1);
 
233
}
 
234
 
 
235
/* --------------- CONFORMING TO CHANGES IN A TEMPLATE ------------ */
 
236
 
 
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... */
 
243
 
 
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)
 
247
{
 
248
    int nfrom = tfrom->t_n, nto = tto->t_n, i;
 
249
    for (i = 0; i < nto; i++)
 
250
    {
 
251
        if (conformaction[i] >= 0)
 
252
        {
 
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;
 
258
        }
 
259
    }
 
260
}
 
261
 
 
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)
 
265
{
 
266
    t_scalar *x;
 
267
    t_gpointer gp;
 
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)
 
273
    {
 
274
            /* see scalar_new() for comment about the gpointer. */
 
275
        gpointer_init(&gp);
 
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);
 
284
 
 
285
        template_conformwords(tfrom, tto, conformaction,
 
286
            scfrom->sc_vec, x->sc_vec);
 
287
            
 
288
            /* replace the old one with the new one in the list */
 
289
        if (glist->gl_list == &scfrom->sc_gobj)
 
290
        {
 
291
            glist->gl_list = &x->sc_gobj;
 
292
            x->sc_gobj.g_next = scfrom->sc_gobj.g_next;
 
293
        }
 
294
        else
 
295
        {
 
296
            t_gobj *y, *y2;
 
297
            for (y = glist->gl_list; y2 = y->g_next; y = y2)
 
298
                if (y2 == &scfrom->sc_gobj)
 
299
            {
 
300
                x->sc_gobj.g_next = y2->g_next;
 
301
                y->g_next = &x->sc_gobj;
 
302
                goto nobug;
 
303
            }
 
304
            bug("template_conformscalar");
 
305
        nobug: ;
 
306
        }
 
307
            /* burn the old one */
 
308
        pd_free(&scfrom->sc_gobj.g_pd);
 
309
        scalartemplate = tto;
 
310
    }
 
311
    else
 
312
    {
 
313
        x = scfrom;
 
314
        scalartemplate = template_findbyname(x->sc_template);
 
315
    }
 
316
        /* convert all array elements and sublists */
 
317
    for (i = 0; i < scalartemplate->t_n; i++)
 
318
    {
 
319
        t_dataslot *ds = scalartemplate->t_vec + i;
 
320
        if (ds->ds_type == DT_LIST)
 
321
        {
 
322
            t_glist *gl2 = x->sc_vec[i].w_list;
 
323
            template_conformglist(tfrom, tto, gl2, conformaction);
 
324
        }
 
325
        else if (ds->ds_type == DT_ARRAY)
 
326
        {
 
327
            template_conformarray(tfrom, tto, conformaction, 
 
328
                x->sc_vec[i].w_array);
 
329
        }
 
330
    }
 
331
    return (x);
 
332
}
 
333
 
 
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)
 
337
{
 
338
    int i, j;
 
339
    t_template *scalartemplate = 0;
 
340
    if (a->a_templatesym == tfrom->t_sym)
 
341
    {
 
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++)
 
350
        {
 
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);
 
356
        }
 
357
        scalartemplate = tto;
 
358
        a->a_vec = newarray;
 
359
        freebytes(oldarray, oldelemsize * a->a_n);
 
360
    }
 
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++)
 
364
    {
 
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++)
 
367
        {
 
368
            t_dataslot *ds = scalartemplate->t_vec + j;
 
369
            if (ds->ds_type == DT_LIST)
 
370
            {
 
371
                t_glist *gl2 = wp[j].w_list;
 
372
                template_conformglist(tfrom, tto, gl2, conformaction);
 
373
            }
 
374
            else if (ds->ds_type == DT_ARRAY)
 
375
            {
 
376
                template_conformarray(tfrom, tto, conformaction, 
 
377
                    wp[j].w_array);
 
378
            }
 
379
        }
 
380
    }
 
381
}
 
382
 
 
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
 
385
    glists recursively.
 
386
    We don't handle redrawing here; this is to be filled in LATER... */
 
387
 
 
388
t_array *garray_getarray(t_garray *x);
 
389
 
 
390
static void template_conformglist(t_template *tfrom, t_template *tto,
 
391
    t_glist *glist,  int *conformaction)
 
392
{
 
393
    t_gobj *g;
 
394
    /* post("conform glist %s", glist->gl_name->s_name); */
 
395
    for (g = glist->gl_list; g; g = g->g_next)
 
396
    {
 
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));
 
405
    }
 
406
}
 
407
 
 
408
    /* globally conform all scalars from one template to another */ 
 
409
void template_conform(t_template *tfrom, t_template *tto)
 
410
{
 
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++)
 
419
    {
 
420
        t_dataslot *dataslot = &tto->t_vec[i];
 
421
        for (j = 0; j < nfrom; j++)
 
422
        {
 
423
            t_dataslot *dataslot2 = &tfrom->t_vec[j];
 
424
            if (dataslot_matches(dataslot, dataslot2, 1))
 
425
            {
 
426
                conformaction[i] = j;
 
427
                conformedfrom[j] = 1;
 
428
            }
 
429
        }
 
430
    }
 
431
    for (i = 0; i < nto; i++)
 
432
        if (conformaction[i] < 0)
 
433
    {
 
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))
 
438
        {
 
439
            conformaction[i] = j;
 
440
            conformedfrom[j] = 1;
 
441
        }
 
442
    }
 
443
    if (nto != nfrom)
 
444
        doit = 1;
 
445
    else for (i = 0; i < nto; i++)
 
446
        if (conformaction[i] != i)
 
447
            doit = 1;
 
448
 
 
449
    if (doit)
 
450
    {
 
451
        t_glist *gl;
 
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);
 
458
    }
 
459
    freebytes(conformaction, sizeof(int) * nto);
 
460
    freebytes(conformedfrom, sizeof(int) * nfrom);
 
461
}
 
462
 
 
463
t_template *template_findbyname(t_symbol *s)
 
464
{
 
465
    return ((t_template *)pd_findbyclass(s, template_class));
 
466
}
 
467
 
 
468
t_canvas *template_findcanvas(t_template *template)
 
469
{
 
470
    t_gtemplate *gt;
 
471
    if (!template) 
 
472
        bug("template_findcanvas");
 
473
    if (!(gt = template->t_list))
 
474
        return (0);
 
475
    return (gt->x_owner);
 
476
    /* return ((t_canvas *)pd_findbyclass(template->t_sym, canvas_class)); */
 
477
}
 
478
 
 
479
void template_notify(t_template *template, t_symbol *s, int argc, t_atom *argv)
 
480
{
 
481
    if (template->t_list)
 
482
        outlet_anything(template->t_list->x_obj.ob_outlet, s, argc, argv);
 
483
}
 
484
 
 
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)
 
489
{
 
490
    t_gpointer gp;
 
491
    gpointer_init(&gp);
 
492
    gpointer_setglist(&gp, owner, sc);
 
493
    SETPOINTER(argv, &gp);
 
494
    template_notify(template, s, argc, argv);
 
495
    gpointer_unset(&gp);
 
496
}
 
497
 
 
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)
 
507
{
 
508
    t_template *x;
 
509
    t_symbol *templatesym =
 
510
        canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
 
511
    if (!argc)
 
512
        return (0);
 
513
    argc--; argv++;
 
514
            /* check if there's already a template by this name. */
 
515
    if ((x = (t_template *)pd_findbyclass(templatesym, template_class)))
 
516
    {
 
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))
 
521
        {
 
522
                /* Are there "struct" objects upholding this template? */
 
523
            if (x->t_list)
 
524
            {
 
525
                    /* don't know what to do here! */
 
526
                error("%s: template mismatch",
 
527
                    templatesym->s_name);
 
528
            }
 
529
            else
 
530
            {
 
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);
 
535
                y2->t_list = 0;
 
536
            }
 
537
        }
 
538
        pd_free(&y->t_pdobj);
 
539
    }
 
540
        /* otherwise, just make one. */
 
541
    else template_new(templatesym, argc, argv);
 
542
    return (0);
 
543
}
 
544
 
 
545
    /* here we assume someone has already cleaned up all instances of this. */
 
546
void template_free(t_template *x)
 
547
{
 
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));
 
551
}
 
552
 
 
553
static void template_setup(void)
 
554
{
 
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);
 
559
        
 
560
}
 
561
 
 
562
/* ---------------- gtemplates.  One per canvas. ----------- */
 
563
 
 
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. */
 
569
 
 
570
static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv)
 
571
{
 
572
    t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
 
573
    t_template *t = template_findbyname(sym);
 
574
    int i;
 
575
    t_symbol *sx = gensym("x");
 
576
    x->x_owner = canvas_getcurrent();
 
577
    x->x_next = 0;
 
578
    x->x_sym = sym;
 
579
    x->x_argc = argc;
 
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];
 
583
 
 
584
        /* already have a template by this name? */
 
585
    if (t)
 
586
    {
 
587
        x->x_template = t;
 
588
            /* if it's already got a "struct" object we
 
589
            just tack this one to the end of the list and leave it
 
590
            there. */
 
591
        if (t->t_list)
 
592
        {
 
593
            t_gtemplate *x2, *x3;
 
594
            for (x2 = x->x_template->t_list; x3 = x2->x_next; x2 = x3)
 
595
                ;
 
596
            x2->x_next = x;
 
597
            post("template %s: warning: already exists.", sym->s_name);
 
598
        }
 
599
        else
 
600
        {
 
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))
 
608
            {
 
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);
 
613
            }
 
614
            pd_free(&y->t_pdobj);
 
615
            t->t_list = x;
 
616
            canvas_redrawallfortemplate(t, 1);
 
617
        }
 
618
    }
 
619
    else
 
620
    {
 
621
            /* otherwise make a new one and we're the only struct on it. */
 
622
        x->x_template = t = template_new(sym, argc, argv);
 
623
        t->t_list = x;
 
624
    }
 
625
    outlet_new(&x->x_obj, 0);
 
626
    return (x);
 
627
}
 
628
 
 
629
static void *gtemplate_new(t_symbol *s, int argc, t_atom *argv)
 
630
{
 
631
    t_symbol *sym = atom_getsymbolarg(0, argc, argv);
 
632
    if (argc >= 1)
 
633
        argc--; argv++;
 
634
    return (gtemplate_donew(canvas_makebindsym(sym), argc, argv));
 
635
}
 
636
 
 
637
    /* old version (0.34) -- delete 2003 or so */
 
638
static void *gtemplate_new_old(t_symbol *s, int argc, t_atom *argv)
 
639
{
 
640
    t_symbol *sym = canvas_makebindsym(canvas_getcurrent()->gl_name);
 
641
    static int warned;
 
642
    if (!warned)
 
643
    {
 
644
        post("warning -- 'template' (%s) is obsolete; replace with 'struct'",
 
645
            sym->s_name);
 
646
        warned = 1;
 
647
    }
 
648
    return (gtemplate_donew(sym, argc, argv));
 
649
}
 
650
 
 
651
t_template *gtemplate_get(t_gtemplate *x)
 
652
{
 
653
    return (x->x_template);
 
654
}
 
655
 
 
656
static void gtemplate_free(t_gtemplate *x)
 
657
{
 
658
        /* get off the template's list */
 
659
    t_template *t = x->x_template;
 
660
    t_gtemplate *y;
 
661
    if (x == t->t_list)
 
662
    {
 
663
        canvas_redrawallfortemplate(t, 2);
 
664
        if (x->x_next)
 
665
        {
 
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)
 
677
                y->x_template = z;
 
678
        }
 
679
        else t->t_list = 0;
 
680
        canvas_redrawallfortemplate(t, 1);
 
681
    }
 
682
    else
 
683
    {
 
684
        t_gtemplate *x2, *x3;
 
685
        for (x2 = t->t_list; x3 = x2->x_next; x2 = x3)
 
686
        {
 
687
            if (x == x3)
 
688
            {
 
689
                x2->x_next = x3->x_next;
 
690
                break;
 
691
            }
 
692
        }
 
693
    }
 
694
    freebytes(x->x_argv, sizeof(t_atom) * x->x_argc);
 
695
}
 
696
 
 
697
static void gtemplate_setup(void)
 
698
{
 
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"),
 
703
        A_GIMME, 0);
 
704
}
 
705
 
 
706
/* ---------------  FIELD DESCRIPTORS ---------------------- */
 
707
 
 
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.
 
712
*/
 
713
 
 
714
struct _fielddesc
 
715
{
 
716
    char fd_type;       /* LATER consider removing this? */
 
717
    char fd_var;
 
718
    union
 
719
    {
 
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 */
 
723
    } fd_un;
 
724
    float fd_v1;        /* min and max values */
 
725
    float fd_v2;
 
726
    float fd_screen1;   /* min and max screen values */
 
727
    float fd_screen2;
 
728
    float fd_quantum;   /* quantization in value */ 
 
729
};
 
730
 
 
731
static void fielddesc_setfloat_const(t_fielddesc *fd, t_float f)
 
732
{
 
733
    fd->fd_type = A_FLOAT;
 
734
    fd->fd_var = 0;
 
735
    fd->fd_un.fd_float = f;
 
736
    fd->fd_v1 = fd->fd_v2 = fd->fd_screen1 = fd->fd_screen2 =
 
737
        fd->fd_quantum = 0;
 
738
}
 
739
 
 
740
static void fielddesc_setsymbol_const(t_fielddesc *fd, t_symbol *s)
 
741
{
 
742
    fd->fd_type = A_SYMBOL;
 
743
    fd->fd_var = 0;
 
744
    fd->fd_un.fd_symbol = s;
 
745
    fd->fd_v1 = fd->fd_v2 = fd->fd_screen1 = fd->fd_screen2 =
 
746
        fd->fd_quantum = 0;
 
747
}
 
748
 
 
749
static void fielddesc_setfloat_var(t_fielddesc *fd, t_symbol *s)
 
750
{
 
751
    char *s1, *s2, *s3, strbuf[MAXPDSTRING];
 
752
    int i;
 
753
    fd->fd_type = A_FLOAT;
 
754
    fd->fd_var = 1;
 
755
    if (!(s1 = strchr(s->s_name, '(')) || !(s2 = strchr(s->s_name, ')'))
 
756
        || (s1 > s2))
 
757
    {
 
758
        fd->fd_un.fd_varsym = s;
 
759
        fd->fd_v1 = fd->fd_v2 = fd->fd_screen1 = fd->fd_screen2 =
 
760
            fd->fd_quantum = 0;
 
761
    }
 
762
    else
 
763
    {
 
764
        int cpy = s1 - s->s_name, got;
 
765
        if (cpy > MAXPDSTRING-5)
 
766
            cpy = MAXPDSTRING-5;
 
767
        strncpy(strbuf, s->s_name, cpy);
 
768
        strbuf[cpy] = 0;
 
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,
 
772
                &fd->fd_quantum);
 
773
        if (got < 2)
 
774
            goto fail;
 
775
        if (got == 3 || (got < 4 && strchr(s2, '(')))
 
776
            goto fail;
 
777
        if (got < 5 && (s3 = strchr(s2, '(')) && strchr(s3+1, '('))
 
778
            goto fail;
 
779
        if (got == 4)
 
780
            fd->fd_quantum = 0;
 
781
        else if (got == 2)
 
782
        {
 
783
            fd->fd_quantum = 0;
 
784
            fd->fd_screen1 = fd->fd_v1;
 
785
            fd->fd_screen2 = fd->fd_v2;
 
786
        }
 
787
        return;
 
788
    fail:
 
789
        post("parse error: %s", s->s_name);
 
790
        fd->fd_v1 = fd->fd_screen1 = fd->fd_v2 = fd->fd_screen2 =
 
791
            fd->fd_quantum = 0;
 
792
    }
 
793
}
 
794
 
 
795
#define CLOSED 1
 
796
#define BEZ 2
 
797
#define NOMOUSE 4
 
798
#define A_ARRAY 55      /* LATER decide whether to enshrine this in m_pd.h */
 
799
 
 
800
static void fielddesc_setfloatarg(t_fielddesc *fd, int argc, t_atom *argv)
 
801
{
 
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);
 
806
}
 
807
 
 
808
static void fielddesc_setsymbolarg(t_fielddesc *fd, int argc, t_atom *argv)
 
809
{
 
810
        if (argc <= 0) fielddesc_setsymbol_const(fd, &s_);
 
811
        else if (argv->a_type == A_SYMBOL)
 
812
        {
 
813
            fd->fd_type = A_SYMBOL;
 
814
            fd->fd_var = 1;
 
815
            fd->fd_un.fd_varsym = argv->a_w.w_symbol;
 
816
            fd->fd_v1 = fd->fd_v2 = fd->fd_screen1 = fd->fd_screen2 =
 
817
                fd->fd_quantum = 0;
 
818
        }
 
819
        else fielddesc_setsymbol_const(fd, &s_);
 
820
}
 
821
 
 
822
static void fielddesc_setarrayarg(t_fielddesc *fd, int argc, t_atom *argv)
 
823
{
 
824
        if (argc <= 0) fielddesc_setfloat_const(fd, 0);
 
825
        else if (argv->a_type == A_SYMBOL)
 
826
        {
 
827
            fd->fd_type = A_ARRAY;
 
828
            fd->fd_var = 1;
 
829
            fd->fd_un.fd_varsym = argv->a_w.w_symbol;
 
830
        }
 
831
        else fielddesc_setfloat_const(fd, argv->a_w.w_float);
 
832
}
 
833
 
 
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)
 
838
{
 
839
    if (f->fd_type == A_FLOAT)
 
840
    {
 
841
        if (f->fd_var)
 
842
            return (template_getfloat(template, f->fd_un.fd_varsym, wp, loud));
 
843
        else return (f->fd_un.fd_float);
 
844
    }
 
845
    else
 
846
    {
 
847
        if (loud)
 
848
            error("symbolic data field used as number");
 
849
        return (0);
 
850
    }
 
851
}
 
852
 
 
853
    /* convert a variable's value to a screen coordinate via its fielddesc */
 
854
t_float fielddesc_cvttocoord(t_fielddesc *f, t_float val)
 
855
{
 
856
    t_float coord, pix, extreme, div;
 
857
    if (f->fd_v2 == f->fd_v1)
 
858
        return (val);
 
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);
 
863
    if (coord < extreme)
 
864
        coord = extreme;
 
865
    extreme = (f->fd_screen1 > f->fd_screen2 ? 
 
866
        f->fd_screen1 : f->fd_screen2);
 
867
    if (coord > extreme)
 
868
        coord = extreme;
 
869
    return (coord);
 
870
}
 
871
 
 
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)
 
875
{
 
876
    if (f->fd_type == A_FLOAT)
 
877
    {
 
878
        if (f->fd_var)
 
879
        {
 
880
            t_float val = template_getfloat(template,
 
881
                f->fd_un.fd_varsym, wp, loud);
 
882
            return (fielddesc_cvttocoord(f, val));
 
883
        }
 
884
        else return (f->fd_un.fd_float);
 
885
    }
 
886
    else
 
887
    {
 
888
        if (loud)
 
889
            error("symbolic data field used as number");
 
890
        return (0);
 
891
    }
 
892
}
 
893
 
 
894
static t_symbol *fielddesc_getsymbol(t_fielddesc *f, t_template *template,
 
895
    t_word *wp, int loud)
 
896
{
 
897
    if (f->fd_type == A_SYMBOL)
 
898
    {
 
899
        if (f->fd_var)
 
900
            return(template_getsymbol(template, f->fd_un.fd_varsym, wp, loud));
 
901
        else return (f->fd_un.fd_symbol);
 
902
    }
 
903
    else
 
904
    {
 
905
        if (loud)
 
906
            error("numeric data field used as symbol");
 
907
        return (&s_);
 
908
    }
 
909
}
 
910
 
 
911
    /* convert from a screen coordinate to a variable value */
 
912
t_float fielddesc_cvtfromcoord(t_fielddesc *f, t_float coord)
 
913
{
 
914
    t_float val;
 
915
    if (f->fd_screen2 == f->fd_screen1)
 
916
        val = coord;
 
917
    else
 
918
    {
 
919
        t_float div = (f->fd_v2 - f->fd_v1)/(f->fd_screen2 - f->fd_screen1);
 
920
        t_float extreme;
 
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;
 
930
    }
 
931
    return (val);
 
932
 }
 
933
 
 
934
void fielddesc_setcoord(t_fielddesc *f, t_template *template,
 
935
    t_word *wp, t_float coord, int loud)
 
936
{
 
937
    if (f->fd_type == A_FLOAT && f->fd_var)
 
938
    {
 
939
        t_float val = fielddesc_cvtfromcoord(f, coord);
 
940
        template_setfloat(template,
 
941
                f->fd_un.fd_varsym, wp, val, loud);
 
942
    }
 
943
    else
 
944
    {
 
945
        if (loud)
 
946
            error("attempt to set constant or symbolic data field to a number");
 
947
    }
 
948
}
 
949
 
 
950
/* ---------------- curves and polygons (joined segments) ---------------- */
 
951
 
 
952
/*
 
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.
 
956
*/
 
957
 
 
958
t_class *curve_class;
 
959
 
 
960
typedef struct _curve
 
961
{
 
962
    t_object x_obj;
 
963
    int x_flags;            /* CLOSED and/or BEZ and/or NOMOUSE */
 
964
    t_fielddesc x_fillcolor;
 
965
    t_fielddesc x_outlinecolor;
 
966
    t_fielddesc x_width;
 
967
    t_fielddesc x_vis;
 
968
    int x_npoints;
 
969
    t_fielddesc *x_vec;
 
970
    t_canvas *x_canvas;
 
971
} t_curve;
 
972
 
 
973
static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv)
 
974
{
 
975
    t_curve *x = (t_curve *)pd_new(curve_class);
 
976
    char *classname = classsym->s_name;
 
977
    int flags = 0;
 
978
    int nxy, i;
 
979
    t_fielddesc *fd;
 
980
    x->x_canvas = canvas_getcurrent();
 
981
    if (classname[0] == 'f')
 
982
    {
 
983
        classname += 6;
 
984
        flags |= CLOSED;
 
985
    }
 
986
    else classname += 4;
 
987
    if (classname[0] == 'c') flags |= BEZ;
 
988
    fielddesc_setfloat_const(&x->x_vis, 1);
 
989
    while (1)
 
990
    {
 
991
        t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
 
992
        if (!strcmp(firstarg->s_name, "-v") && argc > 1)
 
993
        {
 
994
            fielddesc_setfloatarg(&x->x_vis, 1, argv+1);
 
995
            argc -= 2; argv += 2;
 
996
        }
 
997
        else if (!strcmp(firstarg->s_name, "-x"))
 
998
        {
 
999
            flags |= NOMOUSE;
 
1000
            argc -= 1; argv += 1;
 
1001
        }
 
1002
        else break;
 
1003
    }
 
1004
    x->x_flags = flags;
 
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);
 
1019
 
 
1020
    return (x);
 
1021
}
 
1022
 
 
1023
void curve_float(t_curve *x, t_floatarg f)
 
1024
{
 
1025
    int viswas;
 
1026
    if (x->x_vis.fd_type != A_FLOAT || x->x_vis.fd_var)
 
1027
    {
 
1028
        pd_error(x, "global vis/invis for a template with variable visibility");
 
1029
        return;
 
1030
    }
 
1031
    viswas = (x->x_vis.fd_un.fd_float != 0);
 
1032
    
 
1033
    if ((f != 0 && viswas) || (f == 0 && !viswas))
 
1034
        return;
 
1035
    canvas_redrawallfortemplatecanvas(x->x_canvas, 2);
 
1036
    fielddesc_setfloat_const(&x->x_vis, (f != 0));
 
1037
    canvas_redrawallfortemplatecanvas(x->x_canvas, 1);
 
1038
}
 
1039
 
 
1040
/* -------------------- widget behavior for curve ------------ */
 
1041
 
 
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)
 
1045
{
 
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))
 
1052
    {
 
1053
        *xp1 = *yp1 = 0x7fffffff;
 
1054
        *xp2 = *yp2 = -0x7fffffff;
 
1055
        return;
 
1056
    }
 
1057
    for (i = 0, f = x->x_vec; i < n; i++, f += 2)
 
1058
    {
 
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;
 
1067
    }
 
1068
    *xp1 = x1;
 
1069
    *yp1 = y1;
 
1070
    *xp2 = x2;
 
1071
    *yp2 = y2; 
 
1072
}
 
1073
 
 
1074
static void curve_displace(t_gobj *z, t_glist *glist,
 
1075
    t_word *data, t_template *template, t_float basex, t_float basey,
 
1076
    int dx, int dy)
 
1077
{
 
1078
    /* refuse */
 
1079
}
 
1080
 
 
1081
static void curve_select(t_gobj *z, t_glist *glist,
 
1082
    t_word *data, t_template *template, t_float basex, t_float basey,
 
1083
    int state)
 
1084
{
 
1085
    /* fill in later */
 
1086
}
 
1087
 
 
1088
static void curve_activate(t_gobj *z, t_glist *glist,
 
1089
    t_word *data, t_template *template, t_float basex, t_float basey,
 
1090
    int state)
 
1091
{
 
1092
    /* fill in later */
 
1093
}
 
1094
 
 
1095
#if 0
 
1096
static int rangecolor(int n)    /* 0 to 9 in 5 steps */
 
1097
{
 
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;
 
1101
    return (ret);
 
1102
}
 
1103
#endif
 
1104
 
 
1105
static int rangecolor(int n)    /* 0 to 9 in 5 steps */
 
1106
{
 
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;
 
1110
    return (ret);
 
1111
}
 
1112
 
 
1113
static void numbertocolor(int n, char *s)
 
1114
{
 
1115
    int red, blue, green;
 
1116
    if (n < 0) n = 0;
 
1117
    red = n / 100;
 
1118
    blue = ((n / 10) % 10);
 
1119
    green = n % 10;
 
1120
    sprintf(s, "#%2.2x%2.2x%2.2x", rangecolor(red), rangecolor(blue),
 
1121
        rangecolor(green));
 
1122
}
 
1123
 
 
1124
static void curve_vis(t_gobj *z, t_glist *glist, 
 
1125
    t_word *data, t_template *template, t_float basex, t_float basey,
 
1126
    int vis)
 
1127
{
 
1128
    t_curve *x = (t_curve *)z;
 
1129
    int i, n = x->x_npoints;
 
1130
    t_fielddesc *f = x->x_vec;
 
1131
    
 
1132
        /* see comment in plot_vis() */
 
1133
    if (vis && !fielddesc_getfloat(&x->x_vis, template, data, 0))
 
1134
        return;
 
1135
    if (vis)
 
1136
    {
 
1137
        if (n > 1)
 
1138
        {
 
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];
 
1142
            int pix[200];
 
1143
            if (n > 100)
 
1144
                n = 100;
 
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)
 
1150
            {
 
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));
 
1155
            }
 
1156
            if (width < 1) width = 1;
 
1157
            numbertocolor(
 
1158
                fielddesc_getfloat(&x->x_outlinecolor, template, data, 1),
 
1159
                outline);
 
1160
            if (flags & CLOSED)
 
1161
            {
 
1162
                numbertocolor(
 
1163
                    fielddesc_getfloat(&x->x_fillcolor, template, data, 1),
 
1164
                    fill);
 
1165
                sys_vgui(".x%lx.c create polygon\\\n",
 
1166
                    glist_getcanvas(glist));
 
1167
            }
 
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",
 
1173
                fill, outline);
 
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);
 
1177
        }
 
1178
        else post("warning: curves need at least two points to be graphed");
 
1179
    }
 
1180
    else
 
1181
    {
 
1182
        if (n > 1) sys_vgui(".x%lx.c delete curve%lx\n",
 
1183
            glist_getcanvas(glist), data);      
 
1184
    }
 
1185
}
 
1186
 
 
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;
 
1200
 
 
1201
    /* LATER protect against the template changing or the scalar disappearing
 
1202
    probably by attaching a gpointer here ... */
 
1203
 
 
1204
static void curve_motion(void *z, t_floatarg dx, t_floatarg dy)
 
1205
{
 
1206
    t_curve *x = (t_curve *)z;
 
1207
    t_fielddesc *f = x->x_vec + curve_motion_field;
 
1208
    t_atom at;
 
1209
    if (!gpointer_check(&curve_motion_gpointer, 0))
 
1210
    {
 
1211
        post("curve_motion: scalar disappeared");
 
1212
        return;
 
1213
    }
 
1214
    curve_motion_xcumulative += dx;
 
1215
    curve_motion_ycumulative += dy;
 
1216
    if (f->fd_var && (dx != 0))
 
1217
    {
 
1218
        fielddesc_setcoord(f, curve_motion_template, curve_motion_wp,
 
1219
            curve_motion_xbase + curve_motion_xcumulative * curve_motion_xper,
 
1220
                1); 
 
1221
    }
 
1222
    if ((f+1)->fd_var && (dy != 0))
 
1223
    {
 
1224
        fielddesc_setcoord(f+1, curve_motion_template, curve_motion_wp,
 
1225
            curve_motion_ybase + curve_motion_ycumulative * curve_motion_yper,
 
1226
                1); 
 
1227
    }
 
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);
 
1236
}
 
1237
 
 
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)
 
1242
{
 
1243
    t_curve *x = (t_curve *)z;
 
1244
    int i, n = x->x_npoints;
 
1245
    int bestn = -1;
 
1246
    int besterror = 0x7fffffff;
 
1247
    t_fielddesc *f;
 
1248
    if (!fielddesc_getfloat(&x->x_vis, template, data, 0))
 
1249
        return (0);
 
1250
    for (i = 0, f = x->x_vec; i < n; i++, f += 2)
 
1251
    {
 
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)
 
1258
            continue;
 
1259
        if (xerr < 0)
 
1260
            xerr = -xerr;
 
1261
        if (yerr < 0)
 
1262
            yerr = -yerr;
 
1263
        if (yerr > xerr)
 
1264
            xerr = yerr;
 
1265
        if (xerr < besterror)
 
1266
        {
 
1267
            curve_motion_xbase = xval;
 
1268
            curve_motion_ybase = yval;
 
1269
            besterror = xerr;
 
1270
            bestn = i;
 
1271
        }
 
1272
    }
 
1273
    if (besterror > 6)
 
1274
        return (0);
 
1275
    if (doit)
 
1276
    {
 
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);
 
1295
    }
 
1296
    return (1);
 
1297
}
 
1298
 
 
1299
t_parentwidgetbehavior curve_widgetbehavior =
 
1300
{
 
1301
    curve_getrect,
 
1302
    curve_displace,
 
1303
    curve_select,
 
1304
    curve_activate,
 
1305
    curve_vis,
 
1306
    curve_click,
 
1307
};
 
1308
 
 
1309
static void curve_free(t_curve *x)
 
1310
{
 
1311
    t_freebytes(x->x_vec, 2 * x->x_npoints * sizeof(*x->x_vec));
 
1312
}
 
1313
 
 
1314
static void curve_setup(void)
 
1315
{
 
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"),
 
1320
        A_GIMME, 0);
 
1321
    class_addcreator((t_newmethod)curve_new, gensym("filledpolygon"),
 
1322
        A_GIMME, 0);
 
1323
    class_addcreator((t_newmethod)curve_new, gensym("filledcurve"),
 
1324
        A_GIMME, 0);
 
1325
    class_setparentwidget(curve_class, &curve_widgetbehavior);
 
1326
    class_addfloat(curve_class, curve_float);
 
1327
}
 
1328
 
 
1329
/* --------- plots for showing arrays --------------- */
 
1330
 
 
1331
t_class *plot_class;
 
1332
 
 
1333
typedef struct _plot
 
1334
{
 
1335
    t_object x_obj;
 
1336
    t_canvas *x_canvas;
 
1337
    t_fielddesc x_outlinecolor;
 
1338
    t_fielddesc x_width;
 
1339
    t_fielddesc x_xloc;
 
1340
    t_fielddesc x_yloc;
 
1341
    t_fielddesc x_xinc;
 
1342
    t_fielddesc x_style;
 
1343
    t_fielddesc x_data;
 
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 */
 
1349
} t_plot;
 
1350
 
 
1351
static void *plot_new(t_symbol *classsym, t_int argc, t_atom *argv)
 
1352
{
 
1353
    t_plot *x = (t_plot *)pd_new(plot_class);
 
1354
    int defstyle = PLOTSTYLE_POLY;
 
1355
    x->x_canvas = canvas_getcurrent();
 
1356
 
 
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"));
 
1360
    
 
1361
    fielddesc_setfloat_const(&x->x_vis, 1);
 
1362
    fielddesc_setfloat_const(&x->x_scalarvis, 1);
 
1363
    while (1)
 
1364
    {
 
1365
        t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
 
1366
        if (!strcmp(firstarg->s_name, "curve") ||
 
1367
            !strcmp(firstarg->s_name, "-c"))
 
1368
        {
 
1369
            defstyle = PLOTSTYLE_BEZ;
 
1370
            argc--, argv++;
 
1371
        }
 
1372
        else if (!strcmp(firstarg->s_name, "-v") && argc > 1)
 
1373
        {
 
1374
            fielddesc_setfloatarg(&x->x_vis, 1, argv+1);
 
1375
            argc -= 2; argv += 2;
 
1376
        }
 
1377
        else if (!strcmp(firstarg->s_name, "-vs") && argc > 1)
 
1378
        {
 
1379
            fielddesc_setfloatarg(&x->x_scalarvis, 1, argv+1);
 
1380
            argc -= 2; argv += 2;
 
1381
        }
 
1382
        else if (!strcmp(firstarg->s_name, "-x") && argc > 1)
 
1383
        {
 
1384
            fielddesc_setfloatarg(&x->x_xpoints, 1, argv+1);
 
1385
            argc -= 2; argv += 2;
 
1386
        }
 
1387
        else if (!strcmp(firstarg->s_name, "-y") && argc > 1)
 
1388
        {
 
1389
            fielddesc_setfloatarg(&x->x_ypoints, 1, argv+1);
 
1390
            argc -= 2; argv += 2;
 
1391
        }
 
1392
        else if (!strcmp(firstarg->s_name, "-w") && argc > 1)
 
1393
        {
 
1394
            fielddesc_setfloatarg(&x->x_wpoints, 1, argv+1);
 
1395
            argc -= 2; argv += 2;
 
1396
        }
 
1397
        else break;
 
1398
    }
 
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);
 
1413
    return (x);
 
1414
}
 
1415
 
 
1416
void plot_float(t_plot *x, t_floatarg f)
 
1417
{
 
1418
    int viswas;
 
1419
    if (x->x_vis.fd_type != A_FLOAT || x->x_vis.fd_var)
 
1420
    {
 
1421
        pd_error(x, "global vis/invis for a template with variable visibility");
 
1422
        return;
 
1423
    }
 
1424
    viswas = (x->x_vis.fd_un.fd_float != 0);
 
1425
    
 
1426
    if ((f != 0 && viswas) || (f == 0 && !viswas))
 
1427
        return;
 
1428
    canvas_redrawallfortemplatecanvas(x->x_canvas, 2);
 
1429
    fielddesc_setfloat_const(&x->x_vis, (f != 0));
 
1430
    canvas_redrawallfortemplatecanvas(x->x_canvas, 1);
 
1431
}
 
1432
 
 
1433
/* -------------------- widget behavior for plot ------------ */
 
1434
 
 
1435
 
 
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)
 
1444
{
 
1445
    int arrayonset, type;
 
1446
    t_symbol *elemtemplatesym;
 
1447
    t_array *array;
 
1448
 
 
1449
        /* find the data and verify it's an array */
 
1450
    if (x->x_data.fd_type != A_ARRAY || !x->x_data.fd_var)
 
1451
    {
 
1452
        error("plot: needs an array field");
 
1453
        return (-1);
 
1454
    }
 
1455
    if (!template_find_field(ownertemplate, x->x_data.fd_un.fd_varsym,
 
1456
        &arrayonset, &type, &elemtemplatesym))
 
1457
    {
 
1458
        error("plot: %s: no such field", x->x_data.fd_un.fd_varsym->s_name);
 
1459
        return (-1);
 
1460
    }
 
1461
    if (type != DT_ARRAY)
 
1462
    {
 
1463
        error("plot: %s: not an array", x->x_data.fd_un.fd_varsym->s_name);
 
1464
        return (-1);
 
1465
    }
 
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;
 
1475
    *arrayp = array;
 
1476
    *xfield = &x->x_xpoints;
 
1477
    *yfield = &x->x_ypoints;
 
1478
    *wfield = &x->x_wpoints;
 
1479
    return (0);
 
1480
}
 
1481
 
 
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)
 
1489
{
 
1490
    int arrayonset, elemsize, yonset, wonset, xonset, type;
 
1491
    t_template *elemtemplate;
 
1492
    t_symbol *dummy, *varname;
 
1493
    t_canvas *elemtemplatecanvas = 0;
 
1494
 
 
1495
        /* the "float" template is special in not having to have a canvas;
 
1496
        template_findbyname is hardwired to return a predefined 
 
1497
        template. */
 
1498
 
 
1499
    if (!(elemtemplate =  template_findbyname(elemtemplatesym)))
 
1500
    {
 
1501
        error("plot: %s: no such template", elemtemplatesym->s_name);
 
1502
        return (-1);
 
1503
    }
 
1504
    if (!((elemtemplatesym == &s_float) ||
 
1505
        (elemtemplatecanvas = template_findcanvas(elemtemplate))))
 
1506
    {
 
1507
        error("plot: %s: no canvas for this template", elemtemplatesym->s_name);
 
1508
        return (-1);
 
1509
    }
 
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)    
 
1516
            yonset = -1;
 
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) 
 
1522
            xonset = -1;
 
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) 
 
1528
            wonset = -1;
 
1529
 
 
1530
        /* fill in slots for return values */
 
1531
    *elemtemplatecanvasp = elemtemplatecanvas;
 
1532
    *elemtemplatep = elemtemplate;
 
1533
    *elemsizep = elemsize;
 
1534
    *xonsetp = xonset;
 
1535
    *yonsetp = yonset;
 
1536
    *wonsetp = wonset;
 
1537
    return (0);
 
1538
}
 
1539
 
 
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)
 
1543
{
 
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;
 
1550
    t_array *array;
 
1551
    int x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
 
1552
    int i;
 
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) &&
 
1558
                (vis != 0) &&
 
1559
            !array_getfields(elemtemplatesym, &elemtemplatecanvas,
 
1560
                &elemtemplate, &elemsize, 
 
1561
                xfielddesc, yfielddesc, wfielddesc,
 
1562
                &xonset, &yonset, &wonset))
 
1563
    {
 
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)
 
1567
        {
 
1568
            t_float usexloc, useyloc;
 
1569
            t_gobj *y;
 
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);
 
1574
            if (xpix < x1)
 
1575
                x1 = xpix;
 
1576
            if (xpix > x2)
 
1577
                x2 = xpix;
 
1578
            if (ypix - wpix < y1)
 
1579
                y1 = ypix - wpix;
 
1580
            if (ypix + wpix > y2)
 
1581
                y2 = ypix + wpix;
 
1582
            
 
1583
            if (scalarvis != 0)
 
1584
            {
 
1585
                    /* check also the drawing instructions for the scalar */ 
 
1586
                if (xonset >= 0)
 
1587
                    usexloc = basex + xloc + fielddesc_cvttocoord(xfielddesc, 
 
1588
                        *(t_float *)(((char *)(array->a_vec) + elemsize * i)
 
1589
                            + xonset));
 
1590
                else usexloc = basex + xsum, xsum += xinc;
 
1591
                if (yonset >= 0)
 
1592
                    yval = *(t_float *)(((char *)(array->a_vec) + elemsize * i)
 
1593
                        + yonset);
 
1594
                else yval = 0;
 
1595
                useyloc = basey + yloc + fielddesc_cvttocoord(yfielddesc, yval);
 
1596
                for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
 
1597
                {
 
1598
                    int xx1, xx2, yy1, yy2;
 
1599
                    t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
 
1600
                    if (!wb) continue;
 
1601
                    (*wb->w_parentgetrectfn)(y, glist,
 
1602
                        (t_word *)((char *)(array->a_vec) + elemsize * i),
 
1603
                            elemtemplate, usexloc, useyloc, 
 
1604
                                &xx1, &yy1, &xx2, &yy2);
 
1605
                    if (xx1 < x1)
 
1606
                        x1 = xx1;
 
1607
                    if (yy1 < y1)
 
1608
                        y1 = yy1;
 
1609
                     if (xx2 > x2)
 
1610
                        x2 = xx2;
 
1611
                    if (yy2 > y2)
 
1612
                        y2 = yy2;   
 
1613
                }
 
1614
            }
 
1615
        }
 
1616
    }
 
1617
 
 
1618
    *xp1 = x1;
 
1619
    *yp1 = y1;
 
1620
    *xp2 = x2;
 
1621
    *yp2 = y2;
 
1622
}
 
1623
 
 
1624
static void plot_displace(t_gobj *z, t_glist *glist,
 
1625
    t_word *data, t_template *template, t_float basex, t_float basey,
 
1626
    int dx, int dy)
 
1627
{
 
1628
        /* not yet */
 
1629
}
 
1630
 
 
1631
static void plot_select(t_gobj *z, t_glist *glist,
 
1632
    t_word *data, t_template *template, t_float basex, t_float basey,
 
1633
    int state)
 
1634
{
 
1635
    /* not yet */
 
1636
}
 
1637
 
 
1638
static void plot_activate(t_gobj *z, t_glist *glist,
 
1639
    t_word *data, t_template *template, t_float basex, t_float basey,
 
1640
    int state)
 
1641
{
 
1642
        /* not yet */
 
1643
}
 
1644
 
 
1645
static void plot_vis(t_gobj *z, t_glist *glist, 
 
1646
    t_word *data, t_template *template, t_float basex, t_float basey,
 
1647
    int tovis)
 
1648
{
 
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,
 
1655
        scalarvis;
 
1656
    t_array *array;
 
1657
    int nelem;
 
1658
    char *elem;
 
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. */
 
1668
        
 
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))
 
1676
                    return;
 
1677
    nelem = array->a_n;
 
1678
    elem = (char *)array->a_vec;
 
1679
 
 
1680
    if (tovis)
 
1681
    {
 
1682
        if (style == PLOTSTYLE_POINTS)
 
1683
        {
 
1684
            t_float minyval = 1e20, maxyval = -1e20;
 
1685
            int ndrawn = 0;
 
1686
            for (xsum = basex + xloc, i = 0; i < nelem; i++)
 
1687
            {
 
1688
                t_float yval, xpix, ypix, nextxloc;
 
1689
                int ixpix, inextx;
 
1690
 
 
1691
                if (xonset >= 0)
 
1692
                {
 
1693
                    usexloc = basex + xloc +
 
1694
                        *(t_float *)((elem + elemsize * i) + xonset);
 
1695
                    ixpix = glist_xtopixels(glist, 
 
1696
                        fielddesc_cvttocoord(xfielddesc, usexloc));
 
1697
                    inextx = ixpix + 2;
 
1698
                }
 
1699
                else
 
1700
                {
 
1701
                    usexloc = xsum;
 
1702
                    xsum += xinc;
 
1703
                    ixpix = glist_xtopixels(glist,
 
1704
                        fielddesc_cvttocoord(xfielddesc, usexloc));
 
1705
                    inextx = glist_xtopixels(glist,
 
1706
                        fielddesc_cvttocoord(xfielddesc, xsum));
 
1707
                }
 
1708
 
 
1709
                if (yonset >= 0)
 
1710
                    yval = yloc + *(t_float *)((elem + elemsize * i) + yonset);
 
1711
                else yval = 0;
 
1712
                if (yval > maxyval)
 
1713
                    maxyval = yval;
 
1714
                if (yval < minyval)
 
1715
                    minyval = yval;
 
1716
                if (i == nelem-1 || inextx != ixpix)
 
1717
                {
 
1718
                    sys_vgui(
 
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);
 
1726
                    ndrawn++;
 
1727
                    minyval = 1e20;
 
1728
                    maxyval = -1e20;
 
1729
                }
 
1730
                if (ndrawn > 2000 || ixpix >= 3000) break;
 
1731
            }
 
1732
        }
 
1733
        else
 
1734
        {
 
1735
            char outline[20];
 
1736
            int lastpixel = -1, ndrawn = 0;
 
1737
            t_float yval = 0, wval = 0, xpix;
 
1738
            int ixpix = 0;
 
1739
                /* draw the trace */
 
1740
            numbertocolor(fielddesc_getfloat(&x->x_outlinecolor, template,
 
1741
                data, 1), outline);
 
1742
            if (wonset >= 0)
 
1743
            {
 
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));
 
1748
 
 
1749
                for (i = 0, xsum = xloc; i < nelem; i++)
 
1750
                {
 
1751
                    if (xonset >= 0)
 
1752
                        usexloc = xloc + *(t_float *)((elem + elemsize * i)
 
1753
                            + xonset);
 
1754
                    else usexloc = xsum, xsum += xinc;
 
1755
                    if (yonset >= 0)
 
1756
                        yval = *(t_float *)((elem + elemsize * i) + yonset);
 
1757
                    else yval = 0;
 
1758
                    wval = *(t_float *)((elem + elemsize * i) + wonset);
 
1759
                    xpix = glist_xtopixels(glist,
 
1760
                        basex + fielddesc_cvttocoord(xfielddesc, usexloc));
 
1761
                    ixpix = xpix + 0.5;
 
1762
                    if (xonset >= 0 || ixpix != lastpixel)
 
1763
                    {
 
1764
                        sys_vgui("%d %f \\\n", ixpix,
 
1765
                            glist_ytopixels(glist,
 
1766
                                basey + fielddesc_cvttocoord(yfielddesc, 
 
1767
                                    yloc + yval) -
 
1768
                                        fielddesc_cvttocoord(wfielddesc,wval)));
 
1769
                        ndrawn++;
 
1770
                    }
 
1771
                    lastpixel = ixpix;
 
1772
                    if (ndrawn >= 1000) goto ouch;
 
1773
                }
 
1774
                lastpixel = -1;
 
1775
                for (i = nelem-1; i >= 0; i--)
 
1776
                {
 
1777
                    t_float usexloc;
 
1778
                    if (xonset >= 0)
 
1779
                        usexloc = xloc + *(t_float *)((elem + elemsize * i)
 
1780
                            + xonset);
 
1781
                    else xsum -= xinc, usexloc = xsum;
 
1782
                    if (yonset >= 0)
 
1783
                        yval = *(t_float *)((elem + elemsize * i) + yonset);
 
1784
                    else yval = 0;
 
1785
                    wval = *(t_float *)((elem + elemsize * i) + wonset);
 
1786
                    xpix = glist_xtopixels(glist,
 
1787
                        basex + fielddesc_cvttocoord(xfielddesc, usexloc));
 
1788
                    ixpix = xpix + 0.5;
 
1789
                    if (xonset >= 0 || ixpix != lastpixel)
 
1790
                    {
 
1791
                        sys_vgui("%d %f \\\n", ixpix, glist_ytopixels(glist,
 
1792
                            basey + yloc + fielddesc_cvttocoord(yfielddesc,
 
1793
                                yval) +
 
1794
                                    fielddesc_cvttocoord(wfielddesc, wval)));
 
1795
                        ndrawn++;
 
1796
                    }
 
1797
                    lastpixel = ixpix;
 
1798
                    if (ndrawn >= 1000) goto ouch;
 
1799
                }
 
1800
                    /* TK will complain if there aren't at least 3 points.
 
1801
                    There should be at least two already. */
 
1802
                if (ndrawn < 4)
 
1803
                {
 
1804
                    sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
 
1805
                        basey + yloc + fielddesc_cvttocoord(yfielddesc,
 
1806
                            yval) +
 
1807
                                fielddesc_cvttocoord(wfielddesc, wval)));
 
1808
                    sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
 
1809
                        basey + yloc + fielddesc_cvttocoord(yfielddesc,
 
1810
                            yval) -
 
1811
                                fielddesc_cvttocoord(wfielddesc, wval)));
 
1812
                }
 
1813
            ouch:
 
1814
                sys_vgui(" -width 1 -fill %s -outline %s\\\n",
 
1815
                    outline, outline);
 
1816
                if (style == PLOTSTYLE_BEZ) sys_vgui("-smooth 1\\\n");
 
1817
 
 
1818
                sys_vgui("-tags plot%lx\n", data);
 
1819
            }
 
1820
            else if (linewidth > 0)
 
1821
            {
 
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));
 
1826
 
 
1827
                for (xsum = xloc, i = 0; i < nelem; i++)
 
1828
                {
 
1829
                    t_float usexloc;
 
1830
                    if (xonset >= 0)
 
1831
                        usexloc = xloc + *(t_float *)((elem + elemsize * i) +
 
1832
                            xonset);
 
1833
                    else usexloc = xsum, xsum += xinc;
 
1834
                    if (yonset >= 0)
 
1835
                        yval = *(t_float *)((elem + elemsize * i) + yonset);
 
1836
                    else yval = 0;
 
1837
                    xpix = glist_xtopixels(glist,
 
1838
                        basex + fielddesc_cvttocoord(xfielddesc, usexloc));
 
1839
                    ixpix = xpix + 0.5;
 
1840
                    if (xonset >= 0 || ixpix != lastpixel)
 
1841
                    {
 
1842
                        sys_vgui("%d %f \\\n", ixpix,
 
1843
                            glist_ytopixels(glist,
 
1844
                                basey + yloc + fielddesc_cvttocoord(yfielddesc,
 
1845
                                    yval)));
 
1846
                        ndrawn++;
 
1847
                    }
 
1848
                    lastpixel = ixpix;
 
1849
                    if (ndrawn >= 1000) break;
 
1850
                }
 
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)));
 
1856
 
 
1857
                sys_vgui("-width %f\\\n", linewidth);
 
1858
                sys_vgui("-fill %s\\\n", outline);
 
1859
                if (style == PLOTSTYLE_BEZ) sys_vgui("-smooth 1\\\n");
 
1860
 
 
1861
                sys_vgui("-tags plot%lx\n", data);
 
1862
            }
 
1863
        }
 
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. */
 
1867
        if (scalarvis != 0)
 
1868
        {
 
1869
            for (xsum = xloc, i = 0; i < nelem; i++)
 
1870
            {
 
1871
                t_float usexloc, useyloc;
 
1872
                t_gobj *y;
 
1873
                if (xonset >= 0)
 
1874
                    usexloc = basex + xloc +
 
1875
                        *(t_float *)((elem + elemsize * i) + xonset);
 
1876
                else usexloc = basex + xsum, xsum += xinc;
 
1877
                if (yonset >= 0)
 
1878
                    yval = *(t_float *)((elem + elemsize * i) + yonset);
 
1879
                else yval = 0;
 
1880
                useyloc = basey + yloc +
 
1881
                    fielddesc_cvttocoord(yfielddesc, yval);
 
1882
                for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
 
1883
                {
 
1884
                    t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
 
1885
                    if (!wb) continue;
 
1886
                    (*wb->w_parentvisfn)(y, glist,
 
1887
                        (t_word *)(elem + elemsize * i),
 
1888
                            elemtemplate, usexloc, useyloc, tovis);
 
1889
                }
 
1890
            }
 
1891
        }
 
1892
    }
 
1893
    else
 
1894
    {
 
1895
            /* un-draw the individual points */
 
1896
        if (scalarvis != 0)
 
1897
        {
 
1898
            int i;
 
1899
            for (i = 0; i < nelem; i++)
 
1900
            {
 
1901
                t_gobj *y;
 
1902
                for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
 
1903
                {
 
1904
                    t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
 
1905
                    if (!wb) continue;
 
1906
                    (*wb->w_parentvisfn)(y, glist,
 
1907
                        (t_word *)(elem + elemsize * i), elemtemplate,
 
1908
                            0, 0, 0);
 
1909
                }
 
1910
            }
 
1911
        }
 
1912
            /* and then the trace */
 
1913
        sys_vgui(".x%lx.c delete plot%lx\n",
 
1914
            glist_getcanvas(glist), data);      
 
1915
    }
 
1916
}
 
1917
 
 
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)
 
1922
{
 
1923
    t_plot *x = (t_plot *)z;
 
1924
    t_symbol *elemtemplatesym;
 
1925
    t_float linewidth, xloc, xinc, yloc, style, vis, scalarvis;
 
1926
    t_array *array;
 
1927
    t_fielddesc *xfielddesc, *yfielddesc, *wfielddesc;
 
1928
 
 
1929
    if (!plot_readownertemplate(x, data, template, 
 
1930
        &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc, &style,
 
1931
        &vis, &scalarvis,
 
1932
        &xfielddesc, &yfielddesc, &wfielddesc) && (vis != 0))
 
1933
    {
 
1934
        return (array_doclick(array, glist, sc, ap,
 
1935
            elemtemplatesym,
 
1936
            linewidth, basex + xloc, xinc, basey + yloc, scalarvis,
 
1937
            xfielddesc, yfielddesc, wfielddesc,
 
1938
            xpix, ypix, shift, alt, dbl, doit));
 
1939
    }
 
1940
    else return (0);
 
1941
}
 
1942
 
 
1943
t_parentwidgetbehavior plot_widgetbehavior =
 
1944
{
 
1945
    plot_getrect,
 
1946
    plot_displace,
 
1947
    plot_select,
 
1948
    plot_activate,
 
1949
    plot_vis,
 
1950
    plot_click,
 
1951
};
 
1952
 
 
1953
static void plot_setup(void)
 
1954
{
 
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);
 
1960
}
 
1961
 
 
1962
/* ---------------- drawnumber: draw a number (or symbol) ---------------- */
 
1963
 
 
1964
/*
 
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
 
1968
*/
 
1969
 
 
1970
t_class *drawnumber_class;
 
1971
 
 
1972
#define DRAW_SYMBOL 1
 
1973
 
 
1974
typedef struct _drawnumber
 
1975
{
 
1976
    t_object x_obj;
 
1977
    t_fielddesc x_value;
 
1978
    t_fielddesc x_xloc;
 
1979
    t_fielddesc x_yloc;
 
1980
    t_fielddesc x_color;
 
1981
    t_fielddesc x_vis;
 
1982
    t_symbol *x_label;
 
1983
    int x_flags;
 
1984
    t_canvas *x_canvas;
 
1985
} t_drawnumber;
 
1986
 
 
1987
static void *drawnumber_new(t_symbol *classsym, t_int argc, t_atom *argv)
 
1988
{
 
1989
    t_drawnumber *x = (t_drawnumber *)pd_new(drawnumber_class);
 
1990
    char *classname = classsym->s_name;
 
1991
    int flags = 0;
 
1992
    
 
1993
    if (classname[4] == 's')
 
1994
        flags |= DRAW_SYMBOL;
 
1995
    x->x_flags = flags;
 
1996
    fielddesc_setfloat_const(&x->x_vis, 1);
 
1997
    x->x_canvas = canvas_getcurrent();
 
1998
    while (1)
 
1999
    {
 
2000
        t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
 
2001
        if (!strcmp(firstarg->s_name, "-v") && argc > 1)
 
2002
        {
 
2003
            fielddesc_setfloatarg(&x->x_vis, 1, argv+1);
 
2004
            argc -= 2; argv += 2;
 
2005
        }
 
2006
        else break;
 
2007
    }
 
2008
    if (flags & DRAW_SYMBOL)
 
2009
    {
 
2010
        if (argc) fielddesc_setsymbolarg(&x->x_value, argc--, argv++);
 
2011
        else fielddesc_setsymbol_const(&x->x_value, &s_);
 
2012
    }
 
2013
    else
 
2014
    {
 
2015
        if (argc) fielddesc_setfloatarg(&x->x_value, argc--, argv++);
 
2016
        else fielddesc_setfloat_const(&x->x_value, 0);
 
2017
    }
 
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);
 
2024
    if (argc)
 
2025
        x->x_label = atom_getsymbolarg(0, argc, argv);
 
2026
    else x->x_label = &s_;
 
2027
 
 
2028
    return (x);
 
2029
}
 
2030
 
 
2031
void drawnumber_float(t_drawnumber *x, t_floatarg f)
 
2032
{
 
2033
    int viswas;
 
2034
    if (x->x_vis.fd_type != A_FLOAT || x->x_vis.fd_var)
 
2035
    {
 
2036
        pd_error(x, "global vis/invis for a template with variable visibility");
 
2037
        return;
 
2038
    }
 
2039
    viswas = (x->x_vis.fd_un.fd_float != 0);
 
2040
    
 
2041
    if ((f != 0 && viswas) || (f == 0 && !viswas))
 
2042
        return;
 
2043
    canvas_redrawallfortemplatecanvas(x->x_canvas, 2);
 
2044
    fielddesc_setfloat_const(&x->x_vis, (f != 0));
 
2045
    canvas_redrawallfortemplatecanvas(x->x_canvas, 1);
 
2046
}
 
2047
 
 
2048
/* -------------------- widget behavior for drawnumber ------------ */
 
2049
 
 
2050
#define DRAWNUMBER_BUFSIZE 80
 
2051
static void drawnumber_sprintf(t_drawnumber *x, char *buf, t_atom *ap)
 
2052
{
 
2053
    int nchars;
 
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);
 
2058
}
 
2059
 
 
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)
 
2063
{
 
2064
    t_drawnumber *x = (t_drawnumber *)z;
 
2065
    t_atom at;
 
2066
        int xloc, yloc, font, fontwidth, fontheight;
 
2067
    char buf[DRAWNUMBER_BUFSIZE];
 
2068
 
 
2069
    if (!fielddesc_getfloat(&x->x_vis, template, data, 0))
 
2070
    {
 
2071
        *xp1 = *yp1 = 0x7fffffff;
 
2072
        *xp2 = *yp2 = -0x7fffffff;
 
2073
        return;
 
2074
    }
 
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);
 
2086
    *xp1 = xloc;
 
2087
    *yp1 = yloc;
 
2088
    *xp2 = xloc + fontwidth * strlen(buf);
 
2089
    *yp2 = yloc + fontheight;
 
2090
}
 
2091
 
 
2092
static void drawnumber_displace(t_gobj *z, t_glist *glist,
 
2093
    t_word *data, t_template *template, t_float basex, t_float basey,
 
2094
    int dx, int dy)
 
2095
{
 
2096
    /* refuse */
 
2097
}
 
2098
 
 
2099
static void drawnumber_select(t_gobj *z, t_glist *glist,
 
2100
    t_word *data, t_template *template, t_float basex, t_float basey,
 
2101
    int state)
 
2102
{
 
2103
    post("drawnumber_select %d", state);
 
2104
    /* fill in later */
 
2105
}
 
2106
 
 
2107
static void drawnumber_activate(t_gobj *z, t_glist *glist,
 
2108
    t_word *data, t_template *template, t_float basex, t_float basey,
 
2109
    int state)
 
2110
{
 
2111
    post("drawnumber_activate %d", state);
 
2112
}
 
2113
 
 
2114
static void drawnumber_vis(t_gobj *z, t_glist *glist, 
 
2115
    t_word *data, t_template *template, t_float basex, t_float basey,
 
2116
    int vis)
 
2117
{
 
2118
    t_drawnumber *x = (t_drawnumber *)z;
 
2119
    
 
2120
        /* see comment in plot_vis() */
 
2121
    if (vis && !fielddesc_getfloat(&x->x_vis, template, data, 0))
 
2122
        return;
 
2123
    if (vis)
 
2124
    {
 
2125
        t_atom at;
 
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),
 
2132
            colorstring);
 
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);
 
2142
    }
 
2143
    else sys_vgui(".x%lx.c delete drawnumber%lx\n", glist_getcanvas(glist), data);
 
2144
}
 
2145
 
 
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;
 
2155
 
 
2156
    /* LATER protect against the template changing or the scalar disappearing
 
2157
    probably by attaching a gpointer here ... */
 
2158
 
 
2159
static void drawnumber_motion(void *z, t_floatarg dx, t_floatarg dy)
 
2160
{
 
2161
    t_drawnumber *x = (t_drawnumber *)z;
 
2162
    t_fielddesc *f = &x->x_value;
 
2163
    t_atom at;
 
2164
    if (!gpointer_check(&drawnumber_motion_gpointer, 0))
 
2165
    {
 
2166
        post("drawnumber_motion: scalar disappeared");
 
2167
        return;
 
2168
    }
 
2169
    if (drawnumber_motion_symbol)
 
2170
    {
 
2171
        post("drawnumber_motion: symbol");
 
2172
        return;
 
2173
    }
 
2174
    drawnumber_motion_ycumulative -= dy;
 
2175
    template_setfloat(drawnumber_motion_template,
 
2176
        f->fd_un.fd_varsym,
 
2177
            drawnumber_motion_wp, 
 
2178
            drawnumber_motion_ycumulative,
 
2179
                1);
 
2180
    if (drawnumber_motion_scalar)
 
2181
        template_notifyforscalar(drawnumber_motion_template,
 
2182
            drawnumber_motion_glist, drawnumber_motion_scalar,
 
2183
                gensym("change"), 1, &at);
 
2184
 
 
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);
 
2189
}
 
2190
 
 
2191
static void drawnumber_key(void *z, t_floatarg fkey)
 
2192
{
 
2193
    t_drawnumber *x = (t_drawnumber *)z;
 
2194
    t_fielddesc *f = &x->x_value;
 
2195
    int key = fkey;
 
2196
    char sbuf[MAXPDSTRING];
 
2197
    t_atom at;
 
2198
    if (!gpointer_check(&drawnumber_motion_gpointer, 0))
 
2199
    {
 
2200
        post("drawnumber_motion: scalar disappeared");
 
2201
        return;
 
2202
    }
 
2203
    if (key == 0)
 
2204
        return;
 
2205
    if (drawnumber_motion_symbol)
 
2206
    {
 
2207
            /* key entry for a symbol field */
 
2208
        if (drawnumber_motion_firstkey)
 
2209
            sbuf[0] = 0;
 
2210
        else strncpy(sbuf, template_getsymbol(drawnumber_motion_template,
 
2211
            f->fd_un.fd_varsym, drawnumber_motion_wp, 1)->s_name,
 
2212
                MAXPDSTRING);
 
2213
        sbuf[MAXPDSTRING-1] = 0;
 
2214
        if (key == '\b')
 
2215
        {
 
2216
            if (*sbuf)
 
2217
                sbuf[strlen(sbuf)-1] = 0;
 
2218
        }
 
2219
        else
 
2220
        {
 
2221
            sbuf[strlen(sbuf)+1] = 0;
 
2222
            sbuf[strlen(sbuf)] = key;
 
2223
        }
 
2224
    }
 
2225
    else
 
2226
    {
 
2227
            /* key entry for a numeric field.  This is just a stopgap. */
 
2228
        float newf;
 
2229
        if (drawnumber_motion_firstkey)
 
2230
            sbuf[0] = 0;
 
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');
 
2234
        if (key == '\b')
 
2235
        {
 
2236
            if (*sbuf)
 
2237
                sbuf[strlen(sbuf)-1] = 0;
 
2238
        }
 
2239
        else
 
2240
        {
 
2241
            sbuf[strlen(sbuf)+1] = 0;
 
2242
            sbuf[strlen(sbuf)] = key;
 
2243
        }
 
2244
        if (sscanf(sbuf, "%g", &newf) < 1)
 
2245
            newf = 0;
 
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);
 
2256
    }
 
2257
}
 
2258
 
 
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)
 
2263
{
 
2264
    t_drawnumber *x = (t_drawnumber *)z;
 
2265
    int x1, y1, x2, y2;
 
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))
 
2272
    {
 
2273
        if (doit)
 
2274
        {
 
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,
 
2290
                xpix, ypix);
 
2291
        }
 
2292
        return (1);
 
2293
    }
 
2294
    else return (0);
 
2295
}
 
2296
 
 
2297
t_parentwidgetbehavior drawnumber_widgetbehavior =
 
2298
{
 
2299
    drawnumber_getrect,
 
2300
    drawnumber_displace,
 
2301
    drawnumber_select,
 
2302
    drawnumber_activate,
 
2303
    drawnumber_vis,
 
2304
    drawnumber_click,
 
2305
};
 
2306
 
 
2307
static void drawnumber_free(t_drawnumber *x)
 
2308
{
 
2309
}
 
2310
 
 
2311
static void drawnumber_setup(void)
 
2312
{
 
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"),
 
2319
        A_GIMME, 0);
 
2320
    class_setparentwidget(drawnumber_class, &drawnumber_widgetbehavior);
 
2321
}
 
2322
 
 
2323
/* ---------------------- setup function ---------------------------- */
 
2324
 
 
2325
void g_template_setup(void)
 
2326
{
 
2327
    template_setup();
 
2328
    gtemplate_setup();
 
2329
    curve_setup();
 
2330
    plot_setup();
 
2331
    drawnumber_setup();
 
2332
}
 
2333