Fix pdbox makefile to actually take part in dependency generation
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / g_template.c
blobe73ca3ef5ae169abdeaf5756db6bfc62c9eb91c7
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. */
5 #ifdef ROCKBOX
6 #include "plugin.h"
7 #include "../../pdbox.h"
8 #include "m_pd.h"
9 #include "s_stuff.h"
10 #include "g_canvas.h"
11 #define snprintf rb->snprintf
12 #else /* ROCKBOX */
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdio.h>
17 #include "m_pd.h"
18 #include "s_stuff.h" /* for sys_hostfontsize */
19 #include "g_canvas.h"
20 #endif /* ROCKBOX */
23 This file contains text objects you would put in a canvas to define a
24 template. Templates describe objects of type "array" (g_array.c) and
25 "scalar" (g_scalar.c).
28 /* T.Grill - changed the _template.t_pd member to t_pdobj to avoid name clashes
29 with the t_pd type */
31 /* the structure of a "struct" object (also the obsolete "gtemplate"
32 you get when using the name "template" in a box.) */
34 struct _gtemplate
36 t_object x_obj;
37 t_template *x_template;
38 t_canvas *x_owner;
39 t_symbol *x_sym;
40 struct _gtemplate *x_next;
41 int x_argc;
42 t_atom *x_argv;
45 /* ---------------- forward definitions ---------------- */
47 static void template_conformarray(t_template *tfrom, t_template *tto,
48 int *conformaction, t_array *a);
49 static void template_conformglist(t_template *tfrom, t_template *tto,
50 t_glist *glist, int *conformaction);
52 /* ---------------------- storage ------------------------- */
54 static t_class *gtemplate_class;
55 static t_class *template_class;
57 /* there's a pre-defined "float" template. LATER should we bind this
58 to a symbol such as "pd-float"??? */
60 static t_dataslot template_float_vec =
62 DT_FLOAT,
63 &s_y,
64 &s_
67 static t_template template_float =
69 0, /* class -- fill in in setup routine */
70 0, /* list of "struct"/t_gtemplate objects */
71 &s_float, /* name */
72 1, /* number of items */
73 &template_float_vec
76 /* return true if two dataslot definitions match */
77 static int dataslot_matches(t_dataslot *ds1, t_dataslot *ds2,
78 int nametoo)
80 return ((!nametoo || ds1->ds_name == ds2->ds_name) &&
81 ds1->ds_type == ds2->ds_type &&
82 (ds1->ds_type != DT_ARRAY ||
83 ds1->ds_arraytemplate == ds2->ds_arraytemplate));
86 /* -- templates, the active ingredient in gtemplates defined below. ------- */
88 t_template *template_new(t_symbol *templatesym, int argc, t_atom *argv)
90 t_template *x = (t_template *)pd_new(template_class);
91 x->t_n = 0;
92 x->t_vec = (t_dataslot *)t_getbytes(0);
93 while (argc > 0)
95 int newtype, oldn, newn;
96 t_symbol *newname, *newarraytemplate = &s_, *newtypesym;
97 if (argc < 2 || argv[0].a_type != A_SYMBOL ||
98 argv[1].a_type != A_SYMBOL)
99 goto bad;
100 newtypesym = argv[0].a_w.w_symbol;
101 newname = argv[1].a_w.w_symbol;
102 if (newtypesym == &s_float)
103 newtype = DT_FLOAT;
104 else if (newtypesym == &s_symbol)
105 newtype = DT_SYMBOL;
106 else if (newtypesym == &s_list)
107 newtype = DT_LIST;
108 else if (newtypesym == gensym("array"))
110 if (argc < 3 || argv[2].a_type != A_SYMBOL)
112 pd_error(x, "array lacks element template or name");
113 goto bad;
115 newarraytemplate = canvas_makebindsym(argv[2].a_w.w_symbol);
116 newtype = DT_ARRAY;
117 argc--;
118 argv++;
120 else
122 pd_error(x, "%s: no such type", newtypesym->s_name);
123 return (0);
125 newn = (oldn = x->t_n) + 1;
126 x->t_vec = (t_dataslot *)t_resizebytes(x->t_vec,
127 oldn * sizeof(*x->t_vec), newn * sizeof(*x->t_vec));
128 x->t_n = newn;
129 x->t_vec[oldn].ds_type = newtype;
130 x->t_vec[oldn].ds_name = newname;
131 x->t_vec[oldn].ds_arraytemplate = newarraytemplate;
132 bad:
133 argc -= 2; argv += 2;
135 if (templatesym->s_name)
137 x->t_sym = templatesym;
138 pd_bind(&x->t_pdobj, x->t_sym);
140 else x->t_sym = templatesym;
141 return (x);
144 int template_size(t_template *x)
146 return (x->t_n * sizeof(t_word));
149 int template_find_field(t_template *x, t_symbol *name, int *p_onset,
150 int *p_type, t_symbol **p_arraytype)
152 #ifndef ROCKBOX
153 t_template *t;
154 #endif
155 int i, n;
156 if (!x)
158 bug("template_find_field");
159 return (0);
161 n = x->t_n;
162 for (i = 0; i < n; i++)
163 if (x->t_vec[i].ds_name == name)
165 *p_onset = i * sizeof(t_word);
166 *p_type = x->t_vec[i].ds_type;
167 *p_arraytype = x->t_vec[i].ds_arraytemplate;
168 return (1);
170 return (0);
173 t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp,
174 int loud)
176 int onset, type;
177 t_symbol *arraytype;
178 t_sample val = 0;
179 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
181 if (type == DT_FLOAT)
182 val = *(t_sample *)(((char *)wp) + onset);
183 else if (loud) error("%s.%s: not a number",
184 x->t_sym->s_name, fieldname->s_name);
186 else if (loud) error("%s.%s: no such field",
187 x->t_sym->s_name, fieldname->s_name);
188 return (fixtof(val));
191 void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp,
192 t_float f, int loud)
194 int onset, type;
195 t_symbol *arraytype;
196 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
198 if (type == DT_FLOAT)
199 *(t_sample *)(((char *)wp) + onset) = ftofix(f);
200 else if (loud) error("%s.%s: not a number",
201 x->t_sym->s_name, fieldname->s_name);
203 else if (loud) error("%s.%s: no such field",
204 x->t_sym->s_name, fieldname->s_name);
207 t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp,
208 int loud)
210 int onset, type;
211 t_symbol *arraytype;
212 t_symbol *val = &s_;
213 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
215 if (type == DT_SYMBOL)
216 val = *(t_symbol **)(((char *)wp) + onset);
217 else if (loud) error("%s.%s: not a symbol",
218 x->t_sym->s_name, fieldname->s_name);
220 else if (loud) error("%s.%s: no such field",
221 x->t_sym->s_name, fieldname->s_name);
222 return (val);
225 void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp,
226 t_symbol *s, int loud)
228 int onset, type;
229 t_symbol *arraytype;
230 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
232 if (type == DT_SYMBOL)
233 *(t_symbol **)(((char *)wp) + onset) = s;
234 else if (loud) error("%s.%s: not a symbol",
235 x->t_sym->s_name, fieldname->s_name);
237 else if (loud) error("%s.%s: no such field",
238 x->t_sym->s_name, fieldname->s_name);
241 /* stringent check to see if a "saved" template, x2, matches the current
242 one (x1). It's OK if x1 has additional scalar elements but not (yet)
243 arrays or lists. This is used for reading in "data files". */
244 int template_match(t_template *x1, t_template *x2)
246 int i;
247 if (x1->t_n < x2->t_n)
248 return (0);
249 for (i = x2->t_n; i < x1->t_n; i++)
251 if (x1->t_vec[i].ds_type == DT_ARRAY ||
252 x1->t_vec[i].ds_type == DT_LIST)
253 return (0);
255 if (x2->t_n > x1->t_n)
256 post("add elements...");
257 for (i = 0; i < x2->t_n; i++)
258 if (!dataslot_matches(&x1->t_vec[i], &x2->t_vec[i], 1))
259 return (0);
260 return (1);
263 /* --------------- CONFORMING TO CHANGES IN A TEMPLATE ------------ */
265 /* the following routines handle updating scalars to agree with changes
266 in their template. The old template is assumed to be the "installed" one
267 so we can delete old items; but making new ones we have to avoid scalar_new
268 which would make an old one whereas we will want a new one (but whose array
269 elements might still be old ones.
270 LATER deal with graphics updates too... */
272 /* conform the word vector of a scalar to the new template */
273 static void template_conformwords(t_template *tfrom, t_template *tto,
274 int *conformaction, t_word *wfrom, t_word *wto)
276 #ifdef ROCKBOX
277 int nto = tto->t_n, i;
279 (void) tfrom;
280 #else
281 int nfrom = tfrom->t_n, nto = tto->t_n, i;
282 #endif
283 for (i = 0; i < nto; i++)
285 if (conformaction[i] >= 0)
287 /* we swap the two, in case it's an array or list, so that
288 when "wfrom" is deleted the old one gets cleaned up. */
289 t_word wwas = wto[i];
290 wto[i] = wfrom[conformaction[i]];
291 wfrom[conformaction[i]] = wwas;
296 /* conform a scalar, recursively conforming sublists and arrays */
297 static t_scalar *template_conformscalar(t_template *tfrom, t_template *tto,
298 int *conformaction, t_glist *glist, t_scalar *scfrom)
300 t_scalar *x;
301 t_gpointer gp;
302 #ifdef ROCKBOX
303 int i;
304 #else
305 int nto = tto->t_n, nfrom = tfrom->t_n, i;
306 #endif
307 t_template *scalartemplate;
308 /* post("conform scalar"); */
309 /* possibly replace the scalar */
310 if (scfrom->sc_template == tfrom->t_sym)
312 /* see scalar_new() for comment about the gpointer. */
313 gpointer_init(&gp);
314 x = (t_scalar *)getbytes(sizeof(t_scalar) +
315 (tto->t_n - 1) * sizeof(*x->sc_vec));
316 x->sc_gobj.g_pd = scalar_class;
317 x->sc_template = tfrom->t_sym;
318 gpointer_setglist(&gp, glist, x);
319 /* Here we initialize to the new template, but array and list
320 elements will still belong to old template. */
321 word_init(x->sc_vec, tto, &gp);
323 template_conformwords(tfrom, tto, conformaction,
324 scfrom->sc_vec, x->sc_vec);
326 /* replace the old one with the new one in the list */
327 if (glist->gl_list == &scfrom->sc_gobj)
329 glist->gl_list = &x->sc_gobj;
330 x->sc_gobj.g_next = scfrom->sc_gobj.g_next;
332 else
334 t_gobj *y, *y2;
335 for (y = glist->gl_list; (y2 = y->g_next); y = y2)
336 if (y2 == &scfrom->sc_gobj)
338 x->sc_gobj.g_next = y2->g_next;
339 y->g_next = &x->sc_gobj;
340 goto nobug;
342 bug("template_conformscalar");
343 nobug: ;
345 /* burn the old one */
346 pd_free(&scfrom->sc_gobj.g_pd);
348 else x = scfrom;
349 scalartemplate = template_findbyname(x->sc_template);
350 /* convert all array elements and sublists */
351 for (i = 0; i < scalartemplate->t_n; i++)
353 t_dataslot *ds = scalartemplate->t_vec + i;
354 if (ds->ds_type == DT_LIST)
356 t_glist *gl2 = x->sc_vec[i].w_list;
357 template_conformglist(tfrom, tto, gl2, conformaction);
359 else if (ds->ds_type == DT_ARRAY)
361 template_conformarray(tfrom, tto, conformaction,
362 x->sc_vec[i].w_array);
365 return (x);
368 /* conform an array, recursively conforming sublists and arrays */
369 static void template_conformarray(t_template *tfrom, t_template *tto,
370 int *conformaction, t_array *a)
372 int i;
373 if (a->a_templatesym == tfrom->t_sym)
375 /* the array elements must all be conformed */
376 int oldelemsize = sizeof(t_word) * tfrom->t_n,
377 newelemsize = sizeof(t_word) * tto->t_n;
378 char *newarray = getbytes(sizeof(t_word) * tto->t_n * a->a_n);
379 char *oldarray = a->a_vec;
380 if (a->a_elemsize != oldelemsize)
381 bug("template_conformarray");
382 for (i = 0; i < a->a_n; i++)
384 t_word *wp = (t_word *)(newarray + newelemsize * i);
385 word_init(wp, tto, &a->a_gp);
386 template_conformwords(tfrom, tto, conformaction,
387 (t_word *)(oldarray + oldelemsize * i), wp);
390 bug("template_conformarray: this part not written");
391 /* go through item by item conforming subarrays and sublists... */
394 /* this routine searches for every scalar in the glist that belongs
395 to the "from" template and makes it belong to the "to" template. Descend
396 glists recursively.
397 We don't handle redrawing here; this is to be filled in LATER... */
399 static void template_conformglist(t_template *tfrom, t_template *tto,
400 t_glist *glist, int *conformaction)
402 t_gobj *g;
403 /* post("conform glist %s", glist->gl_name->s_name); */
404 for (g = glist->gl_list; g; g = g->g_next)
406 if (pd_class(&g->g_pd) == scalar_class)
407 g = &template_conformscalar(tfrom, tto, conformaction,
408 glist, (t_scalar *)g)->sc_gobj;
409 else if (pd_class(&g->g_pd) == canvas_class)
410 template_conformglist(tfrom, tto, (t_glist *)g, conformaction);
414 /* globally conform all scalars from one template to another */
415 void template_conform(t_template *tfrom, t_template *tto)
417 int nto = tto->t_n, nfrom = tfrom->t_n, i, j,
418 *conformaction = (int *)getbytes(sizeof(int) * nto),
419 *conformedfrom = (int *)getbytes(sizeof(int) * nfrom), doit = 0;
420 for (i = 0; i < nto; i++)
421 conformaction[i] = -1;
422 for (i = 0; i < nfrom; i++)
423 conformedfrom[i] = 0;
424 for (i = 0; i < nto; i++)
426 t_dataslot *dataslot = &tto->t_vec[i];
427 for (j = 0; j < nfrom; j++)
429 t_dataslot *dataslot2 = &tfrom->t_vec[j];
430 if (dataslot_matches(dataslot, dataslot2, 1))
432 conformaction[i] = j;
433 conformedfrom[j] = 1;
437 for (i = 0; i < nto; i++)
438 if (conformaction[i] < 0)
440 t_dataslot *dataslot = &tto->t_vec[i];
441 for (j = 0; j < nfrom; j++)
442 if (!conformedfrom[j] &&
443 dataslot_matches(dataslot, &tfrom->t_vec[j], 1))
445 conformaction[i] = j;
446 conformedfrom[j] = 1;
449 if (nto != nfrom)
450 doit = 1;
451 else for (i = 0; i < nto; i++)
452 if (conformaction[i] != i)
453 doit = 1;
455 if (doit)
457 t_glist *gl;
458 /* post("conforming template '%s' to new structure",
459 tfrom->t_sym->s_name);
460 for (i = 0; i < nto; i++)
461 post("... %d", conformaction[i]); */
462 for (gl = canvas_list; gl; gl = gl->gl_next)
463 template_conformglist(tfrom, tto, gl, conformaction);
465 freebytes(conformaction, sizeof(int) * nto);
466 freebytes(conformedfrom, sizeof(int) * nfrom);
469 t_template *template_findbyname(t_symbol *s)
471 #ifndef ROCKBOX
472 int i;
473 #endif
474 if (s == &s_float)
475 return (&template_float);
476 else return ((t_template *)pd_findbyclass(s, template_class));
479 t_canvas *template_findcanvas(t_template *template)
481 t_gtemplate *gt;
482 if (!template)
483 bug("template_findcanvas");
484 if (!(gt = template->t_list))
485 return (0);
486 return (gt->x_owner);
487 /* return ((t_canvas *)pd_findbyclass(template->t_sym, canvas_class)); */
490 /* call this when reading a patch from a file to declare what templates
491 we'll need. If there's already a template, check if it matches.
492 If it doesn't it's still OK as long as there are no "struct" (gtemplate)
493 objects hanging from it; we just conform everyone to the new template.
494 If there are still struct objects belonging to the other template, we're
495 in trouble. LATER we'll figure out how to conform the new patch's objects
496 to the pre-existing struct. */
497 static void *template_usetemplate(void *dummy, t_symbol *s,
498 int argc, t_atom *argv)
500 t_template *x;
501 t_symbol *templatesym =
502 canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
503 #ifdef ROCKBOX
504 (void) dummy;
505 (void) s;
506 #endif
507 if (!argc)
508 return (0);
509 argc--; argv++;
510 /* check if there's already a template by this name. */
511 if ((x = (t_template *)pd_findbyclass(templatesym, template_class)))
513 t_template *y = template_new(&s_, argc, argv);
514 /* If the new template is the same as the old one,
515 there's nothing to do. */
516 if (!template_match(x, y))
518 /* Are there "struct" objects upholding this template? */
519 if (x->t_list)
521 /* don't know what to do here! */
522 error("%s: template mismatch",
523 templatesym->s_name);
525 else
527 /* conform everyone to the new template */
528 template_conform(x, y);
529 pd_free(&x->t_pdobj);
530 template_new(templatesym, argc, argv);
533 pd_free(&y->t_pdobj);
535 /* otherwise, just make one. */
536 else template_new(templatesym, argc, argv);
537 return (0);
540 /* here we assume someone has already cleaned up all instances of this. */
541 void template_free(t_template *x)
543 if (*x->t_sym->s_name)
544 pd_unbind(&x->t_pdobj, x->t_sym);
545 t_freebytes(x->t_vec, x->t_n * sizeof(*x->t_vec));
548 static void template_setup(void)
550 template_class = class_new(gensym("template"), 0, (t_method)template_free,
551 sizeof(t_template), CLASS_PD, 0);
552 class_addmethod(pd_canvasmaker, (t_method)template_usetemplate,
553 gensym("struct"), A_GIMME, 0);
557 /* ---------------- gtemplates. One per canvas. ----------- */
559 /* this is a "text" object that searches for, and if necessary creates,
560 a "template" (above). Other objects in the canvas then can give drawing
561 instructions for the template. The template doesn't go away when the
562 gtemplate is deleted, so that you can replace it with
563 another one to add new fields, for example. */
565 static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv)
567 t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
568 t_template *t = template_findbyname(sym);
569 int i;
570 #ifndef ROCKBOX
571 t_symbol *sx = gensym("x");
572 #endif
573 x->x_owner = canvas_getcurrent();
574 x->x_next = 0;
575 x->x_sym = sym;
576 x->x_argc = argc;
577 x->x_argv = (t_atom *)getbytes(argc * sizeof(t_atom));
578 for (i = 0; i < argc; i++)
579 x->x_argv[i] = argv[i];
581 /* already have a template by this name? */
582 if (t)
584 x->x_template = t;
585 /* if it's already got a "struct" or "gtemplate" object we
586 just tack this one to the end of the list and leave it
587 there. */
588 if (t->t_list)
590 t_gtemplate *x2, *x3;
591 for(x2 = x->x_template->t_list; (x3 = x2->x_next); x2 = x3)
593 x2->x_next = x;
594 post("template %s: warning: already exists.", sym->s_name);
596 else
598 /* if there's none, we just replace the template with
599 our own and conform it. */
600 t_template *y = template_new(&s_, argc, argv);
601 /* Unless the new template is different from the old one,
602 there's nothing to do. */
603 if (!template_match(t, y))
605 /* conform everyone to the new template */
606 template_conform(t, y);
607 pd_free(&t->t_pdobj);
608 t = template_new(sym, argc, argv);
610 pd_free(&y->t_pdobj);
611 t->t_list = x;
614 else
616 /* otherwise make a new one and we're the only struct on it. */
617 x->x_template = t = template_new(sym, argc, argv);
618 t->t_list = x;
620 return (x);
623 static void *gtemplate_new(t_symbol *s, int argc, t_atom *argv)
625 #ifndef ROCKBOX
626 t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
627 #endif
628 t_symbol *sym = atom_getsymbolarg(0, argc, argv);
629 #ifdef ROCKBOX
630 (void) s;
631 #endif
632 if (argc >= 1)
633 argc--; argv++;
634 return (gtemplate_donew(canvas_makebindsym(sym), argc, argv));
637 /* old version (0.34) -- delete 2003 or so */
638 static void *gtemplate_new_old(t_symbol *s, int argc, t_atom *argv)
640 #ifndef ROCKBOX
641 t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
642 #endif
643 t_symbol *sym = canvas_makebindsym(canvas_getcurrent()->gl_name);
644 static int warned;
645 #ifdef ROCKBOX
646 (void) s;
647 #endif
648 if (!warned)
650 post("warning -- 'template' (%s) is obsolete; replace with 'struct'",
651 sym->s_name);
652 warned = 1;
654 return (gtemplate_donew(sym, argc, argv));
657 t_template *gtemplate_get(t_gtemplate *x)
659 return (x->x_template);
662 static void gtemplate_free(t_gtemplate *x)
664 /* get off the template's list */
665 t_template *t = x->x_template;
666 if (x == t->t_list)
668 if (x->x_next)
670 /* if we were first on the list, and there are others on
671 the list, make a new template corresponding to the new
672 first-on-list and replace teh existing template with it. */
673 t_template *z = template_new(&s_, x->x_argc, x->x_argv);
674 template_conform(t, z);
675 pd_free(&t->t_pdobj);
676 pd_free(&z->t_pdobj);
677 z = template_new(x->x_sym, x->x_argc, x->x_argv);
678 z->t_list = x->x_next;
680 else t->t_list = 0;
682 else
684 t_gtemplate *x2, *x3;
685 for(x2 = t->t_list; (x3 = x2->x_next); x2 = x3)
687 if (x == x3)
689 x2->x_next = x3->x_next;
690 break;
694 freebytes(x->x_argv, sizeof(t_atom) * x->x_argc);
697 static void gtemplate_setup(void)
699 gtemplate_class = class_new(gensym("struct"),
700 (t_newmethod)gtemplate_new, (t_method)gtemplate_free,
701 sizeof(t_gtemplate), CLASS_NOINLET, A_GIMME, 0);
702 class_addcreator((t_newmethod)gtemplate_new_old, gensym("template"),
703 A_GIMME, 0);
706 /* --------------- FIELD DESCRIPTORS ---------------------- */
708 /* a field descriptor can hold a constant or a variable; if a variable,
709 it's the name of a field in the template we belong to. LATER, we might
710 want to cache the offset of the field so we don't have to search for it
711 every single time we draw the object.
714 typedef struct _fielddesc
716 char fd_type; /* LATER consider removing this? */
717 char fd_var;
718 union
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 } t_fielddesc;
726 #define FIELDDESC_SETFLOAT(x, f) \
727 ((x)->fd_type = A_FLOAT, (x)->fd_var = 0, (x)->fd_un.fd_float = (f))
728 #define FIELDDESC_SETSYMBOL(x, s) \
729 ((x)->fd_type = A_SYMBOL, (x)->fd_var = 0, (x)->fd_un.fd_symbol = (s))
730 #define FIELDDESC_SETVAR(x, s, type) \
731 ((x)->fd_type = type, (x)->fd_var = 1, (x)->fd_un.fd_varsym = (s))
733 #define CLOSED 1
734 #define BEZ 2
735 #define A_ARRAY 55 /* LATER decide whether to enshrine this in m_pd.h */
737 static void fielddesc_setfloatarg(t_fielddesc *fd, int argc, t_atom *argv)
739 if (argc <= 0) FIELDDESC_SETFLOAT(fd, 0);
740 else if (argv->a_type == A_SYMBOL)
741 FIELDDESC_SETVAR(fd, argv->a_w.w_symbol, A_FLOAT);
742 else FIELDDESC_SETFLOAT(fd, argv->a_w.w_float);
745 static void fielddesc_setarrayarg(t_fielddesc *fd, int argc, t_atom *argv)
747 if (argc <= 0) FIELDDESC_SETFLOAT(fd, 0);
748 else if (argv->a_type == A_SYMBOL)
749 FIELDDESC_SETVAR(fd, argv->a_w.w_symbol, A_ARRAY);
750 else FIELDDESC_SETFLOAT(fd, argv->a_w.w_float);
753 static t_float fielddesc_getfloat(t_fielddesc *f, t_template *template,
754 t_word *wp, int loud)
756 if (f->fd_type == A_FLOAT)
758 if (f->fd_var)
759 return (template_getfloat(template, f->fd_un.fd_varsym, wp, loud));
760 else return (f->fd_un.fd_float);
762 else
764 if (loud)
765 error("symbolic data field used as number");
766 return (0);
770 static t_symbol *fielddesc_getsymbol(t_fielddesc *f, t_template *template,
771 t_word *wp, int loud)
773 if (f->fd_type == A_SYMBOL)
775 if (f->fd_var)
776 return(template_getsymbol(template, f->fd_un.fd_varsym, wp, loud));
777 else return (f->fd_un.fd_symbol);
779 else
781 if (loud)
782 error("numeric data field used as symbol");
783 return (&s_);
787 /* ---------------- curves and polygons (joined segments) ---------------- */
790 curves belong to templates and describe how the data in the template are to
791 be drawn. The coordinates of the curve (and other display features) can
792 be attached to fields in the template.
795 t_class *curve_class;
797 typedef struct _curve
799 t_object x_obj;
800 int x_flags; /* CLOSED and/or BEZ */
801 t_fielddesc x_fillcolor;
802 t_fielddesc x_outlinecolor;
803 t_fielddesc x_width;
804 int x_npoints;
805 t_fielddesc *x_vec;
806 } t_curve;
808 static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv)
810 t_curve *x = (t_curve *)pd_new(curve_class);
811 char *classname = classsym->s_name;
812 int flags = 0;
813 int nxy, i;
814 t_fielddesc *fd;
815 if (classname[0] == 'f')
817 classname += 6;
818 flags |= CLOSED;
819 if (argc) fielddesc_setfloatarg(&x->x_fillcolor, argc--, argv++);
820 else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
822 else classname += 4;
823 if (classname[0] == 'c') flags |= BEZ;
824 x->x_flags = flags;
825 if (argc) fielddesc_setfloatarg(&x->x_outlinecolor, argc--, argv++);
826 else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
827 if (argc) fielddesc_setfloatarg(&x->x_width, argc--, argv++);
828 else FIELDDESC_SETFLOAT(&x->x_width, 1);
829 if (argc < 0) argc = 0;
830 nxy = (argc + (argc & 1));
831 x->x_npoints = (nxy>>1);
832 x->x_vec = (t_fielddesc *)t_getbytes(nxy * sizeof(t_fielddesc));
833 for (i = 0, fd = x->x_vec; i < argc; i++, fd++, argv++)
834 fielddesc_setfloatarg(fd, 1, argv);
835 if (argc & 1) FIELDDESC_SETFLOAT(fd, 0);
837 return (x);
840 /* -------------------- widget behavior for curve ------------ */
842 static void curve_getrect(t_gobj *z, t_glist *glist,
843 t_word *data, t_template *template, float basex, float basey,
844 int *xp1, int *yp1, int *xp2, int *yp2)
846 t_curve *x = (t_curve *)z;
847 int i, n = x->x_npoints;
848 t_fielddesc *f = x->x_vec;
849 int x1 = 0x7fffffff, x2 = -0x7fffffff, y1 = 0x7fffffff, y2 = -0x7fffffff;
850 for (i = 0, f = x->x_vec; i < n; i++, f += 2)
852 int xloc = glist_xtopixels(glist,
853 basex + fielddesc_getfloat(f, template, data, 0));
854 int yloc = glist_ytopixels(glist,
855 basey + fielddesc_getfloat(f+1, template, data, 0));
856 if (xloc < x1) x1 = xloc;
857 if (xloc > x2) x2 = xloc;
858 if (yloc < y1) y1 = yloc;
859 if (yloc > y2) y2 = yloc;
861 *xp1 = x1;
862 *yp1 = y1;
863 *xp2 = x2;
864 *yp2 = y2;
867 static void curve_displace(t_gobj *z, t_glist *glist,
868 t_word *data, t_template *template, float basex, float basey,
869 int dx, int dy)
871 #ifdef ROCKBOX
872 (void) z;
873 (void) glist;
874 (void) data;
875 (void) template;
876 (void) basex;
877 (void) basey;
878 (void) dx;
879 (void) dy;
880 #endif
881 /* refuse */
884 static void curve_select(t_gobj *z, t_glist *glist,
885 t_word *data, t_template *template, float basex, float basey,
886 int state)
888 #ifdef ROCKBOX
889 (void) z;
890 (void) glist;
891 (void) data;
892 (void) template;
893 (void) basex;
894 (void) basey;
895 (void) state;
896 #endif
897 /* fill in later */
900 static void curve_activate(t_gobj *z, t_glist *glist,
901 t_word *data, t_template *template, float basex, float basey,
902 int state)
904 #ifdef ROCKBOX
905 (void) z;
906 (void) glist;
907 (void) data;
908 (void) template;
909 (void) basex;
910 (void) basey;
911 (void) state;
912 #endif
913 /* fill in later */
916 static int rangecolor(int n) /* 0 to 9 in 5 steps */
918 int n2 = n/2; /* 0 to 4 */
919 int ret = (n2 << 6); /* 0 to 256 in 5 steps */
920 if (ret > 255) ret = 255;
921 return (ret);
924 static void numbertocolor(int n, char *s)
926 int red, blue, green;
927 if (n < 0) n = 0;
928 red = n / 100;
929 blue = ((n / 10) % 10);
930 green = n % 10;
931 #ifdef ROCKBOX
932 snprintf(s, 10, "#%2.2x%2.2x%2.2x",
933 rangecolor(red), rangecolor(blue), rangecolor(green));
934 #else
935 sprintf(s, "#%2.2x%2.2x%2.2x", rangecolor(red), rangecolor(blue),
936 rangecolor(green));
937 #endif
940 static void curve_vis(t_gobj *z, t_glist *glist,
941 t_word *data, t_template *template, float basex, float basey,
942 int vis)
944 t_curve *x = (t_curve *)z;
945 int i, n = x->x_npoints;
946 t_fielddesc *f = x->x_vec;
948 #ifdef ROCKBOX
949 (void) glist;
950 (void) basex;
951 (void) basey;
952 #endif
954 if (vis)
956 if (n > 1)
958 #ifdef ROCKBOX
959 int flags = x->x_flags;
960 #else
961 int flags = x->x_flags, closed = (flags & CLOSED);
962 #endif
963 float width = fielddesc_getfloat(&x->x_width, template, data, 1);
964 char outline[20], fill[20];
965 if (width < 1) width = 1;
966 numbertocolor(
967 fielddesc_getfloat(&x->x_outlinecolor, template, data, 1),
968 outline);
969 if (flags & CLOSED)
971 numbertocolor(
972 fielddesc_getfloat(&x->x_fillcolor, template, data, 1),
973 fill);
974 #ifndef ROCKBOX
975 sys_vgui(".x%x.c create polygon\\\n",
976 glist_getcanvas(glist));
977 #endif
979 #ifndef ROCKBOX
980 else sys_vgui(".x%x.c create line\\\n",
981 glist_getcanvas(glist));
982 #endif
983 for (i = 0, f = x->x_vec; i < n; i++, f += 2)
985 #ifndef ROCKBOX
986 float xloc = glist_xtopixels(glist,
987 basex + fielddesc_getfloat(f, template, data, 1));
988 float yloc = glist_ytopixels(glist,
989 basey + fielddesc_getfloat(f+1, template, data, 1));
990 sys_vgui("%d %d\\\n", (int)xloc, (int)yloc);
991 #endif
993 #ifndef ROCKBOX
994 sys_vgui("-width %f\\\n",
995 fielddesc_getfloat(&x->x_width, template, data, 1));
996 if (flags & CLOSED) sys_vgui("-fill %s -outline %s\\\n",
997 fill, outline);
998 else sys_vgui("-fill %s\\\n", outline);
999 if (flags & BEZ) sys_vgui("-smooth 1\\\n");
1000 sys_vgui("-tags curve%x\n", data);
1001 #endif
1003 else post("warning: curves need at least two points to be graphed");
1005 else
1007 #ifndef ROCKBOX
1008 if (n > 1) sys_vgui(".x%x.c delete curve%x\n",
1009 glist_getcanvas(glist), data);
1010 #endif
1014 static int curve_motion_field;
1015 static float curve_motion_xcumulative;
1016 static float curve_motion_xbase;
1017 static float curve_motion_xper;
1018 static float curve_motion_ycumulative;
1019 static float curve_motion_ybase;
1020 static float curve_motion_yper;
1021 static t_glist *curve_motion_glist;
1022 static t_gobj *curve_motion_gobj;
1023 static t_word *curve_motion_wp;
1024 static t_template *curve_motion_template;
1026 /* LATER protect against the template changing or the scalar disappearing
1027 probably by attaching a gpointer here ... */
1029 static void curve_motion(void *z, t_floatarg dx, t_floatarg dy)
1031 t_curve *x = (t_curve *)z;
1032 t_fielddesc *f = x->x_vec + curve_motion_field;
1033 curve_motion_xcumulative += dx;
1034 curve_motion_ycumulative += dy;
1035 if (f->fd_var)
1037 template_setfloat(curve_motion_template,
1038 f->fd_un.fd_varsym,
1039 curve_motion_wp,
1040 curve_motion_xbase + curve_motion_xcumulative * curve_motion_xper,
1043 if ((f+1)->fd_var)
1045 template_setfloat(curve_motion_template,
1046 (f+1)->fd_un.fd_varsym,
1047 curve_motion_wp,
1048 curve_motion_ybase + curve_motion_ycumulative * curve_motion_yper,
1051 glist_redrawitem(curve_motion_glist, curve_motion_gobj);
1054 static int curve_click(t_gobj *z, t_glist *glist,
1055 t_scalar *sc, t_template *template, float basex, float basey,
1056 int xpix, int ypix, int shift, int alt, int dbl, int doit)
1058 t_curve *x = (t_curve *)z;
1059 int i, n = x->x_npoints;
1060 int bestn = -1;
1061 int besterror = 0x7fffffff;
1062 t_fielddesc *f = x->x_vec;
1063 t_word *data = sc->sc_vec;
1065 #ifdef ROCKBOX
1066 (void) shift;
1067 (void) alt;
1068 (void) dbl;
1069 #endif
1071 for (i = 0, f = x->x_vec; i < n; i++, f += 2)
1073 int xloc = glist_xtopixels(glist,
1074 basex + fielddesc_getfloat(f, template, data, 0));
1075 int yloc = glist_ytopixels(glist,
1076 basey + fielddesc_getfloat(f+1, template, data, 0));
1077 int xerr = xloc - xpix, yerr = yloc - ypix;
1078 if (!f->fd_var && !(f+1)->fd_var)
1079 continue;
1080 if (xerr < 0)
1081 xerr = -xerr;
1082 if (yerr < 0)
1083 yerr = -yerr;
1084 if (yerr > xerr)
1085 xerr = yerr;
1086 if (xerr < besterror)
1088 besterror = xerr;
1089 bestn = i;
1090 curve_motion_xbase = fielddesc_getfloat(f, template, data, 0);
1091 curve_motion_ybase = fielddesc_getfloat(f+1, template, data, 0);
1094 if (besterror > 10)
1095 return (0);
1096 if (doit)
1098 curve_motion_xper = glist_pixelstox(glist, 1)
1099 - glist_pixelstox(glist, 0);
1100 curve_motion_yper = glist_pixelstoy(glist, 1)
1101 - glist_pixelstoy(glist, 0);
1102 curve_motion_xcumulative = curve_motion_ycumulative = 0;
1103 curve_motion_glist = glist;
1104 curve_motion_gobj = &sc->sc_gobj;
1105 curve_motion_wp = data;
1106 curve_motion_field = 2*bestn;
1107 curve_motion_template = template;
1108 glist_grab(glist, z, curve_motion, 0, xpix, ypix);
1110 return (1);
1113 t_parentwidgetbehavior curve_widgetbehavior =
1115 curve_getrect,
1116 curve_displace,
1117 curve_select,
1118 curve_activate,
1119 curve_vis,
1120 curve_click,
1123 static void curve_free(t_curve *x)
1125 t_freebytes(x->x_vec, 2 * x->x_npoints * sizeof(*x->x_vec));
1128 static void curve_setup(void)
1130 curve_class = class_new(gensym("drawpolygon"), (t_newmethod)curve_new,
1131 (t_method)curve_free, sizeof(t_curve), CLASS_NOINLET, A_GIMME, 0);
1132 class_setdrawcommand(curve_class);
1133 class_addcreator((t_newmethod)curve_new, gensym("drawcurve"),
1134 A_GIMME, 0);
1135 class_addcreator((t_newmethod)curve_new, gensym("filledpolygon"),
1136 A_GIMME, 0);
1137 class_addcreator((t_newmethod)curve_new, gensym("filledcurve"),
1138 A_GIMME, 0);
1139 class_setparentwidget(curve_class, &curve_widgetbehavior);
1142 /* --------- plots for showing arrays --------------- */
1144 t_class *plot_class;
1146 typedef struct _plot
1148 t_object x_obj;
1149 int x_flags;
1150 t_fielddesc x_outlinecolor;
1151 t_fielddesc x_width;
1152 t_fielddesc x_xloc;
1153 t_fielddesc x_yloc;
1154 t_fielddesc x_xinc;
1155 t_fielddesc x_data;
1156 } t_plot;
1158 static void *plot_new(t_symbol *classsym, t_int argc, t_atom *argv)
1160 t_plot *x = (t_plot *)pd_new(plot_class);
1161 int flags = 0;
1162 #ifndef ROCKBOX
1163 int nxy, i;
1164 t_fielddesc *fd;
1165 #endif
1166 t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
1168 #ifdef ROCKBOX
1169 (void) classsym;
1170 #endif
1172 if (!strcmp(firstarg->s_name, "curve"))
1174 flags |= BEZ;
1175 argc--, argv++;
1177 if (argc) fielddesc_setarrayarg(&x->x_data, argc--, argv++);
1178 else FIELDDESC_SETFLOAT(&x->x_data, 1);
1179 if (argc) fielddesc_setfloatarg(&x->x_outlinecolor, argc--, argv++);
1180 else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
1181 if (argc) fielddesc_setfloatarg(&x->x_width, argc--, argv++);
1182 else FIELDDESC_SETFLOAT(&x->x_width, 1);
1183 if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
1184 else FIELDDESC_SETFLOAT(&x->x_xloc, 1);
1185 if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
1186 else FIELDDESC_SETFLOAT(&x->x_yloc, 1);
1187 if (argc) fielddesc_setfloatarg(&x->x_xinc, argc--, argv++);
1188 else FIELDDESC_SETFLOAT(&x->x_xinc, 1);
1189 x->x_flags = flags;
1190 return (x);
1193 /* -------------------- widget behavior for plot ------------ */
1196 /* get everything we'll need from the owner template of the array being
1197 plotted. Not used for garrays, but see below */
1198 static int plot_readownertemplate(t_plot *x,
1199 t_word *data, t_template *ownertemplate,
1200 t_symbol **elemtemplatesymp, t_array **arrayp,
1201 float *linewidthp, float *xlocp, float *xincp, float *ylocp)
1203 int arrayonset, type;
1204 t_symbol *elemtemplatesym;
1205 t_array *array;
1207 /* find the data and verify it's an array */
1208 if (x->x_data.fd_type != A_ARRAY || !x->x_data.fd_var)
1210 error("plot: needs an array field");
1211 return (-1);
1213 if (!template_find_field(ownertemplate, x->x_data.fd_un.fd_varsym,
1214 &arrayonset, &type, &elemtemplatesym))
1216 error("plot: %s: no such field", x->x_data.fd_un.fd_varsym->s_name);
1217 return (-1);
1219 if (type != DT_ARRAY)
1221 error("plot: %s: not an array", x->x_data.fd_un.fd_varsym->s_name);
1222 return (-1);
1224 array = *(t_array **)(((char *)data) + arrayonset);
1225 *linewidthp = fielddesc_getfloat(&x->x_width, ownertemplate, data, 1);
1226 *xlocp = fielddesc_getfloat(&x->x_xloc, ownertemplate, data, 1);
1227 *xincp = fielddesc_getfloat(&x->x_xinc, ownertemplate, data, 1);
1228 *ylocp = fielddesc_getfloat(&x->x_yloc, ownertemplate, data, 1);
1229 *elemtemplatesymp = elemtemplatesym;
1230 *arrayp = array;
1231 return (0);
1234 /* get everything else you could possibly need about a plot,
1235 either for plot's own purposes or for plotting a "garray" */
1236 int array_getfields(t_symbol *elemtemplatesym,
1237 t_canvas **elemtemplatecanvasp,
1238 t_template **elemtemplatep, int *elemsizep,
1239 int *xonsetp, int *yonsetp, int *wonsetp)
1241 #ifdef ROCKBOX
1242 int elemsize, yonset, wonset, xonset, type;
1243 #else
1244 int arrayonset, elemsize, yonset, wonset, xonset, type;
1245 #endif
1246 t_template *elemtemplate;
1247 t_symbol *dummy;
1248 t_canvas *elemtemplatecanvas = 0;
1250 /* the "float" template is special in not having to have a canvas;
1251 template_findbyname is hardwired to return a predefined
1252 template. */
1254 if (!(elemtemplate = template_findbyname(elemtemplatesym)))
1256 error("plot: %s: no such template", elemtemplatesym->s_name);
1257 return (-1);
1259 if (!((elemtemplatesym == &s_float) ||
1260 (elemtemplatecanvas = template_findcanvas(elemtemplate))))
1262 error("plot: %s: no canvas for this template", elemtemplatesym->s_name);
1263 return (-1);
1265 elemsize = elemtemplate->t_n * sizeof(t_word);
1266 if (!template_find_field(elemtemplate, gensym("y"), &yonset, &type, &dummy)
1267 || type != DT_FLOAT)
1268 yonset = -1;
1269 if (!template_find_field(elemtemplate, gensym("x"), &xonset, &type, &dummy)
1270 || type != DT_FLOAT)
1271 xonset = -1;
1272 if (!template_find_field(elemtemplate, gensym("w"), &wonset, &type, &dummy)
1273 || type != DT_FLOAT)
1274 wonset = -1;
1276 /* fill in slots for return values */
1277 *elemtemplatecanvasp = elemtemplatecanvas;
1278 *elemtemplatep = elemtemplate;
1279 *elemsizep = elemsize;
1280 *xonsetp = xonset;
1281 *yonsetp = yonset;
1282 *wonsetp = wonset;
1283 return (0);
1286 static void plot_getrect(t_gobj *z, t_glist *glist,
1287 t_word *data, t_template *template, float basex, float basey,
1288 int *xp1, int *yp1, int *xp2, int *yp2)
1290 t_plot *x = (t_plot *)z;
1291 int elemsize, yonset, wonset, xonset;
1292 t_canvas *elemtemplatecanvas;
1293 t_template *elemtemplate;
1294 t_symbol *elemtemplatesym;
1295 float linewidth, xloc, xinc, yloc;
1296 t_array *array;
1297 float x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
1298 int i;
1299 float xpix, ypix, wpix;
1301 if (!plot_readownertemplate(x, data, template,
1302 &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc) &&
1303 !array_getfields(elemtemplatesym, &elemtemplatecanvas,
1304 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
1306 for (i = 0; i < array->a_n; i++)
1308 array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
1309 xonset, yonset, wonset, i, basex + xloc, basey + yloc, xinc,
1310 &xpix, &ypix, &wpix);
1311 if (xpix < x1)
1312 x1 = xpix;
1313 if (xpix > x2)
1314 x2 = xpix;
1315 if (ypix - wpix < y1)
1316 y1 = ypix - wpix;
1317 if (ypix + wpix > y2)
1318 y2 = ypix + wpix;
1322 *xp1 = x1;
1323 *yp1 = y1;
1324 *xp2 = x2;
1325 *yp2 = y2;
1328 static void plot_displace(t_gobj *z, t_glist *glist,
1329 t_word *data, t_template *template, float basex, float basey,
1330 int dx, int dy)
1332 #ifdef ROCKBOX
1333 (void) z;
1334 (void) glist;
1335 (void) data;
1336 (void) template;
1337 (void) basex;
1338 (void) basey;
1339 (void) dx;
1340 (void) dy;
1341 #endif
1342 /* not yet */
1345 static void plot_select(t_gobj *z, t_glist *glist,
1346 t_word *data, t_template *template, float basex, float basey,
1347 int state)
1349 #ifdef ROCKBOX
1350 (void) z;
1351 (void) glist;
1352 (void) data;
1353 (void) template;
1354 (void) basex;
1355 (void) basey;
1356 (void) state;
1357 #endif
1358 /* not yet */
1361 static void plot_activate(t_gobj *z, t_glist *glist,
1362 t_word *data, t_template *template, float basex, float basey,
1363 int state)
1365 #ifdef ROCKBOX
1366 (void) z;
1367 (void) glist;
1368 (void) data;
1369 (void) template;
1370 (void) basex;
1371 (void) basey;
1372 (void) state;
1373 #endif
1374 /* not yet */
1377 static void plot_vis(t_gobj *z, t_glist *glist,
1378 t_word *data, t_template *template, float basex, float basey,
1379 int vis)
1381 t_plot *x = (t_plot *)z;
1382 int elemsize, yonset, wonset, xonset;
1383 t_canvas *elemtemplatecanvas;
1384 t_template *elemtemplate;
1385 t_symbol *elemtemplatesym;
1386 float linewidth, xloc, xinc, yloc;
1387 t_array *array;
1388 int nelem;
1389 char *elem;
1390 if (plot_readownertemplate(x, data, template,
1391 &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc) ||
1392 array_getfields(elemtemplatesym, &elemtemplatecanvas,
1393 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
1394 return;
1395 nelem = array->a_n;
1396 elem = (char *)array->a_vec;
1397 if (vis)
1399 char outline[20];
1400 int lastpixel = -1, ndrawn = 0;
1401 float xsum, yval = 0, wval = 0, xpix;
1402 int ixpix = 0, i;
1404 /* draw the trace */
1405 numbertocolor(fielddesc_getfloat(&x->x_outlinecolor, template, data, 1),
1406 outline);
1407 if (wonset >= 0)
1409 /* found "w" field which controls linewidth. The trace is
1410 a filled polygon with 2n points. */
1411 #ifndef ROCKBOX
1412 sys_vgui(".x%x.c create polygon \\\n",
1413 glist_getcanvas(glist));
1414 #endif
1416 for (i = 0, xsum = xloc; i < nelem; i++)
1418 float usexloc;
1419 if (xonset >= 0)
1420 usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
1421 else usexloc = xsum, xsum += xinc;
1422 if (yonset >= 0)
1423 yval = *(float *)((elem + elemsize * i) + yonset);
1424 else yval = 0;
1425 wval = *(float *)((elem + elemsize * i) + wonset);
1426 xpix = glist_xtopixels(glist, basex + usexloc);
1427 ixpix = xpix + 0.5;
1428 if (xonset >= 0 || ixpix != lastpixel)
1430 #ifndef ROCKBOX
1431 sys_vgui("%d %f \\\n", ixpix,
1432 glist_ytopixels(glist,
1433 basey + yloc + yval - wval));
1434 #endif
1435 ndrawn++;
1437 lastpixel = ixpix;
1438 if (ndrawn >= 1000) goto ouch;
1440 lastpixel = -1;
1441 for (i = nelem-1; i >= 0; i--)
1443 float usexloc;
1444 if (xonset >= 0)
1445 usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
1446 else xsum -= xinc, usexloc = xsum;
1447 if (yonset >= 0)
1448 yval = *(float *)((elem + elemsize * i) + yonset);
1449 else yval = 0;
1450 wval = *(float *)((elem + elemsize * i) + wonset);
1451 xpix = glist_xtopixels(glist, basex + usexloc);
1452 ixpix = xpix + 0.5;
1453 if (xonset >= 0 || ixpix != lastpixel)
1455 #ifndef ROCKBOX
1456 sys_vgui("%d %f \\\n", ixpix, glist_ytopixels(glist,
1457 basey + yloc + yval + wval));
1458 #endif
1459 ndrawn++;
1461 lastpixel = ixpix;
1462 if (ndrawn >= 1000) goto ouch;
1464 /* TK will complain if there aren't at least 3 points. There
1465 should be at least two already. */
1466 if (ndrawn < 4)
1468 #ifndef ROCKBOX
1469 sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
1470 basey + yloc + yval + wval));
1471 sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
1472 basey + yloc + yval - wval));
1473 #endif
1475 ouch:
1476 #ifdef ROCKBOX
1478 #else /* ROCKBOX */
1479 sys_vgui(" -width 1 -fill %s -outline %s\\\n", outline, outline);
1480 if (x->x_flags & BEZ) sys_vgui("-smooth 1\\\n");
1482 sys_vgui("-tags plot%x\n", data);
1483 #endif /* ROCKBOX */
1485 else if (linewidth > 0)
1487 /* no "w" field. If the linewidth is positive, draw a
1488 segmented line with the requested width; otherwise don't
1489 draw the trace at all. */
1490 #ifndef ROCKBOX
1491 sys_vgui(".x%x.c create line \\\n", glist_getcanvas(glist));
1492 #endif
1494 for (xsum = xloc, i = 0; i < nelem; i++)
1496 float usexloc;
1497 if (xonset >= 0)
1498 usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
1499 else usexloc = xsum, xsum += xinc;
1500 if (yonset >= 0)
1501 yval = *(float *)((elem + elemsize * i) + yonset);
1502 else yval = 0;
1503 xpix = glist_xtopixels(glist, basex + usexloc);
1504 ixpix = xpix + 0.5;
1505 if (xonset >= 0 || ixpix != lastpixel)
1507 #ifndef ROCKBOX
1508 sys_vgui("%d %f \\\n", ixpix,
1509 glist_ytopixels(glist, basey + yloc + yval));
1510 #endif
1511 ndrawn++;
1513 lastpixel = ixpix;
1514 if (ndrawn >= 1000) break;
1516 /* TK will complain if there aren't at least 2 points... */
1517 #ifndef ROCKBOX
1518 if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n");
1519 else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix + 10,
1520 glist_ytopixels(glist, basey + yloc + yval));
1522 sys_vgui("-width %f\\\n", linewidth);
1523 sys_vgui("-fill %s\\\n", outline);
1524 if (x->x_flags & BEZ) sys_vgui("-smooth 1\\\n");
1526 sys_vgui("-tags plot%x\n", data);
1527 #endif
1529 /* We're done with the outline; now draw all the points.
1530 This code is inefficient since the template has to be
1531 searched for drawing instructions for every last point. */
1533 for (xsum = xloc, i = 0; i < nelem; i++)
1535 float usexloc, useyloc;
1536 t_gobj *y;
1537 if (xonset >= 0)
1538 usexloc = basex + xloc +
1539 *(float *)((elem + elemsize * i) + xonset);
1540 else usexloc = basex + xsum, xsum += xinc;
1541 if (yonset >= 0)
1542 yval = *(float *)((elem + elemsize * i) + yonset);
1543 else yval = 0;
1544 useyloc = basey + yloc + yval;
1545 for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
1547 t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
1548 if (!wb) continue;
1549 (*wb->w_parentvisfn)(y, glist,
1550 (t_word *)(elem + elemsize * i),
1551 elemtemplate, usexloc, useyloc, vis);
1555 else
1557 /* un-draw the individual points */
1558 int i;
1559 for (i = 0; i < nelem; i++)
1561 t_gobj *y;
1562 for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
1564 t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
1565 if (!wb) continue;
1566 (*wb->w_parentvisfn)(y, glist,
1567 (t_word *)(elem + elemsize * i), elemtemplate,
1568 0, 0, 0);
1571 /* and then the trace */
1572 #ifndef ROCKBOX
1573 sys_vgui(".x%x.c delete plot%x\n",
1574 glist_getcanvas(glist), data);
1575 #endif
1580 static int plot_click(t_gobj *z, t_glist *glist,
1581 t_scalar *sc, t_template *template, float basex, float basey,
1582 int xpix, int ypix, int shift, int alt, int dbl, int doit)
1584 t_plot *x = (t_plot *)z;
1585 t_symbol *elemtemplatesym;
1586 float linewidth, xloc, xinc, yloc;
1587 t_array *array;
1588 t_word *data = sc->sc_vec;
1590 if (!plot_readownertemplate(x, data, template,
1591 &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc))
1593 return (array_doclick(array, glist, &sc->sc_gobj,
1594 elemtemplatesym,
1595 linewidth, basex + xloc, xinc, basey + yloc,
1596 xpix, ypix, shift, alt, dbl, doit));
1598 else return (0);
1601 t_parentwidgetbehavior plot_widgetbehavior =
1603 plot_getrect,
1604 plot_displace,
1605 plot_select,
1606 plot_activate,
1607 plot_vis,
1608 plot_click,
1611 static void plot_setup(void)
1613 plot_class = class_new(gensym("plot"), (t_newmethod)plot_new, 0,
1614 sizeof(t_plot), CLASS_NOINLET, A_GIMME, 0);
1615 class_setdrawcommand(plot_class);
1616 class_setparentwidget(plot_class, &plot_widgetbehavior);
1619 /* ---------------- drawnumber: draw a number ---------------- */
1622 drawnumbers draw numeric fields at controllable locations, with
1623 controllable color and label .
1624 invocation: (drawnumber|drawsymbol) variable x y color label
1627 t_class *drawnumber_class;
1629 #define DRAW_SYMBOL 1
1631 typedef struct _drawnumber
1633 t_object x_obj;
1634 t_fielddesc x_value;
1635 t_fielddesc x_xloc;
1636 t_fielddesc x_yloc;
1637 t_fielddesc x_color;
1638 t_symbol *x_label;
1639 int x_flags;
1640 } t_drawnumber;
1642 static void *drawnumber_new(t_symbol *classsym, t_int argc, t_atom *argv)
1644 t_drawnumber *x = (t_drawnumber *)pd_new(drawnumber_class);
1645 char *classname = classsym->s_name;
1646 int flags = 0;
1647 if (classname[4] == 's')
1648 flags |= DRAW_SYMBOL;
1649 x->x_flags = flags;
1650 if (argc) fielddesc_setfloatarg(&x->x_value, argc--, argv++);
1651 else FIELDDESC_SETFLOAT(&x->x_value, 0);
1652 if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
1653 else FIELDDESC_SETFLOAT(&x->x_xloc, 0);
1654 if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
1655 else FIELDDESC_SETFLOAT(&x->x_yloc, 0);
1656 if (argc) fielddesc_setfloatarg(&x->x_color, argc--, argv++);
1657 else FIELDDESC_SETFLOAT(&x->x_color, 1);
1658 if (argc)
1659 x->x_label = atom_getsymbolarg(0, argc, argv);
1660 else x->x_label = &s_;
1662 return (x);
1665 /* -------------------- widget behavior for drawnumber ------------ */
1667 #define DRAWNUMBER_BUFSIZE 80
1668 static void drawnumber_sprintf(t_drawnumber *x, char *buf, t_atom *ap)
1670 int nchars;
1671 strncpy(buf, x->x_label->s_name, DRAWNUMBER_BUFSIZE);
1672 buf[DRAWNUMBER_BUFSIZE - 1] = 0;
1673 nchars = strlen(buf);
1674 atom_string(ap, buf + nchars, DRAWNUMBER_BUFSIZE - nchars);
1677 static void drawnumber_getrect(t_gobj *z, t_glist *glist,
1678 t_word *data, t_template *template, float basex, float basey,
1679 int *xp1, int *yp1, int *xp2, int *yp2)
1681 t_drawnumber *x = (t_drawnumber *)z;
1682 t_atom at;
1683 int xloc = glist_xtopixels(glist,
1684 basex + fielddesc_getfloat(&x->x_xloc, template, data, 0));
1685 int yloc = glist_ytopixels(glist,
1686 basey + fielddesc_getfloat(&x->x_yloc, template, data, 0));
1687 #ifdef ROCKBOX
1688 int fontwidth = 8, fontheight = 10;
1689 #else
1690 int font = glist_getfont(glist);
1691 int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
1692 #endif
1693 char buf[DRAWNUMBER_BUFSIZE];
1694 if (x->x_flags & DRAW_SYMBOL)
1695 SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
1696 else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
1697 drawnumber_sprintf(x, buf, &at);
1698 *xp1 = xloc;
1699 *yp1 = yloc;
1700 *xp2 = xloc + fontwidth * strlen(buf);
1701 *yp2 = yloc + fontheight;
1704 static void drawnumber_displace(t_gobj *z, t_glist *glist,
1705 t_word *data, t_template *template, float basex, float basey,
1706 int dx, int dy)
1708 #ifdef ROCKBOX
1709 (void) z;
1710 (void) glist;
1711 (void) data;
1712 (void) template;
1713 (void) basex;
1714 (void) basey;
1715 (void) dx;
1716 (void) dy;
1717 #endif
1718 /* refuse */
1721 static void drawnumber_select(t_gobj *z, t_glist *glist,
1722 t_word *data, t_template *template, float basex, float basey,
1723 int state)
1725 #ifdef ROCKBOX
1726 (void) z;
1727 (void) glist;
1728 (void) data;
1729 (void) template;
1730 (void) basex;
1731 (void) basey;
1732 #endif
1733 post("drawnumber_select %d", state);
1734 /* fill in later */
1737 static void drawnumber_activate(t_gobj *z, t_glist *glist,
1738 t_word *data, t_template *template, float basex, float basey,
1739 int state)
1741 #ifdef ROCKBOX
1742 (void) z;
1743 (void) glist;
1744 (void) data;
1745 (void) template;
1746 (void) basex;
1747 (void) basey;
1748 #endif
1749 post("drawnumber_activate %d", state);
1752 static void drawnumber_vis(t_gobj *z, t_glist *glist,
1753 t_word *data, t_template *template, float basex, float basey,
1754 int vis)
1756 t_drawnumber *x = (t_drawnumber *)z;
1758 #ifdef ROCKBOX
1759 (void) glist;
1760 (void) basex;
1761 (void) basey;
1762 #endif
1764 if (vis)
1766 t_atom at;
1767 #ifndef ROCKBOX
1768 int xloc = glist_xtopixels(glist,
1769 basex + fielddesc_getfloat(&x->x_xloc, template, data, 0));
1770 int yloc = glist_ytopixels(glist,
1771 basey + fielddesc_getfloat(&x->x_yloc, template, data, 0));
1772 #endif
1773 char colorstring[20], buf[DRAWNUMBER_BUFSIZE];
1774 numbertocolor(fielddesc_getfloat(&x->x_color, template, data, 1),
1775 colorstring);
1776 if (x->x_flags & DRAW_SYMBOL)
1777 SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
1778 else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
1779 drawnumber_sprintf(x, buf, &at);
1780 #ifndef ROCKBOX
1781 sys_vgui(".x%x.c create text %d %d -anchor nw -fill %s -text {%s}",
1782 glist_getcanvas(glist), xloc, yloc, colorstring, buf);
1783 sys_vgui(" -font -*-courier-bold--normal--%d-*",
1784 sys_hostfontsize(glist_getfont(glist)));
1785 sys_vgui(" -tags drawnumber%x\n", data);
1786 #endif
1788 #ifndef ROCKBOX
1789 else sys_vgui(".x%x.c delete drawnumber%x\n", glist_getcanvas(glist), data);
1790 #endif
1793 static float drawnumber_motion_ycumulative;
1794 static t_glist *drawnumber_motion_glist;
1795 static t_gobj *drawnumber_motion_gobj;
1796 static t_word *drawnumber_motion_wp;
1797 static t_template *drawnumber_motion_template;
1799 /* LATER protect against the template changing or the scalar disappearing
1800 probably by attaching a gpointer here ... */
1802 static void drawnumber_motion(void *z, t_floatarg dx, t_floatarg dy)
1804 t_drawnumber *x = (t_drawnumber *)z;
1805 t_fielddesc *f = &x->x_value;
1806 drawnumber_motion_ycumulative -= dy;
1807 #ifdef ROCKBOX
1808 (void) dx;
1809 #endif
1810 template_setfloat(drawnumber_motion_template,
1811 f->fd_un.fd_varsym,
1812 drawnumber_motion_wp,
1813 drawnumber_motion_ycumulative,
1815 glist_redrawitem(drawnumber_motion_glist, drawnumber_motion_gobj);
1818 static int drawnumber_click(t_gobj *z, t_glist *glist,
1819 t_scalar *sc, t_template *template, float basex, float basey,
1820 int xpix, int ypix, int shift, int alt, int dbl, int doit)
1822 t_drawnumber *x = (t_drawnumber *)z;
1823 int x1, y1, x2, y2;
1824 t_word *data = sc->sc_vec;
1825 #ifdef ROCKBOX
1826 (void) shift;
1827 (void) alt;
1828 (void) dbl;
1829 #endif
1830 drawnumber_getrect(z, glist,
1831 sc->sc_vec, template, basex, basey,
1832 &x1, &y1, &x2, &y2);
1833 if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2
1834 && x->x_value.fd_var)
1836 if (doit)
1838 drawnumber_motion_glist = glist;
1839 drawnumber_motion_gobj = &sc->sc_gobj;
1840 drawnumber_motion_wp = data;
1841 drawnumber_motion_template = template;
1842 drawnumber_motion_ycumulative =
1843 fielddesc_getfloat(&x->x_value, template, data, 0);
1844 glist_grab(glist, z, drawnumber_motion, 0, xpix, ypix);
1846 return (1);
1848 else return (0);
1851 t_parentwidgetbehavior drawnumber_widgetbehavior =
1853 drawnumber_getrect,
1854 drawnumber_displace,
1855 drawnumber_select,
1856 drawnumber_activate,
1857 drawnumber_vis,
1858 drawnumber_click,
1861 static void drawnumber_free(t_drawnumber *x)
1863 #ifdef ROCKBOX
1864 (void) x;
1865 #endif
1868 static void drawnumber_setup(void)
1870 drawnumber_class = class_new(gensym("drawnumber"),
1871 (t_newmethod)drawnumber_new, (t_method)drawnumber_free,
1872 sizeof(t_drawnumber), CLASS_NOINLET, A_GIMME, 0);
1873 class_setdrawcommand(drawnumber_class);
1874 class_addcreator((t_newmethod)drawnumber_new, gensym("drawsymbol"),
1875 A_GIMME, 0);
1876 class_setparentwidget(drawnumber_class, &drawnumber_widgetbehavior);
1879 /* ---------------------- setup function ---------------------------- */
1881 void g_template_setup(void)
1883 template_setup();
1884 gtemplate_setup();
1885 template_float.t_pdobj = template_class;
1886 curve_setup();
1887 plot_setup();
1888 drawnumber_setup();