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. */
7 #include "../../pdbox.h"
11 #define snprintf rb->snprintf
18 #include "s_stuff.h" /* for sys_hostfontsize */
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
31 /* the structure of a "struct" object (also the obsolete "gtemplate"
32 you get when using the name "template" in a box.) */
37 t_template
*x_template
;
40 struct _gtemplate
*x_next
;
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
=
67 static t_template template_float
=
69 0, /* class -- fill in in setup routine */
70 0, /* list of "struct"/t_gtemplate objects */
72 1, /* number of items */
76 /* return true if two dataslot definitions match */
77 static int dataslot_matches(t_dataslot
*ds1
, t_dataslot
*ds2
,
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
);
92 x
->t_vec
= (t_dataslot
*)t_getbytes(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
)
100 newtypesym
= argv
[0].a_w
.w_symbol
;
101 newname
= argv
[1].a_w
.w_symbol
;
102 if (newtypesym
== &s_float
)
104 else if (newtypesym
== &s_symbol
)
106 else if (newtypesym
== &s_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");
115 newarraytemplate
= canvas_makebindsym(argv
[2].a_w
.w_symbol
);
122 pd_error(x
, "%s: no such type", newtypesym
->s_name
);
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
));
129 x
->t_vec
[oldn
].ds_type
= newtype
;
130 x
->t_vec
[oldn
].ds_name
= newname
;
131 x
->t_vec
[oldn
].ds_arraytemplate
= newarraytemplate
;
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
;
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
)
158 bug("template_find_field");
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
;
173 t_float
template_getfloat(t_template
*x
, t_symbol
*fieldname
, t_word
*wp
,
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
,
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
,
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
);
225 void template_setsymbol(t_template
*x
, t_symbol
*fieldname
, t_word
*wp
,
226 t_symbol
*s
, int loud
)
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
)
247 if (x1
->t_n
< x2
->t_n
)
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
)
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))
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
)
277 int nto
= tto
->t_n
, i
;
281 int nfrom
= tfrom
->t_n
, nto
= tto
->t_n
, i
;
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
)
305 int nto
= tto
->t_n
, nfrom
= tfrom
->t_n
, i
;
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. */
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
;
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
;
342 bug("template_conformscalar");
345 /* burn the old one */
346 pd_free(&scfrom
->sc_gobj
.g_pd
);
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
);
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
)
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
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
)
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;
451 else for (i
= 0; i
< nto
; i
++)
452 if (conformaction
[i
] != i
)
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
)
475 return (&template_float
);
476 else return ((t_template
*)pd_findbyclass(s
, template_class
));
479 t_canvas
*template_findcanvas(t_template
*template)
483 bug("template_findcanvas");
484 if (!(gt
= template->t_list
))
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
)
501 t_symbol
*templatesym
=
502 canvas_makebindsym(atom_getsymbolarg(0, 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? */
521 /* don't know what to do here! */
522 error("%s: template mismatch",
523 templatesym
->s_name
);
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
);
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
);
571 t_symbol
*sx
= gensym("x");
573 x
->x_owner
= canvas_getcurrent();
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? */
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
590 t_gtemplate
*x2
, *x3
;
591 for(x2
= x
->x_template
->t_list
; (x3
= x2
->x_next
); x2
= x3
)
594 post("template %s: warning: already exists.", sym
->s_name
);
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
);
616 /* otherwise make a new one and we're the only struct on it. */
617 x
->x_template
= t
= template_new(sym
, argc
, argv
);
623 static void *gtemplate_new(t_symbol
*s
, int argc
, t_atom
*argv
)
626 t_gtemplate
*x
= (t_gtemplate
*)pd_new(gtemplate_class
);
628 t_symbol
*sym
= atom_getsymbolarg(0, argc
, argv
);
634 return (gtemplate_donew(canvas_makebindsym(sym
), argc
, argv
));
637 /* old version (0.34) -- delete 2003 or so */
638 static void *gtemplate_new_old(t_symbol
*s
, int argc
, t_atom
*argv
)
641 t_gtemplate
*x
= (t_gtemplate
*)pd_new(gtemplate_class
);
643 t_symbol
*sym
= canvas_makebindsym(canvas_getcurrent()->gl_name
);
650 post("warning -- 'template' (%s) is obsolete; replace with 'struct'",
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
;
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
;
684 t_gtemplate
*x2
, *x3
;
685 for(x2
= t
->t_list
; (x3
= x2
->x_next
); x2
= x3
)
689 x2
->x_next
= x3
->x_next
;
694 freebytes(x
->x_argv
, sizeof(t_atom
) * x
->x_argc
);
697 static void gtemplate_setup(void)
699 gtemplate_class
= class_new(gensym("struct"),
700 (t_newmethod
)gtemplate_new
, (t_method
)gtemplate_free
,
701 sizeof(t_gtemplate
), CLASS_NOINLET
, A_GIMME
, 0);
702 class_addcreator((t_newmethod
)gtemplate_new_old
, gensym("template"),
706 /* --------------- FIELD DESCRIPTORS ---------------------- */
708 /* a field descriptor can hold a constant or a variable; if a variable,
709 it's the name of a field in the template we belong to. LATER, we might
710 want to cache the offset of the field so we don't have to search for it
711 every single time we draw the object.
714 typedef struct _fielddesc
716 char fd_type
; /* LATER consider removing this? */
720 t_float fd_float
; /* the field is a constant float */
721 t_symbol
*fd_symbol
; /* the field is a constant symbol */
722 t_symbol
*fd_varsym
; /* the field is variable and this is the name */
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))
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
)
759 return (template_getfloat(template, f
->fd_un
.fd_varsym
, wp
, loud
));
760 else return (f
->fd_un
.fd_float
);
765 error("symbolic data field used as number");
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
)
776 return(template_getsymbol(template, f
->fd_un
.fd_varsym
, wp
, loud
));
777 else return (f
->fd_un
.fd_symbol
);
782 error("numeric data field used as symbol");
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
800 int x_flags
; /* CLOSED and/or BEZ */
801 t_fielddesc x_fillcolor
;
802 t_fielddesc x_outlinecolor
;
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
;
815 if (classname
[0] == 'f')
819 if (argc
) fielddesc_setfloatarg(&x
->x_fillcolor
, argc
--, argv
++);
820 else FIELDDESC_SETFLOAT(&x
->x_outlinecolor
, 0);
823 if (classname
[0] == 'c') flags
|= BEZ
;
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);
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
;
867 static void curve_displace(t_gobj
*z
, t_glist
*glist
,
868 t_word
*data
, t_template
*template, float basex
, float basey
,
884 static void curve_select(t_gobj
*z
, t_glist
*glist
,
885 t_word
*data
, t_template
*template, float basex
, float basey
,
900 static void curve_activate(t_gobj
*z
, t_glist
*glist
,
901 t_word
*data
, t_template
*template, float basex
, float basey
,
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;
924 static void numbertocolor(int n
, char *s
)
926 int red
, blue
, green
;
929 blue
= ((n
/ 10) % 10);
932 snprintf(s
, 10, "#%2.2x%2.2x%2.2x",
933 rangecolor(red
), rangecolor(blue
), rangecolor(green
));
935 sprintf(s
, "#%2.2x%2.2x%2.2x", rangecolor(red
), rangecolor(blue
),
940 static void curve_vis(t_gobj
*z
, t_glist
*glist
,
941 t_word
*data
, t_template
*template, float basex
, float basey
,
944 t_curve
*x
= (t_curve
*)z
;
945 int i
, n
= x
->x_npoints
;
946 t_fielddesc
*f
= x
->x_vec
;
959 int flags
= x
->x_flags
;
961 int flags
= x
->x_flags
, closed
= (flags
& CLOSED
);
963 float width
= fielddesc_getfloat(&x
->x_width
, template, data
, 1);
964 char outline
[20], fill
[20];
965 if (width
< 1) width
= 1;
967 fielddesc_getfloat(&x
->x_outlinecolor
, template, data
, 1),
972 fielddesc_getfloat(&x
->x_fillcolor
, template, data
, 1),
975 sys_vgui(".x%x.c create polygon\\\n",
976 glist_getcanvas(glist
));
980 else sys_vgui(".x%x.c create line\\\n",
981 glist_getcanvas(glist
));
983 for (i
= 0, f
= x
->x_vec
; i
< n
; i
++, f
+= 2)
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
);
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",
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
);
1003 else post("warning: curves need at least two points to be graphed");
1008 if (n
> 1) sys_vgui(".x%x.c delete curve%x\n",
1009 glist_getcanvas(glist
), data
);
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
;
1037 template_setfloat(curve_motion_template
,
1040 curve_motion_xbase
+ curve_motion_xcumulative
* curve_motion_xper
,
1045 template_setfloat(curve_motion_template
,
1046 (f
+1)->fd_un
.fd_varsym
,
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
;
1061 int besterror
= 0x7fffffff;
1062 t_fielddesc
*f
= x
->x_vec
;
1063 t_word
*data
= sc
->sc_vec
;
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
)
1086 if (xerr
< besterror
)
1090 curve_motion_xbase
= fielddesc_getfloat(f
, template, data
, 0);
1091 curve_motion_ybase
= fielddesc_getfloat(f
+1, template, data
, 0);
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
);
1113 t_parentwidgetbehavior curve_widgetbehavior
=
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"),
1135 class_addcreator((t_newmethod
)curve_new
, gensym("filledpolygon"),
1137 class_addcreator((t_newmethod
)curve_new
, gensym("filledcurve"),
1139 class_setparentwidget(curve_class
, &curve_widgetbehavior
);
1142 /* --------- plots for showing arrays --------------- */
1144 t_class
*plot_class
;
1146 typedef struct _plot
1150 t_fielddesc x_outlinecolor
;
1151 t_fielddesc x_width
;
1158 static void *plot_new(t_symbol
*classsym
, t_int argc
, t_atom
*argv
)
1160 t_plot
*x
= (t_plot
*)pd_new(plot_class
);
1166 t_symbol
*firstarg
= atom_getsymbolarg(0, argc
, argv
);
1172 if (!strcmp(firstarg
->s_name
, "curve"))
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);
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
;
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");
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
);
1219 if (type
!= DT_ARRAY
)
1221 error("plot: %s: not an array", x
->x_data
.fd_un
.fd_varsym
->s_name
);
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
;
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
)
1242 int elemsize
, yonset
, wonset
, xonset
, type
;
1244 int arrayonset
, elemsize
, yonset
, wonset
, xonset
, type
;
1246 t_template
*elemtemplate
;
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
1254 if (!(elemtemplate
= template_findbyname(elemtemplatesym
)))
1256 error("plot: %s: no such template", elemtemplatesym
->s_name
);
1259 if (!((elemtemplatesym
== &s_float
) ||
1260 (elemtemplatecanvas
= template_findcanvas(elemtemplate
))))
1262 error("plot: %s: no canvas for this template", elemtemplatesym
->s_name
);
1265 elemsize
= elemtemplate
->t_n
* sizeof(t_word
);
1266 if (!template_find_field(elemtemplate
, gensym("y"), &yonset
, &type
, &dummy
)
1267 || type
!= DT_FLOAT
)
1269 if (!template_find_field(elemtemplate
, gensym("x"), &xonset
, &type
, &dummy
)
1270 || type
!= DT_FLOAT
)
1272 if (!template_find_field(elemtemplate
, gensym("w"), &wonset
, &type
, &dummy
)
1273 || type
!= DT_FLOAT
)
1276 /* fill in slots for return values */
1277 *elemtemplatecanvasp
= elemtemplatecanvas
;
1278 *elemtemplatep
= elemtemplate
;
1279 *elemsizep
= elemsize
;
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
;
1297 float x1
= 0x7fffffff, y1
= 0x7fffffff, x2
= -0x7fffffff, y2
= -0x7fffffff;
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
);
1315 if (ypix
- wpix
< y1
)
1317 if (ypix
+ wpix
> y2
)
1328 static void plot_displace(t_gobj
*z
, t_glist
*glist
,
1329 t_word
*data
, t_template
*template, float basex
, float basey
,
1345 static void plot_select(t_gobj
*z
, t_glist
*glist
,
1346 t_word
*data
, t_template
*template, float basex
, float basey
,
1361 static void plot_activate(t_gobj
*z
, t_glist
*glist
,
1362 t_word
*data
, t_template
*template, float basex
, float basey
,
1377 static void plot_vis(t_gobj
*z
, t_glist
*glist
,
1378 t_word
*data
, t_template
*template, float basex
, float basey
,
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
;
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
))
1396 elem
= (char *)array
->a_vec
;
1400 int lastpixel
= -1, ndrawn
= 0;
1401 float xsum
, yval
= 0, wval
= 0, xpix
;
1404 /* draw the trace */
1405 numbertocolor(fielddesc_getfloat(&x
->x_outlinecolor
, template, data
, 1),
1409 /* found "w" field which controls linewidth. The trace is
1410 a filled polygon with 2n points. */
1412 sys_vgui(".x%x.c create polygon \\\n",
1413 glist_getcanvas(glist
));
1416 for (i
= 0, xsum
= xloc
; i
< nelem
; i
++)
1420 usexloc
= xloc
+ *(float *)((elem
+ elemsize
* i
) + xonset
);
1421 else usexloc
= xsum
, xsum
+= xinc
;
1423 yval
= *(float *)((elem
+ elemsize
* i
) + yonset
);
1425 wval
= *(float *)((elem
+ elemsize
* i
) + wonset
);
1426 xpix
= glist_xtopixels(glist
, basex
+ usexloc
);
1428 if (xonset
>= 0 || ixpix
!= lastpixel
)
1431 sys_vgui("%d %f \\\n", ixpix
,
1432 glist_ytopixels(glist
,
1433 basey
+ yloc
+ yval
- wval
));
1438 if (ndrawn
>= 1000) goto ouch
;
1441 for (i
= nelem
-1; i
>= 0; i
--)
1445 usexloc
= xloc
+ *(float *)((elem
+ elemsize
* i
) + xonset
);
1446 else xsum
-= xinc
, usexloc
= xsum
;
1448 yval
= *(float *)((elem
+ elemsize
* i
) + yonset
);
1450 wval
= *(float *)((elem
+ elemsize
* i
) + wonset
);
1451 xpix
= glist_xtopixels(glist
, basex
+ usexloc
);
1453 if (xonset
>= 0 || ixpix
!= lastpixel
)
1456 sys_vgui("%d %f \\\n", ixpix
, glist_ytopixels(glist
,
1457 basey
+ yloc
+ yval
+ wval
));
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. */
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
));
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. */
1491 sys_vgui(".x%x.c create line \\\n", glist_getcanvas(glist
));
1494 for (xsum
= xloc
, i
= 0; i
< nelem
; i
++)
1498 usexloc
= xloc
+ *(float *)((elem
+ elemsize
* i
) + xonset
);
1499 else usexloc
= xsum
, xsum
+= xinc
;
1501 yval
= *(float *)((elem
+ elemsize
* i
) + yonset
);
1503 xpix
= glist_xtopixels(glist
, basex
+ usexloc
);
1505 if (xonset
>= 0 || ixpix
!= lastpixel
)
1508 sys_vgui("%d %f \\\n", ixpix
,
1509 glist_ytopixels(glist
, basey
+ yloc
+ yval
));
1514 if (ndrawn
>= 1000) break;
1516 /* TK will complain if there aren't at least 2 points... */
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
);
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
;
1538 usexloc
= basex
+ xloc
+
1539 *(float *)((elem
+ elemsize
* i
) + xonset
);
1540 else usexloc
= basex
+ xsum
, xsum
+= xinc
;
1542 yval
= *(float *)((elem
+ elemsize
* i
) + yonset
);
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
);
1549 (*wb
->w_parentvisfn
)(y
, glist
,
1550 (t_word
*)(elem
+ elemsize
* i
),
1551 elemtemplate
, usexloc
, useyloc
, vis
);
1557 /* un-draw the individual points */
1559 for (i
= 0; i
< nelem
; i
++)
1562 for (y
= elemtemplatecanvas
->gl_list
; y
; y
= y
->g_next
)
1564 t_parentwidgetbehavior
*wb
= pd_getparentwidget(&y
->g_pd
);
1566 (*wb
->w_parentvisfn
)(y
, glist
,
1567 (t_word
*)(elem
+ elemsize
* i
), elemtemplate
,
1571 /* and then the trace */
1573 sys_vgui(".x%x.c delete plot%x\n",
1574 glist_getcanvas(glist
), data
);
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
;
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
,
1595 linewidth
, basex
+ xloc
, xinc
, basey
+ yloc
,
1596 xpix
, ypix
, shift
, alt
, dbl
, doit
));
1601 t_parentwidgetbehavior plot_widgetbehavior
=
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
1634 t_fielddesc x_value
;
1637 t_fielddesc x_color
;
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
;
1647 if (classname
[4] == 's')
1648 flags
|= DRAW_SYMBOL
;
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);
1659 x
->x_label
= atom_getsymbolarg(0, argc
, argv
);
1660 else x
->x_label
= &s_
;
1665 /* -------------------- widget behavior for drawnumber ------------ */
1667 #define DRAWNUMBER_BUFSIZE 80
1668 static void drawnumber_sprintf(t_drawnumber
*x
, char *buf
, t_atom
*ap
)
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
;
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));
1688 int fontwidth
= 8, fontheight
= 10;
1690 int font
= glist_getfont(glist
);
1691 int fontwidth
= sys_fontwidth(font
), fontheight
= sys_fontheight(font
);
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
);
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
,
1721 static void drawnumber_select(t_gobj
*z
, t_glist
*glist
,
1722 t_word
*data
, t_template
*template, float basex
, float basey
,
1733 post("drawnumber_select %d", state
);
1737 static void drawnumber_activate(t_gobj
*z
, t_glist
*glist
,
1738 t_word
*data
, t_template
*template, float basex
, float basey
,
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
,
1756 t_drawnumber
*x
= (t_drawnumber
*)z
;
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));
1773 char colorstring
[20], buf
[DRAWNUMBER_BUFSIZE
];
1774 numbertocolor(fielddesc_getfloat(&x
->x_color
, template, data
, 1),
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
);
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
);
1789 else sys_vgui(".x%x.c delete drawnumber%x\n", glist_getcanvas(glist
), data
);
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
;
1810 template_setfloat(drawnumber_motion_template
,
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
;
1824 t_word
*data
= sc
->sc_vec
;
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
)
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
);
1851 t_parentwidgetbehavior drawnumber_widgetbehavior
=
1854 drawnumber_displace
,
1856 drawnumber_activate
,
1861 static void drawnumber_free(t_drawnumber
*x
)
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"),
1876 class_setparentwidget(drawnumber_class
, &drawnumber_widgetbehavior
);
1879 /* ---------------------- setup function ---------------------------- */
1881 void g_template_setup(void)
1885 template_float
.t_pdobj
= template_class
;