1 /* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
10 #include "s_stuff.h" /* for sys_hostfontsize */
14 This file contains text objects you would put in a canvas to define a
15 template. Templates describe objects of type "array" (g_array.c) and
16 "scalar" (g_scalar.c).
19 /* T.Grill - changed the _template.t_pd member to t_pdobj to avoid name clashes
22 /* the structure of a "struct" object (also the obsolete "gtemplate"
23 you get when using the name "template" in a box.) */
28 t_template
*x_template
;
31 struct _gtemplate
*x_next
;
36 /* ---------------- forward definitions ---------------- */
38 static void template_conformarray(t_template
*tfrom
, t_template
*tto
,
39 int *conformaction
, t_array
*a
);
40 static void template_conformglist(t_template
*tfrom
, t_template
*tto
,
41 t_glist
*glist
, int *conformaction
);
43 /* ---------------------- storage ------------------------- */
45 static t_class
*gtemplate_class
;
46 static t_class
*template_class
;
48 /* there's a pre-defined "float" template. LATER should we bind this
49 to a symbol such as "pd-float"??? */
51 static t_dataslot template_float_vec
=
58 static t_template template_float
=
60 0, /* class -- fill in in setup routine */
61 0, /* list of "struct"/t_gtemplate objects */
63 1, /* number of items */
67 /* return true if two dataslot definitions match */
68 static int dataslot_matches(t_dataslot
*ds1
, t_dataslot
*ds2
,
71 return ((!nametoo
|| ds1
->ds_name
== ds2
->ds_name
) &&
72 ds1
->ds_type
== ds2
->ds_type
&&
73 (ds1
->ds_type
!= DT_ARRAY
||
74 ds1
->ds_arraytemplate
== ds2
->ds_arraytemplate
));
77 /* -- templates, the active ingredient in gtemplates defined below. ------- */
79 t_template
*template_new(t_symbol
*templatesym
, int argc
, t_atom
*argv
)
81 t_template
*x
= (t_template
*)pd_new(template_class
);
83 x
->t_vec
= (t_dataslot
*)t_getbytes(0);
86 int newtype
, oldn
, newn
;
87 t_symbol
*newname
, *newarraytemplate
= &s_
, *newtypesym
;
88 if (argc
< 2 || argv
[0].a_type
!= A_SYMBOL
||
89 argv
[1].a_type
!= A_SYMBOL
)
91 newtypesym
= argv
[0].a_w
.w_symbol
;
92 newname
= argv
[1].a_w
.w_symbol
;
93 if (newtypesym
== &s_float
)
95 else if (newtypesym
== &s_symbol
)
97 else if (newtypesym
== &s_list
)
99 else if (newtypesym
== gensym("array"))
101 if (argc
< 3 || argv
[2].a_type
!= A_SYMBOL
)
103 pd_error(x
, "array lacks element template or name");
106 newarraytemplate
= canvas_makebindsym(argv
[2].a_w
.w_symbol
);
113 pd_error(x
, "%s: no such type", newtypesym
->s_name
);
116 newn
= (oldn
= x
->t_n
) + 1;
117 x
->t_vec
= (t_dataslot
*)t_resizebytes(x
->t_vec
,
118 oldn
* sizeof(*x
->t_vec
), newn
* sizeof(*x
->t_vec
));
120 x
->t_vec
[oldn
].ds_type
= newtype
;
121 x
->t_vec
[oldn
].ds_name
= newname
;
122 x
->t_vec
[oldn
].ds_arraytemplate
= newarraytemplate
;
124 argc
-= 2; argv
+= 2;
126 if (templatesym
->s_name
)
128 x
->t_sym
= templatesym
;
129 pd_bind(&x
->t_pdobj
, x
->t_sym
);
131 else x
->t_sym
= templatesym
;
135 int template_size(t_template
*x
)
137 return (x
->t_n
* sizeof(t_word
));
140 int template_find_field(t_template
*x
, t_symbol
*name
, int *p_onset
,
141 int *p_type
, t_symbol
**p_arraytype
)
147 bug("template_find_field");
151 for (i
= 0; i
< n
; i
++)
152 if (x
->t_vec
[i
].ds_name
== name
)
154 *p_onset
= i
* sizeof(t_word
);
155 *p_type
= x
->t_vec
[i
].ds_type
;
156 *p_arraytype
= x
->t_vec
[i
].ds_arraytemplate
;
162 t_float
template_getfloat(t_template
*x
, t_symbol
*fieldname
, t_word
*wp
,
168 if (template_find_field(x
, fieldname
, &onset
, &type
, &arraytype
))
170 if (type
== DT_FLOAT
)
171 val
= *(t_sample
*)(((char *)wp
) + onset
);
172 else if (loud
) error("%s.%s: not a number",
173 x
->t_sym
->s_name
, fieldname
->s_name
);
175 else if (loud
) error("%s.%s: no such field",
176 x
->t_sym
->s_name
, fieldname
->s_name
);
177 return (fixtof(val
));
180 void template_setfloat(t_template
*x
, t_symbol
*fieldname
, t_word
*wp
,
185 if (template_find_field(x
, fieldname
, &onset
, &type
, &arraytype
))
187 if (type
== DT_FLOAT
)
188 *(t_sample
*)(((char *)wp
) + onset
) = ftofix(f
);
189 else if (loud
) error("%s.%s: not a number",
190 x
->t_sym
->s_name
, fieldname
->s_name
);
192 else if (loud
) error("%s.%s: no such field",
193 x
->t_sym
->s_name
, fieldname
->s_name
);
196 t_symbol
*template_getsymbol(t_template
*x
, t_symbol
*fieldname
, t_word
*wp
,
202 if (template_find_field(x
, fieldname
, &onset
, &type
, &arraytype
))
204 if (type
== DT_SYMBOL
)
205 val
= *(t_symbol
**)(((char *)wp
) + onset
);
206 else if (loud
) error("%s.%s: not a symbol",
207 x
->t_sym
->s_name
, fieldname
->s_name
);
209 else if (loud
) error("%s.%s: no such field",
210 x
->t_sym
->s_name
, fieldname
->s_name
);
214 void template_setsymbol(t_template
*x
, t_symbol
*fieldname
, t_word
*wp
,
215 t_symbol
*s
, int loud
)
219 if (template_find_field(x
, fieldname
, &onset
, &type
, &arraytype
))
221 if (type
== DT_SYMBOL
)
222 *(t_symbol
**)(((char *)wp
) + onset
) = s
;
223 else if (loud
) error("%s.%s: not a symbol",
224 x
->t_sym
->s_name
, fieldname
->s_name
);
226 else if (loud
) error("%s.%s: no such field",
227 x
->t_sym
->s_name
, fieldname
->s_name
);
230 /* stringent check to see if a "saved" template, x2, matches the current
231 one (x1). It's OK if x1 has additional scalar elements but not (yet)
232 arrays or lists. This is used for reading in "data files". */
233 int template_match(t_template
*x1
, t_template
*x2
)
236 if (x1
->t_n
< x2
->t_n
)
238 for (i
= x2
->t_n
; i
< x1
->t_n
; i
++)
240 if (x1
->t_vec
[i
].ds_type
== DT_ARRAY
||
241 x1
->t_vec
[i
].ds_type
== DT_LIST
)
244 if (x2
->t_n
> x1
->t_n
)
245 post("add elements...");
246 for (i
= 0; i
< x2
->t_n
; i
++)
247 if (!dataslot_matches(&x1
->t_vec
[i
], &x2
->t_vec
[i
], 1))
252 /* --------------- CONFORMING TO CHANGES IN A TEMPLATE ------------ */
254 /* the following routines handle updating scalars to agree with changes
255 in their template. The old template is assumed to be the "installed" one
256 so we can delete old items; but making new ones we have to avoid scalar_new
257 which would make an old one whereas we will want a new one (but whose array
258 elements might still be old ones.
259 LATER deal with graphics updates too... */
261 /* conform the word vector of a scalar to the new template */
262 static void template_conformwords(t_template
*tfrom
, t_template
*tto
,
263 int *conformaction
, t_word
*wfrom
, t_word
*wto
)
265 int nfrom
= tfrom
->t_n
, nto
= tto
->t_n
, i
;
266 for (i
= 0; i
< nto
; i
++)
268 if (conformaction
[i
] >= 0)
270 /* we swap the two, in case it's an array or list, so that
271 when "wfrom" is deleted the old one gets cleaned up. */
272 t_word wwas
= wto
[i
];
273 wto
[i
] = wfrom
[conformaction
[i
]];
274 wfrom
[conformaction
[i
]] = wwas
;
279 /* conform a scalar, recursively conforming sublists and arrays */
280 static t_scalar
*template_conformscalar(t_template
*tfrom
, t_template
*tto
,
281 int *conformaction
, t_glist
*glist
, t_scalar
*scfrom
)
285 int nto
= tto
->t_n
, nfrom
= tfrom
->t_n
, i
;
286 t_template
*scalartemplate
;
287 /* post("conform scalar"); */
288 /* possibly replace the scalar */
289 if (scfrom
->sc_template
== tfrom
->t_sym
)
291 /* see scalar_new() for comment about the gpointer. */
293 x
= (t_scalar
*)getbytes(sizeof(t_scalar
) +
294 (tto
->t_n
- 1) * sizeof(*x
->sc_vec
));
295 x
->sc_gobj
.g_pd
= scalar_class
;
296 x
->sc_template
= tfrom
->t_sym
;
297 gpointer_setglist(&gp
, glist
, x
);
298 /* Here we initialize to the new template, but array and list
299 elements will still belong to old template. */
300 word_init(x
->sc_vec
, tto
, &gp
);
302 template_conformwords(tfrom
, tto
, conformaction
,
303 scfrom
->sc_vec
, x
->sc_vec
);
305 /* replace the old one with the new one in the list */
306 if (glist
->gl_list
== &scfrom
->sc_gobj
)
308 glist
->gl_list
= &x
->sc_gobj
;
309 x
->sc_gobj
.g_next
= scfrom
->sc_gobj
.g_next
;
314 for (y
= glist
->gl_list
; y2
= y
->g_next
; y
= y2
)
315 if (y2
== &scfrom
->sc_gobj
)
317 x
->sc_gobj
.g_next
= y2
->g_next
;
318 y
->g_next
= &x
->sc_gobj
;
321 bug("template_conformscalar");
324 /* burn the old one */
325 pd_free(&scfrom
->sc_gobj
.g_pd
);
328 scalartemplate
= template_findbyname(x
->sc_template
);
329 /* convert all array elements and sublists */
330 for (i
= 0; i
< scalartemplate
->t_n
; i
++)
332 t_dataslot
*ds
= scalartemplate
->t_vec
+ i
;
333 if (ds
->ds_type
== DT_LIST
)
335 t_glist
*gl2
= x
->sc_vec
[i
].w_list
;
336 template_conformglist(tfrom
, tto
, gl2
, conformaction
);
338 else if (ds
->ds_type
== DT_ARRAY
)
340 template_conformarray(tfrom
, tto
, conformaction
,
341 x
->sc_vec
[i
].w_array
);
347 /* conform an array, recursively conforming sublists and arrays */
348 static void template_conformarray(t_template
*tfrom
, t_template
*tto
,
349 int *conformaction
, t_array
*a
)
352 if (a
->a_templatesym
== tfrom
->t_sym
)
354 /* the array elements must all be conformed */
355 int oldelemsize
= sizeof(t_word
) * tfrom
->t_n
,
356 newelemsize
= sizeof(t_word
) * tto
->t_n
;
357 char *newarray
= getbytes(sizeof(t_word
) * tto
->t_n
* a
->a_n
);
358 char *oldarray
= a
->a_vec
;
359 if (a
->a_elemsize
!= oldelemsize
)
360 bug("template_conformarray");
361 for (i
= 0; i
< a
->a_n
; i
++)
363 t_word
*wp
= (t_word
*)(newarray
+ newelemsize
* i
);
364 word_init(wp
, tto
, &a
->a_gp
);
365 template_conformwords(tfrom
, tto
, conformaction
,
366 (t_word
*)(oldarray
+ oldelemsize
* i
), wp
);
369 bug("template_conformarray: this part not written");
370 /* go through item by item conforming subarrays and sublists... */
373 /* this routine searches for every scalar in the glist that belongs
374 to the "from" template and makes it belong to the "to" template. Descend
376 We don't handle redrawing here; this is to be filled in LATER... */
378 static void template_conformglist(t_template
*tfrom
, t_template
*tto
,
379 t_glist
*glist
, int *conformaction
)
382 /* post("conform glist %s", glist->gl_name->s_name); */
383 for (g
= glist
->gl_list
; g
; g
= g
->g_next
)
385 if (pd_class(&g
->g_pd
) == scalar_class
)
386 g
= &template_conformscalar(tfrom
, tto
, conformaction
,
387 glist
, (t_scalar
*)g
)->sc_gobj
;
388 else if (pd_class(&g
->g_pd
) == canvas_class
)
389 template_conformglist(tfrom
, tto
, (t_glist
*)g
, conformaction
);
393 /* globally conform all scalars from one template to another */
394 void template_conform(t_template
*tfrom
, t_template
*tto
)
396 int nto
= tto
->t_n
, nfrom
= tfrom
->t_n
, i
, j
,
397 *conformaction
= (int *)getbytes(sizeof(int) * nto
),
398 *conformedfrom
= (int *)getbytes(sizeof(int) * nfrom
), doit
= 0;
399 for (i
= 0; i
< nto
; i
++)
400 conformaction
[i
] = -1;
401 for (i
= 0; i
< nfrom
; i
++)
402 conformedfrom
[i
] = 0;
403 for (i
= 0; i
< nto
; i
++)
405 t_dataslot
*dataslot
= &tto
->t_vec
[i
];
406 for (j
= 0; j
< nfrom
; j
++)
408 t_dataslot
*dataslot2
= &tfrom
->t_vec
[j
];
409 if (dataslot_matches(dataslot
, dataslot2
, 1))
411 conformaction
[i
] = j
;
412 conformedfrom
[j
] = 1;
416 for (i
= 0; i
< nto
; i
++)
417 if (conformaction
[i
] < 0)
419 t_dataslot
*dataslot
= &tto
->t_vec
[i
];
420 for (j
= 0; j
< nfrom
; j
++)
421 if (!conformedfrom
[j
] &&
422 dataslot_matches(dataslot
, &tfrom
->t_vec
[j
], 1))
424 conformaction
[i
] = j
;
425 conformedfrom
[j
] = 1;
430 else for (i
= 0; i
< nto
; i
++)
431 if (conformaction
[i
] != i
)
437 /* post("conforming template '%s' to new structure",
438 tfrom->t_sym->s_name);
439 for (i = 0; i < nto; i++)
440 post("... %d", conformaction[i]); */
441 for (gl
= canvas_list
; gl
; gl
= gl
->gl_next
)
442 template_conformglist(tfrom
, tto
, gl
, conformaction
);
444 freebytes(conformaction
, sizeof(int) * nto
);
445 freebytes(conformedfrom
, sizeof(int) * nfrom
);
448 t_template
*template_findbyname(t_symbol
*s
)
452 return (&template_float
);
453 else return ((t_template
*)pd_findbyclass(s
, template_class
));
456 t_canvas
*template_findcanvas(t_template
*template)
460 bug("template_findcanvas");
461 if (!(gt
= template->t_list
))
463 return (gt
->x_owner
);
464 /* return ((t_canvas *)pd_findbyclass(template->t_sym, canvas_class)); */
467 /* call this when reading a patch from a file to declare what templates
468 we'll need. If there's already a template, check if it matches.
469 If it doesn't it's still OK as long as there are no "struct" (gtemplate)
470 objects hanging from it; we just conform everyone to the new template.
471 If there are still struct objects belonging to the other template, we're
472 in trouble. LATER we'll figure out how to conform the new patch's objects
473 to the pre-existing struct. */
474 static void *template_usetemplate(void *dummy
, t_symbol
*s
,
475 int argc
, t_atom
*argv
)
478 t_symbol
*templatesym
=
479 canvas_makebindsym(atom_getsymbolarg(0, argc
, argv
));
483 /* check if there's already a template by this name. */
484 if ((x
= (t_template
*)pd_findbyclass(templatesym
, template_class
)))
486 t_template
*y
= template_new(&s_
, argc
, argv
);
487 /* If the new template is the same as the old one,
488 there's nothing to do. */
489 if (!template_match(x
, y
))
491 /* Are there "struct" objects upholding this template? */
494 /* don't know what to do here! */
495 error("%s: template mismatch",
496 templatesym
->s_name
);
500 /* conform everyone to the new template */
501 template_conform(x
, y
);
502 pd_free(&x
->t_pdobj
);
503 template_new(templatesym
, argc
, argv
);
506 pd_free(&y
->t_pdobj
);
508 /* otherwise, just make one. */
509 else template_new(templatesym
, argc
, argv
);
513 /* here we assume someone has already cleaned up all instances of this. */
514 void template_free(t_template
*x
)
516 if (*x
->t_sym
->s_name
)
517 pd_unbind(&x
->t_pdobj
, x
->t_sym
);
518 t_freebytes(x
->t_vec
, x
->t_n
* sizeof(*x
->t_vec
));
521 static void template_setup(void)
523 template_class
= class_new(gensym("template"), 0, (t_method
)template_free
,
524 sizeof(t_template
), CLASS_PD
, 0);
525 class_addmethod(pd_canvasmaker
, (t_method
)template_usetemplate
,
526 gensym("struct"), A_GIMME
, 0);
530 /* ---------------- gtemplates. One per canvas. ----------- */
532 /* this is a "text" object that searches for, and if necessary creates,
533 a "template" (above). Other objects in the canvas then can give drawing
534 instructions for the template. The template doesn't go away when the
535 gtemplate is deleted, so that you can replace it with
536 another one to add new fields, for example. */
538 static void *gtemplate_donew(t_symbol
*sym
, int argc
, t_atom
*argv
)
540 t_gtemplate
*x
= (t_gtemplate
*)pd_new(gtemplate_class
);
541 t_template
*t
= template_findbyname(sym
);
543 t_symbol
*sx
= gensym("x");
544 x
->x_owner
= canvas_getcurrent();
548 x
->x_argv
= (t_atom
*)getbytes(argc
* sizeof(t_atom
));
549 for (i
= 0; i
< argc
; i
++)
550 x
->x_argv
[i
] = argv
[i
];
552 /* already have a template by this name? */
556 /* if it's already got a "struct" or "gtemplate" object we
557 just tack this one to the end of the list and leave it
561 t_gtemplate
*x2
, *x3
;
562 for (x2
= x
->x_template
->t_list
; x3
= x2
->x_next
; x2
= x3
)
565 post("template %s: warning: already exists.", sym
->s_name
);
569 /* if there's none, we just replace the template with
570 our own and conform it. */
571 t_template
*y
= template_new(&s_
, argc
, argv
);
572 /* Unless the new template is different from the old one,
573 there's nothing to do. */
574 if (!template_match(t
, y
))
576 /* conform everyone to the new template */
577 template_conform(t
, y
);
578 pd_free(&t
->t_pdobj
);
579 t
= template_new(sym
, argc
, argv
);
581 pd_free(&y
->t_pdobj
);
587 /* otherwise make a new one and we're the only struct on it. */
588 x
->x_template
= t
= template_new(sym
, argc
, argv
);
594 static void *gtemplate_new(t_symbol
*s
, int argc
, t_atom
*argv
)
596 t_gtemplate
*x
= (t_gtemplate
*)pd_new(gtemplate_class
);
597 t_symbol
*sym
= atom_getsymbolarg(0, argc
, argv
);
600 return (gtemplate_donew(canvas_makebindsym(sym
), argc
, argv
));
603 /* old version (0.34) -- delete 2003 or so */
604 static void *gtemplate_new_old(t_symbol
*s
, int argc
, t_atom
*argv
)
606 t_gtemplate
*x
= (t_gtemplate
*)pd_new(gtemplate_class
);
607 t_symbol
*sym
= canvas_makebindsym(canvas_getcurrent()->gl_name
);
611 post("warning -- 'template' (%s) is obsolete; replace with 'struct'",
615 return (gtemplate_donew(sym
, argc
, argv
));
618 t_template
*gtemplate_get(t_gtemplate
*x
)
620 return (x
->x_template
);
623 static void gtemplate_free(t_gtemplate
*x
)
625 /* get off the template's list */
626 t_template
*t
= x
->x_template
;
631 /* if we were first on the list, and there are others on
632 the list, make a new template corresponding to the new
633 first-on-list and replace teh existing template with it. */
634 t_template
*z
= template_new(&s_
, x
->x_argc
, x
->x_argv
);
635 template_conform(t
, z
);
636 pd_free(&t
->t_pdobj
);
637 pd_free(&z
->t_pdobj
);
638 z
= template_new(x
->x_sym
, x
->x_argc
, x
->x_argv
);
639 z
->t_list
= x
->x_next
;
645 t_gtemplate
*x2
, *x3
;
646 for (x2
= t
->t_list
; x3
= x2
->x_next
; x2
= x3
)
650 x2
->x_next
= x3
->x_next
;
655 freebytes(x
->x_argv
, sizeof(t_atom
) * x
->x_argc
);
658 static void gtemplate_setup(void)
660 gtemplate_class
= class_new(gensym("struct"),
661 (t_newmethod
)gtemplate_new
, (t_method
)gtemplate_free
,
662 sizeof(t_gtemplate
), CLASS_NOINLET
, A_GIMME
, 0);
663 class_addcreator((t_newmethod
)gtemplate_new_old
, gensym("template"),
667 /* --------------- FIELD DESCRIPTORS ---------------------- */
669 /* a field descriptor can hold a constant or a variable; if a variable,
670 it's the name of a field in the template we belong to. LATER, we might
671 want to cache the offset of the field so we don't have to search for it
672 every single time we draw the object.
675 typedef struct _fielddesc
677 char fd_type
; /* LATER consider removing this? */
681 t_float fd_float
; /* the field is a constant float */
682 t_symbol
*fd_symbol
; /* the field is a constant symbol */
683 t_symbol
*fd_varsym
; /* the field is variable and this is the name */
687 #define FIELDDESC_SETFLOAT(x, f) \
688 ((x)->fd_type = A_FLOAT, (x)->fd_var = 0, (x)->fd_un.fd_float = (f))
689 #define FIELDDESC_SETSYMBOL(x, s) \
690 ((x)->fd_type = A_SYMBOL, (x)->fd_var = 0, (x)->fd_un.fd_symbol = (s))
691 #define FIELDDESC_SETVAR(x, s, type) \
692 ((x)->fd_type = type, (x)->fd_var = 1, (x)->fd_un.fd_varsym = (s))
696 #define A_ARRAY 55 /* LATER decide whether to enshrine this in m_pd.h */
698 static void fielddesc_setfloatarg(t_fielddesc
*fd
, int argc
, t_atom
*argv
)
700 if (argc
<= 0) FIELDDESC_SETFLOAT(fd
, 0);
701 else if (argv
->a_type
== A_SYMBOL
)
702 FIELDDESC_SETVAR(fd
, argv
->a_w
.w_symbol
, A_FLOAT
);
703 else FIELDDESC_SETFLOAT(fd
, argv
->a_w
.w_float
);
706 static void fielddesc_setarrayarg(t_fielddesc
*fd
, int argc
, t_atom
*argv
)
708 if (argc
<= 0) FIELDDESC_SETFLOAT(fd
, 0);
709 else if (argv
->a_type
== A_SYMBOL
)
710 FIELDDESC_SETVAR(fd
, argv
->a_w
.w_symbol
, A_ARRAY
);
711 else FIELDDESC_SETFLOAT(fd
, argv
->a_w
.w_float
);
714 static t_float
fielddesc_getfloat(t_fielddesc
*f
, t_template
*template,
715 t_word
*wp
, int loud
)
717 if (f
->fd_type
== A_FLOAT
)
720 return (template_getfloat(template, f
->fd_un
.fd_varsym
, wp
, loud
));
721 else return (f
->fd_un
.fd_float
);
726 error("symbolic data field used as number");
731 static t_symbol
*fielddesc_getsymbol(t_fielddesc
*f
, t_template
*template,
732 t_word
*wp
, int loud
)
734 if (f
->fd_type
== A_SYMBOL
)
737 return(template_getsymbol(template, f
->fd_un
.fd_varsym
, wp
, loud
));
738 else return (f
->fd_un
.fd_symbol
);
743 error("numeric data field used as symbol");
748 /* ---------------- curves and polygons (joined segments) ---------------- */
751 curves belong to templates and describe how the data in the template are to
752 be drawn. The coordinates of the curve (and other display features) can
753 be attached to fields in the template.
756 t_class
*curve_class
;
758 typedef struct _curve
761 int x_flags
; /* CLOSED and/or BEZ */
762 t_fielddesc x_fillcolor
;
763 t_fielddesc x_outlinecolor
;
769 static void *curve_new(t_symbol
*classsym
, t_int argc
, t_atom
*argv
)
771 t_curve
*x
= (t_curve
*)pd_new(curve_class
);
772 char *classname
= classsym
->s_name
;
776 if (classname
[0] == 'f')
780 if (argc
) fielddesc_setfloatarg(&x
->x_fillcolor
, argc
--, argv
++);
781 else FIELDDESC_SETFLOAT(&x
->x_outlinecolor
, 0);
784 if (classname
[0] == 'c') flags
|= BEZ
;
786 if (argc
) fielddesc_setfloatarg(&x
->x_outlinecolor
, argc
--, argv
++);
787 else FIELDDESC_SETFLOAT(&x
->x_outlinecolor
, 0);
788 if (argc
) fielddesc_setfloatarg(&x
->x_width
, argc
--, argv
++);
789 else FIELDDESC_SETFLOAT(&x
->x_width
, 1);
790 if (argc
< 0) argc
= 0;
791 nxy
= (argc
+ (argc
& 1));
792 x
->x_npoints
= (nxy
>>1);
793 x
->x_vec
= (t_fielddesc
*)t_getbytes(nxy
* sizeof(t_fielddesc
));
794 for (i
= 0, fd
= x
->x_vec
; i
< argc
; i
++, fd
++, argv
++)
795 fielddesc_setfloatarg(fd
, 1, argv
);
796 if (argc
& 1) FIELDDESC_SETFLOAT(fd
, 0);
801 /* -------------------- widget behavior for curve ------------ */
803 static void curve_getrect(t_gobj
*z
, t_glist
*glist
,
804 t_word
*data
, t_template
*template, float basex
, float basey
,
805 int *xp1
, int *yp1
, int *xp2
, int *yp2
)
807 t_curve
*x
= (t_curve
*)z
;
808 int i
, n
= x
->x_npoints
;
809 t_fielddesc
*f
= x
->x_vec
;
810 int x1
= 0x7fffffff, x2
= -0x7fffffff, y1
= 0x7fffffff, y2
= -0x7fffffff;
811 for (i
= 0, f
= x
->x_vec
; i
< n
; i
++, f
+= 2)
813 int xloc
= glist_xtopixels(glist
,
814 basex
+ fielddesc_getfloat(f
, template, data
, 0));
815 int yloc
= glist_ytopixels(glist
,
816 basey
+ fielddesc_getfloat(f
+1, template, data
, 0));
817 if (xloc
< x1
) x1
= xloc
;
818 if (xloc
> x2
) x2
= xloc
;
819 if (yloc
< y1
) y1
= yloc
;
820 if (yloc
> y2
) y2
= yloc
;
828 static void curve_displace(t_gobj
*z
, t_glist
*glist
,
829 t_word
*data
, t_template
*template, float basex
, float basey
,
835 static void curve_select(t_gobj
*z
, t_glist
*glist
,
836 t_word
*data
, t_template
*template, float basex
, float basey
,
842 static void curve_activate(t_gobj
*z
, t_glist
*glist
,
843 t_word
*data
, t_template
*template, float basex
, float basey
,
849 static int rangecolor(int n
) /* 0 to 9 in 5 steps */
851 int n2
= n
/2; /* 0 to 4 */
852 int ret
= (n2
<< 6); /* 0 to 256 in 5 steps */
853 if (ret
> 255) ret
= 255;
857 static void numbertocolor(int n
, char *s
)
859 int red
, blue
, green
;
862 blue
= ((n
/ 10) % 10);
864 sprintf(s
, "#%2.2x%2.2x%2.2x", rangecolor(red
), rangecolor(blue
),
868 static void curve_vis(t_gobj
*z
, t_glist
*glist
,
869 t_word
*data
, t_template
*template, float basex
, float basey
,
872 t_curve
*x
= (t_curve
*)z
;
873 int i
, n
= x
->x_npoints
;
874 t_fielddesc
*f
= x
->x_vec
;
880 int flags
= x
->x_flags
, closed
= (flags
& CLOSED
);
881 float width
= fielddesc_getfloat(&x
->x_width
, template, data
, 1);
882 char outline
[20], fill
[20];
883 if (width
< 1) width
= 1;
885 fielddesc_getfloat(&x
->x_outlinecolor
, template, data
, 1),
890 fielddesc_getfloat(&x
->x_fillcolor
, template, data
, 1),
892 sys_vgui(".x%x.c create polygon\\\n",
893 glist_getcanvas(glist
));
895 else sys_vgui(".x%x.c create line\\\n",
896 glist_getcanvas(glist
));
897 for (i
= 0, f
= x
->x_vec
; i
< n
; i
++, f
+= 2)
899 float xloc
= glist_xtopixels(glist
,
900 basex
+ fielddesc_getfloat(f
, template, data
, 1));
901 float yloc
= glist_ytopixels(glist
,
902 basey
+ fielddesc_getfloat(f
+1, template, data
, 1));
903 sys_vgui("%d %d\\\n", (int)xloc
, (int)yloc
);
905 sys_vgui("-width %f\\\n",
906 fielddesc_getfloat(&x
->x_width
, template, data
, 1));
907 if (flags
& CLOSED
) sys_vgui("-fill %s -outline %s\\\n",
909 else sys_vgui("-fill %s\\\n", outline
);
910 if (flags
& BEZ
) sys_vgui("-smooth 1\\\n");
911 sys_vgui("-tags curve%x\n", data
);
913 else post("warning: curves need at least two points to be graphed");
917 if (n
> 1) sys_vgui(".x%x.c delete curve%x\n",
918 glist_getcanvas(glist
), data
);
922 static int curve_motion_field
;
923 static float curve_motion_xcumulative
;
924 static float curve_motion_xbase
;
925 static float curve_motion_xper
;
926 static float curve_motion_ycumulative
;
927 static float curve_motion_ybase
;
928 static float curve_motion_yper
;
929 static t_glist
*curve_motion_glist
;
930 static t_gobj
*curve_motion_gobj
;
931 static t_word
*curve_motion_wp
;
932 static t_template
*curve_motion_template
;
934 /* LATER protect against the template changing or the scalar disappearing
935 probably by attaching a gpointer here ... */
937 static void curve_motion(void *z
, t_floatarg dx
, t_floatarg dy
)
939 t_curve
*x
= (t_curve
*)z
;
940 t_fielddesc
*f
= x
->x_vec
+ curve_motion_field
;
941 curve_motion_xcumulative
+= dx
;
942 curve_motion_ycumulative
+= dy
;
945 template_setfloat(curve_motion_template
,
948 curve_motion_xbase
+ curve_motion_xcumulative
* curve_motion_xper
,
953 template_setfloat(curve_motion_template
,
954 (f
+1)->fd_un
.fd_varsym
,
956 curve_motion_ybase
+ curve_motion_ycumulative
* curve_motion_yper
,
959 glist_redrawitem(curve_motion_glist
, curve_motion_gobj
);
962 static int curve_click(t_gobj
*z
, t_glist
*glist
,
963 t_scalar
*sc
, t_template
*template, float basex
, float basey
,
964 int xpix
, int ypix
, int shift
, int alt
, int dbl
, int doit
)
966 t_curve
*x
= (t_curve
*)z
;
967 int i
, n
= x
->x_npoints
;
969 int besterror
= 0x7fffffff;
970 t_fielddesc
*f
= x
->x_vec
;
971 t_word
*data
= sc
->sc_vec
;
972 for (i
= 0, f
= x
->x_vec
; i
< n
; i
++, f
+= 2)
974 int xloc
= glist_xtopixels(glist
,
975 basex
+ fielddesc_getfloat(f
, template, data
, 0));
976 int yloc
= glist_ytopixels(glist
,
977 basey
+ fielddesc_getfloat(f
+1, template, data
, 0));
978 int xerr
= xloc
- xpix
, yerr
= yloc
- ypix
;
979 if (!f
->fd_var
&& !(f
+1)->fd_var
)
987 if (xerr
< besterror
)
991 curve_motion_xbase
= fielddesc_getfloat(f
, template, data
, 0);
992 curve_motion_ybase
= fielddesc_getfloat(f
+1, template, data
, 0);
999 curve_motion_xper
= glist_pixelstox(glist
, 1)
1000 - glist_pixelstox(glist
, 0);
1001 curve_motion_yper
= glist_pixelstoy(glist
, 1)
1002 - glist_pixelstoy(glist
, 0);
1003 curve_motion_xcumulative
= curve_motion_ycumulative
= 0;
1004 curve_motion_glist
= glist
;
1005 curve_motion_gobj
= &sc
->sc_gobj
;
1006 curve_motion_wp
= data
;
1007 curve_motion_field
= 2*bestn
;
1008 curve_motion_template
= template;
1009 glist_grab(glist
, z
, curve_motion
, 0, xpix
, ypix
);
1014 t_parentwidgetbehavior curve_widgetbehavior
=
1024 static void curve_free(t_curve
*x
)
1026 t_freebytes(x
->x_vec
, 2 * x
->x_npoints
* sizeof(*x
->x_vec
));
1029 static void curve_setup(void)
1031 curve_class
= class_new(gensym("drawpolygon"), (t_newmethod
)curve_new
,
1032 (t_method
)curve_free
, sizeof(t_curve
), CLASS_NOINLET
, A_GIMME
, 0);
1033 class_setdrawcommand(curve_class
);
1034 class_addcreator((t_newmethod
)curve_new
, gensym("drawcurve"),
1036 class_addcreator((t_newmethod
)curve_new
, gensym("filledpolygon"),
1038 class_addcreator((t_newmethod
)curve_new
, gensym("filledcurve"),
1040 class_setparentwidget(curve_class
, &curve_widgetbehavior
);
1043 /* --------- plots for showing arrays --------------- */
1045 t_class
*plot_class
;
1047 typedef struct _plot
1051 t_fielddesc x_outlinecolor
;
1052 t_fielddesc x_width
;
1059 static void *plot_new(t_symbol
*classsym
, t_int argc
, t_atom
*argv
)
1061 t_plot
*x
= (t_plot
*)pd_new(plot_class
);
1065 t_symbol
*firstarg
= atom_getsymbolarg(0, argc
, argv
);
1066 if (!strcmp(firstarg
->s_name
, "curve"))
1071 if (argc
) fielddesc_setarrayarg(&x
->x_data
, argc
--, argv
++);
1072 else FIELDDESC_SETFLOAT(&x
->x_data
, 1);
1073 if (argc
) fielddesc_setfloatarg(&x
->x_outlinecolor
, argc
--, argv
++);
1074 else FIELDDESC_SETFLOAT(&x
->x_outlinecolor
, 0);
1075 if (argc
) fielddesc_setfloatarg(&x
->x_width
, argc
--, argv
++);
1076 else FIELDDESC_SETFLOAT(&x
->x_width
, 1);
1077 if (argc
) fielddesc_setfloatarg(&x
->x_xloc
, argc
--, argv
++);
1078 else FIELDDESC_SETFLOAT(&x
->x_xloc
, 1);
1079 if (argc
) fielddesc_setfloatarg(&x
->x_yloc
, argc
--, argv
++);
1080 else FIELDDESC_SETFLOAT(&x
->x_yloc
, 1);
1081 if (argc
) fielddesc_setfloatarg(&x
->x_xinc
, argc
--, argv
++);
1082 else FIELDDESC_SETFLOAT(&x
->x_xinc
, 1);
1087 /* -------------------- widget behavior for plot ------------ */
1090 /* get everything we'll need from the owner template of the array being
1091 plotted. Not used for garrays, but see below */
1092 static int plot_readownertemplate(t_plot
*x
,
1093 t_word
*data
, t_template
*ownertemplate
,
1094 t_symbol
**elemtemplatesymp
, t_array
**arrayp
,
1095 float *linewidthp
, float *xlocp
, float *xincp
, float *ylocp
)
1097 int arrayonset
, type
;
1098 t_symbol
*elemtemplatesym
;
1101 /* find the data and verify it's an array */
1102 if (x
->x_data
.fd_type
!= A_ARRAY
|| !x
->x_data
.fd_var
)
1104 error("plot: needs an array field");
1107 if (!template_find_field(ownertemplate
, x
->x_data
.fd_un
.fd_varsym
,
1108 &arrayonset
, &type
, &elemtemplatesym
))
1110 error("plot: %s: no such field", x
->x_data
.fd_un
.fd_varsym
->s_name
);
1113 if (type
!= DT_ARRAY
)
1115 error("plot: %s: not an array", x
->x_data
.fd_un
.fd_varsym
->s_name
);
1118 array
= *(t_array
**)(((char *)data
) + arrayonset
);
1119 *linewidthp
= fielddesc_getfloat(&x
->x_width
, ownertemplate
, data
, 1);
1120 *xlocp
= fielddesc_getfloat(&x
->x_xloc
, ownertemplate
, data
, 1);
1121 *xincp
= fielddesc_getfloat(&x
->x_xinc
, ownertemplate
, data
, 1);
1122 *ylocp
= fielddesc_getfloat(&x
->x_yloc
, ownertemplate
, data
, 1);
1123 *elemtemplatesymp
= elemtemplatesym
;
1128 /* get everything else you could possibly need about a plot,
1129 either for plot's own purposes or for plotting a "garray" */
1130 int array_getfields(t_symbol
*elemtemplatesym
,
1131 t_canvas
**elemtemplatecanvasp
,
1132 t_template
**elemtemplatep
, int *elemsizep
,
1133 int *xonsetp
, int *yonsetp
, int *wonsetp
)
1135 int arrayonset
, elemsize
, yonset
, wonset
, xonset
, type
;
1136 t_template
*elemtemplate
;
1138 t_canvas
*elemtemplatecanvas
= 0;
1140 /* the "float" template is special in not having to have a canvas;
1141 template_findbyname is hardwired to return a predefined
1144 if (!(elemtemplate
= template_findbyname(elemtemplatesym
)))
1146 error("plot: %s: no such template", elemtemplatesym
->s_name
);
1149 if (!((elemtemplatesym
== &s_float
) ||
1150 (elemtemplatecanvas
= template_findcanvas(elemtemplate
))))
1152 error("plot: %s: no canvas for this template", elemtemplatesym
->s_name
);
1155 elemsize
= elemtemplate
->t_n
* sizeof(t_word
);
1156 if (!template_find_field(elemtemplate
, gensym("y"), &yonset
, &type
, &dummy
)
1157 || type
!= DT_FLOAT
)
1159 if (!template_find_field(elemtemplate
, gensym("x"), &xonset
, &type
, &dummy
)
1160 || type
!= DT_FLOAT
)
1162 if (!template_find_field(elemtemplate
, gensym("w"), &wonset
, &type
, &dummy
)
1163 || type
!= DT_FLOAT
)
1166 /* fill in slots for return values */
1167 *elemtemplatecanvasp
= elemtemplatecanvas
;
1168 *elemtemplatep
= elemtemplate
;
1169 *elemsizep
= elemsize
;
1176 static void plot_getrect(t_gobj
*z
, t_glist
*glist
,
1177 t_word
*data
, t_template
*template, float basex
, float basey
,
1178 int *xp1
, int *yp1
, int *xp2
, int *yp2
)
1180 t_plot
*x
= (t_plot
*)z
;
1181 int elemsize
, yonset
, wonset
, xonset
;
1182 t_canvas
*elemtemplatecanvas
;
1183 t_template
*elemtemplate
;
1184 t_symbol
*elemtemplatesym
;
1185 float linewidth
, xloc
, xinc
, yloc
;
1187 float x1
= 0x7fffffff, y1
= 0x7fffffff, x2
= -0x7fffffff, y2
= -0x7fffffff;
1189 float xpix
, ypix
, wpix
;
1191 if (!plot_readownertemplate(x
, data
, template,
1192 &elemtemplatesym
, &array
, &linewidth
, &xloc
, &xinc
, &yloc
) &&
1193 !array_getfields(elemtemplatesym
, &elemtemplatecanvas
,
1194 &elemtemplate
, &elemsize
, &xonset
, &yonset
, &wonset
))
1196 for (i
= 0; i
< array
->a_n
; i
++)
1198 array_getcoordinate(glist
, (char *)(array
->a_vec
) + i
* elemsize
,
1199 xonset
, yonset
, wonset
, i
, basex
+ xloc
, basey
+ yloc
, xinc
,
1200 &xpix
, &ypix
, &wpix
);
1205 if (ypix
- wpix
< y1
)
1207 if (ypix
+ wpix
> y2
)
1218 static void plot_displace(t_gobj
*z
, t_glist
*glist
,
1219 t_word
*data
, t_template
*template, float basex
, float basey
,
1225 static void plot_select(t_gobj
*z
, t_glist
*glist
,
1226 t_word
*data
, t_template
*template, float basex
, float basey
,
1232 static void plot_activate(t_gobj
*z
, t_glist
*glist
,
1233 t_word
*data
, t_template
*template, float basex
, float basey
,
1239 static void plot_vis(t_gobj
*z
, t_glist
*glist
,
1240 t_word
*data
, t_template
*template, float basex
, float basey
,
1243 t_plot
*x
= (t_plot
*)z
;
1244 int elemsize
, yonset
, wonset
, xonset
;
1245 t_canvas
*elemtemplatecanvas
;
1246 t_template
*elemtemplate
;
1247 t_symbol
*elemtemplatesym
;
1248 float linewidth
, xloc
, xinc
, yloc
;
1252 if (plot_readownertemplate(x
, data
, template,
1253 &elemtemplatesym
, &array
, &linewidth
, &xloc
, &xinc
, &yloc
) ||
1254 array_getfields(elemtemplatesym
, &elemtemplatecanvas
,
1255 &elemtemplate
, &elemsize
, &xonset
, &yonset
, &wonset
))
1258 elem
= (char *)array
->a_vec
;
1262 int lastpixel
= -1, ndrawn
= 0;
1263 float xsum
, yval
= 0, wval
= 0, xpix
;
1266 /* draw the trace */
1267 numbertocolor(fielddesc_getfloat(&x
->x_outlinecolor
, template, data
, 1),
1271 /* found "w" field which controls linewidth. The trace is
1272 a filled polygon with 2n points. */
1273 sys_vgui(".x%x.c create polygon \\\n",
1274 glist_getcanvas(glist
));
1276 for (i
= 0, xsum
= xloc
; i
< nelem
; i
++)
1280 usexloc
= xloc
+ *(float *)((elem
+ elemsize
* i
) + xonset
);
1281 else usexloc
= xsum
, xsum
+= xinc
;
1283 yval
= *(float *)((elem
+ elemsize
* i
) + yonset
);
1285 wval
= *(float *)((elem
+ elemsize
* i
) + wonset
);
1286 xpix
= glist_xtopixels(glist
, basex
+ usexloc
);
1288 if (xonset
>= 0 || ixpix
!= lastpixel
)
1290 sys_vgui("%d %f \\\n", ixpix
,
1291 glist_ytopixels(glist
,
1292 basey
+ yloc
+ yval
- wval
));
1296 if (ndrawn
>= 1000) goto ouch
;
1299 for (i
= nelem
-1; i
>= 0; i
--)
1303 usexloc
= xloc
+ *(float *)((elem
+ elemsize
* i
) + xonset
);
1304 else xsum
-= xinc
, usexloc
= xsum
;
1306 yval
= *(float *)((elem
+ elemsize
* i
) + yonset
);
1308 wval
= *(float *)((elem
+ elemsize
* i
) + wonset
);
1309 xpix
= glist_xtopixels(glist
, basex
+ usexloc
);
1311 if (xonset
>= 0 || ixpix
!= lastpixel
)
1313 sys_vgui("%d %f \\\n", ixpix
, glist_ytopixels(glist
,
1314 basey
+ yloc
+ yval
+ wval
));
1318 if (ndrawn
>= 1000) goto ouch
;
1320 /* TK will complain if there aren't at least 3 points. There
1321 should be at least two already. */
1324 sys_vgui("%d %f \\\n", ixpix
+ 10, glist_ytopixels(glist
,
1325 basey
+ yloc
+ yval
+ wval
));
1326 sys_vgui("%d %f \\\n", ixpix
+ 10, glist_ytopixels(glist
,
1327 basey
+ yloc
+ yval
- wval
));
1330 sys_vgui(" -width 1 -fill %s -outline %s\\\n", outline
, outline
);
1331 if (x
->x_flags
& BEZ
) sys_vgui("-smooth 1\\\n");
1333 sys_vgui("-tags plot%x\n", data
);
1335 else if (linewidth
> 0)
1337 /* no "w" field. If the linewidth is positive, draw a
1338 segmented line with the requested width; otherwise don't
1339 draw the trace at all. */
1340 sys_vgui(".x%x.c create line \\\n", glist_getcanvas(glist
));
1342 for (xsum
= xloc
, i
= 0; i
< nelem
; i
++)
1346 usexloc
= xloc
+ *(float *)((elem
+ elemsize
* i
) + xonset
);
1347 else usexloc
= xsum
, xsum
+= xinc
;
1349 yval
= *(float *)((elem
+ elemsize
* i
) + yonset
);
1351 xpix
= glist_xtopixels(glist
, basex
+ usexloc
);
1353 if (xonset
>= 0 || ixpix
!= lastpixel
)
1355 sys_vgui("%d %f \\\n", ixpix
,
1356 glist_ytopixels(glist
, basey
+ yloc
+ yval
));
1360 if (ndrawn
>= 1000) break;
1362 /* TK will complain if there aren't at least 2 points... */
1363 if (ndrawn
== 0) sys_vgui("0 0 0 0 \\\n");
1364 else if (ndrawn
== 1) sys_vgui("%d %f \\\n", ixpix
+ 10,
1365 glist_ytopixels(glist
, basey
+ yloc
+ yval
));
1367 sys_vgui("-width %f\\\n", linewidth
);
1368 sys_vgui("-fill %s\\\n", outline
);
1369 if (x
->x_flags
& BEZ
) sys_vgui("-smooth 1\\\n");
1371 sys_vgui("-tags plot%x\n", data
);
1373 /* We're done with the outline; now draw all the points.
1374 This code is inefficient since the template has to be
1375 searched for drawing instructions for every last point. */
1377 for (xsum
= xloc
, i
= 0; i
< nelem
; i
++)
1379 float usexloc
, useyloc
;
1382 usexloc
= basex
+ xloc
+
1383 *(float *)((elem
+ elemsize
* i
) + xonset
);
1384 else usexloc
= basex
+ xsum
, xsum
+= xinc
;
1386 yval
= *(float *)((elem
+ elemsize
* i
) + yonset
);
1388 useyloc
= basey
+ yloc
+ yval
;
1389 for (y
= elemtemplatecanvas
->gl_list
; y
; y
= y
->g_next
)
1391 t_parentwidgetbehavior
*wb
= pd_getparentwidget(&y
->g_pd
);
1393 (*wb
->w_parentvisfn
)(y
, glist
,
1394 (t_word
*)(elem
+ elemsize
* i
),
1395 elemtemplate
, usexloc
, useyloc
, vis
);
1401 /* un-draw the individual points */
1403 for (i
= 0; i
< nelem
; i
++)
1406 for (y
= elemtemplatecanvas
->gl_list
; y
; y
= y
->g_next
)
1408 t_parentwidgetbehavior
*wb
= pd_getparentwidget(&y
->g_pd
);
1410 (*wb
->w_parentvisfn
)(y
, glist
,
1411 (t_word
*)(elem
+ elemsize
* i
), elemtemplate
,
1415 /* and then the trace */
1416 sys_vgui(".x%x.c delete plot%x\n",
1417 glist_getcanvas(glist
), data
);
1422 static int plot_click(t_gobj
*z
, t_glist
*glist
,
1423 t_scalar
*sc
, t_template
*template, float basex
, float basey
,
1424 int xpix
, int ypix
, int shift
, int alt
, int dbl
, int doit
)
1426 t_plot
*x
= (t_plot
*)z
;
1427 t_symbol
*elemtemplatesym
;
1428 float linewidth
, xloc
, xinc
, yloc
;
1430 t_word
*data
= sc
->sc_vec
;
1432 if (!plot_readownertemplate(x
, data
, template,
1433 &elemtemplatesym
, &array
, &linewidth
, &xloc
, &xinc
, &yloc
))
1435 return (array_doclick(array
, glist
, &sc
->sc_gobj
,
1437 linewidth
, basex
+ xloc
, xinc
, basey
+ yloc
,
1438 xpix
, ypix
, shift
, alt
, dbl
, doit
));
1443 t_parentwidgetbehavior plot_widgetbehavior
=
1453 static void plot_setup(void)
1455 plot_class
= class_new(gensym("plot"), (t_newmethod
)plot_new
, 0,
1456 sizeof(t_plot
), CLASS_NOINLET
, A_GIMME
, 0);
1457 class_setdrawcommand(plot_class
);
1458 class_setparentwidget(plot_class
, &plot_widgetbehavior
);
1461 /* ---------------- drawnumber: draw a number ---------------- */
1464 drawnumbers draw numeric fields at controllable locations, with
1465 controllable color and label .
1466 invocation: (drawnumber|drawsymbol) variable x y color label
1469 t_class
*drawnumber_class
;
1471 #define DRAW_SYMBOL 1
1473 typedef struct _drawnumber
1476 t_fielddesc x_value
;
1479 t_fielddesc x_color
;
1484 static void *drawnumber_new(t_symbol
*classsym
, t_int argc
, t_atom
*argv
)
1486 t_drawnumber
*x
= (t_drawnumber
*)pd_new(drawnumber_class
);
1487 char *classname
= classsym
->s_name
;
1489 if (classname
[4] == 's')
1490 flags
|= DRAW_SYMBOL
;
1492 if (argc
) fielddesc_setfloatarg(&x
->x_value
, argc
--, argv
++);
1493 else FIELDDESC_SETFLOAT(&x
->x_value
, 0);
1494 if (argc
) fielddesc_setfloatarg(&x
->x_xloc
, argc
--, argv
++);
1495 else FIELDDESC_SETFLOAT(&x
->x_xloc
, 0);
1496 if (argc
) fielddesc_setfloatarg(&x
->x_yloc
, argc
--, argv
++);
1497 else FIELDDESC_SETFLOAT(&x
->x_yloc
, 0);
1498 if (argc
) fielddesc_setfloatarg(&x
->x_color
, argc
--, argv
++);
1499 else FIELDDESC_SETFLOAT(&x
->x_color
, 1);
1501 x
->x_label
= atom_getsymbolarg(0, argc
, argv
);
1502 else x
->x_label
= &s_
;
1507 /* -------------------- widget behavior for drawnumber ------------ */
1509 #define DRAWNUMBER_BUFSIZE 80
1510 static void drawnumber_sprintf(t_drawnumber
*x
, char *buf
, t_atom
*ap
)
1513 strncpy(buf
, x
->x_label
->s_name
, DRAWNUMBER_BUFSIZE
);
1514 buf
[DRAWNUMBER_BUFSIZE
- 1] = 0;
1515 nchars
= strlen(buf
);
1516 atom_string(ap
, buf
+ nchars
, DRAWNUMBER_BUFSIZE
- nchars
);
1519 static void drawnumber_getrect(t_gobj
*z
, t_glist
*glist
,
1520 t_word
*data
, t_template
*template, float basex
, float basey
,
1521 int *xp1
, int *yp1
, int *xp2
, int *yp2
)
1523 t_drawnumber
*x
= (t_drawnumber
*)z
;
1525 int xloc
= glist_xtopixels(glist
,
1526 basex
+ fielddesc_getfloat(&x
->x_xloc
, template, data
, 0));
1527 int yloc
= glist_ytopixels(glist
,
1528 basey
+ fielddesc_getfloat(&x
->x_yloc
, template, data
, 0));
1529 int font
= glist_getfont(glist
);
1530 int fontwidth
= sys_fontwidth(font
), fontheight
= sys_fontheight(font
);
1531 char buf
[DRAWNUMBER_BUFSIZE
];
1532 if (x
->x_flags
& DRAW_SYMBOL
)
1533 SETSYMBOL(&at
, fielddesc_getsymbol(&x
->x_value
, template, data
, 0));
1534 else SETFLOAT(&at
, fielddesc_getfloat(&x
->x_value
, template, data
, 0));
1535 drawnumber_sprintf(x
, buf
, &at
);
1538 *xp2
= xloc
+ fontwidth
* strlen(buf
);
1539 *yp2
= yloc
+ fontheight
;
1542 static void drawnumber_displace(t_gobj
*z
, t_glist
*glist
,
1543 t_word
*data
, t_template
*template, float basex
, float basey
,
1549 static void drawnumber_select(t_gobj
*z
, t_glist
*glist
,
1550 t_word
*data
, t_template
*template, float basex
, float basey
,
1553 post("drawnumber_select %d", state
);
1557 static void drawnumber_activate(t_gobj
*z
, t_glist
*glist
,
1558 t_word
*data
, t_template
*template, float basex
, float basey
,
1561 post("drawnumber_activate %d", state
);
1564 static void drawnumber_vis(t_gobj
*z
, t_glist
*glist
,
1565 t_word
*data
, t_template
*template, float basex
, float basey
,
1568 t_drawnumber
*x
= (t_drawnumber
*)z
;
1573 int xloc
= glist_xtopixels(glist
,
1574 basex
+ fielddesc_getfloat(&x
->x_xloc
, template, data
, 0));
1575 int yloc
= glist_ytopixels(glist
,
1576 basey
+ fielddesc_getfloat(&x
->x_yloc
, template, data
, 0));
1577 char colorstring
[20], buf
[DRAWNUMBER_BUFSIZE
];
1578 numbertocolor(fielddesc_getfloat(&x
->x_color
, template, data
, 1),
1580 if (x
->x_flags
& DRAW_SYMBOL
)
1581 SETSYMBOL(&at
, fielddesc_getsymbol(&x
->x_value
, template, data
, 0));
1582 else SETFLOAT(&at
, fielddesc_getfloat(&x
->x_value
, template, data
, 0));
1583 drawnumber_sprintf(x
, buf
, &at
);
1584 sys_vgui(".x%x.c create text %d %d -anchor nw -fill %s -text {%s}",
1585 glist_getcanvas(glist
), xloc
, yloc
, colorstring
, buf
);
1586 sys_vgui(" -font -*-courier-bold--normal--%d-*",
1587 sys_hostfontsize(glist_getfont(glist
)));
1588 sys_vgui(" -tags drawnumber%x\n", data
);
1590 else sys_vgui(".x%x.c delete drawnumber%x\n", glist_getcanvas(glist
), data
);
1593 static float drawnumber_motion_ycumulative
;
1594 static t_glist
*drawnumber_motion_glist
;
1595 static t_gobj
*drawnumber_motion_gobj
;
1596 static t_word
*drawnumber_motion_wp
;
1597 static t_template
*drawnumber_motion_template
;
1599 /* LATER protect against the template changing or the scalar disappearing
1600 probably by attaching a gpointer here ... */
1602 static void drawnumber_motion(void *z
, t_floatarg dx
, t_floatarg dy
)
1604 t_drawnumber
*x
= (t_drawnumber
*)z
;
1605 t_fielddesc
*f
= &x
->x_value
;
1606 drawnumber_motion_ycumulative
-= dy
;
1607 template_setfloat(drawnumber_motion_template
,
1609 drawnumber_motion_wp
,
1610 drawnumber_motion_ycumulative
,
1612 glist_redrawitem(drawnumber_motion_glist
, drawnumber_motion_gobj
);
1615 static int drawnumber_click(t_gobj
*z
, t_glist
*glist
,
1616 t_scalar
*sc
, t_template
*template, float basex
, float basey
,
1617 int xpix
, int ypix
, int shift
, int alt
, int dbl
, int doit
)
1619 t_drawnumber
*x
= (t_drawnumber
*)z
;
1621 t_word
*data
= sc
->sc_vec
;
1622 drawnumber_getrect(z
, glist
,
1623 sc
->sc_vec
, template, basex
, basey
,
1624 &x1
, &y1
, &x2
, &y2
);
1625 if (xpix
>= x1
&& xpix
<= x2
&& ypix
>= y1
&& ypix
<= y2
1626 && x
->x_value
.fd_var
)
1630 drawnumber_motion_glist
= glist
;
1631 drawnumber_motion_gobj
= &sc
->sc_gobj
;
1632 drawnumber_motion_wp
= data
;
1633 drawnumber_motion_template
= template;
1634 drawnumber_motion_ycumulative
=
1635 fielddesc_getfloat(&x
->x_value
, template, data
, 0);
1636 glist_grab(glist
, z
, drawnumber_motion
, 0, xpix
, ypix
);
1643 t_parentwidgetbehavior drawnumber_widgetbehavior
=
1646 drawnumber_displace
,
1648 drawnumber_activate
,
1653 static void drawnumber_free(t_drawnumber
*x
)
1657 static void drawnumber_setup(void)
1659 drawnumber_class
= class_new(gensym("drawnumber"),
1660 (t_newmethod
)drawnumber_new
, (t_method
)drawnumber_free
,
1661 sizeof(t_drawnumber
), CLASS_NOINLET
, A_GIMME
, 0);
1662 class_setdrawcommand(drawnumber_class
);
1663 class_addcreator((t_newmethod
)drawnumber_new
, gensym("drawsymbol"),
1665 class_setparentwidget(drawnumber_class
, &drawnumber_widgetbehavior
);
1668 /* ---------------------- setup function ---------------------------- */
1670 void g_template_setup(void)
1674 template_float
.t_pdobj
= template_class
;
1680 /* Copyright (c) 1997-1999 Miller Puckette.
1681 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
1682 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1689 #include "s_stuff.h" /* for sys_hostfontsize */
1690 #include "g_canvas.h"
1693 This file contains text objects you would put in a canvas to define a
1694 template. Templates describe objects of type "array" (g_array.c) and
1695 "scalar" (g_scalar.c).
1698 /* T.Grill - changed the _template.t_pd member to t_pdobj to avoid name clashes
1699 with the t_pd type */
1701 /* the structure of a "struct" object (also the obsolete "gtemplate"
1702 you get when using the name "template" in a box.) */
1707 t_template
*x_template
;
1710 struct _gtemplate
*x_next
;
1715 /* ---------------- forward definitions ---------------- */
1717 static void template_conformarray(t_template
*tfrom
, t_template
*tto
,
1718 int *conformaction
, t_array
*a
);
1719 static void template_conformglist(t_template
*tfrom
, t_template
*tto
,
1720 t_glist
*glist
, int *conformaction
);
1722 /* ---------------------- storage ------------------------- */
1724 static t_class
*gtemplate_class
;
1725 static t_class
*template_class
;
1727 /* there's a pre-defined "float" template. LATER should we bind this
1728 to a symbol such as "pd-float"??? */
1730 static t_dataslot template_float_vec
=
1737 static t_template template_float
=
1739 0, /* class -- fill in in setup routine */
1740 0, /* list of "struct"/t_gtemplate objects */
1741 &s_float
, /* name */
1742 1, /* number of items */
1746 /* return true if two dataslot definitions match */
1747 static int dataslot_matches(t_dataslot
*ds1
, t_dataslot
*ds2
,
1750 return ((!nametoo
|| ds1
->ds_name
== ds2
->ds_name
) &&
1751 ds1
->ds_type
== ds2
->ds_type
&&
1752 (ds1
->ds_type
!= DT_ARRAY
||
1753 ds1
->ds_arraytemplate
== ds2
->ds_arraytemplate
));
1756 /* -- templates, the active ingredient in gtemplates defined below. ------- */
1758 t_template
*template_new(t_symbol
*templatesym
, int argc
, t_atom
*argv
)
1760 t_template
*x
= (t_template
*)pd_new(template_class
);
1762 x
->t_vec
= (t_dataslot
*)t_getbytes(0);
1765 int newtype
, oldn
, newn
;
1766 t_symbol
*newname
, *newarraytemplate
= &s_
, *newtypesym
;
1767 if (argc
< 2 || argv
[0].a_type
!= A_SYMBOL
||
1768 argv
[1].a_type
!= A_SYMBOL
)
1770 newtypesym
= argv
[0].a_w
.w_symbol
;
1771 newname
= argv
[1].a_w
.w_symbol
;
1772 if (newtypesym
== &s_float
)
1774 else if (newtypesym
== &s_symbol
)
1775 newtype
= DT_SYMBOL
;
1776 else if (newtypesym
== &s_list
)
1778 else if (newtypesym
== gensym("array"))
1780 if (argc
< 3 || argv
[2].a_type
!= A_SYMBOL
)
1782 pd_error(x
, "array lacks element template or name");
1785 newarraytemplate
= canvas_makebindsym(argv
[2].a_w
.w_symbol
);
1792 pd_error(x
, "%s: no such type", newtypesym
->s_name
);
1795 newn
= (oldn
= x
->t_n
) + 1;
1796 x
->t_vec
= (t_dataslot
*)t_resizebytes(x
->t_vec
,
1797 oldn
* sizeof(*x
->t_vec
), newn
* sizeof(*x
->t_vec
));
1799 x
->t_vec
[oldn
].ds_type
= newtype
;
1800 x
->t_vec
[oldn
].ds_name
= newname
;
1801 x
->t_vec
[oldn
].ds_arraytemplate
= newarraytemplate
;
1803 argc
-= 2; argv
+= 2;
1805 if (templatesym
->s_name
)
1807 x
->t_sym
= templatesym
;
1808 pd_bind(&x
->t_pdobj
, x
->t_sym
);
1810 else x
->t_sym
= templatesym
;
1814 int template_size(t_template
*x
)
1816 return (x
->t_n
* sizeof(t_word
));
1819 int template_find_field(t_template
*x
, t_symbol
*name
, int *p_onset
,
1820 int *p_type
, t_symbol
**p_arraytype
)
1826 bug("template_find_field");
1830 for (i
= 0; i
< n
; i
++)
1831 if (x
->t_vec
[i
].ds_name
== name
)
1833 *p_onset
= i
* sizeof(t_word
);
1834 *p_type
= x
->t_vec
[i
].ds_type
;
1835 *p_arraytype
= x
->t_vec
[i
].ds_arraytemplate
;
1841 t_float
template_getfloat(t_template
*x
, t_symbol
*fieldname
, t_word
*wp
,
1845 t_symbol
*arraytype
;
1847 if (template_find_field(x
, fieldname
, &onset
, &type
, &arraytype
))
1849 if (type
== DT_FLOAT
)
1850 val
= *(t_sample
*)(((char *)wp
) + onset
);
1851 else if (loud
) error("%s.%s: not a number",
1852 x
->t_sym
->s_name
, fieldname
->s_name
);
1854 else if (loud
) error("%s.%s: no such field",
1855 x
->t_sym
->s_name
, fieldname
->s_name
);
1856 return (fixtof(val
));
1859 void template_setfloat(t_template
*x
, t_symbol
*fieldname
, t_word
*wp
,
1860 t_float f
, int loud
)
1863 t_symbol
*arraytype
;
1864 if (template_find_field(x
, fieldname
, &onset
, &type
, &arraytype
))
1866 if (type
== DT_FLOAT
)
1867 *(t_sample
*)(((char *)wp
) + onset
) = ftofix(f
);
1868 else if (loud
) error("%s.%s: not a number",
1869 x
->t_sym
->s_name
, fieldname
->s_name
);
1871 else if (loud
) error("%s.%s: no such field",
1872 x
->t_sym
->s_name
, fieldname
->s_name
);
1875 t_symbol
*template_getsymbol(t_template
*x
, t_symbol
*fieldname
, t_word
*wp
,
1879 t_symbol
*arraytype
;
1880 t_symbol
*val
= &s_
;
1881 if (template_find_field(x
, fieldname
, &onset
, &type
, &arraytype
))
1883 if (type
== DT_SYMBOL
)
1884 val
= *(t_symbol
**)(((char *)wp
) + onset
);
1885 else if (loud
) error("%s.%s: not a symbol",
1886 x
->t_sym
->s_name
, fieldname
->s_name
);
1888 else if (loud
) error("%s.%s: no such field",
1889 x
->t_sym
->s_name
, fieldname
->s_name
);
1893 void template_setsymbol(t_template
*x
, t_symbol
*fieldname
, t_word
*wp
,
1894 t_symbol
*s
, int loud
)
1897 t_symbol
*arraytype
;
1898 if (template_find_field(x
, fieldname
, &onset
, &type
, &arraytype
))
1900 if (type
== DT_SYMBOL
)
1901 *(t_symbol
**)(((char *)wp
) + onset
) = s
;
1902 else if (loud
) error("%s.%s: not a symbol",
1903 x
->t_sym
->s_name
, fieldname
->s_name
);
1905 else if (loud
) error("%s.%s: no such field",
1906 x
->t_sym
->s_name
, fieldname
->s_name
);
1909 /* stringent check to see if a "saved" template, x2, matches the current
1910 one (x1). It's OK if x1 has additional scalar elements but not (yet)
1911 arrays or lists. This is used for reading in "data files". */
1912 int template_match(t_template
*x1
, t_template
*x2
)
1915 if (x1
->t_n
< x2
->t_n
)
1917 for (i
= x2
->t_n
; i
< x1
->t_n
; i
++)
1919 if (x1
->t_vec
[i
].ds_type
== DT_ARRAY
||
1920 x1
->t_vec
[i
].ds_type
== DT_LIST
)
1923 if (x2
->t_n
> x1
->t_n
)
1924 post("add elements...");
1925 for (i
= 0; i
< x2
->t_n
; i
++)
1926 if (!dataslot_matches(&x1
->t_vec
[i
], &x2
->t_vec
[i
], 1))
1931 /* --------------- CONFORMING TO CHANGES IN A TEMPLATE ------------ */
1933 /* the following routines handle updating scalars to agree with changes
1934 in their template. The old template is assumed to be the "installed" one
1935 so we can delete old items; but making new ones we have to avoid scalar_new
1936 which would make an old one whereas we will want a new one (but whose array
1937 elements might still be old ones.
1938 LATER deal with graphics updates too... */
1940 /* conform the word vector of a scalar to the new template */
1941 static void template_conformwords(t_template
*tfrom
, t_template
*tto
,
1942 int *conformaction
, t_word
*wfrom
, t_word
*wto
)
1944 int nfrom
= tfrom
->t_n
, nto
= tto
->t_n
, i
;
1945 for (i
= 0; i
< nto
; i
++)
1947 if (conformaction
[i
] >= 0)
1949 /* we swap the two, in case it's an array or list, so that
1950 when "wfrom" is deleted the old one gets cleaned up. */
1951 t_word wwas
= wto
[i
];
1952 wto
[i
] = wfrom
[conformaction
[i
]];
1953 wfrom
[conformaction
[i
]] = wwas
;
1958 /* conform a scalar, recursively conforming sublists and arrays */
1959 static t_scalar
*template_conformscalar(t_template
*tfrom
, t_template
*tto
,
1960 int *conformaction
, t_glist
*glist
, t_scalar
*scfrom
)
1964 int nto
= tto
->t_n
, nfrom
= tfrom
->t_n
, i
;
1965 t_template
*scalartemplate
;
1966 /* post("conform scalar"); */
1967 /* possibly replace the scalar */
1968 if (scfrom
->sc_template
== tfrom
->t_sym
)
1970 /* see scalar_new() for comment about the gpointer. */
1972 x
= (t_scalar
*)getbytes(sizeof(t_scalar
) +
1973 (tto
->t_n
- 1) * sizeof(*x
->sc_vec
));
1974 x
->sc_gobj
.g_pd
= scalar_class
;
1975 x
->sc_template
= tfrom
->t_sym
;
1976 gpointer_setglist(&gp
, glist
, x
);
1977 /* Here we initialize to the new template, but array and list
1978 elements will still belong to old template. */
1979 word_init(x
->sc_vec
, tto
, &gp
);
1981 template_conformwords(tfrom
, tto
, conformaction
,
1982 scfrom
->sc_vec
, x
->sc_vec
);
1984 /* replace the old one with the new one in the list */
1985 if (glist
->gl_list
== &scfrom
->sc_gobj
)
1987 glist
->gl_list
= &x
->sc_gobj
;
1988 x
->sc_gobj
.g_next
= scfrom
->sc_gobj
.g_next
;
1993 for (y
= glist
->gl_list
; y2
= y
->g_next
; y
= y2
)
1994 if (y2
== &scfrom
->sc_gobj
)
1996 x
->sc_gobj
.g_next
= y2
->g_next
;
1997 y
->g_next
= &x
->sc_gobj
;
2000 bug("template_conformscalar");
2003 /* burn the old one */
2004 pd_free(&scfrom
->sc_gobj
.g_pd
);
2007 scalartemplate
= template_findbyname(x
->sc_template
);
2008 /* convert all array elements and sublists */
2009 for (i
= 0; i
< scalartemplate
->t_n
; i
++)
2011 t_dataslot
*ds
= scalartemplate
->t_vec
+ i
;
2012 if (ds
->ds_type
== DT_LIST
)
2014 t_glist
*gl2
= x
->sc_vec
[i
].w_list
;
2015 template_conformglist(tfrom
, tto
, gl2
, conformaction
);
2017 else if (ds
->ds_type
== DT_ARRAY
)
2019 template_conformarray(tfrom
, tto
, conformaction
,
2020 x
->sc_vec
[i
].w_array
);
2026 /* conform an array, recursively conforming sublists and arrays */
2027 static void template_conformarray(t_template
*tfrom
, t_template
*tto
,
2028 int *conformaction
, t_array
*a
)
2031 if (a
->a_templatesym
== tfrom
->t_sym
)
2033 /* the array elements must all be conformed */
2034 int oldelemsize
= sizeof(t_word
) * tfrom
->t_n
,
2035 newelemsize
= sizeof(t_word
) * tto
->t_n
;
2036 char *newarray
= getbytes(sizeof(t_word
) * tto
->t_n
* a
->a_n
);
2037 char *oldarray
= a
->a_vec
;
2038 if (a
->a_elemsize
!= oldelemsize
)
2039 bug("template_conformarray");
2040 for (i
= 0; i
< a
->a_n
; i
++)
2042 t_word
*wp
= (t_word
*)(newarray
+ newelemsize
* i
);
2043 word_init(wp
, tto
, &a
->a_gp
);
2044 template_conformwords(tfrom
, tto
, conformaction
,
2045 (t_word
*)(oldarray
+ oldelemsize
* i
), wp
);
2048 bug("template_conformarray: this part not written");
2049 /* go through item by item conforming subarrays and sublists... */
2052 /* this routine searches for every scalar in the glist that belongs
2053 to the "from" template and makes it belong to the "to" template. Descend
2055 We don't handle redrawing here; this is to be filled in LATER... */
2057 static void template_conformglist(t_template
*tfrom
, t_template
*tto
,
2058 t_glist
*glist
, int *conformaction
)
2061 /* post("conform glist %s", glist->gl_name->s_name); */
2062 for (g
= glist
->gl_list
; g
; g
= g
->g_next
)
2064 if (pd_class(&g
->g_pd
) == scalar_class
)
2065 g
= &template_conformscalar(tfrom
, tto
, conformaction
,
2066 glist
, (t_scalar
*)g
)->sc_gobj
;
2067 else if (pd_class(&g
->g_pd
) == canvas_class
)
2068 template_conformglist(tfrom
, tto
, (t_glist
*)g
, conformaction
);
2072 /* globally conform all scalars from one template to another */
2073 void template_conform(t_template
*tfrom
, t_template
*tto
)
2075 int nto
= tto
->t_n
, nfrom
= tfrom
->t_n
, i
, j
,
2076 *conformaction
= (int *)getbytes(sizeof(int) * nto
),
2077 *conformedfrom
= (int *)getbytes(sizeof(int) * nfrom
), doit
= 0;
2078 for (i
= 0; i
< nto
; i
++)
2079 conformaction
[i
] = -1;
2080 for (i
= 0; i
< nfrom
; i
++)
2081 conformedfrom
[i
] = 0;
2082 for (i
= 0; i
< nto
; i
++)
2084 t_dataslot
*dataslot
= &tto
->t_vec
[i
];
2085 for (j
= 0; j
< nfrom
; j
++)
2087 t_dataslot
*dataslot2
= &tfrom
->t_vec
[j
];
2088 if (dataslot_matches(dataslot
, dataslot2
, 1))
2090 conformaction
[i
] = j
;
2091 conformedfrom
[j
] = 1;
2095 for (i
= 0; i
< nto
; i
++)
2096 if (conformaction
[i
] < 0)
2098 t_dataslot
*dataslot
= &tto
->t_vec
[i
];
2099 for (j
= 0; j
< nfrom
; j
++)
2100 if (!conformedfrom
[j
] &&
2101 dataslot_matches(dataslot
, &tfrom
->t_vec
[j
], 1))
2103 conformaction
[i
] = j
;
2104 conformedfrom
[j
] = 1;
2109 else for (i
= 0; i
< nto
; i
++)
2110 if (conformaction
[i
] != i
)
2116 /* post("conforming template '%s' to new structure",
2117 tfrom->t_sym->s_name);
2118 for (i = 0; i < nto; i++)
2119 post("... %d", conformaction[i]); */
2120 for (gl
= canvas_list
; gl
; gl
= gl
->gl_next
)
2121 template_conformglist(tfrom
, tto
, gl
, conformaction
);
2123 freebytes(conformaction
, sizeof(int) * nto
);
2124 freebytes(conformedfrom
, sizeof(int) * nfrom
);
2127 t_template
*template_findbyname(t_symbol
*s
)
2131 return (&template_float
);
2132 else return ((t_template
*)pd_findbyclass(s
, template_class
));
2135 t_canvas
*template_findcanvas(t_template
*template)
2139 bug("template_findcanvas");
2140 if (!(gt
= template->t_list
))
2142 return (gt
->x_owner
);
2143 /* return ((t_canvas *)pd_findbyclass(template->t_sym, canvas_class)); */
2146 /* call this when reading a patch from a file to declare what templates
2147 we'll need. If there's already a template, check if it matches.
2148 If it doesn't it's still OK as long as there are no "struct" (gtemplate)
2149 objects hanging from it; we just conform everyone to the new template.
2150 If there are still struct objects belonging to the other template, we're
2151 in trouble. LATER we'll figure out how to conform the new patch's objects
2152 to the pre-existing struct. */
2153 static void *template_usetemplate(void *dummy
, t_symbol
*s
,
2154 int argc
, t_atom
*argv
)
2157 t_symbol
*templatesym
=
2158 canvas_makebindsym(atom_getsymbolarg(0, argc
, argv
));
2162 /* check if there's already a template by this name. */
2163 if ((x
= (t_template
*)pd_findbyclass(templatesym
, template_class
)))
2165 t_template
*y
= template_new(&s_
, argc
, argv
);
2166 /* If the new template is the same as the old one,
2167 there's nothing to do. */
2168 if (!template_match(x
, y
))
2170 /* Are there "struct" objects upholding this template? */
2173 /* don't know what to do here! */
2174 error("%s: template mismatch",
2175 templatesym
->s_name
);
2179 /* conform everyone to the new template */
2180 template_conform(x
, y
);
2181 pd_free(&x
->t_pdobj
);
2182 template_new(templatesym
, argc
, argv
);
2185 pd_free(&y
->t_pdobj
);
2187 /* otherwise, just make one. */
2188 else template_new(templatesym
, argc
, argv
);
2192 /* here we assume someone has already cleaned up all instances of this. */
2193 void template_free(t_template
*x
)
2195 if (*x
->t_sym
->s_name
)
2196 pd_unbind(&x
->t_pdobj
, x
->t_sym
);
2197 t_freebytes(x
->t_vec
, x
->t_n
* sizeof(*x
->t_vec
));
2200 static void template_setup(void)
2202 template_class
= class_new(gensym("template"), 0, (t_method
)template_free
,
2203 sizeof(t_template
), CLASS_PD
, 0);
2204 class_addmethod(pd_canvasmaker
, (t_method
)template_usetemplate
,
2205 gensym("struct"), A_GIMME
, 0);
2209 /* ---------------- gtemplates. One per canvas. ----------- */
2211 /* this is a "text" object that searches for, and if necessary creates,
2212 a "template" (above). Other objects in the canvas then can give drawing
2213 instructions for the template. The template doesn't go away when the
2214 gtemplate is deleted, so that you can replace it with
2215 another one to add new fields, for example. */
2217 static void *gtemplate_donew(t_symbol
*sym
, int argc
, t_atom
*argv
)
2219 t_gtemplate
*x
= (t_gtemplate
*)pd_new(gtemplate_class
);
2220 t_template
*t
= template_findbyname(sym
);
2222 t_symbol
*sx
= gensym("x");
2223 x
->x_owner
= canvas_getcurrent();
2227 x
->x_argv
= (t_atom
*)getbytes(argc
* sizeof(t_atom
));
2228 for (i
= 0; i
< argc
; i
++)
2229 x
->x_argv
[i
] = argv
[i
];
2231 /* already have a template by this name? */
2235 /* if it's already got a "struct" or "gtemplate" object we
2236 just tack this one to the end of the list and leave it
2240 t_gtemplate
*x2
, *x3
;
2241 for (x2
= x
->x_template
->t_list
; x3
= x2
->x_next
; x2
= x3
)
2244 post("template %s: warning: already exists.", sym
->s_name
);
2248 /* if there's none, we just replace the template with
2249 our own and conform it. */
2250 t_template
*y
= template_new(&s_
, argc
, argv
);
2251 /* Unless the new template is different from the old one,
2252 there's nothing to do. */
2253 if (!template_match(t
, y
))
2255 /* conform everyone to the new template */
2256 template_conform(t
, y
);
2257 pd_free(&t
->t_pdobj
);
2258 t
= template_new(sym
, argc
, argv
);
2260 pd_free(&y
->t_pdobj
);
2266 /* otherwise make a new one and we're the only struct on it. */
2267 x
->x_template
= t
= template_new(sym
, argc
, argv
);
2273 static void *gtemplate_new(t_symbol
*s
, int argc
, t_atom
*argv
)
2275 t_gtemplate
*x
= (t_gtemplate
*)pd_new(gtemplate_class
);
2276 t_symbol
*sym
= atom_getsymbolarg(0, argc
, argv
);
2279 return (gtemplate_donew(canvas_makebindsym(sym
), argc
, argv
));
2282 /* old version (0.34) -- delete 2003 or so */
2283 static void *gtemplate_new_old(t_symbol
*s
, int argc
, t_atom
*argv
)
2285 t_gtemplate
*x
= (t_gtemplate
*)pd_new(gtemplate_class
);
2286 t_symbol
*sym
= canvas_makebindsym(canvas_getcurrent()->gl_name
);
2290 post("warning -- 'template' (%s) is obsolete; replace with 'struct'",
2294 return (gtemplate_donew(sym
, argc
, argv
));
2297 t_template
*gtemplate_get(t_gtemplate
*x
)
2299 return (x
->x_template
);
2302 static void gtemplate_free(t_gtemplate
*x
)
2304 /* get off the template's list */
2305 t_template
*t
= x
->x_template
;
2310 /* if we were first on the list, and there are others on
2311 the list, make a new template corresponding to the new
2312 first-on-list and replace teh existing template with it. */
2313 t_template
*z
= template_new(&s_
, x
->x_argc
, x
->x_argv
);
2314 template_conform(t
, z
);
2315 pd_free(&t
->t_pdobj
);
2316 pd_free(&z
->t_pdobj
);
2317 z
= template_new(x
->x_sym
, x
->x_argc
, x
->x_argv
);
2318 z
->t_list
= x
->x_next
;
2324 t_gtemplate
*x2
, *x3
;
2325 for (x2
= t
->t_list
; x3
= x2
->x_next
; x2
= x3
)
2329 x2
->x_next
= x3
->x_next
;
2334 freebytes(x
->x_argv
, sizeof(t_atom
) * x
->x_argc
);
2337 static void gtemplate_setup(void)
2339 gtemplate_class
= class_new(gensym("struct"),
2340 (t_newmethod
)gtemplate_new
, (t_method
)gtemplate_free
,
2341 sizeof(t_gtemplate
), CLASS_NOINLET
, A_GIMME
, 0);
2342 class_addcreator((t_newmethod
)gtemplate_new_old
, gensym("template"),
2346 /* --------------- FIELD DESCRIPTORS ---------------------- */
2348 /* a field descriptor can hold a constant or a variable; if a variable,
2349 it's the name of a field in the template we belong to. LATER, we might
2350 want to cache the offset of the field so we don't have to search for it
2351 every single time we draw the object.
2354 typedef struct _fielddesc
2356 char fd_type
; /* LATER consider removing this? */
2360 t_float fd_float
; /* the field is a constant float */
2361 t_symbol
*fd_symbol
; /* the field is a constant symbol */
2362 t_symbol
*fd_varsym
; /* the field is variable and this is the name */
2366 #define FIELDDESC_SETFLOAT(x, f) \
2367 ((x)->fd_type = A_FLOAT, (x)->fd_var = 0, (x)->fd_un.fd_float = (f))
2368 #define FIELDDESC_SETSYMBOL(x, s) \
2369 ((x)->fd_type = A_SYMBOL, (x)->fd_var = 0, (x)->fd_un.fd_symbol = (s))
2370 #define FIELDDESC_SETVAR(x, s, type) \
2371 ((x)->fd_type = type, (x)->fd_var = 1, (x)->fd_un.fd_varsym = (s))
2375 #define A_ARRAY 55 /* LATER decide whether to enshrine this in m_pd.h */
2377 static void fielddesc_setfloatarg(t_fielddesc
*fd
, int argc
, t_atom
*argv
)
2379 if (argc
<= 0) FIELDDESC_SETFLOAT(fd
, 0);
2380 else if (argv
->a_type
== A_SYMBOL
)
2381 FIELDDESC_SETVAR(fd
, argv
->a_w
.w_symbol
, A_FLOAT
);
2382 else FIELDDESC_SETFLOAT(fd
, argv
->a_w
.w_float
);
2385 static void fielddesc_setarrayarg(t_fielddesc
*fd
, int argc
, t_atom
*argv
)
2387 if (argc
<= 0) FIELDDESC_SETFLOAT(fd
, 0);
2388 else if (argv
->a_type
== A_SYMBOL
)
2389 FIELDDESC_SETVAR(fd
, argv
->a_w
.w_symbol
, A_ARRAY
);
2390 else FIELDDESC_SETFLOAT(fd
, argv
->a_w
.w_float
);
2393 static t_float
fielddesc_getfloat(t_fielddesc
*f
, t_template
*template,
2394 t_word
*wp
, int loud
)
2396 if (f
->fd_type
== A_FLOAT
)
2399 return (template_getfloat(template, f
->fd_un
.fd_varsym
, wp
, loud
));
2400 else return (f
->fd_un
.fd_float
);
2405 error("symbolic data field used as number");
2410 static t_symbol
*fielddesc_getsymbol(t_fielddesc
*f
, t_template
*template,
2411 t_word
*wp
, int loud
)
2413 if (f
->fd_type
== A_SYMBOL
)
2416 return(template_getsymbol(template, f
->fd_un
.fd_varsym
, wp
, loud
));
2417 else return (f
->fd_un
.fd_symbol
);
2422 error("numeric data field used as symbol");
2427 /* ---------------- curves and polygons (joined segments) ---------------- */
2430 curves belong to templates and describe how the data in the template are to
2431 be drawn. The coordinates of the curve (and other display features) can
2432 be attached to fields in the template.
2435 t_class
*curve_class
;
2437 typedef struct _curve
2440 int x_flags
; /* CLOSED and/or BEZ */
2441 t_fielddesc x_fillcolor
;
2442 t_fielddesc x_outlinecolor
;
2443 t_fielddesc x_width
;
2448 static void *curve_new(t_symbol
*classsym
, t_int argc
, t_atom
*argv
)
2450 t_curve
*x
= (t_curve
*)pd_new(curve_class
);
2451 char *classname
= classsym
->s_name
;
2455 if (classname
[0] == 'f')
2459 if (argc
) fielddesc_setfloatarg(&x
->x_fillcolor
, argc
--, argv
++);
2460 else FIELDDESC_SETFLOAT(&x
->x_outlinecolor
, 0);
2462 else classname
+= 4;
2463 if (classname
[0] == 'c') flags
|= BEZ
;
2465 if (argc
) fielddesc_setfloatarg(&x
->x_outlinecolor
, argc
--, argv
++);
2466 else FIELDDESC_SETFLOAT(&x
->x_outlinecolor
, 0);
2467 if (argc
) fielddesc_setfloatarg(&x
->x_width
, argc
--, argv
++);
2468 else FIELDDESC_SETFLOAT(&x
->x_width
, 1);
2469 if (argc
< 0) argc
= 0;
2470 nxy
= (argc
+ (argc
& 1));
2471 x
->x_npoints
= (nxy
>>1);
2472 x
->x_vec
= (t_fielddesc
*)t_getbytes(nxy
* sizeof(t_fielddesc
));
2473 for (i
= 0, fd
= x
->x_vec
; i
< argc
; i
++, fd
++, argv
++)
2474 fielddesc_setfloatarg(fd
, 1, argv
);
2475 if (argc
& 1) FIELDDESC_SETFLOAT(fd
, 0);
2480 /* -------------------- widget behavior for curve ------------ */
2482 static void curve_getrect(t_gobj
*z
, t_glist
*glist
,
2483 t_word
*data
, t_template
*template, float basex
, float basey
,
2484 int *xp1
, int *yp1
, int *xp2
, int *yp2
)
2486 t_curve
*x
= (t_curve
*)z
;
2487 int i
, n
= x
->x_npoints
;
2488 t_fielddesc
*f
= x
->x_vec
;
2489 int x1
= 0x7fffffff, x2
= -0x7fffffff, y1
= 0x7fffffff, y2
= -0x7fffffff;
2490 for (i
= 0, f
= x
->x_vec
; i
< n
; i
++, f
+= 2)
2492 int xloc
= glist_xtopixels(glist
,
2493 basex
+ fielddesc_getfloat(f
, template, data
, 0));
2494 int yloc
= glist_ytopixels(glist
,
2495 basey
+ fielddesc_getfloat(f
+1, template, data
, 0));
2496 if (xloc
< x1
) x1
= xloc
;
2497 if (xloc
> x2
) x2
= xloc
;
2498 if (yloc
< y1
) y1
= yloc
;
2499 if (yloc
> y2
) y2
= yloc
;
2507 static void curve_displace(t_gobj
*z
, t_glist
*glist
,
2508 t_word
*data
, t_template
*template, float basex
, float basey
,
2514 static void curve_select(t_gobj
*z
, t_glist
*glist
,
2515 t_word
*data
, t_template
*template, float basex
, float basey
,
2521 static void curve_activate(t_gobj
*z
, t_glist
*glist
,
2522 t_word
*data
, t_template
*template, float basex
, float basey
,
2528 static int rangecolor(int n
) /* 0 to 9 in 5 steps */
2530 int n2
= n
/2; /* 0 to 4 */
2531 int ret
= (n2
<< 6); /* 0 to 256 in 5 steps */
2532 if (ret
> 255) ret
= 255;
2536 static void numbertocolor(int n
, char *s
)
2538 int red
, blue
, green
;
2541 blue
= ((n
/ 10) % 10);
2543 sprintf(s
, "#%2.2x%2.2x%2.2x", rangecolor(red
), rangecolor(blue
),
2547 static void curve_vis(t_gobj
*z
, t_glist
*glist
,
2548 t_word
*data
, t_template
*template, float basex
, float basey
,
2551 t_curve
*x
= (t_curve
*)z
;
2552 int i
, n
= x
->x_npoints
;
2553 t_fielddesc
*f
= x
->x_vec
;
2559 int flags
= x
->x_flags
, closed
= (flags
& CLOSED
);
2560 float width
= fielddesc_getfloat(&x
->x_width
, template, data
, 1);
2561 char outline
[20], fill
[20];
2562 if (width
< 1) width
= 1;
2564 fielddesc_getfloat(&x
->x_outlinecolor
, template, data
, 1),
2569 fielddesc_getfloat(&x
->x_fillcolor
, template, data
, 1),
2571 sys_vgui(".x%x.c create polygon\\\n",
2572 glist_getcanvas(glist
));
2574 else sys_vgui(".x%x.c create line\\\n",
2575 glist_getcanvas(glist
));
2576 for (i
= 0, f
= x
->x_vec
; i
< n
; i
++, f
+= 2)
2578 float xloc
= glist_xtopixels(glist
,
2579 basex
+ fielddesc_getfloat(f
, template, data
, 1));
2580 float yloc
= glist_ytopixels(glist
,
2581 basey
+ fielddesc_getfloat(f
+1, template, data
, 1));
2582 sys_vgui("%d %d\\\n", (int)xloc
, (int)yloc
);
2584 sys_vgui("-width %f\\\n",
2585 fielddesc_getfloat(&x
->x_width
, template, data
, 1));
2586 if (flags
& CLOSED
) sys_vgui("-fill %s -outline %s\\\n",
2588 else sys_vgui("-fill %s\\\n", outline
);
2589 if (flags
& BEZ
) sys_vgui("-smooth 1\\\n");
2590 sys_vgui("-tags curve%x\n", data
);
2592 else post("warning: curves need at least two points to be graphed");
2596 if (n
> 1) sys_vgui(".x%x.c delete curve%x\n",
2597 glist_getcanvas(glist
), data
);
2601 static int curve_motion_field
;
2602 static float curve_motion_xcumulative
;
2603 static float curve_motion_xbase
;
2604 static float curve_motion_xper
;
2605 static float curve_motion_ycumulative
;
2606 static float curve_motion_ybase
;
2607 static float curve_motion_yper
;
2608 static t_glist
*curve_motion_glist
;
2609 static t_gobj
*curve_motion_gobj
;
2610 static t_word
*curve_motion_wp
;
2611 static t_template
*curve_motion_template
;
2613 /* LATER protect against the template changing or the scalar disappearing
2614 probably by attaching a gpointer here ... */
2616 static void curve_motion(void *z
, t_floatarg dx
, t_floatarg dy
)
2618 t_curve
*x
= (t_curve
*)z
;
2619 t_fielddesc
*f
= x
->x_vec
+ curve_motion_field
;
2620 curve_motion_xcumulative
+= dx
;
2621 curve_motion_ycumulative
+= dy
;
2624 template_setfloat(curve_motion_template
,
2627 curve_motion_xbase
+ curve_motion_xcumulative
* curve_motion_xper
,
2632 template_setfloat(curve_motion_template
,
2633 (f
+1)->fd_un
.fd_varsym
,
2635 curve_motion_ybase
+ curve_motion_ycumulative
* curve_motion_yper
,
2638 glist_redrawitem(curve_motion_glist
, curve_motion_gobj
);
2641 static int curve_click(t_gobj
*z
, t_glist
*glist
,
2642 t_scalar
*sc
, t_template
*template, float basex
, float basey
,
2643 int xpix
, int ypix
, int shift
, int alt
, int dbl
, int doit
)
2645 t_curve
*x
= (t_curve
*)z
;
2646 int i
, n
= x
->x_npoints
;
2648 int besterror
= 0x7fffffff;
2649 t_fielddesc
*f
= x
->x_vec
;
2650 t_word
*data
= sc
->sc_vec
;
2651 for (i
= 0, f
= x
->x_vec
; i
< n
; i
++, f
+= 2)
2653 int xloc
= glist_xtopixels(glist
,
2654 basex
+ fielddesc_getfloat(f
, template, data
, 0));
2655 int yloc
= glist_ytopixels(glist
,
2656 basey
+ fielddesc_getfloat(f
+1, template, data
, 0));
2657 int xerr
= xloc
- xpix
, yerr
= yloc
- ypix
;
2658 if (!f
->fd_var
&& !(f
+1)->fd_var
)
2666 if (xerr
< besterror
)
2670 curve_motion_xbase
= fielddesc_getfloat(f
, template, data
, 0);
2671 curve_motion_ybase
= fielddesc_getfloat(f
+1, template, data
, 0);
2678 curve_motion_xper
= glist_pixelstox(glist
, 1)
2679 - glist_pixelstox(glist
, 0);
2680 curve_motion_yper
= glist_pixelstoy(glist
, 1)
2681 - glist_pixelstoy(glist
, 0);
2682 curve_motion_xcumulative
= curve_motion_ycumulative
= 0;
2683 curve_motion_glist
= glist
;
2684 curve_motion_gobj
= &sc
->sc_gobj
;
2685 curve_motion_wp
= data
;
2686 curve_motion_field
= 2*bestn
;
2687 curve_motion_template
= template;
2688 glist_grab(glist
, z
, curve_motion
, 0, xpix
, ypix
);
2693 t_parentwidgetbehavior curve_widgetbehavior
=
2703 static void curve_free(t_curve
*x
)
2705 t_freebytes(x
->x_vec
, 2 * x
->x_npoints
* sizeof(*x
->x_vec
));
2708 static void curve_setup(void)
2710 curve_class
= class_new(gensym("drawpolygon"), (t_newmethod
)curve_new
,
2711 (t_method
)curve_free
, sizeof(t_curve
), CLASS_NOINLET
, A_GIMME
, 0);
2712 class_setdrawcommand(curve_class
);
2713 class_addcreator((t_newmethod
)curve_new
, gensym("drawcurve"),
2715 class_addcreator((t_newmethod
)curve_new
, gensym("filledpolygon"),
2717 class_addcreator((t_newmethod
)curve_new
, gensym("filledcurve"),
2719 class_setparentwidget(curve_class
, &curve_widgetbehavior
);
2722 /* --------- plots for showing arrays --------------- */
2724 t_class
*plot_class
;
2726 typedef struct _plot
2730 t_fielddesc x_outlinecolor
;
2731 t_fielddesc x_width
;
2738 static void *plot_new(t_symbol
*classsym
, t_int argc
, t_atom
*argv
)
2740 t_plot
*x
= (t_plot
*)pd_new(plot_class
);
2744 t_symbol
*firstarg
= atom_getsymbolarg(0, argc
, argv
);
2745 if (!strcmp(firstarg
->s_name
, "curve"))
2750 if (argc
) fielddesc_setarrayarg(&x
->x_data
, argc
--, argv
++);
2751 else FIELDDESC_SETFLOAT(&x
->x_data
, 1);
2752 if (argc
) fielddesc_setfloatarg(&x
->x_outlinecolor
, argc
--, argv
++);
2753 else FIELDDESC_SETFLOAT(&x
->x_outlinecolor
, 0);
2754 if (argc
) fielddesc_setfloatarg(&x
->x_width
, argc
--, argv
++);
2755 else FIELDDESC_SETFLOAT(&x
->x_width
, 1);
2756 if (argc
) fielddesc_setfloatarg(&x
->x_xloc
, argc
--, argv
++);
2757 else FIELDDESC_SETFLOAT(&x
->x_xloc
, 1);
2758 if (argc
) fielddesc_setfloatarg(&x
->x_yloc
, argc
--, argv
++);
2759 else FIELDDESC_SETFLOAT(&x
->x_yloc
, 1);
2760 if (argc
) fielddesc_setfloatarg(&x
->x_xinc
, argc
--, argv
++);
2761 else FIELDDESC_SETFLOAT(&x
->x_xinc
, 1);
2766 /* -------------------- widget behavior for plot ------------ */
2769 /* get everything we'll need from the owner template of the array being
2770 plotted. Not used for garrays, but see below */
2771 static int plot_readownertemplate(t_plot
*x
,
2772 t_word
*data
, t_template
*ownertemplate
,
2773 t_symbol
**elemtemplatesymp
, t_array
**arrayp
,
2774 float *linewidthp
, float *xlocp
, float *xincp
, float *ylocp
)
2776 int arrayonset
, type
;
2777 t_symbol
*elemtemplatesym
;
2780 /* find the data and verify it's an array */
2781 if (x
->x_data
.fd_type
!= A_ARRAY
|| !x
->x_data
.fd_var
)
2783 error("plot: needs an array field");
2786 if (!template_find_field(ownertemplate
, x
->x_data
.fd_un
.fd_varsym
,
2787 &arrayonset
, &type
, &elemtemplatesym
))
2789 error("plot: %s: no such field", x
->x_data
.fd_un
.fd_varsym
->s_name
);
2792 if (type
!= DT_ARRAY
)
2794 error("plot: %s: not an array", x
->x_data
.fd_un
.fd_varsym
->s_name
);
2797 array
= *(t_array
**)(((char *)data
) + arrayonset
);
2798 *linewidthp
= fielddesc_getfloat(&x
->x_width
, ownertemplate
, data
, 1);
2799 *xlocp
= fielddesc_getfloat(&x
->x_xloc
, ownertemplate
, data
, 1);
2800 *xincp
= fielddesc_getfloat(&x
->x_xinc
, ownertemplate
, data
, 1);
2801 *ylocp
= fielddesc_getfloat(&x
->x_yloc
, ownertemplate
, data
, 1);
2802 *elemtemplatesymp
= elemtemplatesym
;
2807 /* get everything else you could possibly need about a plot,
2808 either for plot's own purposes or for plotting a "garray" */
2809 int array_getfields(t_symbol
*elemtemplatesym
,
2810 t_canvas
**elemtemplatecanvasp
,
2811 t_template
**elemtemplatep
, int *elemsizep
,
2812 int *xonsetp
, int *yonsetp
, int *wonsetp
)
2814 int arrayonset
, elemsize
, yonset
, wonset
, xonset
, type
;
2815 t_template
*elemtemplate
;
2817 t_canvas
*elemtemplatecanvas
= 0;
2819 /* the "float" template is special in not having to have a canvas;
2820 template_findbyname is hardwired to return a predefined
2823 if (!(elemtemplate
= template_findbyname(elemtemplatesym
)))
2825 error("plot: %s: no such template", elemtemplatesym
->s_name
);
2828 if (!((elemtemplatesym
== &s_float
) ||
2829 (elemtemplatecanvas
= template_findcanvas(elemtemplate
))))
2831 error("plot: %s: no canvas for this template", elemtemplatesym
->s_name
);
2834 elemsize
= elemtemplate
->t_n
* sizeof(t_word
);
2835 if (!template_find_field(elemtemplate
, gensym("y"), &yonset
, &type
, &dummy
)
2836 || type
!= DT_FLOAT
)
2838 if (!template_find_field(elemtemplate
, gensym("x"), &xonset
, &type
, &dummy
)
2839 || type
!= DT_FLOAT
)
2841 if (!template_find_field(elemtemplate
, gensym("w"), &wonset
, &type
, &dummy
)
2842 || type
!= DT_FLOAT
)
2845 /* fill in slots for return values */
2846 *elemtemplatecanvasp
= elemtemplatecanvas
;
2847 *elemtemplatep
= elemtemplate
;
2848 *elemsizep
= elemsize
;
2855 static void plot_getrect(t_gobj
*z
, t_glist
*glist
,
2856 t_word
*data
, t_template
*template, float basex
, float basey
,
2857 int *xp1
, int *yp1
, int *xp2
, int *yp2
)
2859 t_plot
*x
= (t_plot
*)z
;
2860 int elemsize
, yonset
, wonset
, xonset
;
2861 t_canvas
*elemtemplatecanvas
;
2862 t_template
*elemtemplate
;
2863 t_symbol
*elemtemplatesym
;
2864 float linewidth
, xloc
, xinc
, yloc
;
2866 float x1
= 0x7fffffff, y1
= 0x7fffffff, x2
= -0x7fffffff, y2
= -0x7fffffff;
2868 float xpix
, ypix
, wpix
;
2870 if (!plot_readownertemplate(x
, data
, template,
2871 &elemtemplatesym
, &array
, &linewidth
, &xloc
, &xinc
, &yloc
) &&
2872 !array_getfields(elemtemplatesym
, &elemtemplatecanvas
,
2873 &elemtemplate
, &elemsize
, &xonset
, &yonset
, &wonset
))
2875 for (i
= 0; i
< array
->a_n
; i
++)
2877 array_getcoordinate(glist
, (char *)(array
->a_vec
) + i
* elemsize
,
2878 xonset
, yonset
, wonset
, i
, basex
+ xloc
, basey
+ yloc
, xinc
,
2879 &xpix
, &ypix
, &wpix
);
2884 if (ypix
- wpix
< y1
)
2886 if (ypix
+ wpix
> y2
)
2897 static void plot_displace(t_gobj
*z
, t_glist
*glist
,
2898 t_word
*data
, t_template
*template, float basex
, float basey
,
2904 static void plot_select(t_gobj
*z
, t_glist
*glist
,
2905 t_word
*data
, t_template
*template, float basex
, float basey
,
2911 static void plot_activate(t_gobj
*z
, t_glist
*glist
,
2912 t_word
*data
, t_template
*template, float basex
, float basey
,
2918 static void plot_vis(t_gobj
*z
, t_glist
*glist
,
2919 t_word
*data
, t_template
*template, float basex
, float basey
,
2922 t_plot
*x
= (t_plot
*)z
;
2923 int elemsize
, yonset
, wonset
, xonset
;
2924 t_canvas
*elemtemplatecanvas
;
2925 t_template
*elemtemplate
;
2926 t_symbol
*elemtemplatesym
;
2927 float linewidth
, xloc
, xinc
, yloc
;
2931 if (plot_readownertemplate(x
, data
, template,
2932 &elemtemplatesym
, &array
, &linewidth
, &xloc
, &xinc
, &yloc
) ||
2933 array_getfields(elemtemplatesym
, &elemtemplatecanvas
,
2934 &elemtemplate
, &elemsize
, &xonset
, &yonset
, &wonset
))
2937 elem
= (char *)array
->a_vec
;
2941 int lastpixel
= -1, ndrawn
= 0;
2942 float xsum
, yval
= 0, wval
= 0, xpix
;
2945 /* draw the trace */
2946 numbertocolor(fielddesc_getfloat(&x
->x_outlinecolor
, template, data
, 1),
2950 /* found "w" field which controls linewidth. The trace is
2951 a filled polygon with 2n points. */
2952 sys_vgui(".x%x.c create polygon \\\n",
2953 glist_getcanvas(glist
));
2955 for (i
= 0, xsum
= xloc
; i
< nelem
; i
++)
2959 usexloc
= xloc
+ *(float *)((elem
+ elemsize
* i
) + xonset
);
2960 else usexloc
= xsum
, xsum
+= xinc
;
2962 yval
= *(float *)((elem
+ elemsize
* i
) + yonset
);
2964 wval
= *(float *)((elem
+ elemsize
* i
) + wonset
);
2965 xpix
= glist_xtopixels(glist
, basex
+ usexloc
);
2967 if (xonset
>= 0 || ixpix
!= lastpixel
)
2969 sys_vgui("%d %f \\\n", ixpix
,
2970 glist_ytopixels(glist
,
2971 basey
+ yloc
+ yval
- wval
));
2975 if (ndrawn
>= 1000) goto ouch
;
2978 for (i
= nelem
-1; i
>= 0; i
--)
2982 usexloc
= xloc
+ *(float *)((elem
+ elemsize
* i
) + xonset
);
2983 else xsum
-= xinc
, usexloc
= xsum
;
2985 yval
= *(float *)((elem
+ elemsize
* i
) + yonset
);
2987 wval
= *(float *)((elem
+ elemsize
* i
) + wonset
);
2988 xpix
= glist_xtopixels(glist
, basex
+ usexloc
);
2990 if (xonset
>= 0 || ixpix
!= lastpixel
)
2992 sys_vgui("%d %f \\\n", ixpix
, glist_ytopixels(glist
,
2993 basey
+ yloc
+ yval
+ wval
));
2997 if (ndrawn
>= 1000) goto ouch
;
2999 /* TK will complain if there aren't at least 3 points. There
3000 should be at least two already. */
3003 sys_vgui("%d %f \\\n", ixpix
+ 10, glist_ytopixels(glist
,
3004 basey
+ yloc
+ yval
+ wval
));
3005 sys_vgui("%d %f \\\n", ixpix
+ 10, glist_ytopixels(glist
,
3006 basey
+ yloc
+ yval
- wval
));
3009 sys_vgui(" -width 1 -fill %s -outline %s\\\n", outline
, outline
);
3010 if (x
->x_flags
& BEZ
) sys_vgui("-smooth 1\\\n");
3012 sys_vgui("-tags plot%x\n", data
);
3014 else if (linewidth
> 0)
3016 /* no "w" field. If the linewidth is positive, draw a
3017 segmented line with the requested width; otherwise don't
3018 draw the trace at all. */
3019 sys_vgui(".x%x.c create line \\\n", glist_getcanvas(glist
));
3021 for (xsum
= xloc
, i
= 0; i
< nelem
; i
++)
3025 usexloc
= xloc
+ *(float *)((elem
+ elemsize
* i
) + xonset
);
3026 else usexloc
= xsum
, xsum
+= xinc
;
3028 yval
= *(float *)((elem
+ elemsize
* i
) + yonset
);
3030 xpix
= glist_xtopixels(glist
, basex
+ usexloc
);
3032 if (xonset
>= 0 || ixpix
!= lastpixel
)
3034 sys_vgui("%d %f \\\n", ixpix
,
3035 glist_ytopixels(glist
, basey
+ yloc
+ yval
));
3039 if (ndrawn
>= 1000) break;
3041 /* TK will complain if there aren't at least 2 points... */
3042 if (ndrawn
== 0) sys_vgui("0 0 0 0 \\\n");
3043 else if (ndrawn
== 1) sys_vgui("%d %f \\\n", ixpix
+ 10,
3044 glist_ytopixels(glist
, basey
+ yloc
+ yval
));
3046 sys_vgui("-width %f\\\n", linewidth
);
3047 sys_vgui("-fill %s\\\n", outline
);
3048 if (x
->x_flags
& BEZ
) sys_vgui("-smooth 1\\\n");
3050 sys_vgui("-tags plot%x\n", data
);
3052 /* We're done with the outline; now draw all the points.
3053 This code is inefficient since the template has to be
3054 searched for drawing instructions for every last point. */
3056 for (xsum
= xloc
, i
= 0; i
< nelem
; i
++)
3058 float usexloc
, useyloc
;
3061 usexloc
= basex
+ xloc
+
3062 *(float *)((elem
+ elemsize
* i
) + xonset
);
3063 else usexloc
= basex
+ xsum
, xsum
+= xinc
;
3065 yval
= *(float *)((elem
+ elemsize
* i
) + yonset
);
3067 useyloc
= basey
+ yloc
+ yval
;
3068 for (y
= elemtemplatecanvas
->gl_list
; y
; y
= y
->g_next
)
3070 t_parentwidgetbehavior
*wb
= pd_getparentwidget(&y
->g_pd
);
3072 (*wb
->w_parentvisfn
)(y
, glist
,
3073 (t_word
*)(elem
+ elemsize
* i
),
3074 elemtemplate
, usexloc
, useyloc
, vis
);
3080 /* un-draw the individual points */
3082 for (i
= 0; i
< nelem
; i
++)
3085 for (y
= elemtemplatecanvas
->gl_list
; y
; y
= y
->g_next
)
3087 t_parentwidgetbehavior
*wb
= pd_getparentwidget(&y
->g_pd
);
3089 (*wb
->w_parentvisfn
)(y
, glist
,
3090 (t_word
*)(elem
+ elemsize
* i
), elemtemplate
,
3094 /* and then the trace */
3095 sys_vgui(".x%x.c delete plot%x\n",
3096 glist_getcanvas(glist
), data
);
3101 static int plot_click(t_gobj
*z
, t_glist
*glist
,
3102 t_scalar
*sc
, t_template
*template, float basex
, float basey
,
3103 int xpix
, int ypix
, int shift
, int alt
, int dbl
, int doit
)
3105 t_plot
*x
= (t_plot
*)z
;
3106 t_symbol
*elemtemplatesym
;
3107 float linewidth
, xloc
, xinc
, yloc
;
3109 t_word
*data
= sc
->sc_vec
;
3111 if (!plot_readownertemplate(x
, data
, template,
3112 &elemtemplatesym
, &array
, &linewidth
, &xloc
, &xinc
, &yloc
))
3114 return (array_doclick(array
, glist
, &sc
->sc_gobj
,
3116 linewidth
, basex
+ xloc
, xinc
, basey
+ yloc
,
3117 xpix
, ypix
, shift
, alt
, dbl
, doit
));
3122 t_parentwidgetbehavior plot_widgetbehavior
=
3132 static void plot_setup(void)
3134 plot_class
= class_new(gensym("plot"), (t_newmethod
)plot_new
, 0,
3135 sizeof(t_plot
), CLASS_NOINLET
, A_GIMME
, 0);
3136 class_setdrawcommand(plot_class
);
3137 class_setparentwidget(plot_class
, &plot_widgetbehavior
);
3140 /* ---------------- drawnumber: draw a number ---------------- */
3143 drawnumbers draw numeric fields at controllable locations, with
3144 controllable color and label .
3145 invocation: (drawnumber|drawsymbol) variable x y color label
3148 t_class
*drawnumber_class
;
3150 #define DRAW_SYMBOL 1
3152 typedef struct _drawnumber
3155 t_fielddesc x_value
;
3158 t_fielddesc x_color
;
3163 static void *drawnumber_new(t_symbol
*classsym
, t_int argc
, t_atom
*argv
)
3165 t_drawnumber
*x
= (t_drawnumber
*)pd_new(drawnumber_class
);
3166 char *classname
= classsym
->s_name
;
3168 if (classname
[4] == 's')
3169 flags
|= DRAW_SYMBOL
;
3171 if (argc
) fielddesc_setfloatarg(&x
->x_value
, argc
--, argv
++);
3172 else FIELDDESC_SETFLOAT(&x
->x_value
, 0);
3173 if (argc
) fielddesc_setfloatarg(&x
->x_xloc
, argc
--, argv
++);
3174 else FIELDDESC_SETFLOAT(&x
->x_xloc
, 0);
3175 if (argc
) fielddesc_setfloatarg(&x
->x_yloc
, argc
--, argv
++);
3176 else FIELDDESC_SETFLOAT(&x
->x_yloc
, 0);
3177 if (argc
) fielddesc_setfloatarg(&x
->x_color
, argc
--, argv
++);
3178 else FIELDDESC_SETFLOAT(&x
->x_color
, 1);
3180 x
->x_label
= atom_getsymbolarg(0, argc
, argv
);
3181 else x
->x_label
= &s_
;
3186 /* -------------------- widget behavior for drawnumber ------------ */
3188 #define DRAWNUMBER_BUFSIZE 80
3189 static void drawnumber_sprintf(t_drawnumber
*x
, char *buf
, t_atom
*ap
)
3192 strncpy(buf
, x
->x_label
->s_name
, DRAWNUMBER_BUFSIZE
);
3193 buf
[DRAWNUMBER_BUFSIZE
- 1] = 0;
3194 nchars
= strlen(buf
);
3195 atom_string(ap
, buf
+ nchars
, DRAWNUMBER_BUFSIZE
- nchars
);
3198 static void drawnumber_getrect(t_gobj
*z
, t_glist
*glist
,
3199 t_word
*data
, t_template
*template, float basex
, float basey
,
3200 int *xp1
, int *yp1
, int *xp2
, int *yp2
)
3202 t_drawnumber
*x
= (t_drawnumber
*)z
;
3204 int xloc
= glist_xtopixels(glist
,
3205 basex
+ fielddesc_getfloat(&x
->x_xloc
, template, data
, 0));
3206 int yloc
= glist_ytopixels(glist
,
3207 basey
+ fielddesc_getfloat(&x
->x_yloc
, template, data
, 0));
3208 int font
= glist_getfont(glist
);
3209 int fontwidth
= sys_fontwidth(font
), fontheight
= sys_fontheight(font
);
3210 char buf
[DRAWNUMBER_BUFSIZE
];
3211 if (x
->x_flags
& DRAW_SYMBOL
)
3212 SETSYMBOL(&at
, fielddesc_getsymbol(&x
->x_value
, template, data
, 0));
3213 else SETFLOAT(&at
, fielddesc_getfloat(&x
->x_value
, template, data
, 0));
3214 drawnumber_sprintf(x
, buf
, &at
);
3217 *xp2
= xloc
+ fontwidth
* strlen(buf
);
3218 *yp2
= yloc
+ fontheight
;
3221 static void drawnumber_displace(t_gobj
*z
, t_glist
*glist
,
3222 t_word
*data
, t_template
*template, float basex
, float basey
,
3228 static void drawnumber_select(t_gobj
*z
, t_glist
*glist
,
3229 t_word
*data
, t_template
*template, float basex
, float basey
,
3232 post("drawnumber_select %d", state
);
3236 static void drawnumber_activate(t_gobj
*z
, t_glist
*glist
,
3237 t_word
*data
, t_template
*template, float basex
, float basey
,
3240 post("drawnumber_activate %d", state
);
3243 static void drawnumber_vis(t_gobj
*z
, t_glist
*glist
,
3244 t_word
*data
, t_template
*template, float basex
, float basey
,
3247 t_drawnumber
*x
= (t_drawnumber
*)z
;
3252 int xloc
= glist_xtopixels(glist
,
3253 basex
+ fielddesc_getfloat(&x
->x_xloc
, template, data
, 0));
3254 int yloc
= glist_ytopixels(glist
,
3255 basey
+ fielddesc_getfloat(&x
->x_yloc
, template, data
, 0));
3256 char colorstring
[20], buf
[DRAWNUMBER_BUFSIZE
];
3257 numbertocolor(fielddesc_getfloat(&x
->x_color
, template, data
, 1),
3259 if (x
->x_flags
& DRAW_SYMBOL
)
3260 SETSYMBOL(&at
, fielddesc_getsymbol(&x
->x_value
, template, data
, 0));
3261 else SETFLOAT(&at
, fielddesc_getfloat(&x
->x_value
, template, data
, 0));
3262 drawnumber_sprintf(x
, buf
, &at
);
3263 sys_vgui(".x%x.c create text %d %d -anchor nw -fill %s -text {%s}",
3264 glist_getcanvas(glist
), xloc
, yloc
, colorstring
, buf
);
3265 sys_vgui(" -font -*-courier-bold--normal--%d-*",
3266 sys_hostfontsize(glist_getfont(glist
)));
3267 sys_vgui(" -tags drawnumber%x\n", data
);
3269 else sys_vgui(".x%x.c delete drawnumber%x\n", glist_getcanvas(glist
), data
);
3272 static float drawnumber_motion_ycumulative
;
3273 static t_glist
*drawnumber_motion_glist
;
3274 static t_gobj
*drawnumber_motion_gobj
;
3275 static t_word
*drawnumber_motion_wp
;
3276 static t_template
*drawnumber_motion_template
;
3278 /* LATER protect against the template changing or the scalar disappearing
3279 probably by attaching a gpointer here ... */
3281 static void drawnumber_motion(void *z
, t_floatarg dx
, t_floatarg dy
)
3283 t_drawnumber
*x
= (t_drawnumber
*)z
;
3284 t_fielddesc
*f
= &x
->x_value
;
3285 drawnumber_motion_ycumulative
-= dy
;
3286 template_setfloat(drawnumber_motion_template
,
3288 drawnumber_motion_wp
,
3289 drawnumber_motion_ycumulative
,
3291 glist_redrawitem(drawnumber_motion_glist
, drawnumber_motion_gobj
);
3294 static int drawnumber_click(t_gobj
*z
, t_glist
*glist
,
3295 t_scalar
*sc
, t_template
*template, float basex
, float basey
,
3296 int xpix
, int ypix
, int shift
, int alt
, int dbl
, int doit
)
3298 t_drawnumber
*x
= (t_drawnumber
*)z
;
3300 t_word
*data
= sc
->sc_vec
;
3301 drawnumber_getrect(z
, glist
,
3302 sc
->sc_vec
, template, basex
, basey
,
3303 &x1
, &y1
, &x2
, &y2
);
3304 if (xpix
>= x1
&& xpix
<= x2
&& ypix
>= y1
&& ypix
<= y2
3305 && x
->x_value
.fd_var
)
3309 drawnumber_motion_glist
= glist
;
3310 drawnumber_motion_gobj
= &sc
->sc_gobj
;
3311 drawnumber_motion_wp
= data
;
3312 drawnumber_motion_template
= template;
3313 drawnumber_motion_ycumulative
=
3314 fielddesc_getfloat(&x
->x_value
, template, data
, 0);
3315 glist_grab(glist
, z
, drawnumber_motion
, 0, xpix
, ypix
);
3322 t_parentwidgetbehavior drawnumber_widgetbehavior
=
3325 drawnumber_displace
,
3327 drawnumber_activate
,
3332 static void drawnumber_free(t_drawnumber
*x
)
3336 static void drawnumber_setup(void)
3338 drawnumber_class
= class_new(gensym("drawnumber"),
3339 (t_newmethod
)drawnumber_new
, (t_method
)drawnumber_free
,
3340 sizeof(t_drawnumber
), CLASS_NOINLET
, A_GIMME
, 0);
3341 class_setdrawcommand(drawnumber_class
);
3342 class_addcreator((t_newmethod
)drawnumber_new
, gensym("drawsymbol"),
3344 class_setparentwidget(drawnumber_class
, &drawnumber_widgetbehavior
);
3347 /* ---------------------- setup function ---------------------------- */
3349 void g_template_setup(void)
3353 template_float
.t_pdobj
= template_class
;